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

时间:2012-11-22 00:23:52

标签: c# c++ visual-c++ pinvoke marshalling

我有一个带有非托管代码和C#UI的C ++ DLL。有一个从C ++ DLL导入的函数,它将一个由我编写的结构作为参数。

将C语言编写的结构(MyImage)从C#编组到C ++后,我可以访问其中int []数组的内容,但内容不同。我不知道我在这里失踪了什么,因为我花了很长时间并尝试了一些技巧来解决这个问题(显然还不够)。

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
}

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];
    }
}

以MyImage作为参数的C#函数声明:

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

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

因此,在调试问题时,我注意到c ++ struct中的MyImage.bits数组包含不同的数据。

我该如何解决?

3 个答案:

答案 0 :(得分:4)

由于bits字段是指向本机代码中分配的内存的指针,因此您需要在C#代码中将其声明为IntPtr

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

如果要访问C#代码中的单个像素,则需要编写GetPixel方法,就像在C ++代码中一样。

请注意,由于bits字段是指向本机代码中分配的内存的指针,因此我希望实际代码具有调用delete[] bits的结构的析构函数。否则你的代码会泄漏。

这也意味着您将需要在本机代码中创建和销毁实例,而不会在托管代码中执行此操作。这是您目前遵循的政策吗?我怀疑不是基于我在这里看到的代码。

您还需要重新考虑按值传递struct。当你打电话给那个功能时,你真的想要复制它吗?这样做意味着你有两个结构实例,其bits字段都指向同一个内存。但是,哪一个拥有那个记忆?这个结构确实需要通过引用传递。

我认为你的设计遇到了一些问题,但我看不到足够的代码,或者对你的问题了解得足以给你提供具体的建议。


在评论中,您声明您的主要目标是将这些位从C#代码传输到C ++代码。我建议你这样做:

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
}

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

答案 1 :(得分:-1)

您应该尝试的第一件事是使用unsigned int类型声明您的C#代码。有可能将一位解释为int的符号。

所以在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
}

答案 2 :(得分:-1)

您可以使用PInvoke Interop Assistant。您只需粘贴结构和函数声明,它将为您生成C#代码。它帮助了我很多次。