c++ ole automation how to clear excel cell contents - c++

I am using the following function call of IDispatch interface to successfully write Hello World! to a cell in excel sheet excel.
LPOLESTR ptName = L"Value"; //What is the key for clearing the cell contents?
DISPID dispID;
xlCell->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
LCID lcid = GetUserDefaultLCID();
std::wstring cellVal = L"Hello World!";
VARIANT vArgArray[1];
vArgArray[0].vt = VT_BSTR,
vArgArray[0].bstrVal = SysAllocString(cellVal.c_str());
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPPARAMS dp = {NULL, NULL, 0, 0};
dp.cArgs = 1;
dp.rgvarg = vArgArray;
dp.cNamedArgs = 1;
dp.rgdispidNamedArgs = &dispidNamed;
xlCell->Invoke(
dispID,
IID_NULL,
lcid,
DISPATCH_PROPERTYPUT,
&dp,
NULL,
NULL,
NULL);
Now I need to clear a cell using the same IDispatch interface (xlCell)
What value should I use for the LPOLESTR type variable (2nd parameter in GetIDsOfNames function) to initialize the dispID to successfully clear the cell by calling Invoke?

While I could not find the unique DISPID for clearing a cell/cell range, the thing that did work was to modify the VARIANT passed to the Invoke().
All I did was to change the VARIANT from this
vArgArray[0].vt = VT_BSTR,
vArgArray[0].bstrVal = SysAllocString(cellVal.c_str());
to this
vArgArray[0].vt = VT_EMPTY;
Hope it helps someone.

Related

ActiveX Event call fails [duplicate]

I'm unable to successfully invoke create_session member. It's return Type mismatch
// COM class -> member
virtual HRESULT __stdcall create_session(
/*[in]*/ BSTR pbszName,
/*[in]*/ long i32Value ) = 0;
Trying to invoke create_session method as follow:
// test.cpp
HRESULT create_session( IDispatch *dispatch, WCHAR *member ) {
// WCHAR *member = tlib_help::s2ws( "create_session" );
DISPID dispid = -1;
HRESULT hr = dispatch->GetIDsOfNames( IID_NULL, &member, 1, LOCALE_SYSTEM_DEFAULT, &dispid );
if ( SUCCEEDED( hr ) ) {
DISPPARAMS *dispparams = new DISPPARAMS( );
dispparams->cArgs = 2;
dispparams->cNamedArgs = 1;
VARIANTARG *rgvarg = new VARIANTARG[dispparams->cArgs];
rgvarg[0].vt = VARENUM::VT_BSTR;
rgvarg[0].bstrVal = _bstr_t( "loing_info" );
rgvarg[1].vt = VARENUM::VT_UI4;
rgvarg[1].lVal = 12;//i32Value;
dispparams->rgvarg = rgvarg;
dispparams->rgdispidNamedArgs = &dispid;
EXCEPINFO pExcepInfo; UINT puArgErr;
HRESULT hr;
VARIANT pVarResult;
hr = dispatch->Invoke(
dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
dispparams, &pVarResult, &pExcepInfo, &puArgErr
);
delete dispparams;
delete[] rgvarg;
}
return hr;
}
I'm unable to figure it out, what is the reason of this error.
The IDispatch::Invoke() method must be called with parameters in reverse order, as stated in the official documentation:
Implementing IDispatch / Passing Parameters:
The arguments are passed in the array rgvarg[ ], with the number of
arguments passed in cArgs. The arguments in the array should be placed
from last to first, so rgvarg[0] has the last argument and
rgvarg[cArgs -1] has the first argument.
Also, in your case, you don't need "named arguments", only "positional arguments". If cNamedArgs is 0, all of the elements of rgvarg[ ] represent positional arguments.

(WMI) ExecMethod out parameter - ResultingSnapshot is NULL irrespective of the result of the call, Why?

