3

HRESULTSを返すWMI/WBEMインターフェイスでメソッドを呼び出しています。これらのエラーコードに対して意味のあるエラーメッセージをユーザーに表示したいと思います。ただし、HRESULTのエラーメッセージを検索すると、「IDispatchエラー#3598」のような文字列しか表示されません。

それらの意味を説明するこれらのIDispatchエラーコードのリストを見つけることができましたか?

エラーが発生する可能性のあるサンプルコード:

IWbemLocator *pLocator = NULL;
IWbemServices *pNamespace = NULL;
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLocator);
if (FAILED(hr))
   return hr;

hr = pLocator->ConnectServer(wPath, NULL, NULL, NULL, 0, NULL, NULL, &pNamespace);
if(FAILED(hr))
   return hr;

エラールックアップ:

CString sMessage = _com_error(nError).ErrorMessage();

// sMessage now contains a string like "IDispatch error #3598"

注:これは役に立ちません-私が取得したHRESULTSは含まれていません。また、winerror.hには含まれていません。

4

2 に答える 2

6

COMサーバーは、独自のHRESULTエラーコードを生成できます。IErrorInfoインターフェイスは、クライアントがエラーの説明を取得するのに役立ちます。_com_errorクラスにそのジョブを実行する機会を与えているのではなく、IErrorInfoインターフェイスポインターをコンストラクターに渡さないのです。

最初にISupportErrorInfoのインターフェイスをQIし、そのInterfaceSupportsErrorInfo()メソッドを呼び出して、エラーレポートがサポートされていることを確認します。次に、GetErrorInfo()を呼び出して、IErrorInfoインターフェイスポインタを取得します。MSDNのドキュメントはこちらです。

于 2011-02-05T17:51:43.023 に答える
0

そのWMI実装は、との一般的な規則をサポートしていませんISupportErrorInfo。エラー機能を確認します。インターフェイスエラー( )の場合は、QIThatをFACILITY_ITF呼び出します。そのオブジェクトからいくつかの詳細な情報を得ることができますが、おそらくエラーの理由を説明していません。GetErrorInfoIErrorInfoIWbemClassObjectGet()

  string Description;
  string Operation;
  string ParameterInfo;
  string ProviderName;
  uint32 StatusCode;

https://docs.microsoft.com/en-us/windows/win32/wmisdk/retrieveing-an-error-code#handling-an-error-using-c

意味のあるメッセージを取得するには、呼び出してメッセージモジュールとして FormatMessage指定できます。https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-error-constantsC:\Windows\System32\wbem\wmiutils.dll

また

を使用しIWbemStatusCodeText::GetErrorCodeText/GetFacilityCodeTextます。そのインターフェースは同じメッセージを返すはずですが、私にはわかりません。

これがコードです

void CheckErrorWMI(HRESULT orig_hres/*, IUnknown* unk, REFIID iid*/)
{
    if (SUCCEEDED(orig_hres))
        return;

    if (HRESULT_FACILITY(orig_hres) != FACILITY_ITF)
    {
        // Common error handling

        // does the magic ISupportErrorInfo dance for us and raise _com_error
        //_com_issue_errorex(orig_hres, unk, iid);
        // but it's not interface error so, it won't help much
        // -OR-
        // use stdlib (msvc STL will pass orig_hres to FormatMessage)
        throw std::system_error(orig_hres, std::system_category(), "some text");
    }
    else
    {
        // WMI specific error handling

        std::string str = "HRESULT = ";
        str += std::to_string(orig_hres); // TODO: as hex
        str += '\n';

        HRESULT hres;

        if (IErrorInfoPtr errInfo; SUCCEEDED(hres = GetErrorInfo(0, &errInfo))
            && errInfo && reinterpret_cast<intptr_t>(errInfo.GetInterfacePtr()) != -1)
            if (IWbemClassObjectPtr errObj; SUCCEEDED(errInfo.QueryInterface(IID_IWbemClassObject, &errObj)))
            {
                SAFEARRAY* sfArray{};

                hres = errObj->GetNames(nullptr, WBEM_FLAG_NONSYSTEM_ONLY/*WBEM_FLAG_ALWAYS*/, nullptr, &sfArray);
                if (SUCCEEDED(hres))
                {
                    DEFER{ SafeArrayDestroy(sfArray); };

                    LONG lstart, lend;
                    SafeArrayGetLBound(sfArray, 1, &lstart);
                    SafeArrayGetUBound(sfArray, 1, &lend);

                    BSTR* pbstr{};
                    hres = SafeArrayAccessData(sfArray, reinterpret_cast<void**>(&pbstr));
                    if (SUCCEEDED(hres))
                    {
                        DEFER{ SafeArrayUnaccessData(sfArray); };

                        VARIANT var;

                        for (LONG nIdx = lstart; nIdx <= lend; nIdx++)
                        {
                            hres = errObj->Get(pbstr[nIdx], 0, &var, nullptr, nullptr);

                            if (FAILED(hres))
                                continue;

                            DEFER{ VariantClear(&var); };

                            if (!str.empty())
                                str += '\n';
                            str += utf8_encode(pbstr[nIdx]);
                            str += " = ";
                            if (V_VT(&var) == VT_NULL)
                            {
                                str += "<null>";
                                continue;
                            }

                            hres = V_VT(&var) == VT_BSTR ? S_OK : VariantChangeType(&var, &var, VARIANT_ALPHABOOL, VT_BSTR);
                            if (hres != S_OK)
                                continue;

                            if (BSTR ss = V_BSTR(&var))
                                str += utf8_encode(ss);
                        }
                    }
                }
            }

        if (IWbemStatusCodeTextPtr sct; SUCCEEDED(sct.CreateInstance(CLSID_WbemStatusCodeText, nullptr, CLSCTX_INPROC_SERVER)))
        {
            _bstr_t msg;
            // https://referencesource.microsoft.com/#System.Management/managementexception.cs,747 GetMessage(ManagementStatus errorCode)
            hres = sct->GetErrorCodeText(orig_hres, 0, 1, msg.GetAddress()); // pass 1 to lFlags to not append \r\n (from .Net interop impl)
            if (hres != WBEM_S_NO_ERROR) // Just in case it didn't like the flag=1, try it again with flag=0.
                hres = sct->GetErrorCodeText(orig_hres, 0, 0, msg.GetAddress());
            if (SUCCEEDED(hres))
            {
                if (!str.empty())
                    str += "\n\n";
                str += "Message: ";
                str += utf8_encode(msg.GetBSTR());
            }

            hres = sct->GetFacilityCodeText(orig_hres, 0, 0, msg.GetAddress());
            if (SUCCEEDED(hres))
            {
                str += "Facility: ";
                str += utf8_encode(msg.GetBSTR());
            }
        }
        if (str.size() <= 22) // just "HRESULT = 123", probably not WMI error
            _com_raise_error(orig_hres); // raise _com_error

        throw std::runtime_error(str);
    }
}

DEFER単なるScopeGuardマクロ(Boost.ScopeExitなど)です

出力:

HRESULT = -2147217385

Description = <null>
Operation = ExecQuery
ParameterInfo = SELECT 1+8 FROM Win32_PnPAllocatedResource
ProviderName = WinMgmt
StatusCode = <null>

Message: Query was not syntactically valid. Facility: WMI
于 2021-09-13T17:51:46.070 に答える