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";
[
uuid(FB30F62F-4DF3-47CD-A67F-50E0CF7C7B67),
helpstring("ComplexMath Class")
]
coclass ComplexMath
{
[default] interface IComplexMath;
interface ISimpleMath;
};
};
- Open the ComplexMath.h file and add the following code:
The outerCOM
(ComplexMath
) creates an object of innerCOM
(SimpleMath
).
ISimpleMath* SimpleMathptr;
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 the innerCOM
(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"
Add the following code to the OnButton
event:
using namespace COMPLEXCALCULATORLib;
void CContainmentClientDlg::OnButton1()
{
CoInitialize(NULL);
CString str;
long res1;
IComplexMathPtr objComplex(__uuidof(ComplexMath));
res1=objComplex->Mul(10,20);
str.Format("Mul is=%d",res1);
AfxMessageBox(str);
ISimpleMathPtr objSimple;
objSimple=objComplex;
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.