Using a Multidimensional SAFEARRAY to pass data across from COM objects
Posted
by Aravind Corera
on November 10th, 1998
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;
}

Comments
There are no comments yet. Be the first to comment!