Click here to Skip to main content
13,287,834 members (50,550 online)
Click here to Skip to main content
Add your own
alternative version


25 bookmarked
Posted 23 May 2005

Collections Interoperability

, 23 May 2005
Rate this:
Please Sign up or sign in to vote.
This article describes how to move collections between native and managed code.


In my work, I am using a COM object as an interface between a managed server and a HW device that has a C DLL interface. Last week, I encountered the need to pass a collection from the HW device to the server. To do that, I had the COM read it from the device and pass it to the server. The problem was that I couldn’t return a collection of my UDT (User Defined Type) from COM to the managed server.

The code

So how do we return a UDT from native to managed code?

The easiest way to achieve interoperability between native and managed code is by putting the unmanaged code in a COM object. So what is left is to return the collection from COM to the managed code.

COM has two ways to return collections:

  1. Return a C style array like so:
    HRESULT Foo(int Length, [length_is(Length)]  SUDTStruct  Col[]);
  2. Return a SAFEARRAY with the collection like so:

    If you use IDL, the syntax is:


    If you use embedded IDL, the syntax is:

    HRESULT Bar([out, satype(struct PTZPresetsInfo))] SAFEARRAY **Col)

The first way does not work with .NET. The interop proxy that will be created for it will look like:

void Foo(int Length, ref  SUDTStruct  Col)

which means that only one struct will be returned and not the whole collection, so the only way is using a safe array.

To do that we need a few simple stages:

  1. Define the UDT you want to pass in the collection.
  2. Define a GUID for the UDT:
    struct SUDTStruct
  3. Define a get function:
    HRESULT Bar(([out, satype(struct PTZPresetsInfo)) SAFEARRAY **Col)
  4. Implement the get function by creating a SAFEARRAY and returning it:
    SAFEARRAY *pSafeArrayCol;
    unsigned int ndim =  1;
    SAFEARRAYBOUND  rgbounds;
    rgbounds.lLbound = 0;
    rgbounds.cElements = ColSize;
    IRecordInfo*                  pRecInfo = NULL;
    ITypeLib* pTypelib = NULL;
    HRESULT hr = LoadTypeLib(A2OLE("UDT TYPE LIBRARY"),&pTypelib);
    if (FAILED(hr))
            return NULL;
    ITypeInfo *pTypeInfo;
    hr =
    if (FAILED(hr))
            return NULL;
    hr = GetRecordInfoFromTypeInfo(pTypeInfo, &pRecInfo);
    if (FAILED(hr))
            return NULL;
    pSafeArrayCol = SafeArrayCreateEx(VT_RECORD, 1,
                                      &rgbounds, pRecInfo);
    CollectionType::value_type *pItem;
    hr = SafeArrayAccessData(pSafeArrayCol,
  5. Init the collection pointed to by pItem:

A few remarks: if you want to pass a collection of a UDT to COM all you need to do is define a UDT with a GUID and define a function like so:


This function will appear in the .NET interop like so:

void Bar(System.Array Col)

When calling it, pass a SUDTStruct[] as the collection:

In order to ease the process of creating the safe array I created a simple template function that receives a STL collection that has the UDT as its value type and create a safe array out of it with the same data. The source is attached to this article.

For example:

std::vector<SUDTStruct> Col;
// init the collection with the data
SAFEARRAY *pSafeArrayCol = CreateUDTSafeArrayFromCol(Col);

The CreateSafeArray function will create a safe array and initialize it with the data in the STL collection.

The demo project attached is a COM object and a .NET assembly that sends and gets collections from it.

Points of Interest

Microsoft has done a lot of work to make COM a mechanism for interoperability between managed and unmanaged areas, but not all the COM capability is exported through the .NET proxy created for COM.


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


About the Author

Meir Bechor
Web Developer
Israel Israel
6 years C++ and .NET programer in Nice Systems

You may also be interested in...

Comments and Discussions

QuestionRegarding License Pin
Member 1020828215-Jan-17 19:59
memberMember 1020828215-Jan-17 19:59 
GeneralCorrection in LoadTypeLib code and Issue With pSafeArrayCol [modified] Pin
PRISMAY19-Jun-08 4:49
memberPRISMAY19-Jun-08 4:49 
I found this article very helpful, but I did find a "bug" in this line:
HRESULT hr = LoadTypeLib(A2OLE(FileName),&pTypelib);

Which should really be:
HRESULT hr = LoadTypeLib(A2OLE(PathForUDTDefDll),&pTypelib);

to make sure a passed in path would be used.

I did run into an issue with the safearray being created. After the loop that populates pItem, I noticed, when debugging, that pSafeArrayCol has no address and when you look into it deeper, it shows 6 elements that are evaluated as error. These items do not correspond to anything that is in pItem. The same is true right after SafeArrayCreateEx is called and after SafeArrayUnaccessData is called. Any ideas why this is?

The passed in UDT is being processed correctly because the loop through the collection populates pItem correctly.

[EDIT] Regarding the "issue" above with the contents of pSafeArrayCol, after further research, it seems to be the standard behavior. I was able to get it working once I had the correct object on the managed side, i.e., Array in my case. Thanks again for this VERY HELPFUL article as it saved me a lot of time.


General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171207.1 | Last Updated 24 May 2005
Article Copyright 2005 by Meir Bechor
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid