2013-01-15 36 views
1

我有以下C++方法的簽名。最後一個參數應該以2字節的unicode字符串返回設備名稱。如何使用PInvoke將Unicode字符串從C++轉換爲C#

int GetDeviceIdentifier(DWORD deviceIndex, WCHAR** ppDeviceName); 

我用以下簽名包裝到C#中。它的作品,但我得到的字符串很奇怪。難道我做錯了什麼?

[DllImportAttribute("StclDevices.dll", EntryPoint = "GetDeviceIdentifier", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] 
public static extern int GetDeviceIdentifier(uint deviceIndex, StringBuilder ppDeviceName); 

回答

3

傳遞一個StringBuilder參數將匹配WCHAR*類型的C++參數。在這種情況下,內存將由C#代碼通過設置字符串生成器對象的容量進行分配。

對於你的函數,看起來內存是由C++代碼分配的。因此,雙指針。所以,你需要這樣的:

[DllImportAttribute("StclDevices.dll", 
    CallingConvention=CallingConvention.Cdecl)] 
public static extern int GetDeviceIdentifier(
    uint deviceIndex, 
    out IntPtr ppDeviceName 
); 

你這樣稱呼它:

IntPtr ppDeviceName; 
int retval = GetDeviceIdentifier(deviceIndex, out ppDeviceName); 
string DeviceName = Marshal.PtrToStringUni(ppDeviceName); 
+0

現在我知道爲什麼我不喜歡C++。所有這些指針......感謝您的幫助。這工作絕對好。我使用了容量爲128的StringBuilder,之前導致了錯誤的結果。 – Matthias

0
[DllImportAttribute("StclDevices.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] 
internal static extern Int32 GetDeviceIdentifier([In] UInt32 deviceIndex, [MarshalAs(UnmanagedType.LPTStr), Out] out String ppDeviceName); 

String ppDeviceName; 
NativeMethods.GetDeviceIdentifier(i, out ppDeviceName); 

如果你想堅持的StringBuilder的,用這個來代替:

[DllImportAttribute("StclDevices.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] 
internal static extern Int32 GetDeviceIdentifier([In] UInt32 deviceIndex, [In, Out] StringBuilder ppDeviceName); 

StringBuilder ppDeviceName = new StringBuilder(255); 
NativeMethods.GetDeviceIdentifier(i, ppDeviceName); 
+0

變體1將導致在'ppDeviceName'後面的指針上調用'CoTaskMemFree'。變體2不正確,因爲它是C++代碼中的雙指針。而'SetLastError'在這裏不應該是'true'。這是Win32 API函數。 –

+0

忘記刪除SetLastError,感謝David! –

+0

我也試過這個,但結果還是錯的。 – Matthias

相關問題