I am using WMI to create an RCT Checkpoint. Below is the code snippet. The problem is when I call the method Create Snapshot using ExecMethodthe checkpoint gets created but the ResultingSnapshot to still points to NULL.
Since the call is asynchronous (as the return value from pOutParameters is 4096) I have also waited till the job gets completed in WaitForJobCompletion but pOutParameters is not updated and still, the ResultingSnapshot is NULL.
Basically, I need this ResultingSnapshot for creating a reference point. If there is any other way to do it, I can write it, need guidance though.
I am new to WMI, any help or lead is appreciated.
HRESULT hr;
CComPtr<IWbemClassObject> pInParams;
CComPtr<IWbemClassObject> pOutParameters;
IWbemCallResult *pResult = 0;
// Set Method Paramters
this->GetMethodParams(L"Msvm_VirtualSystemSnapshotService", L"CreateSnapshot", &pInParams);
IWbemClassObject * pVirtualSystemSnaphotSettingData = NULL;
hr = m_pWbemServices->GetObject(L"Msvm_VirtualSystemSnapshotSettingData", 0, NULL, &pVirtualSystemSnaphotSettingData, &pResult);
IWbemClassObject * pInpInstOfSnapshotSettingData = NULL;
hr = pVirtualSystemSnaphotSettingData->SpawnInstance(0, &pInpInstOfSnapshotSettingData);
VARIANT consistencyLevel;
VariantInit(&consistencyLevel);
V_VT(&consistencyLevel) = VT_BSTR;
V_BSTR(&consistencyLevel) = SysAllocString(L"1");
hr = pInpInstOfSnapshotSettingData->Put(L"ConsistencyLevel", 0, &consistencyLevel, 0);
VariantClear(&consistencyLevel);
VARIANT elementName;
VariantInit(&elementName);
V_VT(&elementName) = VT_BSTR;
V_BSTR(&elementName) = SysAllocString(L"rhel-1");
hr = pInpInstOfSnapshotSettingData->Put(L"ElementName", 0, &elementName, 0);
VariantClear(&elementName);
hr = m_pWbemServices->PutInstance(pInpInstOfSnapshotSettingData, 0, NULL, &pResult);
BSTR objString = NULL;
hr = pInpInstOfSnapshotSettingData->GetObjectText(0, &objString);
BSTR ArgNameTwo = SysAllocString(L"SnapshotSettings");
VARIANT v;
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = objString;
hr = pInParams->Put(ArgNameTwo, 0, &v, 0);
VARIANT vtProp;
m_pVmWbemClassObject->Get(L"__Path", 0, &vtProp, 0, 0);
wprintf(L"Affected System : : %ls", (LPWSTR)vtProp.bstrVal);
HRESULT hres = pInParams->Put(L"AffectedSystem", 0 , &vtProp, NULL);
VARIANT var;
VariantInit(&var);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"2");
CHK_HRES(pInParams->Put(L"SnapshotType", 0, &var, 0));
IEnumWbemClassObject* pEnumOb = NULL;
hr = m_pWbemServices->ExecQuery(
BSTR(L"WQL"),
BSTR(L"select * from Msvm_VirtualSystemSnapshotService"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumOb);
IWbemClassObject *pclsObj1 = NULL;
ULONG uReturn1 = 0;
while (1)
{
HRESULT hr = pEnumOb->Next(WBEM_INFINITE, 1, &pclsObj1, &uReturn1);
if (0 == uReturn1)
{
break;
}
IWbemCallResult *pCallResult = NULL;
IWbemClassObject *pResObj = NULL;
CComBSTR path(this->GetStrProperty(L"__PATH", pclsObj1));
hr = m_pWbemServices->ExecMethod(path, L"CreateSnapshot", 0, NULL, pInParams, &pOutParameters, &pCallResult);
/* cout << "check1 : " << hex << hr << endl;
hr = pCallResult->GetResultObject(0, &pResObj);
cout << "check2" << endl;*/
this->WaitForJobCompletion(pOutParameters);
}
cout << "\nSnpshot Complete" << endl;
}
EDIT
I found that the SnapshotType Parameter is not set correctly it should be 32768 and I have used the following way to convert uint16 to Variant but no Success and I get 0x80070057 Incorrect Parameter Error.
VARIANT var;
VariantInit(&var);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"32768");
hr = pInParams->Put(L"SnapshotType", 0, &var, CIM_UINT16);
HRESULT GetRelated(PWSTR sAssociatePath, PWSTR sResultClass, IWbemClassObject** ppResultObject)
{
CStringW query;
query.Format(L"associators of {%s} where ResultClass = %s", sAssociatePath, sResultClass);
CComPtr<IEnumWbemClassObject> pEnumOb;
HRESULT hr = m_pWbemServices->ExecQuery(
BSTR(L"WQL"),
CComBSTR(query),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumOb));
ULONG uReturn = 0;
CComPtr<IWbemClassObject> pObject;
hr = pEnumOb->Next(WBEM_INFINITE, 1, &pObject, &uReturn);
return hr;
}
// Call the GetRelated function above with the __PATH parameter of JOB
CComPtr<IWbemClassObject> pOutParam = NULL;
CHK_HRES(this->ExecMethod(pHyperVObject, L"ConvertToReferencePoint", pInParams, &pOutParam, NULL));
CComVariant jobPath;
CHK_HRES(pOutParam->Get(L"Job", 0, &jobPath, NULL, NULL));
CComPtr<IWbemClassObject> pResult;
GetRelated(jobPath.bstrVal, L"Msvm_VirtualSystemReferencePoint", &pResult);
You provide a ppCallResult parameter. From the documentation:
ppCallResult [out] If NULL, this is not used. If ppCallResult is
specified, it must be set to point to NULL on entry. In this case, the
call returns immediately with WBEM_S_NO_ERROR. The ppCallResult
parameter receives a pointer to a new IWbemCallResult object, which
must be polled to obtain the result of the method execution using the
GetCallStatus method. The out parameters for the call are available by
calling IWbemCallResult::GetResultObject.
Therefore you need to use GetCallStatus on pCallResult until the method has finished and then GetResultObject to get the out parameters:
LONG status;
while ((hr = pCallResult->GetCallStatus(1000, &status)) == WBEM_S_TIMEDOUT);
/* check hr and status here */
hr = pCallResult->GetResultObject(0, &pResObj);
or use WBEM_INFINITE:
LONG status;
hr = pCallResult->GetCallStatus(WBEM_INFINITE, &status);
/* check hr and status here */
hr = pCallResult->GetResultObject(0, &pResObj);
Alternatively provide NULL instead of pCallResult and it will be a synchronous call where pOutParameters will be set:
hr = m_pWbemServices->ExecMethod(path, L"CreateSnapshot", 0, NULL, pInParams, &pOutParameters, NULL);
Was SnapshotType=32768 giving error to you?
Because snapshot is not created when I use this Snapshot Type.
The following log is getting created:
Checkpoint creation failed for 'Ubuntu1' because an invalid checkpoint type has been specified. (Virtual machine ID 5C773BB5-B630-48B4-AB9E-71C548F3FAE4)
Edit: I am not sure if it will help but this solved my problem:
https://learn.microsoft.com/en-us/answers/questions/160321/wmi-createsnapshot-not-working-with-snapshottype-3.html

