views:

58

answers:

2

Hi. suppose a dll contains the following functions

extern "C" __declspec(dllexport) void f(bool x)
{
   //do something
}
extern "C" __declspec(dllexport) const char* g()
{
   //do something else
}

My first naive approach to use these functions from C# was as follows:

[DllImport("MyDll.dll")]
internal static extern void f(bool x);
[DllImport("MyDll.dll")]
internal static extern string g();

The first surprise was that C++ bool doesn't convert into C# bool (strange runtime behavior, but no crashes, though). So I had to change bool to byte and convert from one to another by hand. So, first question is, is there any better way to marshal bool (note that this is bool, not BOOL)

The second surprise was that the raw string returned by the dll function was OWNED by the C# string, not copied, as I would expect, and eventually the C# code frees the memory returned by the dll. I found this out because the program crashed, but then I changed the return type to sbyte* and manually initialized the string with that pointer which already does the copy. So the second question is: 2.1: Is there any better way to prevent the marshalled string from owning the pointer. 2.2: WTF?! Why does C# do that? I mean, an obvious case is when the dll func returns a literal, and C# tries to delete it...

Thanks in advance, and hopefully my questions aren't vague or incomprehensible.

+2  A: 

By default .NET marshals between C++ BOOL (4 bytes) and .NET bool type automatically. For the C++ bool (single byte) type you need to specify how to marshal:

[DllImport("MyDll.dll")]
internal static extern void f([MarshalAs(UnmanagedType.I1)] bool x);
Darin Dimitrov
@Darin: funny thing is one of my friends told me exactly the same thing, and guess what? It didn't work. I am using .Net1.1 if that's relevant
Armen Tsirunyan
Actually this is supported from 1.1. see here http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype(v=VS.71).aspx
Vinzenz
@Armen it should work according to the documentation.
Darin Dimitrov
@Darin, @Vinzenz: I know! I saw that exact page. And tried it, but the same wrong behavior kept on going. Only when I used byte everything started working... But thanks anyway, if 2 people say the same thing then I guess I must have done something wrong...
Armen Tsirunyan
What is the *wrong* behavior? When passing `true` in C# you get `0` in C++?
Darin Dimitrov
@Darin: Yes, exactly, or vice versa. I pass true in C# and get false in C++ or vice versa.
Armen Tsirunyan
Well that looks pretty strange indeed. Can you try this on a newer version of .NET than 1.1?
Darin Dimitrov
+1  A: 
[DllImport("MyDll.dll")]
internal static extern void f( [MarshalAs(UnmanagedType.I1)] bool x );
[DllImport("MyDll.dll")]
[return: MarshalAs(UnmanagedType.LPStr)]
internal static extern string g();
Vinzenz