这是一个复杂的问题,涉及与 COM、CLR 和无注册 COM 相关的一些神秘领域。
首先,我的主要应用程序是用 python 编写的。因此,它的代码库(开发中)位于 C:\mainapp\main.py。
当然,在windows上,执行程序的是C:\Python27\python.exe。
我现在想使用 python 中的无注册 COM(使用 win32com)与我控制的用 C# 编写的 COM 对象对话(使用 IDispatch),该对象位于 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 有一个嵌入式清单,它使用 clrClass 标记声明 COM 对象。
结果
ActicateActCtx 调用成功并正确解析了 myapp.manifest 和 ManagedComObject.dll 的清单 - 我使用 sxstrace.exe 验证了这一点。
在探测 C:\Python27\ManagedComObject.dll 后,对 CoCreateInstance 的调用失败并出现 FileNotFound。融合日志声称 PrivatePath 未设置(推测是因为 python.exe.config 不存在),并且根本没有在 C:\mainapp 中查找 C# 对象。
问题
为什么会失败?我相信这是因为 CLR COM 加载程序存根无法导入我的 C# 程序集。如果在这一步之前失败,CLR 甚至不会加载,所以它正在探测和创建融合日志这一事实让我相信这是因为 CLR 找不到 ManagedCOMObject.dll。
请注意,CLR 已加载 - 我相信这意味着 COM 已成功查看当前激活上下文以找到注册。我不确切知道 clrClass 在清单中做了什么,但大概它成功加载了 CLR。
我现在假设问题是 CLR 在加载程序集时没有注意 ActCtx。如果我正在编写托管代码,我可以挂接到 AppDomain.CurrentDomain.AssemblyResolve 事件并自己找到 DLL。由于我正在编写非托管代码,并且仅隐式托管 CLR,我可以以某种方式更改我的应用程序 PrivatePath 和/或如何探测程序集吗?