2013-01-15 38 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

相关问题