The COM model for reusability is containment and aggregation. The NGWS runtime adds the ability to use implementation inheritance. You can even have managed type that derives from a COM objects RCW. The managed type can then expose all the method and properties of the COM object as well as methods and properties implement in managed code. The result is an object that is partly implemented in managed code and partly implemented in unmanaged code sometime called a mixed-mode object.
To accomplish this, there are three requirements that the base, unmanaged type must satisfy:
If the requirements are met, a managed type can then extend the RCW for that unmanaged type and override the methods provided by the base object. The inheritance is done exactly the same as it would if the base object were managed. For example
In Managed C++:
#import “AcmeLib.dll” // provides defintion of Slingshot and class Catapult : public AcmeLib.Slingshot // extend COM type { Load() {…}; Fire() {…}; // delegates to base implementation { Slingshot::Fire(); } } Catapult *cp = new Catapult(); cp.Load(); // calls derived implementation cp.Aim(); // calls base implementation cp.Fire(); // calls derived which delegates to base
[discuss RegisterObjectCreationCallback here]
When importing and interface from a COM type library, all inheritance relationships are preserved with the exception of IUnknown and IDispatch. For example, The following interfaces defined in a type library would be converted to metadata as shown.
In a Type Library:
Interface IUnknown {…}; Interface IDispatch : public IUnknown {…}; Interface IBase : public IDispatch { void m1(); } Interface IDerived : public IBase{ void m2(); } coclass CDerivedImpl { interface IDerived; }
In a Managed C++:
Interface IBase { void m1(); } Interface IDerived : implements IBase { void m1(); void m2(); } class CDerivedImpl implements IDerived { }
Notice that the IBase interface does not derive from IDispatch once it’s imported. The inheritance from IUnknown and IDispatch are automatically removed during import because equivalent functionality is provided thru other mechanisms. Also notice that the methods of IBase (m1) are also added to the definition of the IDerived interface. This is ensures backward compatibility with existing COM types. For example, consider what happens when the interfaces defined in the above type library are imported, implemented in managed code and then exported. COM clients that were using the original unmanaged implementation expect to be able to call methods of IBase directly from through IDerived interface when the implementation is move to managed code. By adding the methods of IBase to IDerived, we ensure that this behavior is still supported.