如何获取WinRT / Windows 10商店代码的HRESULT错误代码说明?

时间:2016-11-13 10:50:13

标签: c++ winapi windows-runtime uwp windows-10

我正在将我的Win32应用转换为UWP,现在使用Windows.Services.Store命名空间编写Windows Store集成代码。对于Win32 C ++,它主要通过COM接口方法实现,这些方法似乎通过HRESULT错误代码返回其失败。

所以我认为将这些HRESULT代码转换为可以为最终用户显示的描述会很好。

我尝试了以下方法:

int nOSError = (int)hresult;

LPVOID lpMsgBuf;
if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    nOSError,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) &lpMsgBuf, 0, NULL))
{
    //Success

    LocalFree(lpMsgBuf);
}

但不幸的是,它并不总是奏效。例如,FormatMessage返回FALSE和错误代码ERROR_MR_MID_NOT_FOUND,表示我通过运行Windows Store集成代码实验获得的以下HRESULT值:

  • 0x80072EFF
  • 0x803F6107

您是否知道如何获取Windows 10中现在使用的大多数HRESULT代码的说明?

编辑:按照下面Sunius的建议,我想出了以下代码来检索WinRT错误代码的说明:

HRESULT hr;

ComPtr<IRestrictedErrorInfo> pErrInfo;
if (SUCCEEDED(hr = ::GetRestrictedErrorInfo(&pErrInfo)) &&
    pErrInfo)
{
    HRESULT hrErr;
    CComBSTR strErrDesc, strErrRestr, strSid;
    if (SUCCEEDED(hr = pErrInfo->GetErrorDetails(&strErrDesc, &hrErr, &strErrRestr, &strSid)))
    {
        //Set empty message
        ::RoOriginateError(-1, NULL);

        //Get empty error message text
        ComPtr<IRestrictedErrorInfo> pEmptyErrInfo;
        if (SUCCEEDED(hr = ::GetRestrictedErrorInfo(&pEmptyErrInfo)) &&
            pEmptyErrInfo)
        {
            HRESULT hrDummy;
            CComBSTR strEmptyErrDesc, strDummy1, strDummy2;
            if (SUCCEEDED(hr = pEmptyErrInfo->GetErrorDetails(&strEmptyErrDesc, &hrDummy, &strDummy1, &strDummy2)))
            {
                //Remove "The text associated with this error code could not be found" messages
                if (strErrDesc.ByteLength() == strEmptyErrDesc.ByteLength() &&
                    memcmp(strErrDesc.operator LPWSTR(), strEmptyErrDesc.operator LPWSTR(), strErrDesc.ByteLength()) == 0)
                {
                    strErrDesc.Empty();
                }

                if (strErrRestr.ByteLength() == strEmptyErrDesc.ByteLength() &&
                    memcmp(strErrRestr.operator LPWSTR(), strEmptyErrDesc.operator LPWSTR(), strErrRestr.ByteLength()) == 0)
                {
                    strErrRestr.Empty();
                }
            }
        }


        LPCTSTR pS_ErrDesc = strErrDesc.operator LPWSTR();
        LPCTSTR pS_Restr = strErrRestr.operator LPWSTR();

        TCHAR buff[1024];
        if(SUCCEEDED(::StringCchPrintf(buff,
            1024,
            L"ERROR hr=0x%X\n"
            L"desc=\"%s\"\n"
            L"restr=\"%s\""
            ,
            hrErr,
            pS_ErrDesc,
            pS_Restr
            )))
        {
            //Get message in 'buff'

        }
    }
    else
        ASSERT(NULL);
}
else
    ASSERT(NULL);

2 个答案:

答案 0 :(得分:3)

Windows运行时API上的HRESULT类似于SetLastError() / GetLastError()机制,除了不是将错误代码存储在线程本地存储中,而是直接返回错误代码并存储扩展错误线程本地存储中的信息。调用GetRestrictedErrorInfo()来检索IRestrictedErrorInfo接口,然后在其上调用GetErrorDetails()以获取错误字符串。

使用时要小心 - 在接收失败的HRESULT和检索IRestrictedErrorInfo接口之间不能调用任何Windows运行时API,因为它可以随时被覆盖(GetLastError()存在同样的限制。有两个函数可以设置受限制的错误信息:RoOriginateLanguageException()RoOriginateError()

我建议不要使用FormatMessage(),除非你在没有IRestrictedErrorInfo时使用它作为后备:在大多数情况下,你不会从中得到合理的信息。

答案 1 :(得分:2)

MSDN描述了HRESULT的一般格式:

Structure of COM Error Codes

如何将HRESULT分解为其构成组件值:

Using Macros for Error Handling

根据所描述的格式:

  • 0x80072EFF是一个失败代码,其设施为FACILITY_WIN32(7),scode为12031. FACILITY_WIN32表示包含在{{1}中的Win32错误代码}。使用HRESULT_FROM_WIN32()宏创建此类值。 12000-12175范围内的Win32错误代码保留给Internet Error Codes。在这种情况下,Win32错误代码12031是HRESULT(“与服务器的连接已被重置”)。

  • ERROR_INTERNET_CONNECTION_RESET是一个失败代码,具有0x803F6107(63)和24839的设施,似乎没有公开定义,但可能是相关的应用程序许可问题。

使用FACILITY_WINDOWS_STORE检索FormatMessage()的文字说明时,通常需要启用HRESULT标记并设置FORMAT_MESSAGE_FROM_HMODULE定义错误代码的库的lpSource的参数。但是,在HMODULE的强制转换中,可以使用FACILITY_WIN32标记检索大多数Win32错误代码。

其他错误代码往往是库定义的,因此您必须追踪哪个库属于哪个工具,然后加载该库,以便将其传递给FORMAT_MESSAGE_FROM_SYSTEM

如果是Internet错误,则会在FormatMessage()中定义,如WinInet的Handling Errors文档中所述:

  

要获取[Internet]错误的错误文本,请调用FormatMessage函数,将HMODULE句柄传递给Wininet.dll,这可以使用GetModuleHandle函数获取。

MSDN关于System Error Codes (12000-15999)的文档似乎与此相矛盾(除非WinInet.dll在内部为您处理此问题,但不会遵循WinInet文档):

  

以下列表描述了系统错误代码(错误12000到15999)。当许多函数失败时,它们由GetLastError函数返回。要在应用程序中检索错误的描述文本,请使用带有FORMAT_MESSAGE_FROM_SYSTEM标志的FormatMessage函数。

如果FormatMessage()(4)错误,则FACILITY_ITF是接口定义的,因此您根本无法使用HRESULT。但您可能会使用GetErrorInfo(),尤其是在实现对象支持ISupportErrorInfo接口的情况下。