Как.NET COM Callable Wrapper генерирует IID?
Просматривая сгенерированный файл TLB, созданный CCW, хотя OLE/COM Object Viewer показывает, что IID остается неизменным, пока я не изменю дизайн интерфейса (что является правильным поведением), меня беспокоит то, что если я скомпилирую этот же код на другой машине, Будет сгенерирован совершенно другой IID, несмотря на то, что интерфейс не меняется и, следовательно, ломает существующие COM-клиенты.
- Как идентификаторы COM-интерфейса генерируются с помощью COM Callable Wrapper?
- Как CCW узнает, изменился ли интерфейс и нужно ли создать новый IID?
- Будет ли безопаснее просто сгенерировать свою собственную и объявить в исходном файле?
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, потому что вы плохо знаете руководства. По общему признанию, загрязнение реестра - достаточно хорошая причина для меня.