C Sharp

Marshalling and PInvoke

Even though you don't typically see the marshalling or define how it works, any time you call a DLL function, .NET has to marshal the parameters to that function and the return value back to the calling .NET application. I didn't have to do anything in the previous examples in this chapter to make this happen because .NET has a defined a default native type for each .NET type. For example, the second and third parameters to the MessageBoxA and MessageBoxW functions were defined as type string. However, the C# compiler knows that the equivalent of a C# string is the Win32 LPSTR. But what happens if you want to override the default .NET marshalling behavior? To do that, you use the MarshallAs attribute, which is also defined in the System.Runtime.InteropServices namespace.

In the following sample, once again I'm using MessageBox to keep things simple. Here I've chosen to use the Unicode version of the Win32 MessageBox function. As you know from the previous section, I need only specify the CharSet.Unicode enumerationfor the DllImport attribute's CharSet named parameter. However, in this case I want the compiler to marshal the data as wide character (LPWSTR), so I use the MarshalAs attribute and specify with an UnmanagedType enumeration the type I want my type converted to. Here's the code: -

using System;
using System.Runtime.InteropServices;
class PInvoke4App
{
    [DllImport("user32.dll", CharSet=CharSet.Unicode)]
    static extern int MessageBox(int hWnd,
                                [MarshalAs(UnmanagedType.LPWStr)]
                                string msg,
                                [MarshalAs(UnmanagedType.LPWStr)]
                                string caption,
                                int type);
    public static void Main()
    {
        MessageBox(0,
                   "Hello, World!",
                   "This is called from a C# app!",
                   0);
    }
}

Note that the MarshalAs attribute can be attached to method parameters (as in this example), method return values, and fields of structures and classes. Note also that to change the default marshaling for a method return value, you need to attach the MarshalAs attribute to the method itself.