2014-02-09 79 views
1

我在我的C++代碼將數據發送到非託管代碼的DllImport

extern "C" __declspec(dllexport) void*__cdecl 
widgetCreate(char* data, size_t length){ 
    return new Widget(data); 
} 

以下簽名而在我的C#代碼如下:

[DllImport(Path, CallingConvention = CallingConvention.Cdecl)] 
public static extern IntPtr widgetCreate(byte[] data, int length); 

我想要的C++代碼,以保持自己的在data的副本,所以我做了memcpy()

extern "C" __declspec(dllexport) void*__cdecl 
widgetCreate(char* data, size_t length){ 
    auto copy = new char[length]; 
    memcpy(copy, data, length); 
    return new Widget(copy); 
} 

有沒有辦法使火星哈勒爲我做這個副本?像下面這樣的東西?

[DllImport(Path, CallingConvention = CallingConvention.Cdecl)] 
public static extern IntPtr widgetCreate([CopyThisThing] byte[] data); 

回答

3

不是。該副本遲早要再次發佈。 pinvoke編組器無法知道本機代碼使用哪個分配器。所以它不能可靠地選擇一個堆來存儲副本。你可以編寫的唯一一個使用UnmanagedType.SafeArray的[MarshalAs]。爲了使互操作安全而創建的特定數組類型,通常僅被明確寫入以支持互操作的代碼才能接受。就像COM代碼一樣,你通常不會糾結這一點。

有些情況下,它需要必須複製,當託管數據不可用並且需要按照[StructLayout]的指示從託管佈局轉換爲本機佈局時發生這種情況。然而,這是完全透明的,在呼叫完成後編組人員總是會刪除副本。

可以通過在您的C#代碼中明確創建副本來使其工作。您將參數聲明爲IntPtr並使用Marshal.AllocHGlobal()或Marshal.AllocCoTaskMem()分配內存。並且自己編組數據,通常通過調用Marshal.StructureToPtr()來處理數據,除非您知道本機代碼使用適當的方式再次發佈副本,否則這種情況並不會很好。換句話說,LocalFree()或CoTaskMemFree()。如果您使用VS2012或更高版本的本機代碼,則賠率顯着增加,其CRT現在使用默認進程堆而不是創建自己的堆。

+0

好的,謝謝你的照明說明。 – Gleno

相關問題