Click here to Skip to main content
15,867,939 members
Articles / Desktop Programming / ATL
Article

Simplify your Safearray loops using macros

Rate me:
Please Sign up or sign in to vote.
3.67/5 (3 votes)
15 Nov 20013 min read 131.4K   1.6K   46   11
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].

<PRE>// 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


Written By
Web Developer
Sweden Sweden
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralGood Exercise done on SAFEARRAY Pin
Member 18700681-Jul-10 4:59
Member 18700681-Jul-10 4:59 
Generalhelp in two dimensional SAFEARRAY Pin
rasred4-Sep-08 1:40
rasred4-Sep-08 1:40 
QuestionMultiDim Pin
cjk0070019-Oct-06 6:35
cjk0070019-Oct-06 6:35 
Does this also work for multi-dimensional safearrays?
AnswerRe: MultiDim Pin
frewah28-Jul-07 13:20
frewah28-Jul-07 13:20 
GeneralVT_BSTR|VT_ARRAY to WCHAR* Pin
dharani14-Sep-04 0:11
dharani14-Sep-04 0:11 
Generalstructure Pin
lioucr17-Nov-01 17:33
lioucr17-Nov-01 17:33 
GeneralGood job for beginner! Pin
4-Aug-01 0:30
suss4-Aug-01 0:30 
GeneralCOleSafeArray Pin
31-Jul-01 22:34
suss31-Jul-01 22:34 
GeneralRe: COleSafeArray Pin
Wictor Wilén31-Jul-01 22:48
Wictor Wilén31-Jul-01 22:48 
GeneralMFC COleSafeArray port to ATL Pin
1-Aug-01 3:42
suss1-Aug-01 3:42 
GeneralRe: COleSafeArray Pin
Anonymous2-Dec-02 9:50
Anonymous2-Dec-02 9:50 

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.