Создание и установка Typelib с помощью WiX - PullRequest
22 голосов
/ 20 февраля 2009

После запроса о том, что Visual Studio делает для регистрации библиотеки COM , выяснилось, что VS сделал две вещи для регистрации COM:

  1. Зарегистрированная библиотека COM
  2. Создает и регистрирует библиотеку типов

Кажется, Visual Studio выполняет эту регистрацию, используя regasm.exe. Для первой части (прямая регистрация COM) использование tallow или heat (WiX 2.0 или WiX 3.0), кажется, дает всю основную информацию о регистрации COM правильно.

Однако то, что, похоже, не делает tallow / heat, - это установка библиотеки типов. Можно было бы создать настраиваемое действие для этого с помощью установщика WiX и regasm.exe, но запуск настраиваемых действий не является наилучшей практикой, когда речь идет об установщиках на основе установщика Microsoft.

После дальнейших исследований похоже, что у msi есть возможность генерировать библиотеку типов после установки. На самом деле WiX, кажется, имеет прямую поддержку для этого! В элемент файла вы можете добавить элемент Typelib . Фактически, статья здесь о wix содержит пример заполнения элемента TypeLib элементами Interface .

Кажется, что для элемента интерфейса есть как минимум два обязательных атрибута:

  1. Id
  2. Имя

Ларри Остерман говорит о других частях интерфейса, которые должны быть зарегистрированы для TypeLib в целом , и эта запись интерфейса, кажется, заботится об отдельных частях. Ларри говорит, что нам нужно указать ProxyStubClassId32 как "{00020424-0000-0000-C000-000000000046}", поэтому мы можем легко добавить это.

Куда пойти оттуда и что заполнить для различных элементов интерфейса, поставило меня в тупик. Я пошел дальше и добавил элемент TypeLib в мой файл wix, и он успешно компилируется. Я немного не понимаю, как настроить элементы интерфейса, хотя. Что нам нужно сделать, чтобы правильно заполнить элемент TypeLib, и какие приложения или инструменты я могу использовать для его получения?

Ответ wcoenen, представленный ниже, выглядит многообещающе ... Я собираюсь дать ему шанс.

Обновление: опубликовано мое окончательное решение ниже в качестве ответа.

Ответы [ 3 ]

16 голосов
/ 06 марта 2009

Вот способ решения этой проблемы для ленивца: используйте heat из WiX 3.0.

Если у вас есть библиотека типов, сгенерированная автоматически и установленная через regasm, heat может принять .tlb в качестве аргумента в

heat file c:\my\path\to\my.tlb -out tlb.wxs

Он сгенерирует все элементы typelib и interface, которые вам нужно зарегистрировать. Это не решит проблему необходимости знать их заранее, и не решит проблему изменения идентификаторов GUID при изменении версии сборки (даже если интерфейс этого не делает - это единственный раз, когда вы '). Я должен изменить это), но это поможет вам там.

8 голосов
/ 20 февраля 2009

Следующий трюк может помочь собрать все изменения реестра и превратить их в файл wxs, включая элемент typelib, за которым вы следите.

  1. Сначала верните реестр в состояние, в котором библиотека типов не была зарегистрирована:

    c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb /u mylib.dll
    
  2. Экспорт этого чистого состояния реестра в hklm-before.reg:

    c:\WINDOWS\system32\reg.exe export HKLM hklm-before.reg
    
  3. Зарегистрировать библиотеку типов еще раз:

    c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb mylib.dll
    
  4. Экспорт нового состояния реестра в hklm-after.reg:

    c:\WINDOWS\system32\reg.exe export HKLM hklm-after.reg
    
  5. Теперь у нас есть два текстовых файла: hklm-before.reg и hklm-after.reg. Создайте файл diff.reg , который содержит только соответствующие различия между ними. Вы можете легко найти различия с помощью инструмента. Мне нравится использовать инструмент сравнения, включенный в TortoiseSVN, так как я уже использую это каждый день. (В этом случае WinDiff не очень хорошо работает из-за проблем с кодировкой текста.)

  6. Теперь мы можем преобразовать diff.reg в .wxs, вызвав heat.exe с помощью команды reg. (Требуется wix 3.5 или новее.)

    heat reg diff.reg -out typelib.wxs
    
3 голосов
/ 27 февраля 2009

Похоже, что при регистрации библиотеки типов лучший способ - создать собственный файл IDL или ODL, который будет содержать ваши GUID. Библиотеки типов, сгенерированные непосредственно из сборки, [i] зависят [/ i] от номеров версий сборки: идентификаторы GUID генерируются на основе этой информации, даже если интерфейс не изменился. Visual Studio использует regasm для регистрации и создания библиотеки типов. Под этим он использует RegisterTypeLib, вызов win32. Использование элемента typelib, похоже, делает нечто подобное. Нет хорошо.

Тем не менее! Создание библиотеки типов вручную является болезненным. Можно получить эти GUID другим способом: выкопать их из библиотеки типов и создать элементы самостоятельно.

У Ларри Остермана есть необходимая информация: есть определенные ключи реестра, которые необходимо установить. Вы можете сделать это с помощью таблицы Registry (а в Wix3 это означает элементы RegistryValue). Хитрость здесь в том, чтобы получить GUID: любой старый GUID не будет работать. Обычно получение GUID - это просто поиск IDL для вашей библиотеки (вы написали свой собственный IDL, верно? :)).

