2014-06-27 54 views
1

在C#C#我有一個數據類型byte[],其欲填在使用C++函數,它返回char*獲取字節[]從在C++中的char *

的C++函數(在ImageData.dll

char* pMemoryBuffer = NULL; 
char* LoadData(const char *fileName) 
{ 
    // processing pMemoryBuffer ... 
    return pMemoryBuffer; 
} 

導入本地的dll到C#:

[DllImport(".\\Modules_Native\\ImageData.dll", EntryPoint = "LoadData")] 
    private extern static byte[] LoadData(string fileName); 

C#中的byte[]數據

byte[] buffer = new byte[256*256]; 
buffer = LoadData("D:\\myPic.tif"); 

顯然它還沒有工作,但它提出了我想要做的想法。所以我想知道如何做這項工作,以及做到這一點的正確方法是什麼。非常感謝您的教育。

+0

它不知道C#數組必須多大。 – prq

+0

查看線程中的更新。大小已初始化。 – Ono

+0

你可以通過指定它的「不工作」來改善你的問題嗎?我不是下來的選民,但這可能是原因。 – jmstoker

回答

5

試試這個

// c++ 

    void LoadData(unsigned char* *pMemoryBuffer, const char *fileName) 
    { 
     // processing pMemoryBuffer ... 
     *pMemoryBuffer = resutss; 

    } 

導入本地的dll到C#:

[DllImport(".\\Modules_Native\\ImageData.dll", EntryPoint = "LoadData")] 
private extern static void LoadData(out IntPtr data, string fileName); 

當函數返回的數據將指向數組,你可以閱讀使用Marshal類的內容。我想你會copy it to a new byte arraŸ。

byte[] buffer = new byte[256*256]; 
buffer = Marshal.Copy(LoadData(buffer ,"D:\\myPic.tif"), buffer , 0, buffer.Length); 
+0

你的'Marshal.Copy'例子對於返回的指針是正確的。如果您可以更改C代碼以使輸出緩衝區成爲參數,那麼請不要使用'IntPtr'和'Marshal.Copy'。 –

+0

所以,感謝您複製我的答案,甚至沒有做出積極的調整 –

+1

你有什麼將無法工作,你需要一個'IntPtr'返回值來使'Marshal.Copy'片段工作。 –

1

我不確定,但我的直覺說,你不能在字節數組中指定一個char *,就像你不能在C++本身中一樣。你可以在C#中使用IntPtr(可能不是非常有用),或者,你可以傳遞一個byte []緩衝區和一些字節來寫入。換句話說,我覺得有以下將工作:

char* pMemoryBuffer = NULL; 
int size = 0; 
int seek = 0; 
bool LoadData(const char* filename) 
{ 
    // load filename 
    // set seek = 0 
    // set size to data size 
} 

int ReadData(char* buffer, int nBytesToRead) 
{ 
    // nCopyBytes = min(nBytesToRead, size - seek) 
    // copy nCopyBytes from pMemoryBuffer+seek to buffer 
    // seek += nCopyBytes 
    // return nCopyBytes 
} 

從C#中,你會使用這樣的:

byte[] buffer = new byte[256*256]; 
LoadData("foo.tif"); 

int bytesRead = ReadData(buffer, 256*256); 

很抱歉,如果您特別想避免做這樣的事情。

+0

'out'關鍵字在這裏不合適,數組是引用類型,並且已經通過p/invoke作爲指針傳遞。 –

+0

@BenVoigt我看到了,謝謝你指出了這一點。 – Patrick87

1

這應做到:

[DllImport(@".\Modules_Native\ImageData.dll")] 
private extern static IntPtr LoadData(string fileName); 

byte[] buffer = new byte[256*256]; 
buffer = Marshal.Copy(LoadData("D:\\myPic.tif"), buffer, 0, buffer.Length); 

但是,它不會釋放內存。希望C(++)庫在下次調用時自動釋放它,否則會提供釋放函數。

一個更好的辦法是使用調用者分配的緩衝區,那麼你就只是做:

byte[] buffer = new byte[256*256]; 
LoadData("D:\\myPic.tif", buffer); 

爲此,C(++)代碼,將需要改變

int LoadData(const char *fileName, char* pMemoryBuffer) 
{ 
    // processing pMemoryBuffer ... 
    return 1; // if success 
} 

和p/Invoke的聲明

[DllImport(@".\Modules_Native\ImageData.dll")] 
private extern static int LoadData(string fileName, byte[] buffer); 
+1

那麼,我的答案或 –

+0

@moez:不,它不是。你展示瞭如何創建一個'out IntPtr'參數,我認爲這是一個壞主意,所以我將它改進爲一個新的答案。你根本沒有展示如何使用調用者提供的緩衝區。而且你沒有提到讓庫在返回緩衝區中釋放的問題。 –

+0

@moez:此外,每個人都可以看到我的答案出現在您的編輯之前......所以我認爲很清楚這些想法正在流向哪個方向(我不會指責您被盜,我留下了一條評論中的更正,因爲我邀請你使用它,但你沒有正確地做) –