2012-11-22 90 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#代碼。它幫了我很多時間。