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

如何从C#向DLL中的原生函数传递char***类型参数

C#中对应C++ char***类型的P/Invoke参数处理

C中的char*** ConnectionNames是一个输出参数,本质是用来传递字符串数组(char**)的地址——C函数会在内部分配内存,创建包含多个char*字符串的数组,再把这个数组的地址通过char***指针返回给调用者(C#)。

在C#的P/Invoke声明中,有两种常用的处理方式:

方式一:用out IntPtr接收,手动解析字符串数组

这种方式更灵活,能明确控制内存处理流程:

  1. 函数声明:
[DllImport("你的动态库文件名.dll", CallingConvention = CallingConvention.StdCall)]
static extern int TCPGetConnectionNames(out IntPtr connectionNamesPtr);
  1. 调用与解析:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 03:34:57