Deleting WMI instance with C++ - c++

I have found some samples with C# and VBS for WMI instance deletion, however I need this implemented with C++.
My sample code:
CoInitialize(NULL);
HRESULT hRes;
//Obtain the initial locator to WMI
CComPtr<IWbemLocator> pLoc = NULL;
hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*) &pLoc);
if(FAILED(hRes))
return 1;
//Connect to WMI through the IWbemLocator::ConnectServer method
CComPtr<IWbemServices> pSvc = NULL;
//Connect to the root namespace with the current user and obtain pointer pSvc to make IWbemServices calls.
hRes = pLoc->ConnectServer(L"ROOT\\SUBSCRIPTION", NULL, NULL, 0, NULL, 0, 0, &pSvc);
if(FAILED(hRes))
return 1;
hRes = pSvc->DeleteInstance(
L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'",
WBEM_FLAG_RETURN_IMMEDIATELY, NULL, NULL);
return 0;
According to that I've found here and here, my code should work. I surely have CommandLineEventConsumer named {709782F3-E860-488E-BD8A-89FBC8C1495C}
And my code fails on IWbemServices::DeleteInstance, error code 0x80041008 (One of the parameters to the call is not correct).
I would appreciate if someone spot mistake in my code. Or maybe some privileges are required to do that?