ATL COM - EnumWindows callback function not working with IDispatch::Invoke

I am trying to implement a wrapper function for EnumWindows API function to be included in my wrapper dll, so it can be used with many scripting languages.
First of all, I had to test it using VBScript. I implemented a wrapper function and a callback function for EnumWindows with the help of my useful researches, but it is not working as I want.
Here is the code I currently have:
Wrapper functions for EnumWindows and EnumWindowsProc callback:
BOOL CALLBACK EnumWindowsProc(__in HWND hWnd, __in LPARAM lParam) {
LPENUMWINDOWSPARAMS pewParams;
VARIANT vhWnd, vResult; HRESULT HR = S_OK;
VariantInit(&vhWnd);
VariantInit(&vResult);
vhWnd.vt = VT_I4;
vhWnd.lVal = (LONG)(LONG_PTR)hWnd;
pewParams = reinterpret_cast<LPENUMWINDOWSPARAMS>(lParam);
// ^ PASSING MY PARAMETERS THROUGH LPARAM
CComVariant varArgs[2] = { &vResult, &vhWnd };
DISPPARAMS Parameters = { &varArgs[0], NULL, 2, 0 };
pewParams->DISPATCH->Invoke(0, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &Parameters, &vResult, NULL, NULL);
// ^ I SUSPECT SOMETHING IS WRONG WITH THIS INVOKE METHOD. BUT IT RETURNS S_OK.
if (vResult.vt != VT_BOOL) { HR = DISP_E_TYPEMISMATCH; }
pewParams->CallbackResult.vt = VT_ERROR;
pewParams->CallbackResult.scode = HR;
if (HR == S_OK)
return (vResult.boolVal == VARIANT_TRUE ? TRUE : FALSE);
else
return FALSE;
}
STDMETHODIMP CWinAPI::WinAPI_EnumWindows(VARIANT EnumFunc, int lParam, int *Result) {
ENUMWINDOWSPARAMS ewParams; HRESULT HR = S_OK;
switch (EnumFunc.vt)
{
case VT_DISPATCH:
ewParams.DISPATCH = EnumFunc.pdispVal;
break;
case VT_VARIANT | VT_BYREF:
if (EnumFunc.pvarVal->vt == VT_DISPATCH) { ewParams.DISPATCH = EnumFunc.pvarVal->pdispVal; }
break;
default: return DISP_E_TYPEMISMATCH;
}
ewParams.lParam = reinterpret_cast<LPVARIANT>(&lParam);
*Result = (int)EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&ewParams));
HR = ewParams.CallbackResult.scode;
return HR;
}
ENUMWINDOWSPARAMS structure:
typedef struct tagENUMWINDOWSPARAMS {
LPDISPATCH DISPATCH;
LPVARIANT lParam;
VARIANT CallbackResult;
} ENUMWINDOWSPARAMS, *PENUMWINDOWSPARAMS, *LPENUMWINDOWSPARAMS;
Here is the testing VBScript I am currently using:
Dim WINAPI: Set WINAPI = WScript.CreateObject("WinAPIWrapperLib.WINAPI")
Function EnumWindowsProc(HWND, lParam)
WScript.Echo "Handle to the window: 0x" + CStr(UCase(Hex(HWND)))
EnumWindowsProc = True
End Function
Dim Result: Result = WINAPI.WinAPI_EnumWindows(GetRef("EnumWindowsProc"), 0)
WScript.Echo "EnumWindows returned " + CStr(Result)
One thing works, EnumWindows is returning True.
But, instead what I expect, I am not getting handles of windows echoed.
And when I call GetLastError, it returns ERROR_SUCCESS.
Thanks in advance for your kind help.
I fixed the problem, nothing special done, it's only a small change:
Changed varArgs's type from CComVariant to VARIANT like this:
VARIANT varArgs[2] = { vResult, vhWnd };
Changed DISPPARAMS as below:
DISPPARAMS Parameters = {};
Parameters.cArgs = 2;
Parameters.rgvarg = varArgs;
Invoke method is still the same:
pewParams->DISPATCH->Invoke(0, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &Parameters, &vResult, NULL, NULL);
Any good suggestions are further appreciated.

