COM Macro Architecture Topology - Clients






4.54/5 (8 votes)
Jul 25, 2001
6 min read

118495
An article about COM Architecture, COM Clients and the Registry
Purpose
This article shows how to implement a simple Client application. It will be developed in C++ using MFC architecture and ATL.
Requirements
All the code in these samples have been written in C++, using Visual C++ 6.0 (sp4) under Windows 2000.They also use the Active-X Template Library (ATL v3.0).
Other articles in this series
This article is part of a series called "COM Macro-Architecture Topology". Here are the links to other articles:
- the main article, "COM Macro-Architecture Topology" (You can download the source code from this article).
- The COM Servers, "COM Macro-Architecture Topology (Servers)".
- COM IDs & Registry keys in a nutshell.
Simple Client Application
What we want in the end
The final Client application will be a simple MFC Dialog based application. It will use theAfx???()
functions from the
MFC (Microsoft Foundation Classes) framework. In addition, it will look
like that (or something similar): 
Creating the Project
In order to create the client application, you have to follow the steps below:- Start the Visual C++ IDE and Select File, New and fill in like below:

- You want to create a Dialog based application:
- Click on Next.

- Uncheck the ActiveX Controls support option.
- You can change the Title.
- Click on Next.

- Keep with the default settings.
- Click on Next.

- Click on Finish.

After that, the MFC wizard will create these files :
- Workspace:
macrotopoclient.dsw
- Project:
macrotopoclient.dsp
- Application code in
macrotopoclient.h/cpp
- Dialog box code in
macrotopoclientDlg.h/cpp
COM Initialisation and Uninitialisation
You have to Initialise and Uninitialise COM in your client application. Here because we are building a MFC application we will use theAfx???()
functions:
AfxOleInit()
to initialise COM.AfxOleTerm()
to uninitialise COM.
Find the
InitInstance()
method of our Client MFC application (e.g.
CMacrotopoclientApp
) and add these lines: BOOL CMacrotopoclientApp::InitInstance() { // Initialise OLE libraries and COM. if (!AfxOleInit()) { AfxMessageBox("Error when Initialising COM."); return(FALSE); } ... CMacrotopoclientDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); ... AfxOleTerm(); // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return(FALSE); }
Of course you can use as well the normal COM API functions:
CoInitializeEx()
and
CoUninitialize().
However, you need to use
the pre-processor definition _WIN32_DCOM
.
The User Interface
In order to make life easy, we will create push buttons and bind them to methods of our Dialog box class. These methods will make a call to the COM Server.Use the resource editor to add a button like that:
- Click on
ResourceView
in the workspace view. - Open the Dialog folder and double-click on the dialog resource for
your application (e.g.
IDD_MACROTOPOCLIENT_DIALOG
).

At the beginning, your Dialog box resource only has 2 push buttons (
OK
and Cancel
) and a static text control
(TODO: Place dialog controls here.
): 
Remove the static text control by selecting it and press the Delete keyboard.
Select the push button control tool in the
Controls toolbar
: 
- right-click anywhere in the dialog box,
- maintain your right mouse button down and move your mouse in order to initialise the push button size,
- then release your right mouse button.
- left-click over your push button,
- select
Properties
from the popup menu, - then:
- Change the
ID
:IDBUT_MACROTOPOEXE_DISP_SHOWHELLO
, - Change the
Caption
:ShowHello()
...
- Change the

To bind the push button to a method double-click in it. A "
Add member function
" dialog box will appear. If you want you can
change the name of the member function, else just click OK. This dialog box shows the
member function name
(OnMacrotopoexeDispShowhello()
) that will be used when the push button
control (ID: IDBUT_MACROTOPOEXE_DISP_SHOWHELLO
) will receive a control
message BN_CLICKED
.
Calling the COM Server
Now we have a push button in our dialog box and its Click event is bound to a method in our Dialog box class (e.g.CMacrotopoclientDlg
). Next step is to call our COM Server. To write
this code you will use the "#import
" statement: ///////////////////////////////////////////////////////////////////////////// // MacroTopoExe - Disptach & Custom. #import "../bin/macrotoposerver_exe.exe" void CMacrotopoclientDlg::OnMacrotopoexeDispShowhello() { try { using namespace MACROTOPOSERVER_EXELib; IMacroTopoDispPtr pDisp(__uuidof(CoMacroTopo)); pDisp->ShowHello(); } catch(_com_error &) { ::MessageBox(GetSafeHwnd(), _T("DCOM exception."), _T("OnMacrotopoexeDispShowhello()"), MB_OK | MB_ICONSTOP); } }The code above uses the
#import
statement to get Type information
from the COM Server (e.g. from macrotoposerver_exe.exe,
macrotoposerver_dll_psdll.dll or macrotoposerver_dllmerged.dll).
It tries to obtain an Interface pointer of
IMacroTopoDisp
from a COM Object CoMacroTopo
, which should implement it. If not, a
COM exception (using the _com_error
class) will be raised.
This code is very short, but in fact the
#import
directive has
generated wrap code for you. Look in your ".\Debug
" directory (if
you are working in Debug build), you will find 2 files:
- macrotoposerver_exe.tlh it is a header file containing a C++ version of the Type information in the Type Library stored (in general) inside your COM Server.
- macrotoposerver_exe.tli it is the file containing inline Interface member functions that serve as wrappers to the remote interface methods implemented by the COM object.
- repeat the creation of a push button,
- bind its click event to a new member function of your Dialog box
- use the snippet code above as a template to call another function.
The #import statement
The #import statement is a Visual C++ compiler directive, and like many other Microsoft tools it works very well with COM. This directive could be see as a COM appWizard, in that sense it helps C++ developers to get the C++ representations of what has been describe in the Type Library (inside the COM Server).The Type Library and its information (in fact the COM Server metadata information) can reside in files with extensions such as: TLB, EXE, DLL and OCX.
The
#import
statement will generate 2 files in your current build working directory (e.g.
".\Debug" if you are working in Debug build):
- TLH file extension is a header file that contains a C++ version of
the Type information from your Type Library COM Server.
All the Type information resides in a C++ namespace for avoiding collision between logical names (or readable names).
Smart pointers on Interface are declared in this file.
At the end of this file, a#include "filename.tli"
statement is defined to include the second file generated by the#import
statement. - TLI file extension is the file that contains implementation of inline Interface member functions. These member functions serve as wrappers to remote interface methods implemented by the COM object.
To go further
If you want to go deeper in ATL look at [Bi7] and [Bi10].If you are more interested in the different techniques for using COM Objects in client code look at [Bi3] chapter 7.
The
#import
statement has a number of
attributes
such as no_namespace
/ rename_namespace
for managing the namespace of the imported Type information, look the Visual
C++ documentation.