У меня есть существующая установка, которая включает сборки .NET, зарегистрированные для COM-взаимодействия и установленные в GAC. Эти библиотеки DLL используются только неуправляемым EXE, который мы также включаем в установку.

Простой примерный компонент (замаскированный от реального) выглядит так:

  <Component Id="MyApp.ClientInterop.dll" Guid="{9A9C2B62-531C-4E60-ABD2-EDD447643C4F}">
    <Class Id="{963057C7-83B4-4602-87B4-B0AB9D3D149A}" Context="InprocServer32" Description="MyApp.ClientInterop.ClientAppUpdate" ThreadingModel="both" ForeignServer="mscoree.dll">
      <ProgId Id="MyApp_Interop.ClientAppUpdate" Description="MyApp.ClientInterop.ClientAppUpdate" />
    </Class>
    <File Id="MyApp.ClientInterop.dll" Name="MyApp.ClientInterop.dll" KeyPath="yes" Assembly=".net">
      <TypeLib Id="{08963623-70A8-4DD8-A8DA-EAF209919797}" Description="MyApp_ClientInterop" Language="0" MajorVersion="1" MinorVersion="0">
        <Interface Id="{207BB6C4-3054-4853-BA20-40D99EA6ACFE}" Name="IClientAppUpdate" ProxyStubClassId="{00020424-0000-0000-C000-000000000046}" ProxyStubClassId32="{00020424-0000-0000-C000-000000000046}" />
      </TypeLib>
    </File>
    <RegistryValue Root="HKCR" Key="CLSID\{963057C7-83B4-4602-87B4-B0AB9D3D149A}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{963057C7-83B4-4602-87B4-B0AB9D3D149A}\InprocServer32\1.0.0.0" Name="Class" Value="MyApp.ClientInterop.ClientAppUpdate" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{963057C7-83B4-4602-87B4-B0AB9D3D149A}\InprocServer32\1.0.0.0" Name="Assembly" Value="MyApp.ClientInterop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cf47a01d50a7b0f5" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{963057C7-83B4-4602-87B4-B0AB9D3D149A}\InprocServer32\1.0.0.0" Name="RuntimeVersion" Value="v4.0.30319" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{963057C7-83B4-4602-87B4-B0AB9D3D149A}\InprocServer32" Name="Class" Value="MyApp.ClientInterop.ClientAppUpdate" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{963057C7-83B4-4602-87B4-B0AB9D3D149A}\InprocServer32" Name="Assembly" Value="MyApp.ClientInterop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cf47a01d50a7b0f5" Type="string" Action="write" />
    <RegistryValue Root="HKCR" Key="CLSID\{963057C7-83B4-4602-87B4-B0AB9D3D149A}\InprocServer32" Name="RuntimeVersion" Value="v4.0.30319" Type="string" Action="write" />
  </Component>

По ряду причин, по которым я не буду здесь вдаваться, мы хотели бы изменить архитектуру приложения, чтобы библиотеки DLL располагались в папке с исполняемым файлом, а не в GAC.

Можно ли сделать это с помощью серьезного обновления, не требуя от пользователя полного удаления предыдущей версии. Наш установщик построен по порядку, поэтому старая версия удаляется во время завершения, потому что большинство обновлений изменяют только небольшой процент компонентов.

Изначально я планировал внести следующие изменения в каждый компонент GAC:

  1. Удалить атрибут Assembly = ". Net"
  2. Создать новый Guid для элемента Component

Это должно работать с файловой системой. Однако я не уверен, что произойдет с элементами,,, и. Если я их не изменю, я подозреваю, что они будут удалены, когда старая версия будет удалена в конце, в результате чего установка будет прервана.

Это точное толкование? Означает ли это, что мне нужно будет принудительно установить новые значения Interface / Typelib / CLSID для всех моих классов взаимодействия? У меня есть более 1000 классов, представленных через Interop в этом проекте.

Могу ли я изменить последовательность так, чтобы сначала устанавливался старый продукт? Я озабочен этим, потому что это означает, что я должен придерживаться этой последовательности, пока я не буду уверен, что все мои клиенты вышли за рамки этого выпуска. Это также значительно увеличит время установки (что было протестировано ранее).

Возможно, есть еще один вариант, о котором я не знаю?

0
hurcane 14 Авг 2014 в 00:42

1 ответ

Лучший ответ

Выполнение крупного обновления с помощью RemoveExistingProducts вначале было бы безопаснее, так сказать, с чистого листа. Однако я думаю, что это сработает с REP в конце, если:

  1. Ваши сборки получают новый идентификатор компонента, чтобы старые сборки продукта были удалены из GAC.

  2. Записи реестра не версируются, поэтому они всегда перезаписываются. У вас должна быть возможность сохранить те же идентификаторы компонентов WiX, но вам все равно нужно будет добавить местоположение CodeBase, чтобы было легко увидеть, все ли это сработало. Очевидно, что после обновления вам не понадобятся сборки в GAC, сборки в обычной файловой системе и записи реестра CodeBase, указывающие на них, и клиенты, которые могут называть их нормально :)

0
PhilDW 14 Авг 2014 в 01:05
Имеет ли смысл создавать два элемента REP с условиями, которые задаются версией? Например: если "критическая" версия - 10.0, переменные будут установлены так, чтобы REP запускался раньше. Последующее выполнение было бы обратным условием.
 – 
hurcane
14 Авг 2014 в 23:18
Вы можете сделать это, если хотите, чтобы все будущие продукты с самого начала обновлялись с помощью REP. Вы должны использовать механизм обновления, чтобы установить свойство, если эта конкретная версия найдена (или более ранние, как я предполагаю), а затем ранний REP зависит от этого свойства, а более поздний - не от этого свойства. Я не могу придумать ничего плохого в этом.
 – 
PhilDW
15 Авг 2014 в 01:02