A Containment Sample






4.50/5 (12 votes)
Jun 20, 2006
2 min read

37052

328
An illustration of the concept of Containment.
Introduction
Trying to learn about reuse mechanisms that can be applied in COM, I searched a lot on the net to find a very simple example on Containment, for starters. I found a lot of theory on the net, but not any simple example. Keeping in mind the starters, I will try to explain the steps involved in attaining Containment. I am not a good technical writer, but I will try to do my best.
Definition
Containment is a reuse mechanism. In this process of reuse mechanism, the outer component acts as a mediator between the client and the inner component, to delegate the calls. This mechanism makes sure that the inner component's interfaces are not exposed directly to the client.
We will build a ComplexCalculator
component that exposes Add
and Multiply
functionalities through its interface. There is an existing component named “Calculator
” that exposes an “Add
” method through its interface, ISimpelMath
. You can download the Calculator
from the link above. I thought: why write code to get an existing functionality, “Add”? So, we will develop a new component, ComplexCalculator
, using the existing component, Calculator
.
Now, it’s enough for us to worry about “Multiply
”.
Steps
- Create a new ATL project, name it “ComplexCalculator”, and select the type as DLL.
- Insert a new ATL object, name it as “
ComplexMath
”, and click OK. - Select the Class Wizard tab, right click on
IComplexMath
, and select “Add method”.Method Name: Mul Parameters: [in] long a, [in] long b, [out, retval] long* result
- Add the following code:
STDMETHODIMP CComplexMath:: Mul (long a, long b, long *result) { *result = a * b; return S_OK; }
- Select the Class Wizard tab, right click on
CComplexMath
, and select Implement Interface. - Click the “Add type library” button->Browse, select the Calculator.tlb, and click Open.
- Open the ComplexCalculator.idl file and do the following changes:
Changes are indicated in bold letters.
library COMPLEXCALCULATORLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); import "Calculator.idl"; //import the Calculator’s IDL file. //If not present in local dir, specify the path. [ uuid(FB30F62F-4DF3-47CD-A67F-50E0CF7C7B67), helpstring("ComplexMath Class") ] coclass ComplexMath { [default] interface IComplexMath; interface ISimpleMath; //Add the interface name to the coclass //so that it can be exposed to the client. }; };
- Open the ComplexMath.h file and add the following code:
The
outerCOM
(ComplexMath
) creates an object ofinnerCOM
(SimpleMath
).ISimpleMath* SimpleMathptr; //Override the FinalConstruct to get the //interface pointer of the Inner Component. HRESULT FinalConstruct() { return CoCreateInstance(__uuidof(SimpleMath),NULL, CLSCTX_INPROC_SERVER, __uuidof(ISimpleMath), (void**)&SimpleMathptr); } void FinalRelease() { SimpleMathptr->Release(); }
- Change the
Add
method code in the ComplexMath.h as follows:This is how the
outerCOM
(ComplexMath
) delegates the calls to theinnerCOM
(SimpleMath
).STDMETHOD(Add)(LONG a, LONG b, LONG * result) { SimpleMathptr->Add(a,b,result); return S_OK; }
That’s it….
The outer component contains the inner component object. The user feels as if he is using the ComplexCalculator
even when he queries for the SimpleMath
interface.
Let's quickly build a client and make sure the containment relation works properly.
Client
Create a dialog based MFC application and place a button on the dialog. In the StdAfx.h, add the following:
#import "ComplexCalculator.tlb" // If this is not present in the current dir, specify the path.
Add the following code to the OnButton
event:
using namespace COMPLEXCALCULATORLib; void CContainmentClientDlg::OnButton1() { CoInitialize(NULL); CString str; long res1; IComplexMathPtr objComplex(__uuidof(ComplexMath)); //Use the smart //pointer to get //ComplexMath res1=objComplex->Mul(10,20); str.Format("Mul is=%d",res1); AfxMessageBox(str); ISimpleMathPtr objSimple; objSimple=objComplex; //Use the assignment operator on the //smart Pointer which will take care of //query interface to SimpleMath interface. long m = objSimple->Add(10,20); str.Format("Add of 10,20 is=%d",m); AfxMessageBox(str); objComplex=NULL; objSimple=NULL; CoUninitialize(); }
Register the DLLs before you use the source code.