Convert uint16 to WMI Variant for CreateSnapshot Method - c++

I want to call CreateSnapshot Method which is a call to provider but I am stuck as I cannot set the input parameter for Snapshot Type which is expected as uint16. This is passed using a Variant. The code snippet is below.
VARIANT var;
VariantInit(&var);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"32768");
hr = pInParams->Put(L"SnapshotType", 0, &var, CIM_UINT16);
cout << "\nValue Set Is: "<<var.uintVal<<endl;
I am not able to pass the required value. Any points on what I am doing wrong ?
Note: Put method is working fine with HRESULT as 0 but CreateSnapshot is unsuccessful.
EDIT
Msvm_VirtualSystemSnapshotService Class -> CreateSnapshot has the following prototype
uint32 CreateSnapshot(
[in] CIM_ComputerSystem REF AffectedSystem,
[in] string SnapshotSettings,
[in] uint16 SnapshotType,
[in, out] CIM_VirtualSystemSettingData REF ResultingSnapshot,
[out] CIM_ConcreteJob REF Job
);

BSTR paramName3 = L"SnapshotType";
VARIANT var;
var.vt = VT_UI2;
var.iVal = (uint16_t)32768;
hresult = pInClass->Put(paramName3,
0,
&var,
CIM_UINT16);
if (FAILED(hresult))
{
string msg = "Failed to set property.";
throw std::exception(msg.c_str());
}
VariantClear(&var);
as question,convert unit16 to varint and it's work

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

Return multiple values from a function in COM Interfaces

