C++ : Disabling a device driver in Windows - c++

Can anybody help me to tell why this code is not disabling the cdrom driver?It builds correctly.I debugged each line everything works perfectly. I have removed the error handling code and the cleanup code.
int main(int argc, char* argv[])
{
IWbemServices *pSvc = NULL;
HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED);
hres = CoInitializeSecurity(NULL,-1,NULL,NULL,RPC_C_AUTHN_LEVEL_DEFAULT,RPC_C_IMP_LEVEL_IMPERSONATE,NULL,EOAC_NONE,NULL);
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(CLSID_WbemLocator,0,CLSCTX_INPROC_SERVER,IID_IWbemLocator,LPVOID *)&pLoc);
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"),NULL,NULL,0,NULL,0,0,&pSvc);
BSTR MethodName = SysAllocString(L"StopService");
BSTR ClassName = SysAllocString(L"Win32_SystemDriver");
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0, &pInParamsDefinition, NULL);
VARIANT varCommand;
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(L"Win32_SystemDriver.Name=\"cdrom\"", MethodName, 0,
NULL,NULL, &pOutParams, NULL);
VARIANT varReturnValue;
hres = pOutParams->Get(L"ReturnValue", 0, &varReturnValue, NULL, 0);
if (!FAILED(hres))
wcout << "ReturnValue " << varReturnValue.intVal << endl;
VariantClear(&varReturnValue);
// Clean up
SysFreeString(ClassName);
SysFreeString(MethodName);
return 0;
}
Please help..

Not all windows driver accept a 'stop' control request even if they say they do. You can not stop cdrom driver even from a command-line running as an administrator like: "sc stop cdrom".
To disable a windows driver, one must set it to SERVICE_DEMAND_START and reboot. Again, you may not be able to disable all drivers. Some drivers have an Error control of 0x3, which means that windows will fallback to last known good control set if those drivers fail to start.
It might be a good idea to try your code with a service/driver that is can be stopped from an administrative command prompt.
Moreover, you may want to check "AcceptStop" property before Executing the "StopService" method.
You might also want to CoSetProxyBlanket as mentioned in the example here.

Related

Change Brightness using WMI

