Search code examples
inno-setup

How to check that CPU has at least 1.5GHz (per single core)


How to pre-check in InnoSetup that CPU has at least 1.5GHz (per single core), so that user is not disappointed, when installing my app to their device and it would be too slow?

This code should do it in C++, but how can I convert this to InnoSetup's Pascal?

#include <iostream>
#include <windows.h>
#include <comdef.h>
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

bool IsCpuAtLeast1_5GHz() {
    HRESULT hres;

    // Initialize COM.
    hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres)) {
        std::cout << "Failed to initialize COM library. Error code = 0x" 
                  << std::hex << hres << std::endl;
        return false;
    }

    // Initialize security.
    hres = CoInitializeSecurity(
        NULL, 
        -1,                          // COM authentication
        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)) {
        std::cout << "Failed to initialize security. Error code = 0x" 
                  << std::hex << hres << std::endl;
        CoUninitialize();
        return false;
    }

    // Obtain the initial locator to WMI.
    IWbemLocator *pLoc = NULL;

    hres = CoCreateInstance(
        CLSID_WbemLocator,             
        0, 
        CLSCTX_INPROC_SERVER, 
        IID_IWbemLocator, (LPVOID *)&pLoc);

    if (FAILED(hres)) {
        std::cout << "Failed to create IWbemLocator object. "
                  << "Error code = 0x" 
                  << std::hex << hres << std::endl;
        CoUninitialize();
        return false;
    }

    // Connect to WMI.
    IWbemServices *pSvc = NULL;
    hres = pLoc->ConnectServer(
         _bstr_t(L"ROOT\\CIMV2"), // WMI namespace
         NULL,                    // User name (NULL = current user)
         NULL,                    // User password (NULL = current user)
         0,                       // Locale             
         NULL,                    // Security flags
         0,                       // Authority        
         0,                       // Context object        
         &pSvc                    // IWbemServices proxy
    );

    if (FAILED(hres)) {
        std::cout << "Could not connect to WMI. Error code = 0x" 
                  << std::hex << hres << std::endl;
        pLoc->Release();     
        CoUninitialize();
        return false;
    }

    // Set security levels on 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)) {
        std::cout << "Could not set proxy blanket. Error code = 0x" 
                  << std::hex << hres << std::endl;
        pSvc->Release();
        pLoc->Release();     
        CoUninitialize();
        return false;
    }

    // Use the IWbemServices pointer to make requests of WMI.
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(
        bstr_t("WQL"), 
        bstr_t("SELECT MaxClockSpeed FROM Win32_Processor"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
        NULL,
        &pEnumerator);

    if (FAILED(hres)) {
        std::cout << "WMI query failed. Error code = 0x" 
                  << std::hex << hres << std::endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return false;
    }

    IWbemClassObject *pclsObj = NULL;
    ULONG uReturn = 0;

    // Get the data from the query.
    while (pEnumerator) {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);

        if (0 == uReturn) {
            break;
        }

        VARIANT vtProp;
        hr = pclsObj->Get(L"MaxClockSpeed", 0, &vtProp, 0, 0);
        
        // Check if the clock speed is greater than or equal to 1500 MHz.
        if (vtProp.intVal >= 1500) {
            pclsObj->Release();
            pSvc->Release();
            pLoc->Release();
            CoUninitialize();
            return true;
        }

        pclsObj->Release();
    }

    // Cleanup.
    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    CoUninitialize();

    return false;
}

int main() {
    if (IsCpuAtLeast1_5GHz()) {
        std::cout << "CPU is 1.5 GHz or higher." << std::endl;
    } else {
        std::cout << "

Solution

  • Building upon my answer to Is there a way to read the system's information in Inno Setup, you can use IDispatch COM automation code like this:

    [Code]
    
    function InitializeSetup: Boolean;
    var
      Query: string;
      WbemLocator, WbemServices: Variant;
      WbemObjectSet: Variant;
      Processor: Variant;
      Msg: string;
    begin
      Result := True;
      WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      WbemServices := WbemLocator.ConnectServer('.', 'root\CIMV2');
      
      Query := 'SELECT MaxClockSpeed FROM Win32_Processor';
      WbemObjectSet := WbemServices.ExecQuery(Query);
      if VarIsNull(WbemObjectSet) or (WbemObjectSet.Count = 0) then
      begin
        Log('Cannot retrieve processor information');
      end
        else
      begin
        Processor := WbemObjectSet.ItemIndex(0);
        if Processor.MaxClockSpeed >= 1500 then
        begin
          Log(Format('Processor max clock speed is %d, what is enough', [
            Integer(Processor.MaxClockSpeed)]));
        end
          else
        begin
          Msg :=
            'Your processor max clock speed is %.2f GHz, ' +
               'what is not enough for this application. '#13#13 +
            'Do you really want to continue with installation?';
          Msg := Format(Msg, [Extended(Processor.MaxClockSpeed) / 1000]);
          if MsgBox(Msg, mbConfirmation, MB_OKCANCEL) = IDCANCEL then
            Result := False;
        end;
      end;
    end;
    

    enter image description here