5

这是一个复杂的问题,涉及与 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# 对象。

问题

  1. 为什么会失败?我相信这是因为 CLR COM 加载程序存根无法导入我的 C# 程序集。如果在这一步之前失败,CLR 甚至不会加载,所以它正在探测和创建融合日志这一事实让我相信这是因为 CLR 找不到 ManagedCOMObject.dll。

  2. 请注意,CLR 已加载 - 我相信这意味着 COM 已成功查看当前激活上下文以找到注册。我不确切知道 clrClass 在清单中做了什么,但大概它成功加载了 CLR。

  3. 我现在假设问题是 CLR 在加载程序集时没有注意 ActCtx。如果我正在编写托管代码,我可以挂接到 AppDomain.CurrentDomain.AssemblyResolve 事件并自己找到 DLL。由于我正在编写非托管代码,并且仅隐式托管 CLR,我可以以某种方式更改我的应用程序 PrivatePath 和/或如何探测程序集吗?

4

1 回答 1

3

我现在假设问题是 CLR 在加载程序集时没有注意 ActCtx

对,那是正确的。CLR 有自己的策略来定位不受 Windows 激活上下文影响的程序集。默认情况下,它只在 GAC 中查找,然后在 EXE 的私有 bin 路径中查找。您可以使用 Fuslogvw.exe 实用程序看到这一点。

你在这里没有很多很好的选择。在 GAC 中安装程序集是显而易见的解决方案,并且通常适用于 [ComVisible] 程序集,因为它有助于解决 COM DLL Hell 问题。您唯一可以做的是将其复制到 C:\Python27 目录或在同一目录中写入 python.exe.config 文件,将探测路径更改为 C:\Python27 的子目录。两者都不能很好地扩展。自己托管 CLR 或编写 AppDomain.AssemblyResolve 事件处理程序是不可能的。

如果您想避免 Regasm.exe /codebase,使用 GAC 是合适的解决方案

于 2012-11-27T19:21:32.003 回答