Подтвердить что ты не робот

Построение и установка Typelib с WiX

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

  • Зарегистрирована COM-библиотека
  • Создает и регистрирует библиотеку типов

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

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

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

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

  • Id
  • Имя

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

    heat reg diff.reg -out typelib.wxs
    

Ответ 3

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

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

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

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

Я просто взглянул на то, как Regasm сделал это! Быстро разобрать позже, и мы обнаруживаем, что regasm также написан на С#. День славы. Я запустил проект, и с несколькими операциями использования и 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 ing вокруг.

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 для начала. Выбор боли: это зависит от вас!