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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 07:20:29