I did a research and implemented a wrapper function for GetWindowRect API, and it works fine. But it can currently only return window coordinates via a SAFEARRAY. But I am thinking about how can I also return its actual return value.
I declared it like this:
[id(10)] HRESULT WinAPI_GetWindowRect([in] VARIANT hWnd, [out, retval] SAFEARRAY(VARIANT) *lpRect);
STDMETHOD(WinAPI_GetWindowRect)(VARIANT hWnd, SAFEARRAY **lpRect);
And implementation:
STDMETHODIMP CWinAPI::WinAPI_GetWindowRect(VARIANT hWnd, SAFEARRAY **lpRect {
CComSafeArray<VARIANT> CCSA_RECT;
RECT Rect;
HRESULT HResult;
if (!lpRect) { return E_INVALIDARG; }
*lpRect = nullptr;
int Result = (int)GetWindowRect(VariantToHWND(hWnd), &Rect);
// ^ I ALSO WANT TO RETURN THIS RESULT TOO
if (Result != 0)
{
HResult = CCSA_RECT.Create(4, 0);
assert(HResult == S_OK);
CCSA_RECT[0] = Rect.left;
CCSA_RECT[1] = Rect.top;
...
}
else
{ ... }
}
But, as I already know, there cannot be multiple [out, retval] values, so any suggestions on how to return this value (Result) are highly appreciated.
UPDATE
When I try to return it like this:
[id(10)] HRESULT WinAPI_GetWindowRect([in] VARIANT hWnd, [out] SAFEARRAY(VARIANT) *lpRect, [out, retval] VARIANT *Result);
STDMETHOD(WinAPI_GetWindowRect)(VARIANT hWnd, SAFEARRAY **lpRect, VARIANT *Result);
Assigning it like:
Result->intVal = (int)GetWindowRect(VariantToHWND(hWnd), &Rect);
I am getting a Type mismatch error in below VBScript line when try to use it:
Dim lpRect, Result: Result = WINAPI.WinAPI_GetWindowRect(AutoItX3.WinGetHandle("[CLASS:ConsoleWindowClass]"), lpRect)
I want this SAFEARRAY to be [out] parameter and Result to be return value.
I solved the problem to a some extent by using a VARIANT as [out] parameter like this:
[id(10)] HRESULT WinAPI_GetWindowRect([in] VARIANT hWnd, [out] VARIANT *Result, [out, retval] SAFEARRAY(VARIANT) *lpRect);
STDMETHOD(WinAPI_GetWindowRect)(VARIANT hWnd, VARIANT *Result, SAFEARRAY **lpRect);
New implementation:
STDMETHODIMP CWinAPI::WinAPI_GetWindowRect(VARIANT hWnd, VARIANT *Result, SAFEARRAY **lpRect) {
CComSafeArray<VARIANT> CCSA_RECT;
RECT Rect;
HRESULT HResult;
if (!lpRect) { return E_INVALIDARG; }
*lpRect = nullptr;
VariantInit(Result);
Result->vt = VT_I2;
Result->intVal = (int)GetWindowRect(VariantToHWND(hWnd), &Rect);
if (Result->intVal != 0)
{...}
else
{...}
}
This has been tested using the following VBScript:
Dim AutoItX3: Set AutoItX3 = WScript.CreateObject("AutoItX3.Control")
Dim WINAPI: Set WINAPI = WScript.CreateObject("WinAPIWrapperLib.WINAPI")
Dim lpRect, Result: lpRect = WINAPI.WinAPI_GetWindowRect(AutoItX3.WinGetHandle("[CLASS:ConsoleWindowClass]"), Result)
WScript.Echo "GetWindowRect returned: " + CStr(Result)
If CInt(Result) <> 0 Then
For iNum = 0 To UBound(lpRect)
WScript.Echo CStr(lpRect(iNum))
Next
End If
WScript.Echo(CStr(WINAPI.WinAPI_GetLastErrorMessage))
But, I still cannot use SAFEARRAY as an [out] only parameter, using it as [out] only parameter and using Result as [out, retval] member in following way:
[id(10)] HRESULT WinAPI_GetWindowRect([in] VARIANT hWnd, [out] SAFEARRAY(VARIANT) *lpRect, [out, retval] VARIANT *Result);
still causes the Type mismatch error.

VirtualBox IGuestSession::ProcessCreate returns 0x8000FFFF (E_UNEXPECTED)

So I'm trying to execute a process in the guest session from the host, but I keep getting a 0x8000FFFF (E_UNEXPECTED) HRESULT from it. Since I'm getting a COM error rather than VBOX_E_IPRT_ERROR it makes me think my SAFEARRAYs are the issue and not the actual parameters if that makes sense. I'm not too familiar with COM, so it might just be a case of me using SAFEARRAY wrong. Either way, here's the code I'm trying right now:
SAFEARRAY *args_and_env, *creation_flags;
SAFEARRAYBOUND arrayDim[1];
arrayDim[0].lLbound= 0;
arrayDim[0].cElements= 1;
args_and_env = SafeArrayCreate(VT_LPWSTR,1,arrayDim);
SafeArrayPutElement(args_and_env, 0, L"");
creation_flags = SafeArrayCreate(VT_INT, 1, arrayDim);
int flag = ProcessCreateFlag_None;
SafeArrayPutElement(creation_flags, 0, &flag);
IGuestProcess *proca;
rc = guestSession->ProcessCreate(proc, args_and_env, args_and_env, creation_flags, 0, &proca);
Documentation for IGuestSession::ProcessCreate is as following:
IGuestProcess IGuestSession::processCreate(
[in] wstring executable,
[in] wstring arguments[],
[in] wstring environmentChanges[],
[in] ProcessCreateFlag flags[],
[in] unsigned long timeoutMS)
And the function declaration is as following:
HRESULT STDMETHODCALLTYPE ProcessCreate(
/* [in] */ BSTR aExecutable,
/* [in] */ SAFEARRAY * aArguments,
/* [in] */ SAFEARRAY * aEnvironmentChanges,
/* [in] */ SAFEARRAY * aFlags,
/* [in] */ ULONG aTimeoutMS,
/* [retval][out] */ IGuestProcess **aGuestProcess)
I've also tried passing NULL to both arguments and environmentChanges as I'm not looking to use any of them, but with the same result.
When i tested my task i realized that this problem can be if you use session OS without password. You have to set password and create session with password:
BSTR login = ...;
BSTR passsword = ...;
BSTR empty = SysAllocString(L"");
HRESULT rc = guest->CreateSession(login, password, empty, sessionName, &guestSession);
And then create a guest process

Problems understanding and using double pointers

I am not sure how to use double pointers.
The function i need to use looks as following:
HRESULT GetBuffer(
[out] IMediaSample **ppBuffer,
[in] REFERENCE_TIME *pStartTime,
[in] REFERENCE_TIME *pEndTime,
[in] DWORD dwFlags
);
Documentation says:
ppBuffer [out]
Receives a pointer to the buffer's IMediaSample interface. The caller must release the interface.
This is what i tried using it:
HRESULT MCMyOutputPin::Deliver(IMediaSample* sample)
{
HRESULT hr = NO_ERROR;
myLogger->LogDebug("In Outputpin Deliver", L"D:\\TEMP\\yc.log");
if (sample->GetActualDataLength() > 0)
{
IMediaSample **outsample;
m_pAllocator->GetBuffer(outsample, NULL, NULL, NULL); //Access violation here
BYTE** sampleBuffer;
BYTE** newBuffer;
sample->GetPointer(sampleBuffer);
(*outsample)->GetPointer(newBuffer);
memcpy((void *)newBuffer, (void *)sampleBuffer, sizeof(**sampleBuffer));
m_pInputPin->Receive(*outsample);
sample->AddRef();
}
return hr;
//Forward to filter
}
Which gives me an:
Access violation reading location 0xFFFFFFFFFFFFFFFF.
Then i tried using the address operator:
hr = m_pAllocator->GetBuffer(&outsample, NULL, NULL, NULL); //outsample is set to NULL
BYTE* sampleBuffer = NULL;
BYTE* newBuffer = NULL;
sample->GetPointer(&sampleBuffer);
outsample->GetPointer(&newBuffer);
memcpy((void *)newBuffer, (void *)sampleBuffer, sizeof(*sampleBuffer));
m_pInputPin->Receive(outsample);
This sets outsample to NULL.
So what is the correct syntax to handle double pointers?
My first, high-level comment, is that you are not checking the return values of the functions that you call. It's a mistake to neglect error checking. Your first step is to add the necessary error checking.
HRESULT GetBuffer(
[out] IMediaSample **ppBuffer,
[in] REFERENCE_TIME *pStartTime,
[in] REFERENCE_TIME *pEndTime,
[in] DWORD dwFlags
);
The first parameter is used to return a IMediaSample* to the caller. You need to declare a variable of type IMediaSample*, and pass its address:
IMediaSample* sample;
....
hr = m_pAllocator->GetBuffer(&outsample, ...);
// check hr
....
So, outsample is of type IMediaSample*. When you take its address, with &outsample, you now have something of type IMediaSample**, which is what you need.
Remember that when working with interfaces, you always work with a pointer to the interface.
You've made the same mistake with the BYTE** parameters. Again, declare variables of type BYTE*, and pass the address of these variables to the functions that you call.
BYTE* sampleBuffer;
BYTE* newBuffer;
....
hr = sample->GetPointer(&sampleBuffer);
// check hr
hr = outsample->GetPointer(newBuffer);
// check hr
Using sizeof(**sampleBuffer) in your call to memcpy is wrong. In your code, where sampleBuffer is wrongly declared as BYTE**, sizeof(**sampleBuffer) is just sizeof(BYTE) which is always 1.
In fact you can conclude that any use of sizeof is incorrect here because sizeof is evaluated at compile time. You need to find the actual size of the dynamic buffer at runtime using whatever functionality these interfaces provide.
The call to sample->AddRef() looks a little suspect. I don't see any evidence that anything has taken a new reference to the interface.
IMediaSample **outsample;
m_pAllocator->GetBuffer(outsample, NULL, NULL, NULL);
You're passing the function the value of outsample, which is a garbage value since it doesn't point to anything. You want:
IMediaSample *outsample;
m_pAllocator->GetBuffer(&outsample, NULL, NULL, NULL);
This gives the function the address of outsample so that it can stuff the pointer it wants to return in it.
I try to simulate the function as test, which using int** as output . the problem here is the function is suppose *output is is valid, so in the first way ,you have to make sure that, you might want to do something as this
sample = new IMediaSample[1]
this is my sample code, hope it helps
#include <iostream>
using namespace std;
void test(int** output ,int* in)
{
*output = new int[1];
output[0][0] = in[0];
}
int main()
{
int a[] ={ 2 };
int* out1;
test(&out1 ,a);
cout << out1[0] << endl;
int** out2;
out2 = new int*[1];
test(out2 ,a);
cout << out2[0][0] << endl;
return 0;
}