0x80020009 OLE Exception accessing any number other than 0

So I'm using COM to access a third party program, I use the following Method to acquire property from server:
HRESULT ConnectToHYSYS::OLEMethod(int nType, VARIANT * pvResult, IDispatch * pDisp, LPOLESTR ptName, int cArgs...){
if (!pDisp) return E_FAIL;
va_list marker;
va_start(marker, cArgs);
DISPPARAMS dp = { NULL, NULL, 0, 0 };
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPID dispID;
char szName[200];
// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);
// Get DISPID for name passed...
HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
if (FAILED(hr)) {
return hr;
}
// Allocate memory for arguments...
VARIANT * pArgs = new VARIANT[cArgs + 1];
// Extract arguments...
for (int i = 0; i < cArgs; i++) {
pArgs[i] = va_arg(marker, VARIANT);
}
// Build DISPPARAMS
dp.cArgs = cArgs;
dp.rgvarg = pArgs;
// Handle special-case for property-puts!
if (nType & DISPATCH_PROPERTYPUT) {
dp.cNamedArgs = 1;
dp.rgdispidNamedArgs = &dispidNamed;
}
// Make the call!
hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, nType, &dp, pvResult, NULL, NULL);
if (FAILED(hr)) {
return hr;
}
// End variable-argument section...
va_end(marker);
delete[] pArgs;
return hr;
}
When I try to access an object in Collection through the following Method:
void ConnectToHYSYS::GetMaterialStream(int index) {
HRESULT hr;
VARIANT result;
VariantInit(&result);
hr = OLEMethod(DISPATCH_PROPERTYGET, &result, hyStreams, L"Item", 1, index);
CheckForHr(hr);
hyStream = result.pdispVal;}
It returns the hyStream member only if index=0; I checked the following:
1- hyStreams (the collection) pointer is not NULL
2- The member with index Im trying to access exists (The collection has 36 hyStreams but fails to get any hyStream with index more than 0)
3- When Debugging, the error happens when I make the Call
hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, nType, &dp, pvResult, NULL, NULL);
Where hr returns above mentioned error...
Can you figure out where is the problem?
Thank you
The problem was in the type that was passed (index type), I think all kinds of types going through COM has to b kind of object.. anyways, changing it to _variant_t and including (without it, u get nasty errors of linking and stuff), the problem was solved and I could loop through the whole collection.

