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

从C++ DLL函数返回wchar_t*至C#失败问题排查

C#调用C++ DLL第二个函数崩溃的排查与解决

问题现象

维护旧C++代码时遇到异常:C#调用DLL的testFunc1运行正常,但调用testFunc2后程序直接退出,返回错误代码3221226356。

相关代码

C++ DLL代码

#define EXPFUNC extern "C" __declspec(dllexport)

static const wchar_t *TEST = const_cast<wchar_t*> (L"TEST");

EXPFUNC const unsigned int __stdcall testFunc1(const wchar_t *str) {
    // 使用*str查找并返回id的逻辑
    return 123;
}

EXPFUNC const wchar_t* __stdcall testFunc2(const unsigned int id) {
    // 使用id查找并返回指针的逻辑
    return TEST;
}

C#调用代码

[DllImport("Test.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern uint testFunc1([MarshalAs(UnmanagedType.BStr)] string symbol);        

[DllImport("Test.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
internal static extern string testFunc2(uint id);

testFunc1("some string");  // 运行正常
testFunc2(123);  // 退出并返回代码3221226356

问题根源

  1. 调用约定不匹配
    C++函数明确使用__stdcall调用约定,但C#的DllImport指定的是CallingConvention.Cdecl。两种约定的栈清理规则不同:__stdcall由被调用方清理栈,Cdecl由调用方清理。这种不匹配会导致栈不平衡,第一个函数未触发崩溃属于偶然,第二个函数直接暴露了问题。

  2. 返回值封送错误
    testFunc2返回的是静态常量宽字符指针(const wchar_t*),但C#用[return: MarshalAs(UnmanagedType.BStr)]来处理返回值。BStr是COM标准字符串,要求内存由SysAllocString分配,CLR会尝试释放返回的BStr内存,但静态常量的内存并非COM分配的,因此会触发非法内存访问,导致程序崩溃。

解决办法

1. 统一调用约定

将C#的DllImport调用约定改为CallingConvention.StdCall,与C++的__stdcall保持一致。

2. 修正封送类型

  • 对于testFunc1的参数:C++接收const wchar_t*,对应C#的UnmanagedType.LPWStr(宽字符指针),而非BStr。
  • 对于testFunc2的返回值:使用UnmanagedType.LPWStr封送静态常量宽字符指针,CLR会正确读取字符串且不会尝试释放内存。

修改后的C#代码:

[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern uint testFunc1([MarshalAs(UnmanagedType.LPWStr)] string symbol);        

[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPWStr)]
internal static extern string testFunc2(uint id);

修改后调用testFunc2(123)即可正常返回"TEST"字符串,不再崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 21:33:23