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

Simplify your Safearray loops using macros

0.00/5 (No votes)
15 Nov 2001 2  
An article describing how to simplify the work with safearrays

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.

// Safearray loop [sample 1]

// this example assumes that you have a Safearray in a VARIANT (vArray) 

// with the type VT_ARRAY | VT_BSTR


// variables

LONG lstart, lend;
LONG idx = -1;
LONG nPos;
HRESULT hr;
BSTR* pbstr;

// assign the Safearray

SAFEARRAY *sa = V_ARRAY( &vArray ); 

// Get the lower and upper bound

hr = SafeArrayGetLBound( sa, 1, &lstart );
if(FAILED(hr)) return hr;
hr = SafeArrayGetUBound( sa, 1, &lend );
if(FAILED(hr)) return hr;

// loop

hr = SafeArrayAccessData(sa,(void HUGEP**)&pbstr);
if(SUCCEEDED(hr))
{
	for(idx=lstart; idx <= lend; idx++)
	{		
		CComBSTR s;
		s = pbstr[idx];
		// s now contains the item at position idx in the array

		
		// ...		

	}
	hr = SafeArrayUnaccessData(sa);	
	if(FAILED(hr)) return hr;
}	
else
	return hr
// (23 lines of code)

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

// Safearray loop [sample 2]

// this example assumes that you have a Safearray in a VARIANT (vArray) with 

// the type VT_ARRAY | VT_BSTR


#include "safearray_macro.h"


// variables

BSTR* pbstr;

// loop

BEGIN_SA_V(vArray,pbstr)
    BEGIN_SA_LOOP()
        CComBSTR s;
        s = pbstr[INDEX_SA];
        // s now contains the item at the current position in the array

        // ...        

    END_SA_LOOP();
END_SA();
        
// (8 lines of code)

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

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