Как заставить COM без регистрации работать в управляемом / неуправляемом взаимодействии
-
28-10-2019 - |
Вопрос
У меня есть неуправляемый внутрипроцессный COM-объект C ++ / ATL (в Unmanaged.dll), который я пытаюсь использовать из управляемой библиотеки C # DLL (Managed.dll). Однако я хочу использовать COM без регистрации. У меня есть следующие шаги:
- Зарегистрируйте COM-объект на компьютере разработчика. Внутренний сервер должен иметь правильно зарегистрированную библиотеку типов.
- Добавьте ссылку на COM-объект в проекте C #, а затем установите для свойства ссылки значение Isolated= True.
В результате создаются Unmanaged.dll, Managed.dll и Native.Managed.manifest. Открыв манифест, довольно ясно, как система использует его для загрузки COM-объекта без регистрации.
Вот в чем проблема. У меня есть управляемый EXE (Managed.exe), который динамически загружает Managed.dll для доступа к общедоступным типам. Под «динамически» я подразумеваю то, что он использует Assembly.LoadFrom («Managed.dll»). Когда код внутри Managed.dll пытается создать COM-объект, он получает исключение «класс не зарегистрирован». Похоже, контекст активации неправильно настраивается при загрузке Managed.dll.
Есть ли способ получить бесплатную регистрацию COM для работы в этом сценарии?
Решение
Два дня без ответа, вот что я придумал за это время ...
Действительно похоже, что контекст активации настраивается ОС при запуске процесса на основе манифеста, связанного с основным EXE. Это означает, что все элементы, связанные с COM, не требующие регистрации, должны находиться в файле Main.exe.manifest во время запуска процесса. Это нарушает изоляцию между EXE и DLL. Если DLL отвечает за создание COM-объектов, вы не ожидаете, что манифест EXE должен содержать информацию COM без регистрации. Вы могли ожидать, что манифест, связанный с DLL, будет объединен с контекстом активации процесса в момент загрузки DLL, но этого не произошло.
Чтобы обойти эту проблему, DLL должна настроить новый контекст активации перед созданием COM-объекта. Что еще хуже, в настоящее время (начиная с .NET 4.0) нет управляемого способа сделать это. Таким образом, DLL должна будет вызвать следующие функции Win32:
Я заключил эти вызовы в управляемый класс, который вызывает CreateActCtx и ActivationActCtx в конструкторе, а DeativateActCtx и ReleaseActCtx в IDisposable :: Dispose.