C++函数参数有结构体,C#调用

 第一部分:参数输入

C++代码

struct LIBCOMPILEERROR_API tagCheckResultInfo
{
    int m_taskId;
    int m_checkResult;
    int m_varCount;
    
};
extern "C" __declspec(dllexport)tagCheckResultInfo GetCheckResult(const tagCheckResultInfo* temp)
{
    tagCheckResultInfo info;
    info.m_taskId = 1001;
    info.m_checkResult = 0;    // 成功
    info.m_varCount = 5;

    
    return info;
}

C#代码

 // 结构体布局必须与 C++ 一致
 [StructLayout(LayoutKind.Sequential)]
 public struct tagCheckResultInfo
 {
     public int m_taskId;
     public int m_checkResult;
     public int m_varCount;
     // 如果 C++ 版本有指针成员(如 tagVarCheckResult* m_varResult),
     // 这里应该用 IntPtr,然后通过 Marshal.PtrToStructure 读取。
 }
 [DllImport("ConsoleApplication1.dll", CallingConvention = CallingConvention.Cdecl)]
 public static extern tagCheckResultInfo GetCheckResult(ref tagCheckResultInfo request);

 private void button1_Click(object sender, EventArgs e)
 {
     tagCheckResultInfo tagCheckResultInfo1= new tagCheckResultInfo
     {
         m_taskId = 123,
         m_checkResult =456,
         m_varCount = 789
     };
     tagCheckResultInfo result = GetCheckResult( ref tagCheckResultInfo1);

     // 使用结果
     MessageBox.Show($"TaskId: {result.m_taskId}, Result: {result.m_checkResult}, VarCount: {result.m_varCount}");
 }

为什么这里可以用 ref

  • 因为 C++ 函数参数是指针 (const tagCheckRequest*),P/Invoke 封送器需要传递托管对象的地址。

  • 在 C# 中传递 ref 结构体,封送器会自动把托管地址转换为非托管指针,非常高效。

  • 即使 C++ 端声明为 const 只读,C# 端用 ref 也完全合法(只是语义上暗示可能修改,但实际不会)。

  • 这是最简单、最安全的方式,强烈推荐

何时用 out 而非 ref

  • 如果 C++ 函数纯粹输出一个结构体(不读取输入值),用 out 更清晰地表达意图,且可以省略调用前的初始化。

  • 如果 C++ 函数需要读取结构体的原有内容并进行修改,则必须用 ref

第二部分:通过输入参数返回

C++代码

struct LIBCOMPILEERROR_API tagCheckResultInfo
{
    int m_taskId;
    int m_checkResult;
    int m_varCount;
    
};
extern "C" __declspec(dllexport)tagCheckResultInfo GetCheckResult(const tagCheckResultInfo* temp, tagCheckResultInfo* outResult)
{
    tagCheckResultInfo info;
    info.m_taskId = 1001;
    info.m_checkResult = 0;    // 成功
    info.m_varCount = 5;

    // 填充输出参数(如果指针不为空)
    if (outResult != nullptr)
    {
        outResult->m_taskId = 2002;
        outResult->m_checkResult = 1;   // 示例状态
        outResult->m_varCount = 8;
    }
    return info;
}

C#代码

 // 结构体布局必须与 C++ 一致
 [StructLayout(LayoutKind.Sequential)]
 public struct tagCheckResultInfo
 {
     public int m_taskId;
     public int m_checkResult;
     public int m_varCount;
     // 如果 C++ 版本有指针成员(如 tagVarCheckResult* m_varResult),
     // 这里应该用 IntPtr,然后通过 Marshal.PtrToStructure 读取。
 }
 [DllImport("ConsoleApplication1.dll", CallingConvention = CallingConvention.Cdecl)]
 public static extern tagCheckResultInfo GetCheckResult(ref tagCheckResultInfo request,out tagCheckResultInfo tagCheckResultInfo);

 private void button1_Click(object sender, EventArgs e)
 {
     tagCheckResultInfo tagCheckResultInfo1= new tagCheckResultInfo
     {
         m_taskId = 123,
         m_checkResult =456,
         m_varCount = 789
     };
     tagCheckResultInfo tagCheckResultInfo;
     tagCheckResultInfo result = GetCheckResult( ref tagCheckResultInfo1,out tagCheckResultInfo);

     // 使用结果
     MessageBox.Show($"TaskId: {result.m_taskId}, Result: {result.m_checkResult}, VarCount: {result.m_varCount}");
 }

通过参数用out返回来结构体

posted @ 2026-05-29 16:04  家煜宝宝  阅读(11)  评论(0)    收藏  举报