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

跨.NET 6 32位COM服务器与64位客户端传递委托触发System.AccessViolationException问题求助

哥们,我太懂你这种跨位COM迁移时踩坑的痛苦了!你遇到的System.AccessViolationException根本原因是32位和64位进程的内存地址空间完全隔离:你直接传递UnmanagedType.FunctionPtr类型的委托,本质是把64位客户端的函数指针传给32位服务器,这个指针在32位进程里完全无效,自然会触发内存访问错误。

问题核心

.NET里的委托跨COM边界传递时,同位数进程下CLR能自动处理封送,但跨位数时这个机制直接失效——32位指针是4字节、64位是8字节,长度都不匹配,更别说地址空间完全不互通了。

解决方案:用COM标准回调接口代替函数指针

COM本身就设计了跨进程/跨位的回调机制,通过接口而非原生函数指针来实现,这是最可靠的做法。下面是具体改造步骤:

1. 修改服务器端代码,定义回调接口

把原来的ChangeDelegate替换成一个COM可见的回调接口,服务器通过这个接口调用客户端逻辑:

namespace OutOfProcCOM;

[ComVisible(true)]
[Guid(Contract.Constants.ServerInterface)] // F586D6F4-AF37-441E-80A6-3D33D977882D
public interface IServer
{
    double Test();
    // 替换原来的TestEvent方法,改为注册回调接口
    void RegisterCallback(IChangeCallback callback);
}

// 新增COM可见的回调接口,务必生成一个唯一GUID
[ComVisible(true)]
[Guid("12345678-ABCD-EFGH-IJKL-MNOPQRSTUVWX")]
public interface IChangeCallback
{
    bool OnChange();
}

[ComVisible(true)]
[Guid(Contract.Constants.ServerClass)] // AF080472-F173-4D9D-8BE7-435776617347
public sealed class DllServer : IServer
{
    private IChangeCallback _callback;

    public double Test()
    {
        return 10;
    }

    public void RegisterCallback(IChangeCallback callback)
    {
        _callback = callback;
        // 测试调用客户端的回调逻辑
        _callback?.OnChange();
    }
}

2. 客户端实现回调接口

客户端需要实现这个回调接口,并且确保类被COM可见:

// 客户端的回调实现类,标记为COM可见
[ComVisible(true)]
public class ChangeCallback : IChangeCallback
{
    public bool OnChange()
    {
        Console.WriteLine("Hello!");
        return true;
    }
}

// 客户端调用逻辑
var type = Type.GetTypeFromProgID("OutOfProcCOM.DllServer");
var obj = (IServer)Activator.CreateInstance(type);
var x = obj.Test();
// 创建回调实例并注册到服务器
var callback = new ChangeCallback();
obj.RegisterCallback(callback);

3. 重新注册服务器

修改代码后重新生成类库,执行注册命令更新COM注册表:

regsvr32.exe "DllServer.comhost.dll"

原来的注册表项配置不需要改动,因为服务器类的GUID没有变化。

为什么这个方案能解决问题?

COM的代理/存根机制会自动处理跨进程/跨位的接口调用:当你把客户端的IChangeCallback实例传给服务器时,COM会在服务器进程里创建一个代理对象,服务器调用接口方法时,实际是通过COM封送层转发到客户端进程执行,完全避开了直接操作无效内存指针的问题。

额外提醒:如果服务器需要持续调用回调,注意在客户端不再需要时通知服务器释放接口引用,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 20:47:43