【问题标题】:C# PInvoke pass reference to int[]C# PInvoke 传递对 int[] 的引用
【发布时间】:2019-10-25 18:50:40
【问题描述】:

我正在尝试将一个 int[8] 引用传递给 C++ DLL,但是当它返回时,C# 中会抛出一个 System.ExecutionEngineException。这是 C++ 代码:

extern "C" __declspec(dllexport) int __stdcall ReadFlashCfg(int* flData);
int __stdcall ReadFlashCfg(int* flData)
{
    return mctl.ReadFlashCfg(flData);
}// breakpoint here shows flData is correct

还有 C# DLL 封装代码:

[DllImport(MyDllPath)]
private static extern int ReadFlashCfg(ref int[] fData);

public static int[] ReadFlashCfgNoRc()
{
   var flData = new int[8];
   var rc = ReadFlashCfg(ref flData); //Exception happens here
   if (rc != 0) throw new Exception(rc.ToString());
   return flData;
}

以及C#调用代码:

var fd = ReadFlashCfgNoRc();

C++ 代码最后一行的断点显示填充了正确数据的数组。

异常发生在从 DLL 包装器中的 ReadFlashCfg(ref flData) 返回时。

我想我需要让 C++ 知道数组的大小(总是 8),这样它才能正确管理堆栈。

我知道我可以通过八个单独的 int*,但必须有更简单的方法 - 有吗?

【问题讨论】:

  • ReturnCode 是什么?为什么在 C++ dll 中返回这种类型而不是 int
  • ReturnCode 是一个整数。这是问题中的一个错字,现在已更正。
  • 删除ref
  • 同意@DavidHeffernan,Int[] 类型应该直接在这里传递。(快速测试并且对我来说很好)对于“我需要让C++知道数组的大小", 常用的方法是将size作为参数传递。
  • @DavidHeffman - 这解决了它,但我不明白为什么会这样。 C++ 参数是int*,我认为在P/Invoke 端需要ref',以便将修改后的参数返回给.NET。提交作为答案,我会选择它。

标签: c# winapi visual-c++ pinvoke


【解决方案1】:

Ref 通过引用传递参数。

正如this answer 所说:

  • ref Int32int* 的正确匹配项。
  • Int[](@DavidHeffman 指出)和IntPtr 也可以工作。 (使用Marshal::AllocHGlobal(8*sizeof(Int32))分配IntPtr大小,Marshal.FreeHGlobal(IntPtr)释放)
  • ref Int[] 将是 int**Int[] 的大小将错误地转换为 1。

对于“我需要让C++知道数组的大小”,常用的方法是将size作为参数传递。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    相关资源
    最近更新 更多