The purpose of this article is show how you can simplify your safearray programming in VC++ and how to make the code even more readable. The article will briefly define safearrays and the introduce a new set of macros and how you can use them.
Safearrays
What are Safearrays? As it's name says it is an array data type that is safe wich means that it keeps track of it's limitations and bounds and therefore limits access within these bounds. Safearrays are used when passing arrays encapsulated in Variants (their base type is VT_?
| VT_ARRAY
), for example between COM objects.
Safearrays must not be confused with C/C++ arrays which are not safe. When working with Visual Basic COM objects and Visual Basic arrays your only choice is to learn how to use Safearrays, MSDN is a good source for more information on this topic (or perhaps a more extended article in the future :-).
How to loop through a Safearray
Those of you familiar with Safearrays knows that it takes quite a large number of code-rows to iterate through a Safearray. The example below [sample 1] shows how the code looks like whe iterating through a Safearray containing Variants.
LONG lstart, lend;
LONG idx = -1;
LONG nPos;
HRESULT hr;
BSTR* pbstr;
SAFEARRAY *sa = V_ARRAY( &vArray );
hr = SafeArrayGetLBound( sa, 1, &lstart );
if(FAILED(hr)) return hr;
hr = SafeArrayGetUBound( sa, 1, &lend );
if(FAILED(hr)) return hr;
hr = SafeArrayAccessData(sa,(void HUGEP**)&pbstr);
if(SUCCEEDED(hr))
{
for(idx=lstart; idx <= lend; idx++)
{
CComBSTR s;
s = pbstr[idx];
}
hr = SafeArrayUnaccessData(sa);
if(FAILED(hr)) return hr;
}
else
return hr
Notice the amount of code, imagine if we could reduce this to 8 lines and think of how much easier your code would be to interpret and for others to understand.
Tip! Also notice how we use the SafeArrayAccessData
to access the data in the loop instead of using SafeArrayGetElement
to improve performance.
How to loop the Safearray using the macros
To make my code easier to read and make the programming faster I created a set of macros to make the Safearray programming easier. Let's see the same example as above [sample 1] using macros [sample 2].
#include "safearray_macro.h"
BSTR* pbstr;
BEGIN_SA_V(vArray,pbstr)
BEGIN_SA_LOOP()
CComBSTR s;
s = pbstr[INDEX_SA];
END_SA_LOOP();
END_SA();
Easy, huh? Just an include file and a new set of macros...
Let's see what the different macros are doing...
Macro definitions
BEGIN_SA_V(vArray, pvar)
Starts the macro section and defines the local variables needed.
vArray
is a Variant containg the Safearray and
pvar
is the variable used in the loop for each item in the array.
BEGIN_SA(sa, pvar)
Starts the macro section and defines the local variables needed.
sa
is a Safearray and
pvar
is the variable used in the loop for each item in the array.
END_SA()
Ends the macro section.
BEGIN_SA_LOOP()
Starts the loop. The
INDEX_SA
is the iterator variable and you can access the current item using
pvar[INDEX_SA]
.
END_SA_LOOP()
The end of the loop.
INDEX_SA
Is the iterator variable inside the loop (the type is
LONG
).
BREAK_SA()
Can be used in the actual loop to break it, as long as it doesn't appear in a nestef for-loop.
QUIT_SA()
If you plan to exit the method inside the loop you should use this macro to be sure that the Safearray is closed.
SAFEARRAY_SA
This macro can be used if you would like to access the
SAFEARRAY
object directly. Useful when the Safearray existed in a Variant.
Demonstration
To test the macros test the included VC++ and VB projects, which illustrates both the BEGIN_SA_V
and BEGIN_SA
macros.
Source and Usage
Just include, #include "safearray_macro.h"
, the file in your code and start using it. If make any extensions/modifications to it please notify me!
Have fun...
/WW