创建无 reg 托管 COM 对象时,如何让 CLR 查看与主应用程序的可执行文件不同的目录?

EB.*_*EB. 5 com clr .net-assembly activation-context-api

这是一个复杂的问题,涉及与 COM、CLR 和无 reg-free COM 相关的一些神秘领域。

首先,我的主要应用程序是用 python 编写的。因此,它的代码库(开发中)位于 C:\mainapp\main.py。

当然,在windows上,执行程序的是C:\Python27\python.exe。

我现在想使用 python 中的 reg-free 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)
Run Code Online (Sandbox Code Playgroud)

结果

失败,因为对象不在注册表中(正如预期的那样),而且我没有提到任何关于清单文件的内容,而且 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)
Run Code Online (Sandbox Code Playgroud)

——

#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>
Run Code Online (Sandbox Code Playgroud)

请注意,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 和/或程序集的探测方式吗?

Han*_*ant 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 是合适的解决方案