The SAFEARRAY is a standard way to pass arrays or collections between COM objects.
Using COM’s standard marshaller , we can pass a collection of OLE Automation compatible
data types using SAFEARRAYs.
Multidimensional SAFARRAYs help us pass various automation compatible data types through the same array
Assume , we own an icecream parlor and would like to give our customers a list of
all the icecream flavors and their prices.
Now wouldn’t it be nice to package an array with both the flavor (represented by a
BSTR) and the price (represented as a float data type).
Notice that we have two diferent data types one a float and another a BSTR and yet
we package them neatly in a SAFEARRAY and send them across using COM’s standard marshaller.
Our data structure should look something like this:
flavor 1 flavor 2 flavor n
Flavors (0,0) (0,1) ………. (0,n)price 1 price 2 price n
Prices (1,0) (1,0) ………. (1,n)
You can extend this whole analogy to actually pack every record in a database
table into an N-dimensional SAFEARRAY where N represents the number of fields
in the table.
While wading through some of the SAFEARRAY documentation , you may happen to come across
the term array descriptor.
An array descriptor is actually a pointer to an allocated SAFEARRAY structure.
Time now to have a look at our Icecream parlor example.
//////////////////////////////////////////////////////////////////////////////
//Function : GetFlavorsWithPrices (Example for Multidimensional SAFEARRAY)
//Parameters: VARIANT (out parameter that contains a SAFEARRAY of VARIANTs
// helping us to pass BSTR and float in the same array)
//Return Type : HRESULT
//////////////////////////////////////////////////////////////////////////////STDMETHODIMP CIceCreamOrder::GetFlavorsWithPrices(VARIANT *pVariant)
{
// TODO: Add your implementation code here//Initialize the bounds for the array
//Ours is a 2 dimensional array
SAFEARRAYBOUND safeBound[2];//Set up the bounds for the first index
//That’s the number of flavors that we have
safeBound[0].cElements = m_vecIcecreamFlavors.size();
safeBound[0].lLbound = 0;//Set up the bounds for the second index
safeBound[1].cElements = m_vecIcecreamPrices.size();
safeBound[1].lLbound = 0 ;///Initialize the VARIANT
VariantInit(pVariant);
//The array type is VARIANT
//Storage will accomodate a BSTR and a float
pVariant->vt = VT_VARIANT | VT_ARRAY;
pVariant->parray = SafeArrayCreate(VT_VARIANT,2,safeBound);//Initialize the vector iterators
std::vector::iterator iterFlavor;
std::vector<float>::iterator iterPrices;//Used for indicating indexes in the Multidimensional array
long lDimension[2];
int iFlavorIndex = 0;//Start iteration
iterPrices = m_vecIcecreamPrices.begin();
iterFlavor = m_vecIcecreamFlavors.begin();//Iterate thru the list of flavors and prices
while(iterFlavor != m_vecIcecreamFlavors.end())
{//Put the Element at (0,0), (0,1) , (0,2) ,………….(0,n)
lDimension[1] = iFlavorIndex;
lDimension[0] = 0;
CComVariant variantFlavor(SysAllocString((*iterFlavor).m_str));
SafeArrayPutElement(pVariant->parray,lDimension,&variantFlavor);//Put the Element at (1,0), (1,1) , (1,2) ,………….(1,n)
lDimension[1] = iFlavorIndex;
lDimension[0] = 1;
CComVariant variantPrices(*iterPrices);
SafeArrayPutElement(pVariant->parray,lDimension,&variantPrices);iFlavorIndex++;
iterPrices++;
iterFlavor++;}
return S_OK;
}
Download demo project (Server) – 32 KB
Download demo project (Client) – 18 KB