VARIANTS inside a SAFEARRAY
I have some data that I want to put inside VARIANTS inside a Safearray.
Im having trouble putting the data inside the SAFEARRAY.
WHen I cast a pointer to a VARIANT,
VARIANT* pvDataIn = reinterpret_cast<VARIANT*>(pSafeData->pvData);
1). Can I just use pointer arithmatic to add SafeArrayPutElement().
2). do I need to first put the data into VARIANTs then put them into the safearray or becuase its an safearray of vairants can I just add them straight into the array, and if so do I need to call VariantInit()...
Thanks for any help..
1 Attachment(s)
Re: VARIANTS inside a SAFEARRAY
When dealing with VARIANTs, use the Smart Wrapper Class CComVariant.
When dealing with SAFEARRAYs, use the Smart Wrapper Class CComSafeArray.
Now, putting these two together, you will create a VARIANT of SAFEARRAYs like this -
Code:
CComSafeArray <BSTR> saBstrArray;
// Insert BSTRs into the array: saBstrArray
// Insert the SafeArray into the Variant
CComVariant varArrayWrapper (saBstrArray);
// Converting to pure variant -
VARIANT *pVal = NULL;
varArrayWrapper.Detach (pVal);
Attached is a sample Solution that comprises of -
- A COM Server - CreateSafeArrays.Dll that provides a SAFEARRAY of Strings to the client
- A Console Application Client called - UseSafeArrays.exe that fetches the SAFEARRAY from the COM DLL and displays them on the screen.
This attached sample will show you how to -
- Create of a Safe Array.
- Assign it to a Variant.
- Interpret the Safe Array on the Client
Re: VARIANTS inside a SAFEARRAY
Thanks for the quick response. I cant seem to get the example working becuase I use vc6 and atlsafe.h is vc7 :(
Re: VARIANTS inside a SAFEARRAY
Quote:
Originally Posted by polus
I cant seem to get the example working becuase I use vc6 and atlsafe.h is vc7
Not using VS 7.0 is indeed a tragic constraint...
Okay, here is how you would pass a Safe Array as a VARIANT - and this is VC 6.0 Compliant:
Code:
// The VARIANT returned contains a Safe Array
STDMETHODIMP CArrayMaker::get_StringArray(VARIANT *pVal)
{
// The Safe Array pointer
SAFEARRAY *pStringArray = NULL;
SAFEARRAYBOUND rgsabound[1];
// Create it - Assume a sample Safe Array of BSTRs
pStringArray = SafeArrayCreate (VT_BSTR, 1, rgsabound);
// Populate the Safe Array... with BSTRs
// Use the CComVariant wrapper class - Good Practice!
CComVariant varOut;
// Tell the VARIANT that it contains an Array
varOut.vt = VT_ARRAY;
// Assign the Array
varOut.parray = pStringArray;
// Detach the wrapped Variant Object to the output paramater
return varOut.Detach (pVal);
}
...The client side code doesn't change much other than the fact that instead of using CComSafeArray wrapper, you would directly use the pVariantIn->parray parameter as a pointer to the received Safe Array.
Re: VARIANTS inside a SAFEARRAY
Quote:
Not using VS 7.0 is indeed a tragic constraint...
Yeah... Not upto me unfortuantly....
Thanks alot for the help. Not meaning to be annoying but... I need a Safearray of Variants.
Basically I need to store a two dimesional safearray to store many (1st Dim->) elements containing (2nd Dim->) 13 ints and floats:
Code:
VARIANT vrDataIn[13];
SAFEARRAY *pSafeData;
SAFEARRAYBOUND rgsabound[2];
for ( int nI=0; nI<13; nI++ )
{
VariantInit( &vrDataIn[nI] );
}
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 2;
rgsabound[1].lLbound = 0;
rgsabound[1].cElements = 13;
pSafeData = SafeArrayCreate( VT_VARIANT, 2, rgsabound );
_ASSERTE( pSafeData != NULL );
// Check bounds.....etc... then fill array
LONG lIndices[2] = { 0, 0 };
for ( 0 to 1 )
{
for (0 to 12)
{
vrDataIn[0].vt = VT_UINT;
vrDataIn[0].uintVal = nType[nElements];
SafeArrayPutElement( pSafeData, lIndices, &vrData[0]);
_ASSERTE( SUCCEEDED(hr) );
lIndices[1]++;
}
lIndices[0]++;
}
Obviously the for loops arnt proper C++, I just want to demostrate what Im trying to accomplish (and I know the code is pretty bad :-/ )
Re: VARIANTS inside a SAFEARRAY
It is absolutely OK to have a Safe Array of VARIANTs. :)
In this case, you would create a SafeArray, populate it with VARIANTs, and then, wrap this SafeArray into another VARIANT and transact that one.
To make things clear, this is a VARIANT version of my sample above -
Code:
// The VARIANT returned contains a Safe Array
STDMETHODIMP CArrayMaker::get_StringArray(VARIANT *pVal)
{
CComVariant varTest;
// The Safe Array pointer
SAFEARRAY *pVariantsArray = NULL;
SAFEARRAYBOUND rgsabound[1];
// Create it: A Safe Array of VARIANTs
pVariantsArray = SafeArrayCreate (VT_VARIANT, 1, rgsabound);
// Populate the Safe Array... With VARIANTs
// Use the CComVariant wrapper class - Good Practice!
CComVariant varOut;
// Tell the VARIANT that it contains an Array
varOut.vt = VT_ARRAY;
// Assign the Array
varOut.parray = pVariantsArray;
// Detach the wrapped Variant Object to the output paramater
return varOut.Detach (pVal);
}
...Now, on the client side pVariantIn->parray will point to a SafeArray of Variants...
BTW, you can do away with this -
Quote:
Originally Posted by polus
Code:
for ( int nI=0; nI<13; nI++ )
{
VariantInit( &vrDataIn[nI] );
}
...Initialization of VARIANTs if you use CComVariant. This is VC 6.0 compliant, and I strongly recommend it...
Code:
// The constructor of the wrapper CComVariant will
// Do this trivial stuff for you!
CComVariant() throw()
{
::VariantInit(this);
}
;)
Re: VARIANTS inside a SAFEARRAY
Ok thats great.
Just out of interest, why do wrap the Safearray in a Variant?
Also; when I create a safearray with 2 dimensions it never seems to have the two dimmensions when I look at pvData in memory, nor does it seem to have the second dimensionm listed, there so many things going wrong its beginning to get irritating which is hampering my ability to understand it all...
Re: VARIANTS inside a SAFEARRAY
Quote:
Originally Posted by polus
why do wrap the Safearray in a Variant?
Because, a VARIANT (by default) is transactable across COM Boundaries. SAFEARRAY is not.
Re: VARIANTS inside a SAFEARRAY
OK Ill do it that way thanks...
Re: VARIANTS inside a SAFEARRAY
Quote:
Originally Posted by polus
OK Ill do it that way thanks...
Great... You are welcome... ;)