Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between MarshalAs(UnmanagedType.LPWStr) and Marshal.PtrToStringUni()

I would like to import a function like this:

[return: MarshalAs(UnmanagedType.LPWStr)]
[DllImport("DLL.dll", EntryPoint="FuncUtf16", ExactSpelling=true, PreserveSig=true, CharSet=CharSet.Unicode)]
public static extern string Func();

But this gives me an error like this:

"Windows has triggered a breakpoint in Test.exe. This may be due to a corruption of the heap, which indicates a bug in Test.exe or any of the DLLs it has loaded. "

And when I press "Continue" repeatedly, the function does give the expected output. However, when I chance the above declaration to:

[DllImport("DLL.dll", EntryPoint="FuncUtf16", ExactSpelling=true, PreserveSig=true, CharSet=CharSet.Unicode)]
public static extern IntPtr Func();

(changing the return type to IntPtr) and call it as follows:

Dim a As IntPtr = Func()
Dim Str As String = Runtime.InteropServices.Marshal.PtrToStringUni(a)

, I get no errors and it works perfectly fine! Whats wrong with using the "MarshalAs" way of declaring a function in a dll?

like image 276
Carucel Avatar asked Apr 03 '13 17:04

Carucel


1 Answers

Writing the PInvoke signature for a method which returns a char* / wchar_t* requires a lot of care because the CLR special cases string return types. It makes the following assumptions

  • The memory for the char* must be freed after converting to string
  • The memory was allocated with CoTaskMemAlloc

If either of these aren't true (usually the case) then the program will run into errors.

In general it's best to simply return an IntPtr and manually marshal the string as you've done with PtrToStringUni.

like image 171
JaredPar Avatar answered Oct 19 '22 16:10

JaredPar