Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using .NET Collections from Native Code

0.00/5 (No votes)
29 May 2008 1  
A short example of how to access a managed ArrayList of Strings from Native C++/ATL

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:

DotNetCollectionsFromNativeCodeDemo_OleView.GIF

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;

// ManagedCSharpDemoLibrary::_ArrayList is a stub struct
// created by InteropServices.  Since everything in COM
// derives from IUnknown, it's safe to cast from an IUnknown *
ptrLibrary->GetBooks((ManagedCSharpDemoLibrary::_ArrayList **)&ptrUnkBooks);

// ICollection is defined in mscorlib.tlb.  It corresponds
// to System.Collections.ICollection

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);

// ArrayLists store objects.  These are marshalled as 
// VARIANTs.  Since this list is storing strings, the
// VARIANTs are of type BSTR;

VARIANT vObj;
_variant_t vtObj; // provides a convenient way to convert to _bstr_t

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 strings. 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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here