The first parameter to IWbemServices::DeleteInstance is a BSTR. A BSTR is different from a UTF-16 encoded C-style string in that it stores an explicit length argument. Even though BSTR is of type wchar_t*, you cannot pass a plain string literal in place of a BSTR.
To create a BSTR from a string literal you need to call SysAllocString:
BSTR objPath = ::SysAllocString(L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'");
hRes = pSvc->DeleteInstance(
objPath,
WBEM_FLAG_RETURN_IMMEDIATELY, NULL, NULL);
::SysFreeString(objPath);
Alternatively, since you are already using ATL for CComPtr you could use CComBSTR to make your life easier:
CComBSTR objPath(L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'");
hRes = pSvc->DeleteInstance(
objPath,
WBEM_FLAG_RETURN_IMMEDIATELY, NULL, NULL);
Note: IWbemLocator::ConnectServer also needs BSTRs as parameters. The sample provided on the documentation page does pass a plain C-style string, so maybe the IWbemLocator interface is more forgiving when presented invalid parameters.

I have found two solutions:
1.Remove WBEM_FLAG_RETURN_IMMEDIATELY flag.
_bstr_t objPath(L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'");
hRes = pSvc->DeleteInstance(objPath, 0, NULL, NULL);
2.Pass IWbemCallResult for result.
_bstr_t objPath(L"CommandLineEventConsumer.Name='{709782F3-E860-488E-BD8A-89FBC8C1495C}'");
CComPtr<IWbemCallResult> pRes = NULL;
hRes = pSvc->DeleteInstance(objPath, WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pRes);
Didn't investigate a lot, but it works both ways. Looks like specs aren't 100% correct.

Related

Access violation in official Microsoft WMI example

I'm trying to learn how the WMI works, but the default examples given have so far been atrocious.
Here's the example for calling the Create method of the Win32_Process class:
https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--calling-a-provider-method
I have added proper error handling to this, we store the HRESULT of each call in a variable hres and check if the calls failed. As such:
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
if (FAILED(hres))
{
wprintf("Failed to get class. Error code = 0x%lx\n", hres);
return hres;
}
The code executes correctly right up until here:
// Create the values for the in parameters
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = _bstr_t(L"notepad.exe");
// Store the value for the in parameters
hres = pClassInstance->Put(L"CommandLine", 0,
&varCommand, 0);
wprintf(L"The command is: %s\n", V_BSTR(&varCommand));
Where the pClassInstance->Put throws 'ol c5.
At this point, hres is S_OK for the call to SpawnInstance but these are the pointers we have for the class instances:
+pClass 0x000001c04e73fca0 IWbemClassObject *
- pClassInstance 0x000001c04e749d60 IWbemClassObject *
- IUnknown {...} IUnknown
- __vfptr 0x00007ff9f8d0ee98 {fastprox.dll!const CWbemInstance::`vftable'{for `_IWmiObject'}} {0x00007ff9f8c6f450 {fastprox.dll!CWbemObject::QueryInterface(void)}, ...} void * *
[0x00000000] 0x00007ff9f8c6f450 {fastprox.dll!CWbemObject::QueryInterface(void)} void *
[0x00000001] 0x00007ff9f8c907d0 {fastprox.dll!CWbemObject::AddRef(void)} void *
[0x00000002] 0x00007ff9f8c8ffd0 {fastprox.dll!CWbemObject::Release(void)} void *
+pInParamsDefinition 0x000001c04e743ca0 IWbemClassObject *
And varCommand:
+varCommand BSTR = 0x000001c04e74ffe8 tagVARIANT
The call stack:
oleaut32.dll!SysAllocString()
vfbasics.dll!AVrfpSysAllocString()
wbemcomn.dll!CVar::SetVariant()
fastprox.dll!CWbemInstance::Put()
> Ele.exe!WMIConnection::InvokeMethod()
So it appears that bstrVal isn't being properly set, I think? I tried initializing it first with VariantInit, and I also tried dynamically allocating it on the heap instead. Neither resolved the issue:
VARIANT varCommand;
VariantInit(&varCommand);
varCommand.vt = VT_BSTR;
varCommand.bstrVal = _bstr_t(L"notepad.exe");
I also tried manually zeroing out the Variant buffer, to no effect. This is what we have for bstrVal in the memory dump when the access violation occurs:
bstrVal 0x000001c04e74ffe8 <Error reading characters of string.> wchar_t *
<Unable to read memory> wchar_t
On this line:
varCommand.bstrVal = _bstr_t(L"notepad.exe");
The code creates a temporary _bstr_t object that goes out of scope, destroying the allocated BSTR memory, immediately after varCommand.bstrVal has been assigned to. Thus, varCommand.bstrVal is left dangling, pointing at invalid memory, when varCommand is passed to pClassInstance->Put(). That is undefined behavior.
Use this instead to keep the BSTR alive until you are actually done using it:
_bstr_t str(L"notepad.exe");
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = str;
// use varCommand as needed...
// DO NOT call VarClear() or SysFreeString()!
// You don't own the BSTR memory...
//VarClear(&varCommand);
Alternatively:
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = SysAllocString(L"notepad.exe");
// use varCommand as needed...
// You DO own the BSTR memory, so free it!
VarClear(&varCommand);
Otherwise, consider using _variant_t instead, let it manage the memory for you:
_variant_t varCommand(L"notepad.exe");
hres = pClassInstance->Put(L"CommandLine", 0, &varCommand, 0);
wprintf(L"The command is: %s\n", V_BSTR(&varCommand));
I figured it out. There are several forum posts on the internet asking about this example, with no solutions given, so I am very happy to provide this now.
The Microsoft example is using the incorrect classes.
In the Microsoft example, they attempt to call the Put method on a class instance of Win32_Process to set the parameters.
This is incorrect. We need to set the parameters via first getting the class method definition for Win32_Process::Create and then setting its parameters inside a new instance of Win32_Process::Create.
We additionally need to construct an instance of the Win32_ProcessStartup class object as it's a required input parameter for Win32_Process::Create.
In the example below I will populate one field of the Win32_ProcessStartup class instance, you can figure out the rest.
So this code from the Microsoft example:
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0,
&pInParamsDefinition, NULL);
IWbemClassObject* pClassInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
// Create the values for the in parameters
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = _bstr_t(L"notepad.exe");
// Store the value for the in parameters
hres = pClassInstance->Put(L"CommandLine", 0,
&varCommand, 0);
wprintf(L"The command is: %s\n", V_BSTR(&varCommand));
Becomes (sans error handling for readability):
// Get the class object
hres = pClass->GetMethod(lpwMethodName, 0,
&pInParamsDefinition, NULL);
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
// Get the Win32_ProcessStartup class object
IWbemClassObject* pStartupObject = NULL;
hres = pSvc->GetObject(_bstr_t(L"Win32_ProcessStartup"), 0, NULL, &pStartupObject, NULL);
// Create an instance of the Win32_ProcessStartup class object
IWbemClassObject* pStartupInstance = NULL;
hres = pStartupObject->SpawnInstance(0, &pStartupInstance);
// Create the value for the ShowWindow variable of the Win32_ProcessStartup class
VARIANT varParams;
VariantInit(&varParams);
varParams.vt = VT_I2;
varParams.intVal = SW_SHOW;
// And populate it
hres = pStartupInstance->Put(_bstr_t(L"ShowWindow"), 0, &varParams, 0);
// Get the method definition for Win32_Process::Create and store it in pInParamsDefinition
hres = pClass->GetMethod(_bstr_t(lpwMethodName), 0, &pInParamsDefinition, NULL);
// Spawn an instance of the Create method and store it in pParamsInstance
IWbemClassObject* pParamsInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pParamsInstance);
// Now we can set the parameters without error
hres = pParamsInstance->Put(_bstr_t(L"CurrentDirectory"), 0, pvCurrentDirectory, 0);
Please note that all of these hres returns should be checked for failure.
The definition for Win32_ProcessStartup is provided here:
https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processstartup
And the definition for the Create method of Win32_Process:
https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/create-method-in-class-win32-process

Win32_SystemDriver to disable device drivers

Trying to find an answer to my question: https://stackoverflow.com/questions/29181012/c-control-usb-drives-connected-to-my-system, I figured it out using the SetupDiXxx Classes. But the problem was that,once it is disabled/enabled, it was able to enable/disable the device from device manager. So any user can easily overcome the ban.
On further study, I saw that Win32_SystemDriver class of WMI has a StopService method that can be used to disable the driver for the device. But I am not sure on how to write the code for the same. Can anyone help me in coding this in C++. I am in MSVS 2010.
You can access WMI classes in C++ with this:
https://msdn.microsoft.com/en-us/library/aa392109(v=vs.85).aspx
But that seems very hacky and not very easy. If you do this anyway, here is the shortest example I can find: https://msdn.microsoft.com/en-us/library/aa390421(v=vs.85).aspx . I've updated it to match what you're doing:
#define _WIN32_DCOM
#include <windows.h>
#include <Wbemidl.h>
#include <comdef.h>
# pragma comment(lib, "wbemuuid.lib")
void main()
{
BSTR MethodName = SysAllocString(L"StopService");
BSTR ClassName = SysAllocString(L"WINMGMTS:\\\\.\\ROOT\\CIMV2\\ms_409:Win32_SystemDriver");
IWbemServices *pSvc = NULL;
HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
return;
}
hres = CoInitializeSecurity(
NULL,
-1, // COM negotiates service
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
CoUninitialize();
return;
}
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *)&pLoc);
if (FAILED(hres))
{
CoUninitialize();
return;
}
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
if (FAILED(hres))
{
CoUninitialize();
return;
}
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0,
&pInParamsDefinition, NULL);
// Execute Method
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(ClassName, MethodName, 0, NULL, NULL, &pOutParams, NULL);
CoUninitialize();
}
You would replace the classname to point to your driver. If you don't, it will fail with WBEM_E_INVALID_OBJECT_PATH. To find this, You need to enumerate your wmi objects so you can see/pick. This is definitely easiest in powershell, just open powershell and run Get-WmiObject -class Win32_SystemDriver. Although you should probably do all of this from powershell, come to think of it.
It sounds like you might instead want to consider learning how to leverage windows security policies for restricting which devices can be used:
https://msdn.microsoft.com/en-us/library/bb530324.aspx . You would start by launching gpedit and follow the directions until you've blocked device installation.