I have tried this Windows example Getting WMI Data from a Remote Computer and this other Calling a Provider Method, and both work correctly in my computer. However I have tried to use WMI to change the brightness and I am getting an error on step 6, in this part:
//Get the Next Object from the collection
hres = pEnum->Next(WBEM_INFINITE, //Timeout
1, //No of objects requested
&pObj, //Returned Object
&ulReturned /*No of object returned*/);
pEnum is a negative value.
IMPORTANT: While I was writing this question, I tried with different computers and I get errors in all of them, except when I use a laptop. Therefore, how can I change the brightness of a monitor?
I also realize that if I go to wbemtest.exe, in all my computers the class WmiMonitorBrightnessMethods and the method WmiSetBrightness exist, but only in the laptop there is an instance of it. In fact, in the computers when I click on view objects of the class I get this message (see image)
This is my code:
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
int main(int iArgCnt, char ** argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
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))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object. "
<< "Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: ---------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the local root\wminamespace
// and obtain pointer pSvc to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\WMI"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels for the proxy ------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Call WmiSetBrightness method -----------------------------
// set up to call the Win32_Process::Create method
BSTR ClassName = SysAllocString(L"WmiMonitorBrightnessMethods");
BSTR MethodName = SysAllocString(L"WmiSetBrightness");
BSTR bstrQuery = SysAllocString(L"Select * from WmiMonitorBrightnessMethods");
IEnumWbemClassObject *pEnum = NULL;
hres = pSvc->ExecQuery(_bstr_t(L"WQL"), //Query Language
bstrQuery, //Query to Execute
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, //Make a semi-synchronous call
NULL, //Context
&pEnum /*Enumeration Interface*/);
hres = WBEM_S_NO_ERROR;
ULONG ulReturned;
IWbemClassObject *pObj;
DWORD retVal = 0;
//Get the Next Object from the collection
hres = pEnum->Next(WBEM_INFINITE, //Timeout
1, //No of objects requested
&pObj, //Returned Object
&ulReturned /*No of object returned*/);
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);
VARIANT var1;
VariantInit(&var1);
BSTR ArgName0 = SysAllocString(L"Timeout");
V_VT(&var1) = VT_BSTR;
V_BSTR(&var1) = SysAllocString(L"0");
hres = pClassInstance->Put(ArgName0,
0,
&var1,
CIM_UINT32); //CIM_UINT64
VariantClear(&var1);
VARIANT var;
VariantInit(&var);
BSTR ArgName1 = SysAllocString(L"Brightness");
V_VT(&var2) = VT_BSTR;
V_BSTR(&var2) = SysAllocString(L"80"); //Brightness value
hres = pClassInstance->Put(ArgName1,
0,
&var2,
CIM_UINT8);
VariantClear(&var2);
// Call the method
VARIANT pathVariable;
VariantInit(&pathVariable);
hres = pSvc->ExecMethod(pathVariable.bstrVal,
MethodName,
0,
NULL,
pClassInstance,
NULL,
NULL);
VariantClear(&pathVariable);
return 0;
}
As Amit Shakya has stated. changing the brightness throught WMI is only possible in systems that can dynamically set the brightness (laptops and some some all-in-one devices).
However, there is a Microsoft function that allows you to change the brightness of an external monitor, SetMonitorBrightness.
See Microsoft library
I attach a simple example of how to do it:
// Includes
#include "PhysicalMonitorEnumerationAPI.h"
#include "HighLevelMonitorConfigurationAPI.h"
(...)
// Prepare variables
HMONITOR hMonitor = NULL;
HMONITOR hMonitorTest = NULL;
DWORD cPhysicalMonitors;
LPPHYSICAL_MONITOR pPhysicalMonitors = NULL;
// Get the screen
HWND hWnd = GetDesktopWindow();
hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY);
_BOOL success = GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &cPhysicalMonitors);
if(success)
{
pPhysicalMonitors = (LPPHYSICAL_MONITOR)malloc(cPhysicalMonitors* sizeof(PHYSICAL_MONITOR));
if(pPhysicalMonitors != NULL)
{
success = GetPhysicalMonitorsFromHMONITOR(hMonitor,cPhysicalMonitors, pPhysicalMonitors);
HANDLE hPhysicalMonitor = pPhysicalMonitors[0].hPhysicalMonitor;
// Set brightness to 50%
DWORD dwNewBrightness = 50;
success = SetMonitorBrightness(hPhysicalMonitor, dwNewBrightness);
// Free resources
free(pPhysicalMonitors);
}
}
It is mostly because your PC does not support brightness controls via a software. For example in laptops there are hotkeys that can be used to control the brightness, if that exists that you will get an instance and make use of it via WMI.
To be sure, you can run below mentioned command in powershell. If it returns Not supported then you can not use WMI for these controls.
Get-CimInstance -Namespace root/WMI -ClassName WmiMonitorBrightnessMethods
Note : Hotkeys work via another softwares like Mobility Center etc.

WMI C++ IWbemServices . ExecMethod for WBEM_E_INVALID_METHOD_PARAMETERS

