Какие теги необходимы в манифесте для регистрации бесплатного COM?

TL; DR Должны ли все записи реестра, созданные regsvr32, присутствовать в манифесте reg-free-COM SxS и наоборот?


Я пытаюсь получить бесплатную регистрацию COM для стороннего компонента.

Чтение вверх on, я обнаружил, что есть несколько элементов, которые могут быть помещены в манифест:

Из документов мы можем добавить следующие теги в манифест для описания COM-компонента:

  • assemblyIdentity - который действительно просто описывает "абстрактную сборку, насколько я могу судить
  • comClass - описывает COM-класс (интерфейс IID). Казалось бы, это всегда необходимо.
  • typelib - когда?
  • comInterfaceExternalProxyStub - когда?
  • comInterfaceProxyStub - когда?

Из других документов для HKEY_LOCAL_MACHINE\SOFTWARE\Classes мы можем заметить, что для записей реестра COM есть несколько категорий:

Используя regsvr42, чтобы извлечь материал, который dll, который я пытаюсь выполнить regfree, дает манифест, содержащий только записи comClass нет записей typelib или ProxyStub. (И я перекрестно проверил написанные ключи, DLL, о которых идет речь, pdm.dll, MS Process Debug Manager записывает только эти ключи, т.е. В реестре нет библиотеки типов или информации о прокси-прокси, видимой в реестре.)

Если реестр содержит только информацию, относящуюся к comClass, значит ли это, что этой информации будет достаточно в манифесте SxS или может потребоваться дополнительная информация в манифесте?


В стороне я заметил, что в реестре есть VersionIndependentProgId и ProgId, у которых есть номер версии, добавленный в конце. В манифесте есть только запись ProgId, а документы:

progid: программный идентификатор, зависящий от версии, связанный с COM. Формат ProgID - это <vendor>.<component>.<version>.

Но в документах также указано

Элемент comClass может иметь элементы <progid>...</progid> как дети, которые перечисляют версии, зависящие от версии.

и они говорят, что атрибут progid должен быть независимым от версии.

Итак, что здесь поставить? И действительно ли имеет значение, когда клиент не запрашивает определенную версию?

Ответ 1

Элемент assemblyIdentity всегда требуется, часть манифестной сантехники. Вы всегда должны предоставлять элемент comClass, он заменяет ключ реестра HKLM\Software\Classes\CLSID и используется для вызова клиента CoCreateInstance(). Элемент файла называет исполняемый файл сервера COM.

Остальные ключи необязательны, они необходимы для работы маршалинга. Маршалинг происходит, когда вызов клиента должен выполняться в другом потоке. Это всегда произойдет, когда сервер и клиент находятся в разных процессах, случае для сервера вне процесса или когда сервер работает на другом компьютере. И это может произойти, когда требует ThreadingModel, указанная в элементе comClass. Другими словами, когда COM-объект был создан в одном потоке, но вызывается на другом, а сервер не является потокобезопасным.

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

Существует четыре основных случая:

  • COM-сервер не поддерживает так называемый способ и всегда должен использоваться из того же потока, на котором он был создан. Остановитесь там, не нужно ничего добавлять к манифесту.

  • Сервер COM реализует интерфейс IMarshal. Автоматически запрашивается COM, когда он не может найти другой способ маршалирования вызова. Это довольно редко, за исключением случая, когда COM-сервер агрегирует свободно-threaded marshaller. Другими словами, он полностью потокобезопасен сам по себе без какой-либо помощи и всегда работает в процессе. PDM, вероятно, будет работать именно так. Остановитесь там, не нужно ничего добавлять к манифесту.

  • Автор COM-сервера начал свой проект, написав описание интерфейса сервера на языке IDL. Затем был скомпилирован MIDL. Одним из доступных вариантов является автоматическое создание кода из объявлений IDL, код, который может быть использован для создания отдельной библиотеки DLL, которая реализует прокси-сервер и заглушку. IDL достаточно богат для описания деталей типов аргументов функции и использования, чтобы позволить маршалинг выполняться с помощью этого автоматически сгенерированного кода. Иногда атрибутов IDL недостаточно, автор COM затем записывает собственный маршаллер. COM загружает эту DLL во время выполнения, чтобы автоматически создавать объекты прокси и заглушки.

  • Спецификация подмножества COM Automation (интерфейс IDispatch), у Windows есть встроенный маршаллер, который знает, как маршировать вызовы, соответствующие требованиям подмножества. Очень распространен. Он использует библиотеку типов для обнаружения объявления функции.

Последние две пули требуют использования HKLM\Software\Classes\Interface, для каждого интерфейса есть записи для IID. Это как COM узнает, как создать прокси-сервер и заглушку для интерфейса. Если он не может найти ключ, он возвращается к IMarshal. Вы должны использовать элемент comInterfaceExternalProxyStub для замены раздела реестра. Использование comInterfaceProxyStub - это особый случай, когда код прокси и заглушки включен в исполняемый файл COM-сервера вместо отдельного файла. Например, опция в проектах ATL включается с помощью мастера "Разрешить слияние прокси/заглушки".

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

Прогид требуется, когда клиент COM использует позднюю привязку через IDispatch, вспомогательная функция CreateObject() в библиотеке поддержки времени выполнения клиента является шаблоном. Используется в любом скриптовом узле, например.

Наличие некоторых инсайдерских знаний о том, как создается COM-сервер, безусловно, помогает, всегда обращайтесь к поставщику или автору за советом. Это может быть обратное проектирование, однако, наблюдая, какие ключи реестра записываются при регистрации сервера, инструмент ProcMon SysInternals - лучший способ это увидеть. Основные вещи, которые нужно искать:

  • Если вы видите, что пишите ключ HKLM\Software\Classes\Interface, вы можете предположить, что вы должны предоставить элемент comInterface | External | ProxyStub

  • Если вы видите, что для ключа ProxyStubClsid32 написано {00020420-0000-0000-C000-000000000046}, вы можете предположить, что он использует стандартный маршаллер, и вы должны использовать элемент comInterfaceExternalProxyStub, а также элемент typelib. Затем вы также увидите, что он записывает ключ реестра IID TypeLib, а также запись в разделе реестра HKLM\Software\Classes\Typelib. Последний дает путь библиотеки типов. Почти всегда то же самое, что и COM-сервер, вложение библиотеки типов в качестве ресурса очень распространено. Если он отдельный (файл .tlb), вы должны его развернуть.

  • Если значение ключа ProxyStubClsid32 является другим ориентиром, вы можете предположить, что он использует свою собственную прокси/заглушку DLL. Затем вы также увидите, что он пишет CLSID-ключ для прокси-сервера, его ключ InProcServer32 дает вам путь к DLL. Если это имя файла совпадает с именем файла сервера, вы можете предположить, что код прокси/заглушки был объединен, и вместо этого вы должны использовать элемент comInterfaceProxyStub. Если нет, то comInterfaceExternalProxyStub требуется, и вы должны развернуть DLL

  • Если вы видите, что он записывает ProgID в HKLM\Software\Classes, то используйте элемент progid, точно так же, как показано в трассировке.