NGWS SDK Documentation  

This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!

The Need for Marshaling

As method calls are made between managed and unmanaged code, the data associated with the call often requires marshaling. The data to be marshaled includes the method arguments as well as the method return value. Marshaling is required whenever the caller and the callee have different representations for the data being passed between them.

To better understand why the marshaling service is needed, consider the following method definition written in C#:

[DllImport("UTILITY.DLL", EntryPoint="PrintMessage")]
public static extern void PrintMessage(String msg);

This method uses the Runtime’s Platform Invocation Service (PInvoke) to call the unmanaged method PrintMessage from managed code. The DllImport attribute provides the name of the unmanaged DLL containing the implementation of PrintMessage as well as the entry point within that DLL. The method has a single string parameter and could be called like this:

System.String msg = "Hello World";
PrintMessage(msg);

The type System.String is a managed type that stores the characters of the string as a buffer of Unicode characters. The String class dynamically manages the size of the buffer internally so the programmer using the class doesn’t have to. When an instance of the String type is declared, as in the example above, the variable msg refers to an instance of the String class not to the character buffer stored within the class.

Now consider the unmanaged implementation of the PrintMessage routine. The definition may look like this if it were written in C++:

void PrintMessage(LPSTR msg);

It expects a pointer to an ANSI character buffer to be passed to it, not a reference to a String class. If fact, it doesn’t even know what the String Type is because it was built with and compiler that isn’t even NGWS aware. The string argument being passed therefore needs to be converted from a System.String object to a buffer of ANSI characters. It’s the runtime’s marshaling service that’s responsible for performing this conversion.

The marshaling service has built-in rules that govern the conversions that take place for each type. For the String type for example, the marshaler will automatically copy the contents of String classes internal Unicode character buffer into a new buffer containing ANSI characters. Other types have other marshaling characteristics. In spite of the built-in rules, it is often necessary to be more explicit about the exact marshaling behavior that is needed. For example, consider a different implementation of PrintMessage that expects a buffer of Unicode characters to be passed instead of an ASNI character buffer.

In that case the managed method definition could be attributed with the MarshalAs attribute explicitly control the msg argument.

[DllImport("UTILITY.DLL", EntryPoint="PrintMessage")]
public static extern void PrintMessage(
   [MarshalAs(UnmanagedType.LPWSTR)]String msg);

The MarshalAs attribute tells the marshaler the format of the data that is expected on the unmanaged side of the boundary. The marshaler then ensures that the data is copied and transformed to the correct format in the unmanaged space. In this case the data would be copied to a buffer containing Unicode characters.

The runtime’s marshaling service is responsible for performing the conversions needed to represent the data accurately on both sides of the managed and unmanaged boundary.