Introduction
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):
ILibraryPtr ptrLibrary(__uuidof(Library));
IUnknown *ptrUnkBooks = NULL;
ptrLibrary->GetBooks((ManagedCSharpDemoLibrary::_ArrayList **)&ptrUnkBooks);
ICollection *ptrCol = NULL;
ptrUnkBooks->QueryInterface(__uuidof(ICollection), (void **)&ptrCol);
long count = -1;
ptrCol->get_Count(&count);
cout << "Number of books: " << count << endl;
The System.Collections.ICollection.Count
property contains the number of items in the ArrayList
. 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 ArrayList
, 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);
VARIANT vObj;
_variant_t vtObj;
for (int i=0; i < count; i++)
{
ptrList->get_Item(i, &vObj);
vtObj.Attach(vObj);
wcout << "Found book: " << ((_bstr_t)vtObj) << endl;
}
ptrCol->Release();
This example prints out each element in the list. It can be easily adapted for lists that are not string
s. The 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.
History
- 29th May, 2008: First version submitted