I used the mechanism of WMI. Through the modification of dsdt.dsl and production of MOF file, I accomplish the custom WMI function by C#. But there is a problem, when I want to use the C++ - MFC to communicate with the MOF file. While the code runs to the IWbemServices . ExecMethod function, it shows the error message: WBEM_E_INVALID_METHOD_PARAMETERS(0x8004102F). I think the reason occurs with the input parameter: boolean… Hope everyone can provide some suggestions!
Many thanks!
acpimof.mof:
class WMIEvent : __ExtrinsicEvent
{
};
[WMI,
Dynamic,
Provider("WmiProv"),
Locale("MS\\0x409"),
Description("Acpi_Commands"),
guid("{ABBC0F6D-8EA1-11d1-00A0-C90629100000}")
]
class Acpi_Commands
{
[key, read]
string InstanceName;
[read] boolean Active;
[WmiMethodId(1),
Implemented,
read, write,
Description("setReadLight")]
void setReadLight([in, Description("Status")] boolean Status);
};
acpi.cpp:
Copy the MSDN – Example: Calling a Provider Method (https://msdn.microsoft.com/en-us/library/aa390421(v=vs.85).aspx ). The Step 1, 2, 3 & 5 are same totally with the example, so I don’t show the code. I modify the Step 4 & 6.
// Step 4: ---------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the local namespace
// and obtain pointer pSvc to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\WMI"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// set up to call the Win32_Process::Create method
BSTR ClassName = SysAllocString(L"Acpi_Commands");
BSTR MethodName = SysAllocString(L"setReadLight");
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_BOOL;
varCommand.boolVal = VARIANT_TRUE;
// Store the value for the in parameters
hres = pClassInstance->Put(L"Status", 0, &varCommand, CIM_BOOLEAN);
// Execute Method
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(ClassName, MethodName, 0, NULL, pClassInstance, &pOutParams, NULL);
//Get error message: WBEM_E_INVALID_METHOD_PARAMETERS(0x8004102f)
if (FAILED(hres))
{
cout << "Could not execute method. Error code = 0x" << hex << hres << endl;
// Clean up(don't show here)
return 1; // Program has failed.
}
// Clean up(don't show here)
system("pause");
return 0;
I found the solution by myself, and I share this for someone who needs:)
The issue occurs in the first parameter for the IWbemServices::ExecMethod which needs the specified property value rather than the simple class name. So it needs some setting to get the specified property value.(But the "Example: Calling a Provider Method" only sets the class name for the parameter and it works... I guess the reason happen in the namesapce(original: "ROOT\CIMV2" => that is a standard model for Windows), and I use the "ROOT\WMI" to connect with the WMI, so it needs specified property value. If I'm wrong, please correct me!)
Please revise the Step 6 of the acpi.cpp above.
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
BSTR ClassName = SysAllocString(L"Acpi_Commands");
BSTR MethodName = SysAllocString(L"setReadLight");
BSTR bstrQuery = SysAllocString(L"Select * from Acpi_Commands");
//The IEnumWbemClassObject interface is used to enumerate Common Information Model (CIM) objects
//and is similar to a standard COM enumerator.
IEnumWbemClassObject *pEnum = NULL;
hres = pSvc->ExecQuery(_bstr_t(L"WQL"), //Query Language
bstrQuery, //Query to Execute
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, //Make a semi-synchronous call
NULL, //Context
&pEnum /*Enumeration Interface*/);
hres = WBEM_S_NO_ERROR;
ULONG ulReturned;
IWbemClassObject *pObj;
DWORD retVal = 0;
//Get the Next Object from the collection
hres = pEnum->Next(WBEM_INFINITE, //Timeout
1, //One of object requested
&pObj, //Returned Object
&ulReturned /*No of object returned*/);
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);
VARIANT var1;
VariantInit(&var1);
BSTR ArgName0 = SysAllocString(L"Status");
V_VT(&var1) = VT_BOOL;
V_BOOL(&var1) = VARIANT_FALSE;
hres = pClassInstance->Put(ArgName0, 0, &var1, CIM_BOOLEAN);
printf("\nPut ArgName0 returned 0x%x:", hres);
VariantClear(&var1);
// Call the method
VARIANT pathVariable;
VariantInit(&pathVariable);
//The IWbemClassObject::Get method retrieves the specified property value, if it exists.
hres = pObj->Get(_bstr_t(L"__PATH"),
0,
&pathVariable,
NULL,
NULL);
printf("\npObj Get returned 0x%x:", hres);
hres = pSvc->ExecMethod(pathVariable.bstrVal,
MethodName,
0,
NULL,
pClassInstance,
NULL,
NULL);
VariantClear(&pathVariable);
printf("\nExecMethod returned 0x%x:", hres);
printf("Terminating normally\n");
// Clean up
SysFreeString(ClassName);
SysFreeString(MethodName);
pClass->Release();
pClassInstance->Release();
pInParamsDefinition->Release();
pLoc->Release();
pSvc->Release();
CoUninitialize();
system("pause");
return 0;

Deleting WMI instance with 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.

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.

WMI query for Win32_BaseBoard returns no results

The following C++ code to retrieve the motherboard info via WMI works on most machines, except one:
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("Select * from Win32_BaseBoard"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
// handle error, exit
}
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
hr = pclsObj->Get(L"Product", 0, &vtProp, 0, 0);
std::wstring productNo = vtProp.bstrVal;
// do stuff with productNo
}
Specifically, pEnumerator->Next() returns 0, and therefore pclsObj is left NULL.
Have you ever run into a situation where a WMI query on Win32_BaseBoard returns no entries?
My clean Windows XP SP3 /w .NET Framework 2.0 machine in a VirtualBox virtual machine does not return any records, as indicated by the "wmic" tool:
wmic:root\cli>BASEBOARD
No Instance(s) Available
So this appears to be a normal circumstance and not just an isolated incidence. I would plan on the possibility that no records may appear.