2011-07-20 236 views
4

我有一個在C#中編寫的應用程序,它使用編寫在C中的DLL。 通過一些委託(函數指針),我設法調用了一個C函數。預計此功能會對某些數據執行大量處理,然後將處理後的二進制數據連同數據大小一起返回到C#代碼。將數據從非託管代碼(C)傳遞到託管代碼(C#)

原型爲管理c#功能是:

private unsafe delegate void MyCallback (IntPtr cs_buf, Int32 cs_size);

而且我從我C code因調用該:

void* c_buf = NULL; 
int c_size = 0; 

.... some processing here to fill buf and size...... 

MyCallback (c_buf, c_size); 

在管理C#代碼,我需要調用一個函數來自MyCallback的原型:

void foo (byte[] cs_buf, int cs_size)

現在有與cs_size值沒有問題,但什麼是使用/從C代碼的二進制緩衝區傳遞到C#代碼,以便它可以被用作C#代碼byte[]的正確方法。

如果我正在做的是正確的方法,應該將接收的IntPtr cs_buf轉換爲byte[]的推薦方式是什麼?

謝謝, 維克拉姆

回答

2

應使用Marshal.Copy

Marshal.Copy Method (IntPtr, Byte[], Int32, Int32)

複製數據從非託管存儲器指針管理8位 無符號整數數組。

假設cs_size是字節大小:

var array = new byte[cs_size]; 
Marshal.Copy(pointer, array, 0, cs_size); 
foo(array, cs_size); 

順便說INT這種情況下foo()不需要採取cs_size參數,因爲它可以使用數組的.Length屬性。


這個

此外,由於C#代碼複製數組,你可以只調用回調後free()從C代碼的緩衝區。

否則你需要或者從C導出mylib_free()方法或使用已知的內存分配器(NOT malloc)像LocalAlloc(從C)和Windows下Marshal.FreeHGlobal(從C#)。

+0

如果您的項目中沒有託管的C++代碼,並且只是這一個調用,那麼這是最佳解決方案。 –

+0

+1。這工作。謝謝 :)。但是,我只是在想,這不會引入額外的複製開銷嗎? –

+0

它的確如此,但它仍然是最好的解決方案,如果您沒有任何託管C++並且您沒有太多這樣的調用,並且性能不是很重要。我的答案可以用來避免額外的副本,但是你必須創建一個C++項目(可以編譯成一個點網絡程序集)。 –

4

這是Microsoft爲C++/CLI製作的(也稱爲託管C++)。你可以寫這樣的功能:

void call_foo(array<Byte>^ bytes) 
{ 
    pin_ptr<Byte> ptrBuffer = &bytes[bytes->GetLowerBound(0)]; 
    foo(ptrBuffer, bytes->Length); 
} 

這將需要字節的C#陣列,其引腳內存,然後把它作爲字節FOO的一個C風格的數組,它的長度。沒有必要清理或釋放任何東西。固定指針在call_foo結束時超出範圍時將自動取消固定。清潔和簡單。