See the question and my original answer on StackOverflow

The return value is always a special case with p/invoke methods. Because you don't use a CLR compatible string allocator (=COM) on the native side, you should define your method like this:

[DllImport("NativeCore.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetNodeName(IntPtr ptr);

and call it like this:

var ptr = GetNodeName(whatever);
var str = Marshal.PtrToStringUni(ptr); // unicode because you use wstring

Note this is only ok if the C string (or more generally whatever memory the returned pointer points to) is not deallocated on the native side when the called method returns. For example, if the wstring is defined locally somewhere in the method, it will be automatically deallocated on native call return (and a crash will most likely happen).

Or if you want to avoid that extra call on the .NET side, pass the string as an argument, and use the return value as an error code, as most Windows APIs do.