#c# #.net-core #com #interop #.net-core-3.1
#c# #.net-core #com #взаимодействие #.net-core-3.1
Вопрос:
Я пытаюсь отладить COM-сервер, ориентированный на .NET Core 3.1, с платформой, установленной на «Любой процессор». У меня есть класс, украшенный ComVisible
Guid
атрибутами и, которые у меня есть <EnableComHosting>true</EnableComHosting>
в .csproj. Когда я создаю проект, я получаю все файлы, упомянутые в разделе «Предоставление компонентов .NET Core для COM«, и после запуска regsvr32
реестр должным образом обновляется и InprocServer32
устанавливается на My.Namespace.comhost.dll
.
Сторона C вызывает CoCreateInstance()
:
IUnknown* ptr;
HRESULT hr = CoCreateInstance(clsid, 0, CLSCTX_ALL, iid, (void**)amp;ptr);
Если клиент скомпилирован как 64-разрядное приложение, вызов завершается успешно. Если он скомпилирован как 32-разрядное приложение, вызов завершается с ошибкой «Класс не зарегистрирован», несмотря на то, что InprocServer32
он установлен в обоих HKCRCLSID{class-id-value}
и HKCRWOW6432NodeCLSID{class-id-value}
(что является стандартным подходом для двух версий одного и того же COM-сервера).
Однако, если я настрою COM-сервер на платформу «x86» вместо платформы «Any CPU», а затем перекомпилирую его (с точно таким же путем к файлу и именем для сборки), тогда клиент C сможет создать его без проблем.
Итак:
- 64-разрядный клиент C может создать экземпляр COM-сервера «любого процессора»
- 32-разрядный клиент C не может создать экземпляр COM-сервера «любого процессора»
- 32-разрядный клиент C может создать экземпляр COM-сервера x86
Конечно, я могу создать обходной путь — иметь два проекта с «интерфейсными» COM-серверами или, возможно, иметь две конфигурации, которые будут создавать один и тот же проект дважды или что-то еще, чтобы один и тот же COM-сервер отображался как сборка «x64» и «x86». Было бы лучше, чтобы версия «Любой процессор» просто работала.
Нет ли более прямого способа использовать библиотеку классов «Любой процессор» как с 32-разрядных, так и с 64-разрядных COM-клиентов?
Комментарии:
1. Я не знаком с .NET Core. Но с обычным .NET вы обычно используете regasm, а не regsvr32. Кроме того, в обычном .NET вы используете 64-разрядный regasm для регистрации в 64-разрядном кусте, и вы используете 32-разрядный regasm.exe чтобы зарегистрироваться для 32-разрядного улья. В обычном .NET, чтобы иметь возможность использовать AnyCPU, у вас должно быть две регистрации. Но это работает. IDK, для чего это изменено. NET core. Может быть, мой комментарий будет полезен … или нет?
2. В (текущем) .NET core есть несколько мест, где мы потеряли крутость «Любого процессора». Для COM-объекта .NET core требуется собственный «[проект].comhost.dll » файл, который никогда не является каким-либо процессором. Итак, «Любой процессор» в данном случае — большая шутка (не такая уж забавная): github.com/dotnet/runtime/issues/32493
3. @SimonMourier Не могли бы вы добавить это в качестве ответа?
Ответ №1:
COM-клиент не может загружать IL напрямую, поэтому всегда есть какой-то посредник, который загружает код IL и преобразует его в машинный код.
С .NET Framework это был mscoree.dll, которая установлена в windows system32, довольно стабильна и, я думаю, поставляется с Windows уже довольно давно. Так что это общее для всех COM-объектов .NET Framework (в процессе)
В .NET Core есть собственный хост, который, к сожалению или нет, должен поставляться с проектом, он называется [project] .comhost.dll .
Выбор «Любой процессор» / «x86» / «x64» влияет на это для .NET assemby, но он не может поддерживать параметр «Любой процессор» для comhost.dll , он должен быть x86 или x64.
Вот небольшой визуальный:
Основная идея дизайна заключается в том, чтобы максимально ослабить связь между .NET (core) и ОС (здесь Windows). У него определенно есть некоторые недостатки, он не ограничивается COM.
Вот обсуждение этого вопроса на официальном dotnet github: Поддержка двойного comhost.dll (x86, x64) генерация для сборок .NET Core с использованием «Любого процессора