Default Marshaling for Classes
Classes can be marshaled only by COM interop and are always marshaled as interfaces. In some cases the interface used to marshal the class is known as the class interface. For information about overriding the class interface with an interface of your choice, see Introducing the Class Interface.
Passing Classes to COM
When a managed class is passed to COM, the interop marshaler automatically wraps the class with a COM proxy and passes the class interface produced by the proxy to the COM method call. The proxy then delegates all calls on the class interface back to the managed object. The proxy also exposes other interfaces that are not explicitly implemented by the class. The proxy automatically implements interfaces such as IUnknown and IDispatch on behalf of the class.
Passing Classes to .NET Code
Coclasses are not typically used as method arguments in COM. Instead, a default interface is usually passed in place of the coclass.
When an interface is passed into managed code, the interop marshaler is responsible for wrapping the interface with the proper wrapper and passing the wrapper to the managed method. Determining which wrapper to use can be difficult. Every instance of a COM object has a single, unique wrapper, no matter how many interfaces the object implements. For example, a single COM object that implements five distinct interfaces has only one wrapper. The same wrapper exposes all five interfaces. If two instances of the COM object are created, then two instances of the wrapper are created.
For the wrapper to maintain the same type throughout its lifetime, the interop marshaler must identify the correct wrapper the first time an interface exposed by the object is passed through the marshaler. The marshaler identifies the object by looking at one of the interfaces the object implements.
For example, the marshaler determines that the class wrapper should be used to wrap the interface that was passed into managed code. When the interface is first passed through the marshaler, the marshaler checks whether the interface is coming from a known object. This check occurs in two situations:
- An interface is being implemented by another managed object that was passed to COM elsewhere. The marshaler can readily identify interfaces exposed by managed objects and is able to match the interface with the managed object that provides the implementation. The managed object is then passed to the method and no wrapper is needed.
- An object that has already been wrapped is implementing the interface. To determine whether this is the case, the marshaler queries the object for its IUnknown interface and compares the returned interface to the interfaces of other objects that are already wrapped. If the interface is the same as that of another wrapper, the objects have the same identity and the existing wrapper is passed to the method.
If an interface is not from a known object, the marshaler does the following:
- The marshaler queries the object for the IProvideClassInfo2 interface. If provided, the marshaler uses the CLSID returned from IProvideClassInfo2.GetGUID to identify the coclass providing the interface. With the CLSID, the marshaler can locate the wrapper from the registry if the assembly has previously been registered.
- The marshaler queries the interface for the IProvideClassInfo interface. If provided, the marshaler uses the ITypeInfo returned from IProvideClassInfo.GetClassinfo to determine the CLSID of the class exposing the interface. The marshaler can use the CLSID to locate the metadata for the wrapper.
- If the marshaler still cannot identify the class, it wraps the interface with a generic wrapper class called System.__ComObject.