3

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 ;)

Alanight
  • 353
  • 2
  • 8
  • 23
Mnt DXM
  • 168
  • 1
  • 7

2 Answers2

1

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.

zellus
  • 9,617
  • 5
  • 39
  • 56
Dennis
  • 37,026
  • 10
  • 82
  • 150
  • Thanks! Unfortunately, I'd not like to do this way. Let's imagine that DLL is written already and it returns const wchar_t * :). Thank you very much! – Mnt DXM May 30 '13 at 11:18
  • Let's imagine that DLL is written already - so, use `LPTStr` when marshaling. This works in both cases (with `CoTaskMemAlloc` and without it). There's no need for custom marshaller here. – Dennis May 30 '13 at 11:23
  • LPTStr doesn't work and sometimes summons System.AccessViolationException. And there is nothing extraordinary according to MS documentation – Mnt DXM May 30 '13 at 11:51
1

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();
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Thanks, it is an option. There is no way to do such a thing simpler than implementing ICustomMarshaler interface, is there? – Mnt DXM May 30 '13 at 11:14
  • Custom marshaller for standard string type? Smells like another wheel. – Dennis May 30 '13 at 11:25
  • Hm. To allow this "[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshaller))]" I need create class MyMarshaller which implements ICustomMarshaler interface, correct? In MyMarshaller#MarshalNativeToManaged I will use PtrToStringUni.... Or do you mean that there is a standard class which already does this? – Mnt DXM May 30 '13 at 11:43