Question

It is just a curiosity. Perhaps there is a person in this world who did such things:

I have to export C function and load it from C# code via DllImport

const wchar_t * SysGetLibInfo() {
    return dllmanager.SysGetLibInfo();
}

The best things to do that, and it is recommended widely, is to declare IntPtr and then convert it to string using some function. In other words, something like this

[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr SysGetLibInfo(); 
// ...
Marshal.PtrToStringUni(SysGetLibInfo());

This approach works. But Is there a way to do that automatically? To make SysGetLibInfo to be returning a string? I found some suggestions like this:

[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPWStr)]
private static extern string SysGetLibInfo();

But it doesn't work, and, according to a variety of examples and scant reports it should not work.

Is there a way to write my own attribute like MarshalAs which will convert IntPtr to string? Something similar to this:

[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
[return: MyOwnMarshalPtrToStringUni]
private static extern string SysGetLibInfo();

Thanks in advance for any information or useful links, examples, books. Again, it is just a curiosity.

P.S. Suggestion to wrap SysGetLibInfo with a separate function which convert result to string using PtrToStringUni is not an option ;)

Was it helpful?

Solution

You can't override MarshalAs but you can use custom marshalling instead

http://msdn.microsoft.com/en-us/library/w22x2hw6.aspx

  [DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
  [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshaller))]
  private static extern string SysGetLibInfo();

OTHER TIPS

I think, the problem is with the LPWStr:

you cannot use the LPWStr value with an unmanaged string unless the string was created by using the unmanaged CoTaskMemAlloc function

This works fine. Native code:

// header
extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void);

// implementation
extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void)
{
    return TEXT("Hello from unmanaged world!");
}

Managed code:

    [DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
    [return: MarshalAs(UnmanagedType.LPTStr)]
    static extern string SysGetLibInfo();

If you'll change native function this way:

extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void)
{
    wchar_t* pStr = (wchar_t*)CoTaskMemAlloc(100);

    ZeroMemory(pStr, 100);

    wcscpy(pStr, TEXT("Hello from unmanaged world!"));

    return pStr;
}

then [return: MarshalAs(UnmanagedType.LPWStr)] will work too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top