COM script activation sometimes fails - c++

I am running com scripts from c++ on windows xp
Usually the script executes without problems, but sometimes the execution fails with hresult DISP_E_MEMBERNOTFOUND. (Invoke is the function that fails)
Does anybody have any idea why it happens?
The code is below
CLSID clsid;
MULTI_QI mqi;
HRESULT hr ;
mqi.hr = 0;
mqi.pIID = &IID_IDispatch;
mqi.pItf = NULL;
hr = CLSIDFromProgID(T2W(progId.c_str()), &clsid);
CHECK_HRESULT(hr);
hr = CoCreateInstanceEx(clsid, NULL, CLSCTX_INPROC_SERVER, NULL, 1, &mqi);
CHECK_HRESULT(hr);
tMethodArguments argTemp(arguments.size()) ;
USES_CONVERSION ;
HRESULT hr;
DISPID index ;
OLECHAR FAR* szMember = T2W(method.c_str());
unsigned int err ;
hr = m_pScriptComObj->GetIDsOfNames( IID_NULL, &szMember, 1, LOCALE_SYSTEM_DEFAULT, &index ) ;
CHECK_HRESULT(hr);
DISPPARAMS params ;
params.rgvarg = pArgs ;
params.rgdispidNamedArgs = NULL ;
params.cArgs = arguments.size() ;
params.cNamedArgs = 0 ;
EXCEPINFO excep_info;
hr = m_pScriptComObj->Invoke(index,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
&params,
&res,
&excep_info,
&err);
I omitted method and arguments initialization
The vbscript that is called by INVOKE looks like this
<?xml version="1.0"?>
<component id="script_wsc_script">
<?component?>
<registration
description="script_wsc_script"
progid="wscScript.WSC"
version="1.00"
classid="{A1C14070-EBAB-41A0-BC9C-B4330A73437D}"
remotable="true"
>
</registration>
<public>
<method name="PrintMessage">
<PARAMETER name="first"/>
<PARAMETER name="second"/>
</method>
</public>
<script language="VBScript">
<![CDATA[
Function PrintMessage ( first, second)
''do something
End Function

Related

c++ ole automation how to clear excel cell contents

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.

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

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.

COM IDispatch->Invoke fails with error DISP_E_EXCEPTION

I'm trying to invoke a IDispatch->Invoke call to get the name of the IDispatch object and the method fails with error DISP_E_EXCEPTION.
The property I'm trying to get is "accName".
Below is the code that tries to do this:
HRESULT getParentName(IAccessible* pAcc) {
IDispatch *parent;
HRESULT hr;
if ((hr = pAcc->get_accParent(&parent)) == S_OK) {
DISPID dispid;
WCHAR *member = L"accName";
DISPPARAMS dispparams = { NULL, NULL, 0, 0 };
VARIANT result;
result.lVal = CHILDID_SELF;
result.vt = VT_I4;
hr = parent->GetIDsOfNames(IID_NULL, &member, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (SUCCEEDED(hr)) {
//OK till now
EXCEPINFO exc;
UINT numErrs;
hr = parent->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET, &dispparams, &result, &exc, &numErrs);
if (hr == S_OK) {
MessageBox(NULL, result.bstrVal, L"Got the name", MB_OK);
} else {
//fails with error DISP_E_EXCEPTION
// exception EXCEPINFO return nothing
}
}