Leveraging C++ Applications Using COM (An Extension of the Document View Architecture)



Implementation


Although the big picture view of COM technology is straightforward, the
actual implementation is intimidating. In the big picture, COM lets a program
(the client) safely run binary code in another executable or DLL (the COM
server) on your computer or on any computer to which you are linked. 
In practice this means that the client uses COM to ask a COM server for
an interface to an object.  If the object supports this interface
the server will return to the client a pointer to this interface. The client
can then use this pointer to manipulate and exchange information with the
object. If the server does not support the interface (or it could be returned
for some other reason), then the return code will let you know.  What
makes this special is that the language used to generate the server’s binary
code is irrelevant. COM takes care of all the details to ensure that the
execution and exchange of data between the client code and the COM server
is handled correctly. [3]

The intimidating part of COM is making sure all these details get handled
correctly.  Among the details involved include: 1) making sure the
client code can locate the COM object to use, 2) ensuring that the client
code and the COM object can share information, and 3) making sure that
resources used to create the COM object are managed correctly. These items
have associated with them legions of new acronyms, data types, and methods.
The most important thing to do while learning these new acronyms, data
types, and methods is to keep yourself from running from the room screaming.
We recommend the books listed below which will help you get up and running
with COM.

Fortunately, MFC and ATL have created Wizards, macros, templates, and
other tools that automate most of the particularly inscrutable aspects
of implementing a COM server or COM client. We have written two companion
articles that describe the steps to convert an existing class in a monolithic
C++ application into a COM server. Because we needed to access the COM
server from an Active Server Page web site and from within Excel using
VBA, we needed to provide an Automation interface rather than the more
general custom interfaces. Clients such as VBA and VBScript only support
automation interfaces and not custom interfaces. Automation uses the IDispatch
interface and can only pass automation data such as VARIANTs and not, for
example, abstract data types.  However, if you are trying to drive
the server from VBA or VBScript, being limited to the basic data types
(through VARIANT) is probably not a problem. (The server code itself is,
free to use whatever data types it needs to use – the data type limitation
is only on what can be passed back and forth to the client application.)


Example


The attached code and example is not from DBViewer but it illustrates the
same concepts.  The sample demonstrates how COM technology can enhance
well-designed applications using the document-view architecture.
    The attached zip file contains the following:

    1. Source code to build a COM server: ComSample.zip.

    2. Source code to build the View application: DlgView.zip.

    3. Source Code for the Document DLL: DocEngine2.zip.

    4. COMDEMO.xls.  An Excel 97 spreadsheet file.

    5. All the EXEs and DLLs if you simply want to run the code. 
    Please remember to register the ComSample.DLL.

To run the sample you will need to build the attached source code for the
COM server, the view application, and the document DLL.


The View


The sample takes a very simple application that implements the document
view architecture.  The view comprises of a single dialog based application
that displays some text in a static control.  This application is
dependent on a document  for what it will display but the application
does not contain the document.  In this sample the document is provided
by the DocEngine DLL using COM.


The Document


The DocEngine DLL has a single class called CSomethingComplicated. 
CSomethingComplicated represents a complex class hierarchy of classes representing
a document engine for a system.  The system’s document engine is responsible
for manipulating data, performing computations, and any other data related
processes. However, in this sample CSomethingComplicated only has a single
function HelloWorld() which returns "Hello World" as a CString (MFC). 
The CSomethingComplicated class is exported from the DLL making it available
to the user for use and allowing the user to derive new classes from it.


The COM Server


The COM server is a very simple class that inherits from CCmdTarget. 
The COM server accesses the DocEngine DLL and provides an interface to
the CSomethingComplicated.HelloWorld() function.  In a more realistic
world, several COM classes could be built each representing some part of
the DocEngine and providing an interface for it. The COM server makes the
DocEngine available to other applications/systems such as ASP, MS Excel,
Visual Basic etc.

Notice that converting the existing C++ code to be COM compatible was
quite easy.


Conclusion


This article shows how easy it can be to a convert a typical monolithic
MFC Document/View application into a COM Server.  However, this only
scratches the surface for what COM can do. For example, the DBViewer application
could be broken into a series of COM server chunks to provide even greater
flexibility to client applications. Each of the C++ application’s views
can be turned into ActiveX Controls and used by both the C++ executable
and the web server. The views could even be embedded into presentation
software to allow clients (i.e., the paying kind) to create spiffy up-to-the
minute tables, charts, and maps without the nuisance of manually exporting
data to a spreadsheet, manipulating it, and creating a table, chart, or
map.

EndNotes

[1] These fields are for illustrative purposes only. The DBViewer can
work with any relational database that supports SQL. The only significant
setup required is to create a table that acts like a data dictionary.

[2] The SQLs must be created dynamically because they generally include
criteria such as "get me the last two months of data," or "get me the top
ten percent of these values." This means that it is not possible to simple
store the actual SQL statement and retrieve it for later use.

[3] Although this process sounds similar to calling an exported function
in a DLL, the COM solution is more robust and allows DLL calls to be correctly
made even if the DLL was generated by another vendor’s compiler or even
in a completely different language. Even calling non-COM DLLs generated
in C++ but from different vendors is problematic because different vendors
implement the features of C++ differently (e.g., RTTI, exception handling).
Chapter 1 of Essential COM by Don Box (Addison-Wesley. 1998) provides an
excellent description of these issues.


References


Box, Don. Essential COM, Addison-Wesley, 1998.

Grimes, Dr. Richard, Alex Stockton, George Reilly, and Julian Templeman.
Beginning ATL COM Programming. Wrox Press Ltd., 1998.

Templeman, Julian. Beginning MFC COM Programming. Wrox Press Ltd.,
1997.



Following is an example of VBA code used to access the DocEngine using
the COM server.  Similar code can be written in VB, VB Script for
ASP, and other applications and/or languages, thus making one library available
to a vast array of systems.

Sub Test1()
Set dll = CreateObject("ComSample.DocEngineInterface")
Dim str As Variant
Dim blah As String
str = dll.HelloWorld()
blah = CStr(str)
Worksheets("Sheet1").Range("E7").Select
ActiveCell.Value = CStr(str)
End Sub

Download Demo and Source – [86] KB 

More by Author

Must Read