在 C++ 中为结构体赋值时出现问题到从 C# 传递的结构

发布于 2024-08-14 22:57:10 字数 1478 浏览 5 评论 0原文

我有一个 C# 函数,它将结构数组传递到用 C++ 编写的 DLL 中。该结构是一组整数,当我读出 DLL 中的数据时,所有值都显示正常。但是,如果我尝试从 C++ 写入元素,则当我尝试在 C# 中读回时,这些值永远不会显示。

C#

[StructLayout(LayoutKind.Sequential)]
struct Box
{
  public int x;
  public int y;
  public int width;
  public int height;
}

[StructLayout(LayoutKind.Sequential)]
struct Spot
{
  public int x;
  public int y;
}

static void TestCvStructs()
{
  int len = 100;
  Box[] r = new Box[len];
  Spot[] p = new Spot[len];

  for (int i = 0; i < len; i++)
  {
    r[i].x = i*10;
    r[i].y = i * 200;
    r[i].width = r[i].x * 10;
    r[i].height = r[i].y * 100 + r[i].x * 5;

    p[i].x = i * 8;
    p[i].y = i * 12;
  }

  PassCvStructs(len, r, p);

  for (int i = 0; i < len; i++)
  {
    Console.WriteLine("Point/x:{0} Boxes/x{1}", p[i].x, r[i].x );
  }
}

[DllImport(dll)]
private static extern int PassSomeStructs(int count, Box[] boxes, Spot[] points);

C++

typedef struct Box
{
  int x;
  int y;
  int width;
  int height;
} Box;

typedef struct Spot
{
  int x;
  int y;
} Spot;

CPPDLL_API int PassSomeStructs(int arrayLength, Box *boxes, Spot *points)
{
  for(int i = 0; i < arrayLength; ++i)
  {
    printf("Group:%i\n", i);
    printf("Rect - x:%i y:%i width:%i length:%i\n", boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
    printf("Point - x:%i y:%i\n", points[i].x, points[i].y);
    printf("\n");

    points[i].x = 3;
    boxes[i].x = 1;
  }
  return 0;
}

I have a function in C# that is passing an array of structures into a DLL written in C++. The struct is a group of ints and when I read out the data in the DLL all the values come out fine. However if I try to write to the elements from C++ the values never show up when I try to read then back in C#.

C#

[StructLayout(LayoutKind.Sequential)]
struct Box
{
  public int x;
  public int y;
  public int width;
  public int height;
}

[StructLayout(LayoutKind.Sequential)]
struct Spot
{
  public int x;
  public int y;
}

static void TestCvStructs()
{
  int len = 100;
  Box[] r = new Box[len];
  Spot[] p = new Spot[len];

  for (int i = 0; i < len; i++)
  {
    r[i].x = i*10;
    r[i].y = i * 200;
    r[i].width = r[i].x * 10;
    r[i].height = r[i].y * 100 + r[i].x * 5;

    p[i].x = i * 8;
    p[i].y = i * 12;
  }

  PassCvStructs(len, r, p);

  for (int i = 0; i < len; i++)
  {
    Console.WriteLine("Point/x:{0} Boxes/x{1}", p[i].x, r[i].x );
  }
}

[DllImport(dll)]
private static extern int PassSomeStructs(int count, Box[] boxes, Spot[] points);

C++

typedef struct Box
{
  int x;
  int y;
  int width;
  int height;
} Box;

typedef struct Spot
{
  int x;
  int y;
} Spot;

CPPDLL_API int PassSomeStructs(int arrayLength, Box *boxes, Spot *points)
{
  for(int i = 0; i < arrayLength; ++i)
  {
    printf("Group:%i\n", i);
    printf("Rect - x:%i y:%i width:%i length:%i\n", boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
    printf("Point - x:%i y:%i\n", points[i].x, points[i].y);
    printf("\n");

    points[i].x = 3;
    boxes[i].x = 1;
  }
  return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

╭⌒浅淡时光〆 2024-08-21 22:57:10

来自关于编组数组的 MDSN 文章:尝试在你的数组类型。这通常用于从 C++ 调用 C#,但也可能需要将更新后的值返回到 C#。

[DllImport(dll)]
private static extern int PassSomeStructs(int count, 
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] Box[] boxes, 
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] Spot[] points);

另请参阅本文,了解成功双向编组的示例:

http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/ff0123d0-506b-4de2-bfb5-f690c9358826/

From an MDSN article on marshalling arrays: try setting the following attribute on your array types. This is normally used for calling into C# from C++, but it may also be required for getting updated values back into C#.

[DllImport(dll)]
private static extern int PassSomeStructs(int count, 
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] Box[] boxes, 
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] Spot[] points);

Also see this article for an example of successful two-way marshalling:

http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/ff0123d0-506b-4de2-bfb5-f690c9358826/

刘备忘录 2024-08-21 22:57:10

您是否尝试过将 ref/out 关键字添加到 C# extern 中?

另一个想法是尝试传递 IntPtr 而不是类本身,或者将其作为 IntPtr 传递...

我相信结构是被复制的,默认情况下不是通过引用传递的。

老实说,在黑暗中刺伤,但你还没有任何答案,所以希望这会有所帮助......

互操作对我来说仍然处于“它很神奇”的阶段......

Have you tried adding the ref/out keyword to your C# extern?

Another idea is try passing in an IntPtr instead of the class itself, or passing it in -as- an IntPtr...

I believe that structs are copied, not passed by reference by default.

Honestly stabbing in the dark, but you don't have any answers yet, so hopefully this helps...

Interop is still in the "it's magic" stage for me...

誰認得朕 2024-08-21 22:57:10

我找到了另一个问题的答案:如何编组C# 中的结构数组?

显然,当封送时,默认是将参数封送为 In。否则,需要将它们显式声明为 Out 或 In, Out。明确指定我的代码后,该示例现在可以运行了。

感谢他的Skeetness的回答以及antonmarkov 接触元帅。

private static extern int PassSomeStructs(int count, [In, Out] Box[] boxes, [In, Out] Spot[] points);

I found the answer posted to another question: How to marshall array of structs in C#?

When marshaling apparently the default is to marshal the parameters as In. Otherwise they need to be explicitly declared as Out or In, Out. After specifying that explicitly my code the example now works.

Thanks to his Skeetness for the answer and to antonmarkov for the exposure to the MarshalAs.

private static extern int PassSomeStructs(int count, [In, Out] Box[] boxes, [In, Out] Spot[] points);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文