тип данных BSTR

Хочется сказать много неприятных слов по поводу типов данных от Майкрософт языке С плюс плюс, а именно тех что участвуют в работе  WMI сервиса.

Это про типы _bstr_t и  _variant_t , VARIANT.

После использования QString из Qt работа с _bstr_t вводит в какой-то ступор.

Память надо выделять и не забывать освобождать, но самое не приятное, что даже имея исходный код от Майкрософт не понятно почему программа вылетает в исключение. И не понятно сама идея, чего хотели добится.

Как проверить валидность строки _bstr_t тоже пока не понятно.

В интернете нашел,что у MS есть такой класс для инкапсуляции строки и упрощения работы с ней _bstr_t:

_bstr_t( ) throw( );
_bstr_t(
   const _bstr_t& s1
) throw( );
_bstr_t(
   const char* s2
);
_bstr_t(
   const wchar_t* s3
);
_bstr_t(
   const _variant_t& var
);
_bstr_t(
   BSTR bstr,
   bool fCopy
);

Насколько я понимаю выше представлен просто набор конструкторов класса _bstr_t.

Класс  _variant_t по набору методов похож на _bstr_t. В Qt этот кажется аналог QVariant.

Но в отличии от QVariant класс _variant_t не содержит метода проверки валидности объекта.

Кстати _variant_t это обёртка над еще одним классов VARIANT.

А без этого мы получаем исключения и после пол дня не понятно даже как работать с этим _variant_t.

У MS все классы с которыми мы разбираемся относятся к :

Классы поддержки компилятора COM

После долгих траблов родили функцию, которая выводит наконец-то все свойства  для объектов хранилища WMI:

bool Wmi::Win32_CPU()
{
    // ---------------------------------------------
    //  SELECT ProcessorId FROM Win32_Processor
    // ---------------------------------------------

    if(! query("Win32_Processor"))

        return false;

    // ---------------------------------------------
    //      navigating for all properties
    // ---------------------------------------------

    IWbemClassObject *pclsObj = NULL;

    ULONG uReturn = 0;

    SAFEARRAY* psaNames=NULL;

    LONG nLower=0, nUpper=0;

    while (pEnumerator)
    {

        HRESULT hr = pEnumerator->Next(WBEM_INFINITE,
                                       1,
                                       &pclsObj,
                                       &uReturn);

        if(0 == uReturn)
        {
            break; // finish
        }

        qDebug() << "CPU: ";

        hr=pclsObj->GetNames(NULL,
                             WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY,
                             NULL,
                             &psaNames);

        if (hr==WBEM_S_NO_ERROR )
        {
            nLower=nUpper=0;

            SafeArrayGetLBound(psaNames, 1, &nLower);

            SafeArrayGetUBound(psaNames, 1, &nUpper);

            qDebug() << " nLower " << nLower << " nUpper " << nUpper;

            for (long i = nLower; i <= nUpper; i  )
            {
                _bstr_t	PropName;

                variant_t		vtProp;
                variant_t		vtName;

                VariantInit(&vtProp);
                VariantInit(&vtName);

                //BSTR bsValue = NULL;

                vtProp.Clear();
                vtName.Clear();

                V_VT(&vtName) = VT_BSTR;


                HRESULT res = SafeArrayGetElement( psaNames, &i, &vtName.bstrVal) ;

                if(FAILED(res))
                {
                    continue;
                }

                char *pName = const_cast(_com_util::ConvertBSTRToString(vtName.bstrVal));

                QString name = QString::fromLocal8Bit(pName);


                switch (V_VT(&vtName))
                {
                case VT_EMPTY:
                {
                    qDebug()<< name <<" : VT_EMPTY " ;

                    break;
                }
                case VT_NULL:
                {
                    qDebug()<< name <<" : VT_NULL " ;

                    break;
                }                
                case VT_I4:
                {
                    qDebug() << name << " is VT_I4";
                    
                    break;
                }
                case VT_BSTR:
                {

                    hr = pclsObj->Get(vtName.bstrVal, 0, &vtProp, 0, 0);


                    if ( hr != WBEM_S_NO_ERROR)
                        continue;


                    switch (V_VT(&vtProp))
                    {
                    case VT_EMPTY:
                    {
                        qDebug()<< name <<" : VT_EMPTY " ;

                        break;
                    }
                    case VT_NULL:
                    {
                        qDebug()<< name <<" : VT_NULL " ;

                        break;
                    }
                    case VT_I4:
                    {
                        //printf("prop %d : %d\n", i, V_I4(&vtProp));

                        vtProp.ChangeType(VT_BSTR);

                        char *pVal = const_cast(_com_util::ConvertBSTRToString(vtProp.bstrVal));

                        QString val = QString::fromLocal8Bit(pVal);

                        qDebug()<< name <<" : " << val;

                        break;
                    }
                    case VT_BSTR:
                    {
                        char *pVal = const_cast(_com_util::ConvertBSTRToString(vtProp.bstrVal));

                        QString val = QString::fromLocal8Bit(pVal);


                        qDebug()<< name <<" : " << val;

                        break;
                    }

                    default:
                    {
                        qDebug()<< name << " ??????  type " << vtProp.vt;


//                        vtProp.ChangeType(VT_BSTR); // exception for VT_NULL

//                        char *pVal = const_cast(_com_util::ConvertBSTRToString(vtProp.bstrVal));

//                        QString val = QString::fromLocal8Bit(pVal);

//                        qDebug()<< name <<" : " << val;

                        break;
                    }
                    }

                    break;
                }

                default:
                {
                    vtName.ChangeType(VT_BSTR);

                    if(vtName.vt != VT_BSTR)
                    {
                        qDebug()<< "ERROR " << name;
                        continue;
                    }
                    qDebug()<< name  << " ???????  type not BSTR or VT_I4";
                }
                }


                vtName.Clear();
                vtProp.Clear();

            }

        }
    }

    if (psaNames)
        ::SafeArrayDestroy(psaNames);

    pclsObj->Release();


    pEnumerator->Release();


    return true;

}

