You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在.NET中通过后期绑定实现类型安全的COM组件调用问题

问题描述

我需要在x64进程中调用x32库,查资料后决定用COM组件实现。我用C#创建了三个项目:

  • 编译为X64的WinForms项目
  • 编译为AnyCPU的BaseDll项目(仅包含一个接口BaseInter,里面有someMethod方法)
  • 编译为x32且勾选“Register for COM interop”的Dll32项目(引用BaseDll并实现BaseInter接口;仅在此项目中添加了ComVisible和Guid特性)

手动在注册表的Wow6432Node路径下添加了DllSurrogate属性,完成了Dll32组件的注册,确保x64进程能调用x32组件。

WinForms项目中用以下代码调用时可以正常运行:

Type ComType = Type.GetTypeFromCLSID(new Guid("85840403-68F7-4B39-B015-7ED3506FD06B"));
dynamic c2 = Activator.CreateInstance(ComType);
string dd = c2.someMethod("asd");
MessageBox.Show(dd);

但我希望引用BaseDll后用强类型转换调用:

BaseInter c2 = (BaseInter) Activator.CreateInstance(ComType);

执行这段代码时抛出异常:

System.InvalidCastException: 'Unable to cast COM object of type 'System.__ComObject'
to interface type 'BaseDll.BaseInter'. This operation failed because the
QueryInterface call on the COM component for the interface with IID
'{40E88E31-DFEA-357E-8A97-E5F0077666C2}' failed due to the following error:
No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).'

当WinForms编译为x32时,强类型转换代码可以正常运行,请问是不是因为x64编译的WinForms里的接口和x32的Dll32项目中的接口不一致导致的?


更新内容

BaseInter代码

public interface BaseInter
{
    string someMethod(String ime);
}

Dll32代码

[ComVisible(true)]
[Guid("85840403-68F7-4B39-B015-7ED3506FD06B")]
public class JaviSe : BaseInter
{
    public string someMethod(string ime)
    {
        return "Hi from 32 " + ime;
    }
}

手动添加的注册表项

REGEDIT4

[HKEY_CLASSES_ROOT\Wow6432Node\Dll32.JaviSe]
@="Dll32.JaviSe"

[HKEY_CLASSES_ROOT\Wow6432Node\Dll32.JaviSe\CLSID]
@="{85840403-68F7-4B39-B015-7ED3506FD06B}"

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}]
@="Dll32.JaviSe"
"AppID"="{85840403-68F7-4B39-B015-7ED3506FD06B}"

[HKEY_CLASSES_ROOT\Wow6432Node\AppID\{85840403-68F7-4B39-B015-7ED3506FD06B}]
"DllSurrogate"=""

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}\InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="Dll32.JaviSe"
"Assembly"="Dll32, Version=1.0.0.0, Culture=neutral, PublicKeyToken=143740cba1c5c559"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///C:/Users/default.DESKTOP-VNP7D7O/source/repos/SurogateTests/Dll32/bin/Debug/Dll32.dll"

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}\InprocServer32\1.0.0.0]
"Class"="Dll32.JaviSe"
"Assembly"="Dll32, Version=1.0.0.0, Culture=neutral, PublicKeyToken=143740cba1c5c559"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///C:/Users/default.DESKTOP-VNP7D7O/source/repos/SurogateTests/Dll32/bin/Debug/Dll32.dll"

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}\ProgId]
@="Dll32.JaviSe"

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}\Implemented Categories\{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]

问题原因与解决方法

问题核心是你没有给BaseInter接口指定固定的GUID,且没有标记它为COM可见。

当x64的WinForms项目引用BaseDll时,.NET会自动为BaseInter生成一个IID;而x32的Dll32项目实现该接口时,又会生成另一个不同的IID。跨进程(x64到x32通过DllSurrogate本质是跨进程调用)时,COM要求两边使用完全一致的接口IID才能完成类型转换,这就是强类型转换失败的原因——而dynamic调用通过后期绑定方法,不依赖接口IID匹配,所以能正常运行。

要解决这个问题,需要做以下两步:

  1. 为BaseInter接口添加ComVisible(true)和固定的Guid特性
    修改BaseInter的代码:

    [ComVisible(true)]
    [Guid("请替换为你自己生成的固定GUID")]
    public interface BaseInter
    {
        string someMethod(String ime);
    }
    

    注意:这个GUID要固定,不能每次编译自动生成。可以用Visual Studio的「工具→创建GUID」工具生成(选择格式5)。

  2. 重新注册Dll32组件
    先卸载旧的COM注册(执行命令regasm /u Dll32.dll),然后重新生成Dll32项目(确保勾选「Register for COM interop」),或者手动执行regasm /codebase Dll32.dll完成注册。

修改后,x64的WinForms项目和x32的Dll32项目会使用同一个接口IID,跨进程调用时强类型转换就能正常工作了。

另外补充:BaseDll项目最好设置为强签名,避免因程序集标识问题导致的COM调用异常。可以在项目属性的「签名」选项卡中勾选「签署程序集」,创建一个强名称密钥文件。


内容的提问来源于stack exchange,提问作者Bojan Vukasovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:17:57