Если вы не написали файл IDL или ODL для компиляции в библиотеку типов, они все еще существуют в этом файле. Microsoft предоставляет несколько удобных инструментов: LoadTypeLibEx и интерфейс ITypeLib. С помощью этих интерфейсов вы можете просматривать библиотеку типов и получать все виды информации. Как мы просматриваем библиотеку?

Я просто взглянул на то, как это сделал Регасм! Быстрая разборка позже, и мы находим, что regasm написан также на C #. День славы Я запустил проект, и с помощью нескольких операторов using и PInvoke позже мы получили:

using System.Runtime.InteropServices;          // for struct marshaling 
using System.Runtime.InteropServices.ComTypes; // for the ITypeLib + related types

// TYPELIBATTR lives in two places: Interop and ComTypes, but the one
// in Interop is deprecated.
using TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR; 

/// <summary>
/// The registry kind enumeration for LoadTypeLibEx.  This must be made
/// here, since it doesn't exist anywhere else in C# afaik.  This is found
/// here: http://msdn.microsoft.com/en-us/library/ms221159.aspx
/// </summary>
enum REGKIND
{
    REGKIND_DEFAULT,
    REGKIND_REGISTER,
    REGKIND_NONE
}

// and this is how we get the library.
[DllImport("oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
  private static extern void LoadTypeLibEx(string strTypeLibName, REGKIND regKind, out ITypeLib TypeLib);

Уф! Как только мы это выясним, мы должны ориентироваться в структуре. Это взаимодействует с неуправляемыми ресурсами, так что будьте готовы к Marshal изучению вещей.

ITypeLib lib = null;
LoadTypeLibEx(Value, REGKIND.REGKIND_NONE, out lib);
IntPtr libInfoPtr = IntPtr.Zero;
lib.GetLibAttr(out libInfoPtr);
TYPELIBATTR libInfo = 
    (TYPELIBATTR) Marshal.PtrToStructure(libInfoPtr, typeof(TYPELIBATTR));
int typeCount = lib.GetTypeInfoCount();
for (int i = 0; i < typeCount; ++i)
{
    ITypeInfo info;
    lib.GetTypeInfo(i, out info);
    IntPtr typeDescrPtr = IntPtr.Zero;
    info.GetTypeAttr(out typeDescrPtr);
    TYPELIBATTR type =
        (TYPELIBATTR)Marshal.PtrToStructure(typeDescrPtr, typeof(TYPELIBATTR));
    // get GUID, other info from the specific type
}

lib.ReleaseTLibAttr(libInfoPtr);
libInfoPtr = IntPtr.Zero;

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

Конечно, вы можете избежать этого шага, просто написав свой собственный файл IDL для начала. Выбор за болью: решать только вам!

...