Как.NET COM Callable Wrapper генерирует IID?

Просматривая сгенерированный файл TLB, созданный CCW, хотя OLE/COM Object Viewer показывает, что IID остается неизменным, пока я не изменю дизайн интерфейса (что является правильным поведением), меня беспокоит то, что если я скомпилирую этот же код на другой машине, Будет сгенерирован совершенно другой IID, несмотря на то, что интерфейс не меняется и, следовательно, ломает существующие COM-клиенты.

  1. Как идентификаторы COM-интерфейса генерируются с помощью COM Callable Wrapper?
  2. Как CCW узнает, изменился ли интерфейс и нужно ли создать новый IID?
  3. Будет ли безопаснее просто сгенерировать свою собственную и объявить в исходном файле?

1 ответ

Решение

Guid для типа не является специфическим для взаимодействия COM, все типы.NET имеют guid. Вы можете получить его из свойства Type.GUID. Код в CLR, который его генерирует, доступен из дистрибутива SSCLI20. Вы можете взглянуть на алгоритм, проверив код в методе clr/scr/vm/methodtable.cpp, MethodTable::GetGuid().

Подводя итог алгоритму:

  • если тип имеет атрибут [Guid], верните
  • если тип является типом интерфейса, то генерируют строковую версию определения типа интерфейса. Это делается с помощью GetStringizedItfDef() в interoputil.cpp. Он начинается с полного имени типа и добавляет строковую версию каждого определения члена.
  • для всех других типов создайте строковую версию класса. Он начинается с полного имени типа, добавляет имя класса и добавляет полное имя сборки.
  • результирующая строка затем хэшируется в Guid с помощью вспомогательной функции CorGuidFromNameW().

Этого достаточно, чтобы ответить на ваши вопросы:

Как идентификаторы COM-интерфейса генерируются с помощью COM Callable Wrapper?

Он использует Type.GUID, сгенерированный с помощью алгоритма выше. Ни один из элементов алгоритма не относится к машине, на которой он выполняется, поэтому вам не нужно бояться получать разные идентификаторы IID и CLSID на разных машинах сборки.

Как CCW узнает, изменился ли интерфейс и нужно ли создать новый IID?

Это не так. Он основан исключительно на алгоритме, создающем разные идентификаторы GUID для разных определений интерфейса.

Будет ли безопаснее просто сгенерировать свою собственную и объявить в исходном файле?

На самом деле, нет. Для этого алгоритма нет документированного режима отказа. Использование собственного атрибута [Guid] значительно увеличивает вероятность того, что вы забудете изменить его, когда это необходимо. Это ярлык, который часто используется и основной источник DLL Hell. Мерзкий тип, который приводит к сбою клиента с почти невозможной диагностикой аппаратных исключений. В отличие от все еще сложного, но не невозможного вида E_NOINTERFACE. На самом деле я могу думать только о двух недостатках, полагаясь на автоматически сгенерированный Guid: он имеет тенденцию вызывать загрязнение реестра на вашем компьютере разработчика, если вы забыли отменить сборку сборок перед их сборкой. И это немного замедляет работу при поиске и устранении ошибок COM, потому что вы плохо знаете руководства. По общему признанию, загрязнение реестра - достаточно хорошая причина для меня.

Другие вопросы по тегам