我知道这个主题在这里讨论过很多次,但我找不到适合我具体情况的答案。
我需要在 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/