Wes
Wes

Reputation: 1255

Managing returned string pointers in C#

So I created a custom dll callsed FileGuidUtils.dll written in C/C++ and one of the functions returns a WCHAR * string (as a LPWStr in C#). This string gets allocated heap memory inside the function of type (WCHAR *).

Right now I just use the returned string and that's it. Should I be freeing it somewhere in the C#? What code should I use if so? Or is the CLR garbage collector taking care of it for me?

    [DllImport(@"FileGuidUtils.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.LPWStr)]
    private static extern string getReparseTarget([MarshalAsAttribute(UnmanagedType.LPWStr)] string linkPath);

I occasionally get unhandled out of memory exceptions but am unable to pinpoint the cause because I don't get it very often. For right now I just wanna know if I'm handling the returned string properly?

Upvotes: 2

Views: 454

Answers (1)

xanatos
xanatos

Reputation: 111940

You are creating a memory leak. .NET can't free memory allocated by malloc, C++ new, or any other allocator of Windows, because it can't know which allocator was used (there are some exceptions on this).

Possible solutions:

1) Return a IntPtr:

private static extern IntPtr getReparseTarget([MarshalAsAttribute(UnmanagedType.LPWStr)] string linkPath);

and have a corresponding

private static extern void freeMemory(IntPtr ptr);

and then manually rebuild the C# string with PtrToStringUni()

2) Have a function that returns the length needed and then pass a StringBuilder of that length (new StringBuilder(len)):

private static extern int getReparseTargetLength([MarshalAsAttribute(UnmanagedType.LPWStr)] string linkPath);

private static extern void getReparseTarget([MarshalAsAttribute(UnmanagedType.LPWStr)] string linkPath, [MarshalAsAttribute(UnmanagedType.LPWStr)] StringBuilder output, int maxLen);

3) Use MarshalAs(UnmanagedType.BSTR)

[return: MarshalAs(UnmanagedType.BSTR)]
private static extern string getReparseTarget([MarshalAsAttribute(UnmanagedType.LPWStr)] string linkPath);

The CLR automatically frees strings allocated as BSTR. Note that you will need to create them as BSTR C++-side (with SysAllocString/SysAllocStringLen).

Upvotes: 2

Related Questions