8

I am writing my own C++ code to read the computer model and manufacturer on a Windows computer by reading and parsing the registry key

HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/mssmbios/Data/SMBiosData

Is there any library function in Windows / C++ / Visual Studio that allows me to get this information directly?

10
  • 4
    That information is available through the WMI (Windows Machine Instrumentation), but that is far form a simple library function.
    – rodrigo
    Commented Sep 6, 2012 at 12:47
  • So I had rather parse the registry entry and look for the relevant entries myself (?).
    – Giorgio
    Commented Sep 6, 2012 at 12:52
  • Probably, yes, but I know little about the WMI API. Maybe it will surprise me and be too easy...
    – rodrigo
    Commented Sep 6, 2012 at 15:02
  • I have managed to read the content of the registry entry. I am trying to parse it using the information I have found at codeproject.com/Articles/24730/SMBIOS-Peek. It does not seem too difficult. bvi is also my friend at the moment.
    – Giorgio
    Commented Sep 6, 2012 at 15:23
  • I wrote a small program according to the format indicated in the article I have cited. I have assumed that the SMBiosData contains a sequence of entries, each with that table format. Unfortunately, this does not seem to be that case: at the beginning of the data there are bytes 0x00, 0x02, and this must be wrong since I would expect the second byte to be at least 0x04 because it should indicate the size of the formatted section of the first entry (see the format description to understand what this means).
    – Giorgio
    Commented Sep 7, 2012 at 9:21

2 Answers 2

6

The steps you need are explained on Creating a WMI Application Using C++. MSDN even includes a sample program. You just need to change two strings.

  1. Change SELECT * FROM Win32_Process to SELECT * FROM Win32_ComputerSystem
  2. Change Name to Manufacturer and then again for Model.
1
  • I had no idea you were even on this site, Raymond. Allow me to grovel for a minute -- and done. Much better now.
    – Stu
    Commented Jan 1, 2014 at 3:20
5

With the help of the Microsoft example code, I was able to create this method.

#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")

std::pair<CString,CString> getComputerManufacturerAndModel() {
    // Obtain the initial locator to Windows Management on a particular host computer.
    IWbemLocator *locator = nullptr;
    IWbemServices *services = nullptr;
    auto hResult = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&locator);

    auto hasFailed = [&hResult]() {
        if (FAILED(hResult)) {
            auto error = _com_error(hResult);
            TRACE(error.ErrorMessage());
            TRACE(error.Description().Detach());
            return true;
        }
        return false;
    };

    auto getValue = [&hResult, &hasFailed](IWbemClassObject *classObject, LPCWSTR property) {
        CString propertyValueText = "Not set";
        VARIANT propertyValue;
        hResult = classObject->Get(property, 0, &propertyValue, 0, 0);
        if (!hasFailed()) {
            if ((propertyValue.vt == VT_NULL) || (propertyValue.vt == VT_EMPTY)) {
            } else if (propertyValue.vt & VT_ARRAY) {
                propertyValueText = "Unknown"; //Array types not supported
            } else {
                propertyValueText = propertyValue.bstrVal;
            }
        }
        VariantClear(&propertyValue);
        return propertyValueText;
    };

    CString manufacturer = "Not set";
    CString model = "Not set";
    if (!hasFailed()) {
        // Connect to the root\cimv2 namespace with the current user and obtain pointer pSvc to make IWbemServices calls.
        hResult = locator->ConnectServer(L"ROOT\\CIMV2", nullptr, nullptr, 0, NULL, 0, 0, &services);

        if (!hasFailed()) {
            // Set the IWbemServices proxy so that impersonation of the user (client) occurs.
            hResult = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL,
                RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);

            if (!hasFailed()) {
                IEnumWbemClassObject* classObjectEnumerator = nullptr;
                hResult = services->ExecQuery(L"WQL", L"SELECT * FROM Win32_ComputerSystem", WBEM_FLAG_FORWARD_ONLY |
                    WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, &classObjectEnumerator);
                if (!hasFailed()) {
                    IWbemClassObject *classObject;
                    ULONG uReturn = 0;
                    hResult = classObjectEnumerator->Next(WBEM_INFINITE, 1, &classObject, &uReturn);
                    if (uReturn != 0) {
                        manufacturer = getValue(classObject, (LPCWSTR)L"Manufacturer");
                        model = getValue(classObject, (LPCWSTR)L"Model");
                    }
                    classObject->Release();
                }
                classObjectEnumerator->Release();
            }
        }
    }

    if (locator) {
        locator->Release();
    }
    if (services) {
        services->Release();
    }
    CoUninitialize();
    return { manufacturer, model };
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.