C++类型转C++/CLI:包装原生C++库供C#调用时类型转换报错如何解决
C++/CLI 包装原生C++接口类型转换解决方案
报错原因说明
你遇到的String^转wchar_t*不支持的报错,核心原因是msclr::interop::marshal_context的marshal_as方法将托管字符串转为宽字符指针时,默认返回const wchar_t*类型,指向由context管理的只读内存块,不允许直接赋值给非const的wchar_t*,所以换成const wchar_t*就可以正常编译。
同时你写的string_to_wchar函数存在严重野指针问题:context被delete后,它管理的所有转换后的非托管内存都会被释放,返回的wchar_t*是无效指针,调用原生函数时大概率触发崩溃。
三类原生指针的正确转换方式
1. void* 和 IntPtr 转换
你当前的转换逻辑完全正确:
- 原生C的
void*对应C/CLI的IntPtr托管类型 - 传入原生函数时调用
IntPtr::ToPointer()即可拿到原生void*指针,只需确保传入的IntPtr指向的原生资源未提前释放即可
2. wchar_t* 和 String^ 转换
需根据原生函数是否修改Feature参数分两种情况处理:
情况1:原生函数不会修改Feature内容(绝大多数场景)
直接在当前函数作用域内使用栈分配的marshal_context,保证context生命周期覆盖原生函数调用全程,对返回的const指针做强转即可:
int CppCliFunc(IntPtr Handle, String^ Feature, long long% Value) { marshal_context context; // 栈分配自动释放,无需手动管理 const wchar_t* unmanagedFeature = context.marshal_as<const wchar_t*>(Feature); return ::CppFunc(Handle.ToPointer(), const_cast<wchar_t*>(unmanagedFeature), &Value); }
情况2:原生函数确实会修改Feature内容
需要手动分配非托管内存,拷贝字符串后传入,调用完成后释放内存:
int CppCliFunc(IntPtr Handle, String^ Feature, long long% Value) { int strLen = Feature->Length + 1; wchar_t* unmanagedFeature = new wchar_t[strLen]; // 托管字符串拷贝到非托管内存 Marshal::Copy(Feature->ToCharArray(), 0, IntPtr(unmanagedFeature), strLen); int ret = ::CppFunc(Handle.ToPointer(), unmanagedFeature, &Value); // 若需要把修改后的字符串传回托管侧,可在此处把unmanagedFeature转为String^返回 delete[] unmanagedFeature; return ret; }
3. long long* 对应托管类型转换
你当前的写法不符合托管代码调用习惯,原生的long long*(单值输出场景)对应C++/CLI的long long%跟踪引用,C#侧会自动识别为out long long参数:
- 如果是输入参数,直接用
long long值类型即可,调用原生函数时取地址传入 - 如果是输出/输入输出参数,用
long long%,调用原生函数时取&Value即可
内容的提问来源于stack exchange,提问作者bricx
相关产品推荐
相关产品推荐

