Как создать управляемый COM-объект без регистрации, как мне заставить CLR выглядеть в каталоге, отличном от исполняемого файла основного приложения?
Это довольно сложный вопрос, затрагивающий несколько загадочные области, связанные с COM, CLR и COM без регистрации.
Во-первых, мое основное приложение написано на python. Таким образом, его кодовая база (в разработке) находится, скажем, в C:\mainapp\main.py.
Конечно, в Windows это C:\Python27\python.exe, который выполняет программу.
Теперь я хочу использовать reg-free COM из python (используя win32com) для связи (используя IDispatch) с COM-объектом, написанным на C#, который я контролирую, который находится в C:\mainapp\ManagedCOMObject.dll
Примечание. Если вы не говорите на python / pythoncom, обратите внимание, что вызов Dispatch() в конечном итоге сводится к CoCreateInstance().
Попытка 1
#main.py:
import win32com.client
CLSID_ManagedComObject_MyClass = "{zzzzz....}" #This is correct
myclass = win32com.client.Dispatch(CLSID_ManagedComObject_MyClass)
Результат
Ошибка, потому что объект отсутствует в реестре (как и ожидалось), и я ничего не упомянул о файлах манифеста, а манифест python.exe явно не знает о моем объекте.
Попытка 2
#main.py:
ac = ActivationContext("C:\mainapp\myapp.manifest", asm_dir="C:\mainapp")
with ac.activate():
#The above two lines fill in a ACTCTX structure, call CreateActCtx, and call ActivateActCtx
import win32com.client
CLSID_ManagedComObject_MyClass = "{zzzzz....}" #This is correct
myclass = win32com.client.Dispatch(CLSID_ManagedComObject_MyClass)
-
#myapp.manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"
name="My.Main.App"
version="1.0.0.0"
processorArchitecture="x86"
/>
<dependency>
<dependentAssembly>
<assemblyIdentity
name="ManagedComObject"
version="1.0.0.0"
processorArchitecture="msil"
/>
</dependentAssembly>
</dependency>
</assembly>
Обратите внимание, что ManagedCOMObject имеет встроенный манифест, который объявляет COM-объект с помощью тега clrClass.
Результат
Вызов ActicateActCtx завершается успешно и корректно анализирует манифесты myapp.manifest и ManagedComObject.dll - я проверил это с помощью sxstrace.exe.
Вызов CoCreateInstance завершается неудачно с FileNotFound после поиска C:\Python27\ManagedComObject.dll. Журнал слияния утверждает, что PrivatePath не установлен (вероятно, потому что python.exe.config не существует), и просто не ищет объект C# в C:\mainapp.
Вопросы
Почему это не удается? Я считаю, что это потому, что заглушка загрузчика COM CLR не может импортировать мою сборку C#. Если до этого этапа произошел сбой, CLR даже не загрузился бы, поэтому сам факт проверки и создания журналов слияния заставляет меня верить, что CLR не может найти ManagedCOMObject.dll.
Обратите внимание, что CLR загружен - я считаю, что это означает, что COM успешно просмотрел текущий контекст активации, чтобы найти регистрацию. Я не знаю точно, что делает clrClass в манифесте, но, вероятно, он успешно загрузил CLR.
Теперь я предполагаю, что проблема в том, что CLR не обращает внимания на ActCtx при загрузке сборок. Если бы я писал управляемый код, я мог бы подключиться к событию AppDomain.CurrentDomain.AssemblyResolve и найти DLL самостоятельно. Поскольку вместо этого я пишу неуправляемый код и размещаю CLR только неявно, могу ли я как-то изменить свои приложения PrivatePath и / или как проверяются сборки?
1 ответ
Теперь я предполагаю, что проблема в том, что CLR не обращает внимания на ActCtx при загрузке сборок
Да, это правильно. CLR имеет собственную стратегию поиска сборок, на которые иначе не влияет контекст активации Windows. По умолчанию он смотрит только в GAC, а затем в путь к приватной корзине EXE. Это можно увидеть при работе с утилитой Fuslogvw.exe.
У вас не так много хороших вариантов здесь. Установка сборки в GAC является очевидным решением и в целом подходит для сборок [ComVisible], поскольку она помогает решить проблему с адом COM DLL. Единственное, что вы можете сделать, это скопировать его в каталог C:\Python27 или записать файл python.exe.config в тот же каталог, который изменяет путь поиска на подкаталог C:\Python27. Ни один не масштабируется хорошо. Хостинг CLR самостоятельно или написание обработчика событий AppDomain.AssemblyResolve не обсуждаются.
Использование GAC является подходящим решением, если вы хотите избежать Regasm.exe /codebase