Create a shortcut to my application in startup

I want Create a shortcut to my application in startup . I used visual c++ 2010 and windows 7.
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc){
HRESULT hres;
IShellLink* psl;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
}
But, when I was performing not creating. in line :
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
get error. and not performing Remains my program.
The returned HRESULT does not just indicate success and failure. In the case of failure, the HRESULT tells you why the call failed. When you encounter a failure, you need to decode the HRESULT to find out why the call failed.
In this case the call is so simple that there is just one obvious failure mode. You did not initialize COM. With probability very close to 1, the value returned by the call to CoCreateInstance is CO_E_FIRST, with value 0x800401f0, which indicates that COM has not been initialized.
You'll want to add a call to CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) at startup, and match it with a call to CoUninitialize() when you are done with COM.
For what it is worth, I think that your function would be better if all of its parameters were wide strings. A function like this should not be worrying itself with such conversions. If you need to make such conversions, then include some helper methods in your code to perform them. You can add a function to convert from std::string to std::wstring and that should be all you ever need.
You need to initialize COM before performing your tasks:
HRESULT CreateLink(LPCSTR lpszPathObj, LPCSTR lpszPathLink, LPCSTR lpszDesc){
HRESULT hres;
IShellLink* psl;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
}
int main()
{
CoInitialize(0); // Initialize COM
CreateLink("C:\\hello.lnk", "C:\\hello.obj", "hello");
CoUninitialize();
return 0;
}
Also: watch out for LPCSTR/LPCWSTR (wide) conversions. The hres parameter contains additional information in case you were wondering what's wrong with your code.

