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.
Related
I have a COM object which exposes a function. I would like to pass parameters to this function and receive a return value. I'm using C++ with CoCreateInstance(). The error I receive is:
hr = 0x8002000e : Invalid number of parameters.
I'm reasonably sure that I have the correct number of parameters, which I can view in OleView:
[id(0x68030001), propget]
double My_function(
[in, out] double* PdblPrice,
[in, out] DATE* PdateStartDate,
[in, out] short* PintFlag,
[in, out] VARIANT_BOOL* PbolXP,
[in, out] SAFEARRAY(double)* PdblScale),
[out, retval] double*);
A summary of my code is as follows, and it works up to the point marked below:
#include <windows.h>
#include <objbase.h>
#include <comutil.h>
#include <vector>
#include <atlcomcli.h>
int main()
{
HRESULT hr;
// Create an instance of COM object
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
CLSID clsid;
HRESULT nResult1 = CLSIDFromProgID(OLESTR("My_Library.clsMy_Library"), &clsid);
IUnknown* pUnknown;
hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&pUnknown);
// Get the IDispatch interface
IDispatch* pDispatch;
hr = pUnknown->QueryInterface(IID_IDispatch, (void**)&pDispatch);
// Call the Invoke method
DISPID dispid;
BSTR bstrFunction = SysAllocString(L"My_function");
hr = pDispatch->GetIDsOfNames(IID_NULL, &bstrFunction, 1, LOCALE_USER_DEFAULT, &dispid);
// ALL OF THE ABOVE WORKS.
// Prepare the arguments for the method call
// first convert a std::vector to SAFEARRAY
std::vector<double> _PdblScale = { 0, 0.25, 0.5, 0.75, 1.0, 0, 0, 0.5, 1, 1 };
SAFEARRAY* psa = SafeArrayCreateVector(VT_R8, 0, _PdblScale.size());
int* pData;
HRESULT hr_ = SafeArrayAccessData(psa, (void**)&pData);
if (SUCCEEDED(hr_))
{
for (unsigned int i = 0; i < _PdblScale.size(); i++)
{
pData[i] = _PdblScale[i];
}
SafeArrayUnaccessData(psa);
}
DISPPARAMS dispparams;
dispparams.cArgs = 5;
dispparams.rgvarg = new VARIANT[5];
dispparams.cNamedArgs = 5;
VARIANT PdblPrice;
PdblPrice.vt = VT_R8;
PdblPrice.dblVal = 28.0;
dispparams.rgvarg[0] = PdblPrice;
VARIANT PdateStartDate;
PdateStartDate.vt = VT_DATE;
PdateStartDate.date = 41052;
dispparams.rgvarg[1] = PdateStartDate;
VARIANT PintFlag;
PintFlag.vt = VT_I2;
PintFlag.iVal = 1;
dispparams.rgvarg[2] = PintFlag;
VARIANT PbolXP;
PbolXP.vt = VT_BOOL;
PbolXP.boolVal = false;
dispparams.rgvarg[3] = PbolXP;
VARIANT PdblScale;
PdblScale.vt = VT_SAFEARRAY;
PdblScale.pvRecord = psa;
dispparams.rgvarg[4] = PdblScale;
VARIANT varResult;
VariantInit(&varResult);
EXCEPINFO excepinfo;
memset(&excepinfo, 0, sizeof(excepinfo));
UINT nArgErr = (UINT)-1;
// Invoke the method ## THIS IS WHERE hr returns 0x8002000e : Invalid number of parameters
hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, &varResult, &excepinfo, &nArgErr);
if (FAILED(hr))
{
printf("Failed to invoke method.");
pDispatch->Release();
pUnknown->Release();
CoUninitialize();
return 1;
}
// Print the result
printf("Result: %d\n", varResult.intVal);
// Clean up
VariantClear(&varResult);
pDispatch->Release();
pUnknown->Release();
CoUninitialize();
return 0;
}
I see from IDispatch Invoke() returns Type mismatch that the arguments should be in reverse order. I have tried that, ie. used [4], [3], [2], etc instead of [0], [1], etc above, but this still gives the error.
Any suggestions as to where I might be going wrong?
By the way, the COM is from a 32bit DLL, and I am compiling my code to x86.
There are many problems with your code:
lack of error handling.
when creating the COM object, you don't need to get its IUnknown just to immediately query it for IDispatch. You can get its IDispatch directly.
memory leaks on bstrFunction and dispparams.rgvarg.
you are creating a SAFEARRAY of VT_R8 (double) elements, but you are using an int* pointer to populate its values. You need to use a double* pointer instead.
you are not populating the DISPPARAMS or the VARIANTs correctly. The parameters have to be stored in the DISPPARAMS in revere order. And the VARIANTs need to use the VT_BYREF flag, which means they need to point at external variables that hold the actual values, rather than storing the values inside the VARIANTs themselves.
calling IDispatch::Invoke() with the wrong flag. You need to use DISPATCH_PROPERTYGET instead of DISPATCH_METHOD since the method is marked as propget in the IDL.
not using VARIANT_BOOL correctly for the bolXP parameter.
after invoking the method, you are printing out the wrong field of varResult. The method is declared as returning a double in the IDL, not an int.
With all of that said, try something more like this:
#include <windows.h>
#include <objbase.h>
#include <comutil.h>
#include <comdef.h>
#include <atlcomcli.h>
#include <vector>
// tweaked from https://devblogs.microsoft.com/oldnewthing/20040520-00/?p=39243
class CCoInitializeEx {
HRESULT m_hr;
public:
CCoInitializeEx() : m_hr(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)) { }
~CCoInitializeEx() { if (SUCCEEDED(m_hr)) CoUninitialize(); }
operator HRESULT() const { return m_hr; }
};
int main()
{
HRESULT hr;
// Initialize COM
CCoInitializeEx init;
hr = init;
if (FAILED(hr)) {
printf("Failed to init COM.");
return -1;
}
// Create an instance of COM object and get its IDispatch interface
CLSID clsid;
hr = CLSIDFromProgID(OLESTR("My_Library.clsMy_Library"), &clsid);
if (FAILED(hr)) {
printf("Failed to get CLSID.");
return -1;
}
IDispatchPtr pDispatch;
hr = pDispatch.CreateInstance(clsid);
if (FAILED(hr)) {
printf("Failed to create COM object.");
return -1;
}
// Call the Invoke method
DISPID dispid;
_bstr_t bstrFunction = OLESTR("My_function");
LPOLESTR pbstrFunction = bstrFunction;
hr = pDispatch->GetIDsOfNames(IID_NULL, &pbstrFunction, 1, LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr)) {
printf("Failed to get DispID.");
return -1;
}
// ...
// first convert a std::vector to SAFEARRAY
// TODO: wrap the SAFEARRAY inside a RAII class...
std::vector<double> vecDblScale = { 0, 0.25, 0.5, 0.75, 1.0, 0, 0, 0.5, 1, 1 };
SAFEARRAY* psa = SafeArrayCreateVector(VT_R8, 0, vecDblScale.size());
if (!psa) {
printf("Failed to allocate SAFEARRAY.");
return -1;
}
double* pData;
hr = SafeArrayAccessData(psa, reinterpret_cast<void**>(&pData));
if (FAILED(hr))
printf("Failed to access SAFEARRAY data.");
SafeArrayDestroy(psa);
return -1;
}
for (size_t i = 0; i < vecDblScale.size(); ++i)
{
pData[i] = vecDblScale[i];
}
// alternatively:
//
// #include <algorithm>
// std::copy(vecDblScale.begin(), vecDblScale.end(), pData);
SafeArrayUnaccessData(psa);
// Prepare the arguments for the method call
std::vector<VARIANT> vecRgvarg(5);
DOUBLE dblPrice = 28.0;
vecRgvarg[4].vt = VT_R8 | VT_BYREF;
vecRgvarg[4].pdblVal = &dblPrice;
DATE dateStartDate = 41052;
vecRgvarg[3].vt = VT_DATE | VT_BYREF;
vecRgvarg[3].pdate = &dateStartDate;
short intFlag = 1;
vecRgvarg[2].vt = VT_I2 | VT_BYREF;
vecRgvarg[2].piVal = &intFlag;
VARIANT_BOOL bolXP = VARIANT_FALSE;
vecRgvarg[1].vt = VT_BOOL | VT_BYREF;
vecRgvarg[1].pboolVal = &bolXP;
vecRgvarg[0].vt = VT_R8 | VT_ARRAY | VT_BYREF;
vecRgvarg[0].pparray = &psa;
DISPPARAMS dispparams = {};
dispparams.cArgs = vecRgvarg.size();
dispparams.rgvarg = vecRgvarg.data();
// Invoke the method
_variant_t varResult;
EXCEPINFO excepinfo = {};
UINT nArgErr = (UINT)-1;
hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispparams, &varResult, &excepinfo, &nArgErr);
if (FAILED(hr)) {
printf("Failed to invoke method.");
SafeArrayDestroy(psa);
return -1;
}
// Print the result
printf("Result: %f\n", varResult.dblVal);
// Clean up
SafeArrayDestroy(psa);
return 0;
}
I am looking for a reliable method to map a DirectShow capture device GUID to its corresponding waveID value.
I found the following project by Chris_P:
The solution works great, and it relies on an a rather obscure IKsPropertySet interface to retrieve the mapping.
Unfortunately, if I attempt the same technique from a C++/CLI library, the code fails with E_NOTIMPL (this behavior has been described on this question, - see the answer by Vladimir Hmelyoff)
So, I figured that I could write a simple console-based auxiliary app to retrieve the mappings and print them. My library could then launch this auxiliary app and parse the redirected output to obtain the mappings.
The console program runs fine, however, the GUIDs that are being passed to the enumeration callback are completely different to the ones passed by Chris_P's solution.
In fact they all share the same basic structure:
lpGuid = 0x02ad0808 {BDF35A00-B9AC-11D0-A619-00AA00A7C000}
The only variation occurs in the last digits of the GUID, where coincidentally, they match the mapped waveId value.
Another weird thing is that the capture device description is truncated to 31 characters, as if the enumeration was being performed using WaveIn APIs!
It would almost seem that some DirectSound facade is now wrapping the WaveIn API.
Any pointers on what could be happening?, Can I disable this behavior and enumerate the same GUIDS that the WIN32 app is enumerating?
Here is the code for the console application:
#include "stdafx.h"
#include <mmreg.h>
#include <initguid.h>
#include <Dsound.h>
#include <dsconf.h>
static BOOL CALLBACK DSEnumCallback(
LPGUID lpGuid,
LPCTSTR lpcstrDescription,
LPCTSTR lpcstrModule,
LPVOID lpContext
);
static BOOL GetInfoFromDSoundGUID(GUID i_sGUID, DWORD &dwWaveID);
static HRESULT DirectSoundPrivateCreate(OUT LPKSPROPERTYSET * ppKsPropertySet);
typedef WINUSERAPI HRESULT(WINAPI *LPFNDLLGETCLASSOBJECT) (const CLSID &, const IID &, void **);
BOOL GetInfoFromDSoundGUID(GUID i_sGUID, DWORD &dwWaveID) {
LPKSPROPERTYSET pKsPropertySet = NULL;
HRESULT hr;
BOOL retval = FALSE;
PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA psDirectSoundDeviceDescription = NULL;
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA sDirectSoundDeviceDescription;
memset(&sDirectSoundDeviceDescription, 0, sizeof(sDirectSoundDeviceDescription));
hr = DirectSoundPrivateCreate(&pKsPropertySet);
if( SUCCEEDED(hr) ) {
ULONG ulBytesReturned = 0;
sDirectSoundDeviceDescription.DeviceId = i_sGUID;
// On the first call the final size is unknown so pass the size of the struct in order to receive
// "Type" and "DataFlow" values, ulBytesReturned will be populated with bytes required for struct+strings.
hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
NULL,
0,
&sDirectSoundDeviceDescription,
sizeof(sDirectSoundDeviceDescription),
&ulBytesReturned
);
if( ulBytesReturned ) {
// On the first call it notifies us of the required amount of memory in order to receive the strings.
// Allocate the required memory, the strings will be pointed to the memory space directly after the struct.
psDirectSoundDeviceDescription = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA)new BYTE[ulBytesReturned];
*psDirectSoundDeviceDescription = sDirectSoundDeviceDescription;
hr = pKsPropertySet->Get(DSPROPSETID_DirectSoundDevice,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
NULL,
0,
psDirectSoundDeviceDescription,
ulBytesReturned,
&ulBytesReturned
);
dwWaveID = psDirectSoundDeviceDescription->WaveDeviceId;
delete[] psDirectSoundDeviceDescription;
retval = TRUE;
}
pKsPropertySet->Release();
}
return retval;
}
HRESULT DirectSoundPrivateCreate(OUT LPKSPROPERTYSET * ppKsPropertySet) {
HMODULE hLibDsound = NULL;
LPFNDLLGETCLASSOBJECT pfnDllGetClassObject = NULL;
LPCLASSFACTORY pClassFactory = NULL;
LPKSPROPERTYSET pKsPropertySet = NULL;
HRESULT hr = DS_OK;
// Load dsound.dll
hLibDsound = LoadLibrary(TEXT("dsound.dll"));
if( !hLibDsound ) {
hr = DSERR_GENERIC;
}
// Find DllGetClassObject
if( SUCCEEDED(hr) ) {
pfnDllGetClassObject =
(LPFNDLLGETCLASSOBJECT)GetProcAddress(hLibDsound, "DllGetClassObject");
if( !pfnDllGetClassObject ) {
hr = DSERR_GENERIC;
}
}
// Create a class factory object
if( SUCCEEDED(hr) ) {
hr = pfnDllGetClassObject(CLSID_DirectSoundPrivate, IID_IClassFactory, (LPVOID *)&pClassFactory);
}
// Create the DirectSoundPrivate object and query for an IKsPropertySet
// interface
if( SUCCEEDED(hr) ) {
hr = pClassFactory->CreateInstance(NULL, IID_IKsPropertySet, (LPVOID *)&pKsPropertySet);
}
// Release the class factory
if( pClassFactory ) {
pClassFactory->Release();
}
// Handle final success or failure
if( SUCCEEDED(hr) ) {
*ppKsPropertySet = pKsPropertySet;
} else if( pKsPropertySet ) {
pKsPropertySet->Release();
}
FreeLibrary(hLibDsound);
return hr;
}
BOOL CALLBACK DSEnumCallback(
LPGUID lpGuid,
LPCTSTR lpcstrDescription,
LPCTSTR lpcstrModule,
LPVOID lpContext
) {
LPWSTR psz = NULL;
StringFromCLSID(*lpGuid, &psz);
DWORD WaveID = 0xFFFFFFFF;
if( lpGuid ) {
GUID i_guid = *lpGuid;
GetInfoFromDSoundGUID(i_guid, WaveID);
}
if( WaveID != 0xFFFFFFFF )
wprintf(_T("%d %s\r\n"), WaveID, psz);
if( psz ) {
CoTaskMemFree(psz);
}
return TRUE;
}
int main()
{
DirectSoundCaptureEnumerate(DSEnumCallback, NULL);
Sleep(10000);
return 0;
}
It turns out I was not initializing COM.
I added the following snippet at the beginning of my main() procedure and the program retrieved the expected GUIDs:
HRESULT hr = NULL;
hr = CoInitialize(NULL);
if( FAILED(hr) ) {
printf("Failed to initialize COM");
return -1;
}
So I guess that if COM is not initialized, the DirectSound engine falls back to the WaveIn API (creating a DirectShow facade around it).
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
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.
I am trying to call a mthod that takes 2 strings here you are the code
VARIANT vArgs[2];
VariantInit(&vArgs[0]);
VariantInit(&vArgs[1]);
//VariantInit(&vArgs[2]);
//vArgs[2].pdispVal = pDisptEntries;
vArgs[1].bstrVal = bstrSrc;
vArgs[0].bstrVal = bstrtrgt;
vArgs[0].vt = VT_BSTR;
vArgs[1].vt = VT_BSTR;
//vArgs[2].vt = VT_DISPATCH;
dpEntry.rgvarg = vArgs;
dpEntry.cArgs = 2;
dpEntry.cNamedArgs = 0;
//dpEntry.rgdispidNamedArgs = new DISPID[2];
//dpEntry.rgdispidNamedArgs[0] = 0;
//dpEntry.rgdispidNamedArgs[1] = 1;
UINT index = -1;
EXCEPINFO ex;
hr = pDisptEntries->Invoke(dispid_Add, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
&dpEntry, NULL, &ex, &index);
The error code unequivocally tells you that the function does not in fact take two arguments of type string. Getting the dispid wrong is possible too, it will call the wrong function. Watch out for the return value, not sure what happens when you pass NULL but the function returns a value.