微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 使用带有P / Invoke的ref struct或类

我知道这个问题已在这里多次讨论,但我无法找到适合我具体情况的答案.

我需要在C#中调用一个非托管的C方法,它接受一个struct对象的指针(我不会流利地说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”对象并通过“ref”传递它,就像P / Invoke Interop Assistant建议我一样吗?这意味着以下代码

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);

或者我可以使用“class”而不是“struct”来获得以下非常简单的代码

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

myGrid.image = myImage;

doStuff(myGrid,0);

在第一种情况下,我在结构MyGrid中使用“IntPtr”,在第二种情况下只使用MyImage对象.

解决方法

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

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

下面是我测试的一些示例代码. 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函数并验证类是否已正确编组.

原文地址:https://www.jb51.cc/csharp/99721.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