2012-11-22 57 views
4

我有一个非托管代码和C#UI的C++ DLL。有一个从C++ DLL导入的函数,该函数采用write-by-me结构作为参数。编组结构包含int和int []从C#到C++

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

MYIMAGE结构在C#:

[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结构在C++:

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#函数声明与MYIMAGE作为参数:

[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++结构中的MyImage.bits数组包含不同的数据。

我该如何解决?

回答

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

是否有可能创建一个IntPtr int []数组没有不安全的代码?这个结构只有一个存在的目的 - >将图像传递给C++层,在那里我可以处理它。你是说我应该在IntPtr中传递整个结构? –

+0

在这种情况下,我不会在C#中声明结构。只需在传递数据的本地代码中调用一个函数,并创建本地结构。 –

+0

你说什么为我工作。还有1个问题:当我把它看作是正确的,当作为函数参数传递时,int []数组被整理为int *而没有问题,并且当数组作为int []传递给结构时,这不起作用?难道我们不能强制程序在结构内对待这个数组,就好像它将被作为参数传递给函数一样吗? –

-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 
} 
-1

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