SCODE WINAPI CalcCells(LPDISPATCH *ppdsSourceRange, VARIANTARG *pvtResult)
{
HRESULT hr;
EXCEPINFO excep;
ULONG cElements, i;
DISPPARAMS dispparams;
unsigned int uiArgErr, cDims;
DISPID dispidValue, dispidPut;
VARIANTARG vSource, vResult, vTemp, *pvdata;
LPOLESTR lpszName = L"Value";
hr = (*((*ppdsSourceRange)->lpVtbl->GetIDsOfNames))
(*ppdsSourceRange, &IID_NULL, &lpszName,
1, LOCALE_SYSTEM_DEFAULT, &dispidValue);
if (hr != NOERROR)
goto calc_error;
// PropertyGet has no arguments
dispparams.cArgs = 0;
dispparams.cNamedArgs = 0;
// Invoke PropertyGet
hr = (*((*ppdsSourceRange)->lpVtbl->Invoke))
(*ppdsSourceRange, dispidValue, &IID_NULL,
LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,
&dispparams, &vSource, &excep, &uiArgErr);
//ClearAllArgs();
//hr = Invoke(*ppdsSourceRange, lpszName, &vSource, DISPATCH_PROPERTYGET, DISP_FREEARGS);
if (hr != NOERROR){ MessageBox(0,"Loi","Thong bao",MB_OK);
goto calc_error;}
// initialize the result variant
VariantInit(&vResult);
vResult.vt = VT_R8;
vResult.dblVal = 0.0;
// If there is more than one cell in the source range,
// it's a variant containing an array.
// Access this using the SafeArray functions
if (vSource.vt & VT_ARRAY)
{
// iterate the dimensions; number of elements is x*y*z
for (cDims = 0, cElements = 1;
cDims < vSource.parray->cDims; cDims++)
cElements *= vSource.parray->rgsabound[cDims].cElements;
// get a pointer to the data
hr = SafeArrayAccessData(vSource.parray, (LPVOID)&pvdata);
if (hr != NOERROR)
goto calc_error;
// iterate the data. try to convert non-double values to double
for (i = 0; i < cElements; i++)
{
vTemp = pvdata[i];
if (vTemp.vt != VT_R8)
{
hr = VariantChangeType(&vTemp,
&vTemp, 0, VT_R8);
if (hr != NOERROR)
goto calc_error;
}
// add the data. this is where we could
// add a more complicated function
vResult.dblVal += vTemp.dblVal;
}
SafeArrayUnaccessData(vSource.parray);
}
else
{
// only one cell in the source range.
// if it's not a double, try to convert it.
if (vSource.vt != VT_R8)
{
hr = VariantChangeType(&vSource, &vSource, 0, VT_R8);
if (hr != NOERROR)
goto calc_error;
}
vResult = vSource;
}
// if the result value is an object,
// get the DISPID for its Value property
if (pvtResult->vt == VT_DISPATCH)
{
hr = (*(pvtResult->pdispVal->lpVtbl->GetIDsOfNames))
(pvtResult->pdispVal, &IID_NULL, &lpszName,
1, LOCALE_SYSTEM_DEFAULT, &dispidValue);
if (hr != NOERROR)
goto calc_error;
dispidPut = DISPID_PROPERTYPUT;
dispparams.rgdispidNamedArgs = &dispidPut;
dispparams.rgvarg = &vResult;
dispparams.cArgs = 1;
dispparams.cNamedArgs = 1;
// Invoke PropertyPut
hr = (*(pvtResult->pdispVal->lpVtbl->Invoke))
(pvtResult->pdispVal, dispidValue, &IID_NULL,
LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT,
&dispparams, NULL, &excep, &uiArgErr);
if (hr != NOERROR)
goto calc_error;
}
else
{
// Result is not an object; it's a variable passed by reference.
// Must free any existing allocation in the variant.
// The ReleaseVariant function is in dispargs.c
ReleaseVariant(pvtResult);
*pvtResult = vResult;
}
return 0;
calc_error:
return GetScode(hr);
}