IPersistFile::Save method keeps failing to save the shortcut

I am trying to save a shortcut to my application in the startup folder. It all compiles, but it fails to actually save the game. The error seems to occur at hres = ppf->Save(wsz, TRUE);, where hres is set to -2147024891. If that means something specific, I haven't discovered what yet. My code is copied almost verbatim from MSDN, so I'm pretty confused why it isn't working. Perhaps I don't have permission to save a shortcut to the startup folder? Then again, I am also fairly new to all this, so it might be some basic error I am making. I am copying in all my #includes as well in case that is the problem.
Edit:
First, to avoid confusion, this is CLI based C++.
Checking hres for errors is just part of the MDSN code. This is really almost the exact same code from the website example. I have put in breakpoints, which is how I know that hres becomes -2147024891 right after the line hres = ppf->Save(wsz, TRUE); is run.
In case these are wrong, mediaMaestroLocation is set to "C:\Users\Keith\Documents\Visual Studio 2012\Projects\MediaMaestro\Debug\MediaMaestro.exe" and startupDestination is "C:\Users\Keith\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup". While the exe location looks great, I wonder if it matters that there isn't a \ after the destination folder path. I would have checked it already, but I need to spend a couple minutes figure out how to do it first.
#include <windows.h>
#include <string>
#include <stdio.h>
#include <shobjidl.h>
#include <shlobj.h>
#include "objbase.h"
#include <objidl.h>
#include <shlguid.h>
#include <winnls.h>
#using <System.dll>
#using <System.Windows.Forms.dll>
using namespace System;
using namespace System::Windows::Forms;
char startupDestination[MAX_PATH];
char mediaMaestroLocation[MAX_PATH];
DWORD nChars = 0;
BOOL yChars = 0;
HRESULT CreateLink()
{
CoInitializeEx( NULL, 0 );
HRESULT hres = 0;
IShellLink* psl;
if (SUCCEEDED(hres))
{
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(mediaMaestroLocation);
psl->SetDescription("Media Maestro");
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, startupDestination, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
}
CoUninitialize();
return hres;
}
Here is the click event in the UI that calls the function:
void settingsLaunchOnStart_Click( Object^ Sender, EventArgs^ e )
{
if (settingsLaunchOnStart->Checked == false)
{
HRESULT r;
nChars = GetModuleFileName( NULL, mediaMaestroLocation, sizeof(mediaMaestroLocation) );
yChars = SHGetFolderPath( NULL, CSIDL_STARTUP, NULL, SHGFP_TYPE_CURRENT, startupDestination);
r = CreateLink();
}
else if (settingsLaunchOnStart->Checked == true)
{
//code to remove the shortcut
}
}
Is there something I am missing?
It turns out that it wasn't enough to name the output folder path, I had to name the file and extension as well. It seems strange to me, considering I don't think I have seen a single other example doing this. Anyway, here is my updated working code:
HRESULT CreateLink()
{
CoInitializeEx( NULL, 0 );
HRESULT hres = 0;
IShellLink* psl;
if (SUCCEEDED(hres))
{
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLink, (LPVOID*)&psl); //CLSCTX_ALL CLSCTX_INPROC_SERVER (void**)&psl (LPVOID*)&psl
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(mediaMaestroLocation);
psl->SetDescription(L"Media Maestro");
psl->SetIconLocation(mediaMaestroLocation, 0);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); //(void**)&psl (LPVOID*)&ppf
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Save the link by calling IPersistFile::Save.
hres = _wmakepath_s( wsz, _MAX_PATH, NULL, startupDestination,
L"MediaMaestro", L"lnk" );
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
}
CoUninitialize();
return hres;
}
The addition of _wmakepath_s lets me append the name of my program and its extension onto the filepath I got from SHGetFolderPath. Once I feed that into the IPersistFile interface it saves as it should.
you have only initialized hres to 0 and then ur checking if it succeded ? u are never realling declaring it somewhere, and -2147024891 probably means that the variable is not initialized yet.
a wild guess is that it never even reahes the: hres = ppf->Save(wsz, TRUE); line and therefore it is not initialized :P try putting out some breakpoints when debugging and maybe use some watches to peek into variables :)
Best regards.

