c# - 在 P/Invoke 中使用 ref struct 或 class

标签 c# struct pinvoke unmanaged

我知道这个主题在这里讨论过很多次,但我找不到适合我具体情况的答案。

我需要在 C# 中调用一个非托管 C 方法,该方法采用结构对象上的指针(我不会说流利的 C:

int doStuff(MYGRID* grid, int x);

但结构本身引用了另一个结构对象:

struct MYGRID {

    int hgap;
    int vgap;

    MYIMAGE* image;

}

struct MYIMAGE {

    int res;
    int width;
    int height;

}

而且我还需要像这样直接设置图像指针:

MYGRID* pGrid = new MYGRID;
MYIMAGE* pImage = new MYIMAGE;
pGrid->image = pImage;

所以,我的问题是:在 C# 代码中,我是否应该使用“struct”对象并像 P/Invoke Interop Assistant 建议的那样通过“ref”传递它?这意味着以下代码:

MyGrid myGrid = new MyGrid();
MyImage myImage = new MyImage();

myGrid.image = Marshal.AllocHGlobal(Marshal.SizeOf(image)); // A IntPtr in my struct
myGrid.image = Marshal.StructureToPtr(image, myGrid.image, false);

doStuff(ref myGrid, 0);

或者我可以使用“类”而不是“结构”来获得非常简单的以下代码:

MyGrid myGrid = new MyGrid();
MyImage myImage = new MyImage();

myGrid.image = myImage;

doStuff(myGrid, 0);

在第一种情况下,我在我的结构 MyGrid 中使用了一个“IntPtr”,而在第二种情况中只使用了一个 MyImage 对象。

最佳答案

不要混淆 C# 结构和 C++ 结构。它们不是同一件事。 C# 结构用于声明值类型。当您在另一种类型中聚合一个值类型时,您将它直接存储在包含实例中,而不是存储对存储在堆中的实例的引用。 C++ 结构只是一个默认情况下所有成员都是公共(public)的类。

在您的情况下,因为 MYGRID 包含指向 MYIMAGE 的指针,您应该像在第二个示例中那样使用 class。但是,应删除 myGrid 参数上的 ref

下面是我测试过的一些示例代码。 C++代码:

#include "windows.h"

struct MYIMAGE {

  int res;
  int width;
  int height;

};

struct MYGRID {

  int hgap;
  int vgap;

  MYIMAGE* image;

};

extern "C" __declspec(dllexport) int doStuff(MYGRID* grid, int x) {
  return 0;
}

声明 C# 类和外部函数:

[StructLayout(LayoutKind.Sequential)]
class MyGrid {

  public int hgap;
  public int vgap;

  public IntPtr image;

}

[StructLayout(LayoutKind.Sequential)]
class MyImage {

  public int res;
  public int width;
  public int height;

}

[DllImport("MyDll")]
static extern int doStuff(MyGrid grid, int x);

调用外部函数:

MyImage image = new MyImage();

MyGrid grid = new MyGrid();
grid.image = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyImage)));
Marshal.StructureToPtr(image, grid.image, false);

doStuff(grid, 0);

如果您在 C# 项目中打开非托管调试,您可以使用调试器进入 C++ 函数并验证类是否已正确编码。

关于c# - 在 P/Invoke 中使用 ref struct 或 class,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14315801/

相关文章:

c# - LINQ 在 MAX 中的哪个位置

c# - 如何从通过 FtpCommand 运行的 FTP 命令获取结果?

c# - 如何将以下 c(++)-struct 转换为 C# 以供 p/invoke 使用

c# - P/Invoke 调用的方法是否在同一个线程中运行?

c# - 如何在 ASP.NET Core 2.0、RAZOR Tag Helpers 中格式化日期、时间、数字

c# - 当 DB 消失时,MySqlConnection Connect() 方法抛出异常的速度非常慢 C#

c# - 如何设置 UWP 元素的状态?

go - 绑定(bind)请求方式POST

c - 使用malloc和直接初始化到堆栈在内存空间方面的区别

c - 什么是哈希表?如何在C语言中创建哈希表?