SAFEARRAY - Multidimensions
-
Hey all, I'm working on a component that returns a SAFEARRAY. Here's the IDL for the method as well as the C++ declaration:
[id(2), helpstring("List of Report Type (Names) available to a user on a specific date")] HRESULT GetReportTypes([in] BSTR UserID, [in] INT CloseDate, [out, retval] VARIANT* pReportTypes);
STDMETHODIMP CReports::GetReportTypes(BSTR UserID, INT CloseDate, VARIANT *pReportTypes)
Now without loading this up with a ton of code I'll explain what I am doing and then show the important parts of the code. Basically, I want to return a SAFEARRAY that is mulitdimensionl, in this case the array is [x][1] in size and x is determined by the number of records retrieved. So here's how I'm creating the SAFEARRAY:// Setup/Create our SAFEARRAY SAFEARRAYBOUND SABounds[2]; SABounds[0].cElements = (DWORD)pRsHPASReports->RecordCount + 1; // Why do I need to add 1 to this??? SABounds[1].cElements = SABounds[0].cElements; SABounds[0].lLbound = 0; SABounds[1].lLbound = 0; // Initialize the variant and set it up as an array of variants VariantInit(pReportTypes); pReportTypes->vt = VT_VARIANT | VT_ARRAY; pReportTypes->parray = SafeArrayCreate(VT_VARIANT, 2, SABounds);
and then after opening the recordset I loop through the records filling in the SAFEARRAY with my data, like so:while(! pRsHPASReports->IsEOF) { ldimension[0] = lLoop++; ldimension[1] = 0; CComVariant bstrTmp( pRsHPASReports->Fields->Item["RptType"]->Value ); TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp )); ldimension[1] = 1; CComVariant bstrTmp2( pRsHPASReports->Fields->Item["Title"]->Value ); TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp2 )); pRsHPASReports->MoveNext(); }
pretty standard stuff, right? Well, as you can see from the comment above, If I have a record count of 1 then the SAFEARRAY does not appear to be initialized properly... I'm forced to add 1 to the count so that I can build the array. My question is why can't I create a SAFEARRAY with a size [1][1]? On the client side, when checking the bounds on the SAFEARRAY I see 0 to 1 ... yet the element at postion 1 is empty. I've looked high and low on the web for a soloution and have not been successful... So, anyone know how I can create a SAFEARRAY with just one element? Thanks, Dave "Dak Lozar" Loeser -
Hey all, I'm working on a component that returns a SAFEARRAY. Here's the IDL for the method as well as the C++ declaration:
[id(2), helpstring("List of Report Type (Names) available to a user on a specific date")] HRESULT GetReportTypes([in] BSTR UserID, [in] INT CloseDate, [out, retval] VARIANT* pReportTypes);
STDMETHODIMP CReports::GetReportTypes(BSTR UserID, INT CloseDate, VARIANT *pReportTypes)
Now without loading this up with a ton of code I'll explain what I am doing and then show the important parts of the code. Basically, I want to return a SAFEARRAY that is mulitdimensionl, in this case the array is [x][1] in size and x is determined by the number of records retrieved. So here's how I'm creating the SAFEARRAY:// Setup/Create our SAFEARRAY SAFEARRAYBOUND SABounds[2]; SABounds[0].cElements = (DWORD)pRsHPASReports->RecordCount + 1; // Why do I need to add 1 to this??? SABounds[1].cElements = SABounds[0].cElements; SABounds[0].lLbound = 0; SABounds[1].lLbound = 0; // Initialize the variant and set it up as an array of variants VariantInit(pReportTypes); pReportTypes->vt = VT_VARIANT | VT_ARRAY; pReportTypes->parray = SafeArrayCreate(VT_VARIANT, 2, SABounds);
and then after opening the recordset I loop through the records filling in the SAFEARRAY with my data, like so:while(! pRsHPASReports->IsEOF) { ldimension[0] = lLoop++; ldimension[1] = 0; CComVariant bstrTmp( pRsHPASReports->Fields->Item["RptType"]->Value ); TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp )); ldimension[1] = 1; CComVariant bstrTmp2( pRsHPASReports->Fields->Item["Title"]->Value ); TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp2 )); pRsHPASReports->MoveNext(); }
pretty standard stuff, right? Well, as you can see from the comment above, If I have a record count of 1 then the SAFEARRAY does not appear to be initialized properly... I'm forced to add 1 to the count so that I can build the array. My question is why can't I create a SAFEARRAY with a size [1][1]? On the client side, when checking the bounds on the SAFEARRAY I see 0 to 1 ... yet the element at postion 1 is empty. I've looked high and low on the web for a soloution and have not been successful... So, anyone know how I can create a SAFEARRAY with just one element? Thanks, Dave "Dak Lozar" LoeserIf you want to have the VB array (a to b) in i-th dimension bounds, you should initialize the SABounds[i].lLbound = a; and SABounds[i].cElements = b-a+1; As a rule, a is equal 0, so cElements = b-0+1 and = b+1. But RecordCount is equal to size of array (cElements), therefore, you haven't to add extra "1". Your array in VB will have (0 to x-1) bounds.
// Setup/Create our SAFEARRAY
SAFEARRAYBOUND SABounds[2];
SABounds[0].cElements = (DWORD)pRsHPASReports->RecordCount;
SABounds[0].lLbound = 0;
SABounds[1].cElements = 2; // You have only [0] and [1] in this dimension. Ok?
SABounds[1].lLbound = 0;// Initialize the variant and set it up as an array of variants
VariantInit(pReportTypes);
pReportTypes->vt = VT_VARIANT | VT_ARRAY;
pReportTypes->parray = SafeArrayCreate(VT_VARIANT, 2, SABounds);lLoop = 0; // SABounds[0].lLbound
while(! pRsHPASReports->IsEOF)
{
ldimension[0] = lLoop++;
ldimension[1] = 0; // SABounds[1].lLboundCComVariant bstrTmp( pRsHPASReports->Fields->Item\["RptType"\]->Value ); TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp )); ldimension\[1\]++; CComVariant bstrTmp2( pRsHPASReports->Fields->Item\["Title"\]->Value ); TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp2 )); pRsHPASReports->MoveNext();
}
With best wishes, Vita