You cannot pass a string from native managed this way. Your code is incorrect in the 32-bit version, you just can handle it. The second version of the code is also incorrect. It only works.
You need to either:
- Allocate from the shared heap so that managed code can free this heap. The general heap for p / invoke is the COM heap.
- Allocate memory on the managed side and copy the contents to this buffer from the inside.
Option 2 is always preferable. It looks like this:
[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)] public static extern int GetString(StringBuilder str, int len);
From your home side you will have
function GetString(str: PChar; len: Integer): Integer; stdcall; begin StrLCopy(str, 'abc', len); Result := 1; // real code would have real error handling end;
Then call it this:
StringBuilder str = new StringBuilder(256); int retval = GetString(str, str.Capacity);
If you want to try option 1, it looks like this on the managed side:
[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)] public static extern int GetString(out string str);
and like this native:
function GetString(out str: PChar): Integer; stdcall; begin str = CoTaskMemAlloc(SizeOf(Char)*(Length('abc')+1)); StrCopy(str, 'abc'); Result := 1; // real code would have real error handling end;
When managed code copies the contents of str to a string value, it calls the CoTaskMemFree pointer that you returned.
And it's trivially easy to call:
string str; int retval = GetString(out str);
source share