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返回来结构体

浙公网安备 33010602011771号