Customizing COM Callable Wrappers 

Customizing a COM Callable Wrapper is a straightforward task. If the type you want to expose to a COM client has nonstandard marshaling requirements, apply the System.Runtime.InteropServices.MarshalAsAttribute attribute to a method parameter, class field, or return value to change the marshaling behavior.

As the following illustration shows, you can export a managed DLL without customizing the wrapper (shown on the left). Or you can add marshaling information to the source, compile it, and use the Type Library Exporter (Tlbexp.exe) to export the modified DLL and produce a custom wrapper.


Marshaling information in exported DLLs

Type Library Exporter

NoteNote

All managed types, methods, properties, fields, and events that you want to expose to COM must be public. Types must have a public default constructor, which is the only constructor that can be invoked through COM. For additional information, seeQualifying .NET Types for Interoperation..

When marshaling data between managed and unmanaged code, the interop marshaler must recognize the representations of the data being passed:

  • For blittable types, managed and unmanaged representations are always the same. For example, a 4-byte integer is always marshaled to a 4-byte integer. The interop marshaler uses the managed signature to determine the data representation.

  • For non-blittable types, the interop marshaler recognizes the managed representation from its method signature, but is unable to do the same for the unmanaged representation. To marshal non-blittable types, you can use one of the following techniques:

    • Allow the marshaler to infer the representation from the managed representation.

    • Supply the unmanaged data representation explicitly.

For example, a string is converted to a BSTR type when marshaled from managed to unmanaged code, unless you explicitly apply the MarshalAsAttribute to marshal the string to another type, such as LPWSTR. You can apply this attribute to a parameter, field, or return value within the source of the type definition, as shown in the following examples.

Apply the MarshalAsAttribute to a parameter

Public Sub M1
(<MarshalAs(UnmanagedType.LPWStr)> msg As String)
public void M1
([MarshalAs(UnmanagedType.LPWStr)]String msg);

Apply the MarshalAsAttribute to a field within a class

Class MsgText
<MarshalAs(UnmanagedType.LPWStr)> Public msg As String
End Class
class MsgText {
[MarshalAs(UnmanagedType.LPWStr)] Public String msg;
}

Apply the MarshalAsAttribute to a return value

Public Function M2() _
As <MarshalAs(UnmanagedType.LPWStr)> String
[return: MarshalAs(UnmanagedType.LPWStr)]
public String GetMessage();

You set the System.Runtime.InteropServices.UnmanagedType enumeration to indicate the desired format of the unmanaged type. In the previous signatures, msg data is marshaled as a null-terminated buffer of Unicode characters (LPWStr).

At times, the interop marshaler requires more information than is provided by the managed and unmanaged data format. To marshal an array, for example, you must supply the element type, rank, size, and bounds of the array. You can use the MarshalAsAttribute to specify required additional information.

See Also

Reference

Customizing COM Callable Wrappers

Concepts

COM Data Types
Customizing Runtime Callable Wrappers

Other Resources

Marshaling Data with COM Interop
Default Marshaling Behavior