How to use the "__ProviderArchitecture" flag of IWbemContext in c?

I've been trying to follow the following MSDN tutorial to query the 64 bit registry provider from a 32 bit application.
Sadly, the examples are all written in VB, and I'm stuck with something.
For C++ developers, the article mentions that...
C++ applications can use the IWbemContext interface with IWbemServices::ExecMethod to communicate the use of a nondefault provider to WMI.
...although, when you look at the sample VB code, the context object is also used in the ConnectServer method:
Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet")
objCtx.Add "__ProviderArchitecture", 32
Set objLocator = CreateObject("Wbemscripting.SWbemLocator")
Set objServices = objLocator.ConnectServer("","root\default","","",,,,objCtx)
Set objStdRegProv = objServices.Get("StdRegProv")
I've tried reproducing this in VC++:
HRESULT res;
CComPtr<IWbemContext> ctx;
if (!create_registry_redirection_context_(hive, ctx)) {
return false;
}
res = locator_->ConnectServer(CComBSTR(namespace_.c_str()), // Namespace to use
0, // Current security context (username)
0, // Current security context (password)
0, // Use current locale
WBEM_FLAG_CONNECT_USE_MAX_WAIT, // Return if connexion is unsuccessful after 2 minutes
0, // Name of the domain of the user to authenticate
ctx, // Optional context
&service_); // Fill this pointer
The create_registry_redirection_context_ method uses CoCreateInstance to instantiate my context, and I use the following lines to set the architecture:
CComVariant value_arch(64, VT_I4);
ctx->SetValue(L"__ProviderArchitecture", 0, &value_arch);
Now the problem is, the ConnectServer method returns an error (0x80041008 - WMI Invalid Parameter). If I comment out the ctx->SetValue(L"__ProviderArchitecture", 0, &value_arch); line, everything works properly, but of course, I end up querying the 32 bit registry provider.
I've also tried not setting any context during the ConnectServer call, but only during the ExecMethod call (as specified in the MSDN article), but although I don't get any error, I'm still querying the 32 bit provider, and not seeing my 64bit registry keys.
What am I doing wrong?
Thanks in advance for your time.
I know, it's a little bit late, but for archive (and because MS is unable to provide such a sample):
HRESULT hres;
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
m_nExitCode = TCP1;
return FALSE;
}
IWbemContext *pContext = NULL;
hres = CoCreateInstance(CLSID_WbemContext, 0, CLSCTX_INPROC_SERVER, IID_IWbemContext, (LPVOID *) &pContext);
if (FAILED(hres))
{
m_nExitCode = TCP1_2;
return FALSE;
}
VARIANT vArchitecture;
VariantInit(&vArchitecture);
V_VT(&vArchitecture) = VT_I4;
V_INT(&vArchitecture) = 64;
hres = pContext->SetValue(_bstr_t(L"__ProviderArchitecture"), 0, &vArchitecture);
VariantClear(&vArchitecture);
//VARIANT vRequiredArchicture;
//VariantInit(&vRequiredArchicture);
//V_VT(&vRequiredArchicture) = VT_BOOL;
//V_BOOL(&vRequiredArchicture) = VARIANT_TRUE;
//hres = pContext->SetValue(_bstr_t(L"__RequiredArchitecture"), 0, &vRequiredArchicture);
//VariantClear(&vRequiredArchicture);
IWbemServices *pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t(L"root\\Microsoft\\SqlServer\\ComputerManagement10"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (for example, Kerberos)
pContext, // Context object
&pSvc // pointer to IWbemServices proxy
);
The block with RequiredArchitecture is untested and seems to be unnecessary.
PS: Error-handling needs to be improved!
have you looked at
http://msdn.microsoft.com/en-us/library/windows/desktop/aa393067(v=vs.85).aspx
and tried setting "__RequiredArchitecture" = TRUE as well?
Also have to tried to get it to work in the way that the same code shows ( ie 64 bit to 32 bit) first?