As projects are migrated to the .NET Framework, there is often a need to integrate newly developed .NET based functionality into existing, not-yet-migrated, legacy COM applications. Ideally, the code being developed on the .NET Framework should take advantage of the rich class libraries that the framework has to offer. This can pose several problems for COM clients that want to use the managed code since COM and .NET have differing object models, memory models and runtime requirements.
Fortunately, many of the .NET Framework classes are exposed to COM clients via mscorlib.tlb. A quick look at mscorlib.tlb in OleView reveals just how much of the basic framework is COM Visible:
There are many more classes that are visible to COM objects. In fact, every class that is marked
ComVisible(true) in the API documentation can be easily accessed from COM clients.
Using the Code
This example shows how to use a
System.Collections.ArrayList from native C++. The C++ client makes use of ATL.
The managed class method
Library.GetBooks() returns an
ArrayList. A single
string was added to this list in the
Library() constructor. The following snippet prints a
count of the number of items in the list (in this example, there is only 1):
IUnknown *ptrUnkBooks = NULL;
ICollection *ptrCol = NULL;
ptrUnkBooks->QueryInterface(__uuidof(ICollection), (void **)&ptrCol);
long count = -1;
cout << "Number of books: " << count << endl;
System.Collections.ICollection.Count property contains the number of items in the
ICollection is only one of many interfaces implemented by
ArrayList. Each of these interfaces is declared as a dual interface so it can be accessed by early bound clients (like this C++ client) as well as late bound clients (e.g. VBscript).
To access the individual items in the
IList interface is required. The
IList.Item property in the managed world provides zero based indexed access to the elements of the list. This property can be accessed as follows:
IList *ptrList = NULL;
ptrCol->QueryInterface(__uuidof(IList), (void **)&ptrList);
for (int i=0; i < count; i++)
wcout << "Found book: " << ((_bstr_t)vtObj) << endl;
This example prints out each element in the list. It can be easily adapted for lists that are not
VT_* VARIANT macros can be used to determine the type of
VARIANT in the list.
Points of Interest
The COM C++ compiler extensions can greatly simplify COM programming in C++. Attributed programming also provides another way to easily create and consume COM types from C++ but there are still a lot of legacy projects out there using versions of VC++ that predate attributed programming.
- 29th May, 2008: First version submitted