Programmatically copy a cell from Excel using VC++

Without:
MFC
ATL
using COM, with pure C++, steps taken thus far:
//steps above omitted
_ApplicationPtr application(__uuidof(Excel::Application));
//omitted
const BSTR wcharFileName = SysAllocString(L"...");
application->Workbooks->Open(wcharFileName);
application->put_Visible(10, true);
Question:
How to then copy a cell, for instance A4, B4 and C4, into an array?
Try this http://support.microsoft.com/kb/216388/en-us
I earlier posted that
"For Excel - COM using C++
http://shaktisaran.tech.officelive.com/ExcelCOM.aspx
It also has Windows Programming tutorials."
I've deleted that post because it wouldn't help easily.
I'm providing more info related to example on web-site,
In ExcelProcessor.cpp
ReadRange function reads a range of Excel cells but you need to read a cell of data.
ShowAddedCells function writes to an Excel cell which you can use like below.
In ShowAddedCells function,
//Comment the following
/*
DISPID dispidPUT = DISPID_PROPERTYPUT;
DISPPARAMS dparams = {vDblVal, &dispidPUT, 1, 1};
EXCEPINFO excepinfo;
hr = pXlCell->Invoke(dispID,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYPUT,
&dparams,
NULL,
&excepinfo,
NULL);
*/
//Add the following
DISPPARAMS dparams = {NULL, NULL, 0, 0};
EXCEPINFO excepinfo;
VARIANT vResult;
VariantInit(&vResult);
hr = pXlCell->Invoke(dispID,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET,
&dparams,
&vResult,
&excepinfo,
NULL);
//You get the cell value in vResult
So you create a ReadCell function like ShowAddedCells function.