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

C#向C++传递委托数组触发AccessViolationException异常求助

问题根因

你遇到的崩溃主要是2个核心错误导致的:

  1. C++侧结构体的字段定义类型不匹配,C#封送的函数指针数组是连续存储的函数指针值,而你声明的是MyCallback* MyHandlers[32](函数指针的指针数组),类型层级多了一层间接寻址,调用时会把指针值当成函数入口地址执行,直接触发访问违规。
  2. .NET委托实例没有被手动持有强引用,GC在运行时会判定没有被引用的委托实例可回收,导致C++侧持有的函数指针变为野指针。

可行解决方案

步骤1:修正C++侧类型定义

首先修正回调函数的参数类型、调用约定,以及结构体的数组定义:

// 显式指定调用约定,修正字符串参数为指针类型
typedef void* (__cdecl *MyCallback)(const wchar_t* inStringParam, int* outIntParam, wchar_t* outStringParam);

// 结构体中直接定义函数指针数组,而非指针的指针数组
struct NativeParameters {
    // 其他字段...
    MyCallback MyHandlers[32];
};

// 调用方式不需要额外强转,直接使用即可
initParams->MyHandlers[0](L"test", &outInt, outStrBuf);

步骤2:C#侧手动持有委托强引用

在使用委托数组的类中声明类级别的私有字段持有委托数组,防止GC回收:

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)] 
public delegate IntPtr MyDelegate(string inStringParam, out int outIntParam, out string outStringParam);

[StructLayout(LayoutKind.Sequential)]
internal struct NativeParameters
{
    // 其他字段...
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.FunctionPtr, SizeConst = 32)] 
    internal MyDelegate[] MyHandlers;
}

// 类级别字段,持有强引用避免GC回收委托实例
private MyDelegate[] _myHandlersHolder;
private NativeParameters _startupParameters;

// 初始化逻辑
private void InitParams()
{
    _myHandlersHolder = new MyDelegate[32];
    // 赋值委托实例
    _myHandlersHolder[0] = OnMyEvent;
    // 其他委托赋值...
    
    // 赋值给结构体字段
    _startupParameters = new NativeParameters {
        MyHandlers = _myHandlersHolder
    };
    
    // 后续传递结构体到C++的逻辑
}

可选检查项

如果你的out string参数是需要C++侧写入字符串,建议将C#委托的out string改为StringBuilder类型,预先分配缓冲区再传递,避免字符串封送时的内存访问错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 06:06:02