C#向C++ DLL传递字符串至char指针参数报错排查
问题:C#字符串传递到C++ DLL的char*指针时参数错误排查
我需要将C#中的IP字符串“192.168.1.1”传递给C++编写的DLL里用typedef定义的char指针。已做如下声明:
char *pcAddrs; //C++端
[MarshalAs(UnmanagedType.LPStr)] public string ip //C#端
并声明Open函数:
//C++端 int Open( COMMIF_INFO *pInfo )
//C#端 [DllImport("Open-IF.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int Open(COMMIFINFO info);
点击Button1触发Open函数时出现参数错误,请问是否是字符串与char指针的映射问题?
C++ DLL相关定义
typedef struct CommIfInfo { char *pcAddrs; long lPortNo; long lRetry; long lSendTimeOut; long lCommSide; long lMode; long lKind; } COMMIF_INFO; // 需要调用的函数 int Open( COMMIF_INFO *pInfo )
C#端代码
// DLL导入 [DllImport("Open-IF.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int Open(COMMIFINFO info); // 结构体定义 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct COMMIFINFO { [MarshalAs(UnmanagedType.LPStr)] public string ip; public int PortNo; public int Retry; public int SendTimeOut; public int CommSide; public int Mode; public int Kind; } private void button1_Click(object sender, EventArgs e) { string _ip = "192.168.1.1"; COMMIFINFO info = new COMMIFINF(); // 拼写错误:应为COMMIFINFO info.ip = _ip; info.Kind = 1; int ErrCode = Open(info); }
问题分析与解决
核心问题与修正
- 结构体传递方式错误:C++函数接收的是
COMMIF_INFO *pInfo(结构体指针),但当前C#的Open函数声明是传递值类型COMMIFINFO info,这会导致CLR封送时传递结构体副本的临时指针,而非你创建的结构体的指针,这是引发参数错误的核心原因。 - 代码拼写错误:按钮点击事件中
new COMMIFINF()是笔误,必须修正为new COMMIFINFO()。 - 未初始化成员风险:仅设置
ip和Kind,其他成员为默认值(0),若DLL要求这些成员必须显式赋值,可能引发异常,建议初始化所有成员。 - 字符串映射无问题:你使用的
[MarshalAs(UnmanagedType.LPStr)]是正确的,C#string会被正确封送为C++的ANSI编码char*,这部分无需修改。
正确实现代码
方案1:使用ref传递结构体引用
修改DllImport声明和调用逻辑:
// 修正后的DLL导入 [DllImport("Open-IF.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int Open(ref COMMIFINFO info); // 修正后的按钮点击事件 private void button1_Click(object sender, EventArgs e) { string _ip = "192.168.1.1"; COMMIFINFO info = new COMMIFINFO(); info.ip = _ip; info.Kind = 1; // 显式初始化所有成员 info.PortNo = 0; info.Retry = 0; info.SendTimeOut = 0; info.CommSide = 0; info.Mode = 0; int ErrCode = Open(ref info); }
方案2:手动管理非托管内存(可选)
若需要更精细的内存控制,可手动分配非托管内存传递指针:
// 对应的DllImport声明 [DllImport("Open-IF.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int Open(IntPtr pInfo); private void button1_Click(object sender, EventArgs e) { COMMIFINFO info = new COMMIFINFO(); info.ip = "192.168.1.1"; info.Kind = 1; info.PortNo = 0; info.Retry = 0; info.SendTimeOut = 0; info.CommSide = 0; info.Mode = 0; // 分配非托管内存 IntPtr pInfo = Marshal.AllocHGlobal(Marshal.SizeOf(info)); try { // 将结构体封送到非托管内存 Marshal.StructureToPtr(info, pInfo, false); // 调用DLL函数 int ErrCode = Open(pInfo); } finally { // 释放非托管内存 Marshal.FreeHGlobal(pInfo); } }
内容的提问来源于stack exchange,提问作者TK.C
相关产品推荐
相关产品推荐

