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; }
Download demo project (Server) - 32 KB
Download demo project (Client) - 18 KB
Comments
There are no comments yet. Be the first to comment!