По итогу получается, что главные проблемы связаны с отсутствием проверки валидности _variant_t. Поэтому каждый раз надо значение проверять на VT_NULL иначе ChangeType(VT_...) выкидывает исключение.

И есть еще нюанс:  для 
hr = pclsObj->Get(vtName.bstrVal, 0, &vtProp, 0, 0);
в первом парметре мы используем не _bstr_t, а _variant_t, из которого выделяем bstrVal
В этом случае как раз исключений не происходит и вроде _variant_t  сам заботится о выделении и освобождении памяти для своего _bstr_t.

В итоге получаем такой вывод в консоль:

12:36:09 888 Debug: "AddressWidth"  :  "64" 
12:36:09 888 Debug: "Architecture"  :  "9" 
12:36:09 888 Debug: "AssetTag"  :  "To Be Filled By O.E.M." 
12:36:09 889 Debug: "Availability"  :  "3" 
12:36:09 889 Debug: "Caption"  :  "Intel64 Family 6 Model 94 Stepping 3" 
12:36:09 889 Debug: "Characteristics"  :  "252" 
12:36:09 889 Debug: "ConfigManagerErrorCode"  : VT_NULL  
12:36:09 889 Debug: "ConfigManagerUserConfig"  : VT_NULL  
12:36:09 889 Debug: "CpuStatus"  :  "1" 
12:36:09 889 Debug: "CreationClassName"  :  "Win32_Processor" 
12:36:09 889 Debug: "CurrentClockSpeed"  :  "3700" 
12:36:09 890 Debug: "CurrentVoltage"  :  "12" 
12:36:09 890 Debug: "DataWidth"  :  "64" 
12:36:09 890 Debug: "Description"  :  "Intel64 Family 6 Model 94 Stepping 3" 
12:36:09 890 Debug: "DeviceID"  :  "CPU0" 
12:36:09 890 Debug: "ErrorCleared"  : VT_NULL  
12:36:09 890 Debug: "ErrorDescription"  : VT_NULL  
12:36:09 890 Debug: "ExtClock"  :  "100" 
12:36:09 890 Debug: "Family"  :  "206" 
12:36:09 890 Debug: "InstallDate"  : VT_NULL  
12:36:09 890 Debug: "L2CacheSize"  :  "512" 
12:36:09 890 Debug: "L2CacheSpeed"  : VT_NULL  
12:36:09 891 Debug: "L3CacheSize"  :  "3072" 
12:36:09 891 Debug: "L3CacheSpeed"  :  "0" 
12:36:09 891 Debug: "LastErrorCode"  : VT_NULL  
12:36:09 891 Debug: "Level"  :  "6" 
12:36:09 891 Debug: "LoadPercentage"  :  "10" 
12:36:09 891 Debug: "Manufacturer"  :  "GenuineIntel" 
12:36:09 891 Debug: "MaxClockSpeed"  :  "3700" 
12:36:09 891 Debug: "Name"  :  "Intel(R) Core(TM) i3-6100 CPU @ 3.70GHz" 
12:36:09 891 Debug: "NumberOfCores"  :  "2" 
12:36:09 891 Debug: "NumberOfEnabledCore"  :  "2" 
12:36:09 891 Debug: "NumberOfLogicalProcessors"  :  "4" 
12:36:09 892 Debug: "OtherFamilyDescription"  : VT_NULL  
12:36:09 892 Debug: "PartNumber"  :  "To Be Filled By O.E.M." 
12:36:09 892 Debug: "PNPDeviceID"  : VT_NULL  
12:36:09 892 Debug: "PowerManagementCapabilities"  : VT_NULL  
12:36:09 892 Debug: "PowerManagementSupported"  ??????  type  11 
12:36:09 892 Debug: "ProcessorId"  :  "BFEBFBFF000506E3" 
12:36:09 892 Debug: "ProcessorType"  :  "3" 
12:36:09 892 Debug: "Revision"  :  "24067" 
12:36:09 892 Debug: "Role"  :  "CPU" 
12:36:09 892 Debug: "SecondLevelAddressTranslationExtensions"  ??????  type  11 
12:36:09 892 Debug: "SerialNumber"  :  "To Be Filled By O.E.M." 
12:36:09 892 Debug: "SocketDesignation"  :  "U3E1" 
12:36:09 892 Debug: "Status"  :  "OK" 
12:36:09 892 Debug: "StatusInfo"  :  "3" 
12:36:09 892 Debug: "Stepping"  : VT_NULL  
12:36:09 893 Debug: "SystemCreationClassName"  :  "Win32_ComputerSystem" 
12:36:09 893 Debug: "SystemName"  :  "BIT-DEVELOPMENT" 
12:36:09 893 Debug: "ThreadCount"  :  "4" 
12:36:09 893 Debug: "UniqueId"  : VT_NULL  
12:36:09 893 Debug: "UpgradeMethod"  :  "1" 
12:36:09 893 Debug: "Version"  :  "" 
12:36:09 893 Debug: "VirtualizationFirmwareEnabled"  ??????  type  11 
12:36:09 893 Debug: "VMMonitorModeExtensions"  ??????  type  11 
12:36:09 893 Debug: "VoltageCaps"  : VT_NULL