COM reusability is accomplished through containment and aggregation. Managed objects can participate in both models as the inner object in the relationship. Inheritance is used in special cases. Use the inheritance, aggregation, or containment models under the following circumstances:
Model | Use For |
---|---|
Inheritance | Exposing the managed object as the outer object. |
Aggregation | Enabling the outer object to expose another object's implementation of an interface without modification. |
Containment | Enabling the outer object to modify the behavior of the inner object. |
Inheritance is typically used when you want the managed object to be the outer object. When managed interfaces are exposed to COM, they always extend IUnknown or IDispatch even when the interface is inherited from another interface on the managed side. The same applies for the class interface that is generated for managed classes. For example:
Interface IBase { void m1(); } Interface IDerived : implements IBase { void m2();{ } class CDerivedImpl : implements IDerived { void m1(); void m2(); }
Interface IBase : public IDispatch { void m1(); } Interface IDerived : public IDispatch { void m2(); } Interface _CDerivedImpl : public IDispatch { Boolean Equals(); int GetHashCode() // … plus all other methods of object void m1(); void m2(); } coclass CDerivedImpl { interface IBase; interface IDerived; interface _CDerivedImpl; interface _Object; }
To expose the interfaces of one COM class as though they were implemented on a second COM class, the second class aggregates the first. A COM object can aggregate a NGWS object, in which case all of the object's interfaces, including its class interface, are available through the outer object. The inner NGWS object delegates calls to its IUnknown methods to the controlling IUnknown.
The analogous behavior in the NGWS runtime is for the first class to inherit the second. When a COM class is imported into the NGWS runtime, it is marked as a static final class. This means that a COM class cannot be a base class for a NGWS class.
Aggregation is slightly more complex than containment. It is typically used to enable the outer object to expose another object's implementation of an interface without modification. All managed objects automatically support COM-style aggregation with the managed object being used as the inner object. In order to aggregate a managed object, the unmanaged outer object creates the managed inner object by calling CoCreateInstance, passing the outer object's IUnknown as an OuterUnknown parameter. When an outer IUnknown is passed to a managed object during construction, the managed object caches the interface and uses it as follows:
These three behaviors make it possible to aggregate any managed object. With this type of aggregation relationship, it is possible to have a single COM object that is partly implemented in managed code (the inner portion) and partly in unmanaged code (the outer portion).
A NGWS object can contain a COM object by importing its metadata into a NGWS component file, then declaring a data member of that type within another class. As with normal COM containment, you can call the COM object's interfaces in your own interface implementations, but the contained object is not exposed outside the class. Containment is simpler than aggregation. Containment is typically used when the outer object needs to modify the behavior of the inner object. To do so, the outer object simply creates an instance of the inner object during constructor and delegate calls to the inner object as necessary. The outer object can choose which calls to delegate and which calls to handle directly. There are no special requirements of the runtime in order for objects to support containment.
A COM object can also contain a NGWS object. Behavior with respect to clients of the COM object will be exactly the same as if the contained object was any other COM object.