in library/src/WmiQuery.cpp [195:351]
Device WmiQuery::ExtractDeviceDetails(const com_ptr<IWbemClassObject>& device) const
{
Device details;
DeviceDiscoveryError error;
// Retrieve the unique PnP device ID of the device
unique_variant vtDeviceID;
error = CheckHresult(device->Get(L"DeviceID", 0, &vtDeviceID, nullptr, nullptr));
if (error) {
throw error.Wrap(L"failed to retrieve DeviceID property of PnP device");
}
details.ID = winrt::to_hstring(vtDeviceID.bstrVal);
// Retrieve the human-readable description of the device
unique_variant vtDescription;
error = CheckHresult(device->Get(L"Description", 0, &vtDescription, nullptr, nullptr));
if (error) {
throw error.Wrap(L"failed to retrieve Description property of PnP device");
}
details.Description = winrt::to_hstring(vtDescription.bstrVal);
// Retrieve the vendor of the device
unique_variant vtVendor;
error = CheckHresult(device->Get(L"Manufacturer", 0, &vtVendor, nullptr, nullptr));
if (error) {
throw error.Wrap(L"failed to retrieve Manufacturer property of PnP device");
}
details.Vendor = winrt::to_hstring(vtVendor.bstrVal);
// Retrieve the object path for the instance so we can call instance methods with it
unique_variant vtPath;
error = CheckHresult(device->Get(L"__Path", 0, &vtPath, nullptr, nullptr));
if (error) {
throw error.Wrap(L"failed to retrieve __Path property of PnP device");
}
// Create an instance of the input parameters type for the `GetDeviceProperties` instance method
com_ptr<IWbemClassObject> inputArgs;
error = CheckHresult(this->inputParameters->SpawnInstance(0, inputArgs.put()));
if (error) {
throw error.Wrap(L"failed to spawn input parameters instance for Win32_PnPEntity::GetDeviceProperties");
}
// Populate the input parameters with the list of decive property keys we want to retrieve
unique_variant vtPropertyKeys = SafeArrayFactory::CreateStringArray({
L"DEVPKEY_Device_Driver",
L"DEVPKEY_Device_LocationPaths",
this->devPropKeyLUID
});
error = CheckHresult(inputArgs->Put(L"devicePropertyKeys", 0, &vtPropertyKeys, CIM_FLAG_ARRAY | CIM_STRING));
if (error) {
throw error.Wrap(L"failed to assign input parameters array for Win32_PnPEntity::GetDeviceProperties");
}
// Call the `GetDeviceProperties` instance method
com_ptr<IWbemCallResult> callResult;
error = CheckHresult(this->wbemServices->ExecMethod(
vtPath.bstrVal,
wil::make_bstr(L"GetDeviceProperties").get(),
0,
nullptr,
inputArgs.get(),
nullptr,
callResult.put()
));
if (error) {
throw error.Wrap(L"failed to invoke Win32_PnPEntity::GetDeviceProperties()");
}
// Retrieve the return value
com_ptr<IWbemClassObject> returnValue;
error = CheckHresult(callResult->GetResultObject(WBEM_INFINITE, returnValue.put()));
if (error) {
throw error.Wrap(L"failed to retrieve return value for Win32_PnPEntity::GetDeviceProperties");
}
// Extract the device properties array and verify that it matches the expected type
unique_variant vtPropertiesArray;
error = CheckHresult(returnValue->Get(L"deviceProperties", 0, &vtPropertiesArray, nullptr, nullptr));
if (error) {
throw error.Wrap(L"failed to retrieve deviceProperties property of Win32_PnPEntity::GetDeviceProperties return value");
}
if (vtPropertiesArray.vt != (VT_ARRAY | VT_UNKNOWN)) {
throw CreateError(L"deviceProperties value was not an array of IUnknown objects");
}
// Iterate over the device properties array
SafeArrayIterator<IUnknown*> propertiesIterator(vtPropertiesArray.parray);
for (auto element : propertiesIterator)
{
// Cast the property object to an IWbemClassObject
IWbemClassObject* object = nullptr;
error = CheckHresult(element->QueryInterface(&object));
if (error) {
throw error.Wrap(L"IUnknown::QueryInterface() failed for Win32_PnPDeviceProperty object");
}
// Retrieve the key name of the property
unique_variant vtKeyName;
error = CheckHresult(object->Get(L"KeyName", 0, &vtKeyName, nullptr, nullptr));
if (error) {
throw error.Wrap(L"failed to retrieve KeyName property of PnP device property");
}
wstring keyName(winrt::to_hstring(vtKeyName.bstrVal));
// Attempt to retrieve the value of the property
unique_variant data;
HRESULT result = object->Get(L"Data", 0, &data, nullptr, nullptr);
if (FAILED(result))
{
// The property has no value, so ignore it
continue;
}
// Determine which device property we are dealing with
if (keyName == L"DEVPKEY_Device_Driver")
{
// Verify that the device driver value is of the expected type
if (data.vt != VT_BSTR) {
throw CreateError(L"DeviceDriver value was not a string");
}
// Construct the full path to the registry key for the device's driver
details.DriverRegistryKey =
L"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\" +
winrt::to_hstring(data.bstrVal);
}
else if (keyName == L"DEVPKEY_Device_LocationPaths")
{
// Verify that the LocationPaths array is of the expected type
if (data.vt != (VT_ARRAY | VT_BSTR)) {
throw CreateError(L"LocationPaths value was not an array of strings");
}
// Retrieve the first element from the LocationPaths array
SafeArrayIterator<BSTR> locationIterator(data.parray);
details.LocationPath = winrt::to_hstring(*locationIterator.begin());
}
else if (keyName == this->devPropKeyLUID)
{
// Determine whether the LUID value is represented as a raw 64-bit integer or a string representation
if (data.vt == VT_I8) {
details.DeviceAdapter.InstanceLuid = data.llVal;
}
else if (data.vt == VT_BSTR)
{
// Parse the string back into a 64-bit integer
details.DeviceAdapter.InstanceLuid = std::stoll(winrt::to_string(data.bstrVal));
}
else {
throw CreateError(L"LUID value was not a 64-bit integer or a string");
}
}
}
return details;
}