1

I am attempting to use SoftwareLicensingService::InstallProductKey to install a product key on Windows 7 through WMI/C++ in a Service. However every time I attempt to call the method via IWbemServices::ExecMethod I get 0x8004102f which is WBEM_E_INVALID_METHOD_PARAMETERS. I thought this was something to do with the product key I am passing, but I have since then tried similar code for Win32_WindowsProductActivation::ActivateOnline [which is a no parameter method available on XP] with the same error. Does anyone know what is suspect in my code fragment below (I have skipped some cleanup code to be brief) ? The same sequence of code successfully invokes other WMI methods however.

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = S_OK;
    IWbemLocator *pLoc = NULL;
    IWbemServices *pServices = NULL;
    IWbemClassObject *pInputParamsClass = NULL;
    IWbemClassObject *pInputParams = NULL;
    IWbemClassObject *pOutputParams = NULL;
    IWbemClassObject *pLicensingClsObj = NULL;
    VARIANT vtProductKey = {0};
    VARIANT vtPath = {0};


    hr =  CoInitializeEx(0, COINIT_MULTITHREADED);
    if(FAILED(hr))
        goto cleanup;

hr =  CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, 
            RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
_ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
    goto cleanup;

hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, 
            IID_IWbemLocator, (LPVOID *)&pLoc);
_ASSERT(SUCCEEDED(hr) && (NULL != pLoc));
if(FAILED(hr) || (NULL == pLoc))
    goto cleanup;

hr = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 
            0, 0, &pServices);
_ASSERT(SUCCEEDED(hr) && (NULL != pServices));
if(FAILED(hr) || (NULL == pServices))
    goto cleanup;

hr = CoSetProxyBlanket(pServices, RPC_C_AUTHN_WINNT, 
   RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
   NULL, EOAC_NONE);
_ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
    goto cleanup;

hr = pServices->GetObject(_bstr_t(L"SoftwareLicensingService"), 
                        0, NULL, &pLicensingClsObj, NULL);
_ASSERT(SUCCEEDED(hr) && (NULL != pLicensingClsObj));
if(FAILED(hr) || (NULL == pLicensingClsObj))
    goto cleanup;

hr = pLicensingClsObj->Get(L"__Path", 0, &vtPath, 0, 0);
_ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
    goto cleanup;

hr = pLicensingClsObj->GetMethod(L"InstallProductKey", 0, 
            &pInputParamsClass, NULL);
_ASSERT(SUCCEEDED(hr) && (NULL != pInputParamsClass));
if(FAILED(hr) || (NULL == pInputParamsClass))
    goto cleanup;

hr = pInputParamsClass->SpawnInstance(0, &pInputParams);
_ASSERT(SUCCEEDED(hr) && (NULL != pInputParams));
if(FAILED(hr) || (NULL == pInputParams))
    goto cleanup;

vtProductKey.vt = VT_BSTR;
vtProductKey.bstrVal = SysAllocString(L"XXXXXXXXXXXXXXXXXXXXXXXXX");
hr = pInputParams->Put(L"ProductKey", 0, &vtProductKey, 0);
_ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
    goto cleanup;

hr = pServices->ExecMethod(vtPath.bstrVal, 
            _bstr_t(L"InstallProductKey"), 
            0, NULL, pInputParams, 
            &pOutputParams, NULL);
_ASSERT(SUCCEEDED(hr) && (NULL != pOutputParams));
if(FAILED(hr) || (NULL == pOutputParams))
    goto cleanup;

hr = S_OK;//all success

cleanup:
if(NULL != pLoc)
{
    pLoc->Release();
    pLoc = NULL;
}
if(NULL != pServices)
{
    pServices->Release();
    pServices = NULL;
}
(VOID)CoUninitialize();
return hr;

}

banal
  • 98
  • 1
  • 8
  • `"ROOT\CIMV2"` needs to be `"ROOT\\CIMV2"`. And where is your error checking on any of the COM calls? And how are you populating `vtProductKey`? Please provide a [MCVE](http://stackoverflow.com/help/mcve). – Remy Lebeau May 13 '15 at 18:40
  • @Remy - That is a typo. Assume that this is working code with error checking and successfully invokes other wmi methods. I will fix the string in question. – banal May 13 '15 at 18:42
  • please don't make people assume. Please provide the "actual" code, not "simplified" code. – Remy Lebeau May 13 '15 at 18:44
  • @Remy Apologies, posting actual code will violate company policy. Thanks. – banal May 13 '15 at 18:46
  • Hence the need for a MCVE that reproduces the same problem. Nothing in this code example is proprietary, though, other than the value of `vtProductKey`. – Remy Lebeau May 13 '15 at 19:21
  • @Remy - legal considerations also cover code not just inputs to code that could be sensitive. In any case I have put in a sanitized mcve into my question. – banal May 13 '15 at 21:01

2 Answers2

2

I have since figured what the issue was. The method call was being made on the class not the instance.

banal
  • 98
  • 1
  • 8
  • Have the same problem I guess. I didn't get what this means "The method call was being made on the class not the instance". Can you tell what to change in the original code you posted to make it work? – Alex Sep 13 '18 at 06:02
1

This code will work properly:

 IEnumWbemClassObject * enum_obj;
    hres = pSvc>CreateInstanceEnum(_bstr_t(L"SoftwareLicensingService"),WBEM_FLAG_RETURN_IMMEDIATELY , NULL ,&enum_obj);


   IWbemClassObject * spInstance;
   ULONG uNumOfInstances = 0;
   hres = enum_obj->Next(10000, 1,&spInstance,&uNumOfInstances);

   VARIANT path;
   hres = spInstance->Get(_bstr_t("__Path"), 0,&path, 0, 0);

   IWbemClassObject *results = NULL;
   hres = pSvc->ExecMethod( path.bstrVal, _bstr_t( L"InstallProductKey" ), 0,
   NULL,NULL,&results, NULL );

This code is not only for this class and method.Generally for any class you can get the objectPath(1st parameter of ExecMethod()) and use it.This code mentioned is for Calling a method without parameters.

The code for method calling with parameters is available here.In some cases, calling ExecMethod with input parameters for a method returns WBEM_E_INVALID_METHOD_PARAMETERS error. In that case you can get the object path first and then call GetObejct and GetMethod functions.

anjlairaj
  • 41
  • 3