如何从C#向DLL中的原生函数传递char***类型参数
C#中对应C++ char***类型的P/Invoke参数处理
C中的char*** ConnectionNames是一个输出参数,本质是用来传递字符串数组(char**)的地址——C函数会在内部分配内存,创建包含多个char*字符串的数组,再把这个数组的地址通过char***指针返回给调用者(C#)。
在C#的P/Invoke声明中,有两种常用的处理方式:
方式一:用out IntPtr接收,手动解析字符串数组
这种方式更灵活,能明确控制内存处理流程:
- 函数声明:
[DllImport("你的动态库文件名.dll", CallingConvention = CallingConvention.StdCall)] static extern int TCPGetConnectionNames(out IntPtr connectionNamesPtr);
- 调用与解析:
int count = TCPGetConnectionNames(out IntPtr namesPtr); string[] connectionNames = new string[count]; for (int i = 0; i < count; i++) { // 取出数组中第i个字符串的指针 IntPtr strPtr = Marshal.ReadIntPtr(namesPtr, i * IntPtr.Size); // 转换为C#字符串(对应C++ char*的ANSI编码) connectionNames[i] = Marshal.PtrToStringAnsi(strPtr); }
方式二:直接用out string[]结合Marshal特性
如果函数返回值是字符串数组的长度,可以通过SizeParamIndex让Marshal自动解析:
[DllImport("你的动态库文件名.dll", CallingConvention = CallingConvention.StdCall)] static extern int TCPGetConnectionNames( [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 0)] out string[] connectionNames );
调用时直接接收字符串数组即可:
int count = TCPGetConnectionNames(out string[] connectionNames);
关键注意事项
- 调用约定必须匹配:C++用了
__stdcall,C#声明里要显式指定CallingConvention = CallingConvention.StdCall(.NET Framework默认是StdCall,但显式声明更稳妥)。 - 内存释放:C++函数分配的字符串数组和每个字符串的内存,必须调用该动态库提供的对应释放函数(比如可能叫
TCPFreeConnectionNames)回收,否则会造成内存泄漏。 - 字符编码适配:如果C++里是
char*(ANSI编码)用Marshal.PtrToStringAnsi;如果是宽字符wchar_t*,则对应Marshal.PtrToStringUni,Marshal特性要改成UnmanagedType.LPWStr。
内容的提问来源于stack exchange,提问作者steve
相关产品推荐
相关产品推荐

