通过P/Invoke从C#向C++传递字符串的问题求助
问题根源与解决方案
你遇到的核心问题是:C++的std::wstring是标准库的自定义类类型,而.NET的P/Invoke机制只能直接处理POD(Plain Old Data)类型或COM兼容类型。直接将C#的ref string与C++的std::wstring&绑定,会因为内存布局、内存管理机制完全不匹配,导致调用失败、内存损坏甚至程序崩溃。
下面给你两种最实用的解决方案,你可以根据现有代码结构选择:
方案1:改用C风格宽字符串(最推荐,无额外依赖)
这种方式直接用P/Invoke原生支持的wchar_t*作为参数,避免C++类类型的跨语言绑定问题。
调整后的C++代码
头文件:
namespace NMSP { extern "C" { // 传入缓冲区指针和缓冲区大小,确保写入不会溢出 __declspec(dllexport) int MyCPPMethod(wchar_t* StrCode, size_t bufferSize); } }
源文件:
#include <cstring> __declspec(dllexport) int NMSP::MyCPPMethod(wchar_t* StrCode, size_t bufferSize) { const wchar_t* result = L"12345"; // 使用wcscpy_s保证安全,避免缓冲区溢出 if (bufferSize > wcslen(result)) { wcscpy_s(StrCode, bufferSize, result); } return 1; }
对应的C#代码
using System.Text; using System.Runtime.InteropServices; class NativeMethods { [DllImport(@"MyExternal.dll", CharSet = CharSet.Unicode)] static extern int MyCPPMethod(StringBuilder strCode, int bufferSize); } // 调用示例 var codeBuffer = new StringBuilder(256); // 预先分配足够大的缓冲区 int returnValue = NativeMethods.MyCPPMethod(codeBuffer, codeBuffer.Capacity); string finalCode = codeBuffer.ToString();
为什么用StringBuilder? 因为C#的string是不可变的,底层内存由CLR管理;而StringBuilder会分配一块可修改的原生内存缓冲区,正好匹配C++端wchar_t*的写入需求。
方案2:通过BSTR做中间适配(兼容现有std::wstring代码)
如果你不想修改原有的std::wstring版本方法,可以封装一个适配层,用COM兼容的BSTR类型作为跨语言传递的桥梁(.NET对BSTR有原生的内存管理支持)。
调整后的C++代码
#include <comutil.h> #include <string> #pragma comment(lib, "comsuppw.lib") // 链接COM辅助库 namespace NMSP { // 原有的std::wstring方法保持不变 int MyCPPMethod(std::wstring &StrCode) { StrCode = L"12345"; return 1; } // 对外导出的适配方法,用BSTR传递字符串 extern "C" { __declspec(dllexport) int MyCPPMethodWrapper(BSTR* outStr); } __declspec(dllexport) int MyCPPMethodWrapper(BSTR* outStr) { std::wstring tempStr; int result = MyCPPMethod(tempStr); // 将std::wstring转换为BSTR,由.NET负责释放内存 *outStr = SysAllocString(tempStr.c_str()); return result; } }
对应的C#代码
using System.Runtime.InteropServices; class NativeMethods { [DllImport(@"MyExternal.dll", CharSet = CharSet.Unicode)] static extern int MyCPPMethodWrapper([MarshalAs(UnmanagedType.BStr)] out string strCode); } // 调用示例 int returnValue = NativeMethods.MyCPPMethodWrapper(out string finalCode);
内存管理说明:SysAllocString分配的BSTR内存,.NET的Marshal会在out string参数销毁时自动释放,不需要你手动调用SysFreeString。
内容的提问来源于stack exchange,提问作者Dave Gahan
相关产品推荐
相关产品推荐

