you're reading...
COM, Programming Issues/Tips

SafeArrayGetElement() API and Clearing SAFEARRAY UDT Elements.

1. When we use SafeArrayGetElement() to retrieve an element from a SAFEARRAY, special attention must be afforded to situations where the element is a User-Defined Type (UDT) (i.e. a structure in common programming terms).

2. More specifically, a UDT which contains member fields which are pointers to allocated memory (e.g. BSTRs).

3. Just before calling the API, the UDT structure that is to receive a copy of the array element must be cleared of random data (the example C++ code below demonstrates this by using the memset() function).

4. This is because as part of the SafeArrayGetElement() call, SysFreeString() will be invoked on BSTR member fields inside the UDT.

5. Now, if any BSTR member field contained random data, SysFreeString() will crash. If it is NULL, SysFreeString() will go through fine. In fact SysFreeString() may not even be called.

6. Also note that for such UDTs, when an instance is no longer required, it must once again be cleared. Note that this clearing is different from that which was mentioned previously using memset. This clearance is done to specifically free any members which are references to allocated memory (e.g. BSTRs).

7. This can be done manually by going through each memory reference member fields or (preferrably) by using the IRecordInfo::RecordClear() method. The reason this is necessary is because COM SAFEARRAYs use copy-semantics : all data retrieved from a SAFEARRAY are actually copies of corresponding elements. Hence each retrieved element must be subsequently cleared when no longer required.

8. The following is a sample code that demonstrates this :

long  rgIndices[1];
TestStruct value;  // TestStruct is a UDT which contain a BSTR member field.

// Note that we must set all fields
// inside "value" to zero.
// This is important because
// SafeArrayGetElement() will first
// clear all members of "value".
// For BSTR member fields,
// it will call the ::SysFreeString()
// API. Now if the BSTR members contain
// random data, it will result in
// a crash. If it is NULL, it is OK.
memset(&value, 0, sizeof(value));

// SafeArrayGetElement() will return
// a copy of the relevant element in
// the SAFEARRAY. Hence it is important
// that when "value" is no longer required,
// its members be cleared. This is especially
// so for members which point to allocated
// memory (e.g. BSTRs).
rgIndices[0] = i;
  (void FAR*)&value

// We clear the members of "value"
// which includes the BSTR member fields.
spIRecordInfo -> RecordClear((PVOID)&value);

About Lim Bio Liong

I've been in software development for nearly 20 years specializing in C , COM and C#. It's truly an exicting time we live in, with so much resources at our disposal to gain and share knowledge. I hope my blog will serve a small part in this global knowledge sharing network. For many years now I've been deeply involved with C development work. However since circa 2010, my current work has required me to use more and more on C# with a particular focus on COM interop. I've also written several articles for CodeProject. However, in recent years I've concentrated my time more on helping others in the MSDN forums. Please feel free to leave a comment whenever you have any constructive criticism over any of my blog posts.


One thought on “SafeArrayGetElement() API and Clearing SAFEARRAY UDT Elements.

  1. Thank you!!!!! I spent so long trying to figure out a heap corruption error I was having and this was the reason. Thank you again. I had needed this line.

    Posted by malkie | July 26, 2011, 2:40 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: