简体   繁体   English

从C#到C ++的包含int和int []的编组结构

[英]Marshalling struct containing int and int[] from C# to C++

I have a C++ DLL with unmanaged code and a C# UI. 我有一个带有非托管代码和C#UI的C ++ DLL。 There's a function imported from C++ DLL that takes a written-by-me struct as parameter. 有一个从C ++ DLL导入的函数,该函数将“按我编写”结构作为参数。

After marshalling the written-by-me struct (MyImage) from C# to C++ I can access the content of the int[] array inside of it, but the content is different. 从C#将按我编写的结构(MyImage)整理到C ++之后,我可以访问其中的int []数组的内容,但是内容有所不同。 I do not know what I am missing here as I spent quite some time and tried a few tricks to resolve this (obviously not enough). 我不知道我在这里缺少什么,因为我花了很多时间并尝试了一些技巧来解决此问题(显然这还不够)。

MyImage struct in C#: C#中的MyImage结构:

[StructLayout(LayoutKind.Sequential)]
struct MyImage
{
    public int width;
    public int height;
    public int[] bits; //these represent colors of image - 4 bytes for each pixel
}

MyImage struct in C++: C ++中的MyImage结构:

struct MyImage
{
    int width;
    int height;
    Color* bits; //typedef unsigned int Color;

    MyImage(int w, int h)
    {
         bits = new Color[w*h];
    }

    Color GetPixel(int x, int y)
    {
          if (x or y out of image bounds) return UNDEFINED_COLOR;
          return bits[y*width+x];
    }
}

C# function declaration with MyImage as parameter: 以MyImage作为参数的C#函数声明:

[DLLImport("G_DLL.dll")]
public static extern void DisplayImageInPolygon(Point[] p, int n, MyImage texture, 
                                                  int tex_x0, int tex_y0);

C++ implementation C ++实现

DLLEXPORT void __stdcall DisplayImageInPolygon(Point *p, int n, MyImage img,
                                               int imgx0, int imgy0)
{
    //And below they have improper values (i don't know where they come from)
    Color test1 = img.GetPixel(0,0);
    Color test2 = img.GetPixel(1,0);
}

So when debugging the problem I noticed that the MyImage.bits array in c++ struct holds different data. 因此,在调试问题时,我注意到c ++结构中的MyImage.bits数组保存了不同的数据。

How can I fix it? 我该如何解决?

Since the bits field is a pointer to memory allocated in the native code, you are going to need to declare it as IntPtr in the C# code. 由于bits字段是指向本机代码中分配的内存的指针,因此您将需要在C#代码中将其声明为IntPtr

struct MyImage
{
    public int width;
    public int height;
    public IntPtr bits;
}

If you want to access individual pixels in the C# code you'll need to write a GetPixel method, just as you did in the C++ code. 如果要访问C#代码中的各个像素,则需要编写GetPixel方法,就像在C ++代码中一样。

Note that since the bits field is a pointer to memory allocated in the native code, I'd expect the actual code to have a destructor for the struct that calls delete[] bits . 请注意,由于bits字段是指向在本机代码中分配的内存的指针,因此我希望实际代码具有针对调用delete[] bits的结构的析构函数。 Otherwise your code will leak. 否则您的代码将泄漏。

This also means that you are going to need to create and destroy instances in the native code, and never do so in the managed code. 这也意味着您将需要在本机代码中创建和销毁实例,而永远不要在托管代码中这样做。 Is this the policy you currently follow? 这是您当前遵循的政策吗? I suspect not based on the code that I can see here. 我怀疑不是基于我在这里看到的代码。

You also need to reconsider passing the struct by value. 您还需要重新考虑按值传递struct Do you really want to take a copy of it when you call that function? 调用该函数时,您真的要复制它吗? Doing so means you've got two instances of the struct whose bits fields both point to the same memory. 这样做意味着您拥有该结构的两个实例,这些实例的bits字段均指向同一内存。 But, which one owns that memory? 但是,谁拥有那个记忆? This structure really needs to be passed by reference. 确实需要通过引用传递此结构。

I think you've got some problems in your design, but I can't see enough of the code, or know enough about your problem to be able to give you concrete advice. 我认为您的设计中存在一些问题,但是我看不到足够的代码,或者对问题的了解不足,无法为您提供具体建议。


In comments you state that your main goal is to transfer these bits from your C# code to the C++ code. 在注释中,您声明您的主要目标是将这些位从C#代码转换为C ++代码。 I suggest you do it like this: 我建议你这样做:

MyImage* NewImage(int w, int h, Color* bits)
{
    MyImage* img = new MyImage;
    img->w = w;
    img->h = h;
    img->bits = new Color[w*h];
    for (int i=0; i<w*h; i++)
        img->bits[i] = bits[i];
    return img;
}

void DeleteImage(MyImage* img)
{
    delete[] img->bits;
    delete img;
}

void DoSomethingWithImage(MyImage* img)
{
    // do whatever it is you need to do
}

On the C# side you can declare it like this: 在C#端,您可以这样声明:

[DllImport(@"dllname.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr NewImage(int w, int h, int[] bits);

[DllImport(@"dllname.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void DeleteImage(ImtPtr img);

[DllImport(@"dllname.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void DoSomethingWithImage(ImtPtr img);

The first thing you should try is declaring your C# code with unsigned int types as well. 您应该尝试的第一件事就是用无符号的int类型声明您的C#代码。 It is possible that one bit is being interpreted as a sign for your int. 一位可能被解释为您的int的符号。

So in C# something like this (just note the bits is now uint[] ): 因此在C#中类似这样(请注意,现在这些位是uint[] ):

[StructLayout(LayoutKind.Sequential)]
struct MyImage
{
    public int width;
    public int height;
    public uint[] bits; //these represent colors of image - 4 bytes for each pixel
}

You can use the PInvoke Interop Assistant . 您可以使用PInvoke Interop Assistant You simply paste your struct and function declaration and it will generate the C# code for you. 您只需粘贴您的结构和函数声明,它将为您生成C#代码。 It has helped me a lot quite a few times. 它对我有很多帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM