如何获取 WinRT / Windows 10 存储代码的 HRESULT 错误代码的说明?
How to get descriptions for HRESULT error codes for WinRT / Windows 10 Store code?
我正在将我的 Win32 应用程序转换为 UWP,现在正在使用 Windows.Services.Store 命名空间编写 Windows 商店集成代码。对于 Win32 C++,它主要是通过 COM 接口方法实现的,这些方法似乎通过 HRESULT
错误代码 return 它们的失败。
所以我认为将这些 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
returns FALSE
和错误代码 ERROR_MR_MID_NOT_FOUND
以下 HRESULT
值是我从 运行 我的 [=44] 实验得到的=] 商店集成代码:
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);
MSDN描述了HRESULT
的一般格式:
以及如何将 HRESULT
分解为其组成部分值:
Using Macros for Error Handling
在描述的格式下:
0x80072EFF
是一个失败代码,其设施为 FACILITY_WIN32
(7),scode 为 12031。FACILITY_WIN32
表示包含在一个 Win32 错误代码中HRESULT
。这些值是使用 HRESULT_FROM_WIN32()
macro. Win32 error codes in the 12000-12175 range are reserved for Internet Error Codes 创建的。在这种情况下,Win32 错误代码 12031 是 ERROR_INTERNET_CONNECTION_RESET
("The connection with the server has been reset").
0x803F6107
是failure为FACILITY_WINDOWS_STORE
(63),scode为24839的failure code,貌似没有公开定义,但可能与应用程序许可问题。
当使用 FormatMessage()
检索 HRESULT
的文本描述时,您 通常 需要启用 FORMAT_MESSAGE_FROM_HMODULE
标志并设置lpSource
参数到定义错误代码的库的 HMODULE
。但是,在 FACILITY_WIN32
的转换中,大多数 Win32 错误代码都可以使用 FORMAT_MESSAGE_FROM_SYSTEM
标志检索。
其他错误代码往往是由库定义的,因此您必须追踪哪个库属于哪个设施,然后加载该库以便将其传递给 FormatMessage()
。
在 Internet 错误的情况下,它们在 WinInet.dll
中定义,如 WinInet 的 Handling Errors 文档所述:
To get the error text for an [Internet] error, call the FormatMessage function, passing it an HMODULE handle to Wininet.dll, which can be obtained using the GetModuleHandle function.
MSDN 关于 System Error Codes (12000-15999) 的文档似乎与此矛盾(除非 FormatMessage()
在内部为您处理,这不会遵循 WinInet 文档):
The following list describes system error codes (errors 12000 to 15999). They are returned by the GetLastError function when many functions fail. To retrieve the description text for the error in your application, use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTEM flag.
在FACILITY_ITF
(4)错误的情况下,HRESULT
是接口定义的,所以根本不能使用FormatMessage()
。但是您也许可以使用 GetErrorInfo()
instead, particularly if the implementing object supports the ISupportErrorInfo
界面。
windows 运行时 API 上的
HRESULT 的工作方式类似于 SetLastError()/GetLastError() mechanism, except that rather than storing the error code in the thread local storage, these APIs instead return the error code directly and store extended error information in thread local storage. Call GetRestrictedErrorInfo() to retrieve IRestrictedErrorInfo interface, and then call GetErrorDetails() 获取错误字符串。
使用它时要小心 - 您不得在接收失败的 HRESULT 和检索 IRestrictedErrorInfo 接口之间调用任何 Windows 运行时 API,因为它可以随时被覆盖(GetLastError() 存在相同的限制) . 设置受限错误信息的函数有两个:RoOriginateLanguageException() and RoOriginateError().
我不建议使用 FormatMessage(),除非您在没有可用的 IRestrictedErrorInfo 时将其用作后备:在大多数情况下,您不会从中获得合理的消息。
我正在将我的 Win32 应用程序转换为 UWP,现在正在使用 Windows.Services.Store 命名空间编写 Windows 商店集成代码。对于 Win32 C++,它主要是通过 COM 接口方法实现的,这些方法似乎通过 HRESULT
错误代码 return 它们的失败。
所以我认为将这些 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
returns FALSE
和错误代码 ERROR_MR_MID_NOT_FOUND
以下 HRESULT
值是我从 运行 我的 [=44] 实验得到的=] 商店集成代码:
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);
MSDN描述了HRESULT
的一般格式:
以及如何将 HRESULT
分解为其组成部分值:
Using Macros for Error Handling
在描述的格式下:
0x80072EFF
是一个失败代码,其设施为FACILITY_WIN32
(7),scode 为 12031。FACILITY_WIN32
表示包含在一个 Win32 错误代码中HRESULT
。这些值是使用HRESULT_FROM_WIN32()
macro. Win32 error codes in the 12000-12175 range are reserved for Internet Error Codes 创建的。在这种情况下,Win32 错误代码 12031 是ERROR_INTERNET_CONNECTION_RESET
("The connection with the server has been reset").0x803F6107
是failure为FACILITY_WINDOWS_STORE
(63),scode为24839的failure code,貌似没有公开定义,但可能与应用程序许可问题。
当使用 FormatMessage()
检索 HRESULT
的文本描述时,您 通常 需要启用 FORMAT_MESSAGE_FROM_HMODULE
标志并设置lpSource
参数到定义错误代码的库的 HMODULE
。但是,在 FACILITY_WIN32
的转换中,大多数 Win32 错误代码都可以使用 FORMAT_MESSAGE_FROM_SYSTEM
标志检索。
其他错误代码往往是由库定义的,因此您必须追踪哪个库属于哪个设施,然后加载该库以便将其传递给 FormatMessage()
。
在 Internet 错误的情况下,它们在 WinInet.dll
中定义,如 WinInet 的 Handling Errors 文档所述:
To get the error text for an [Internet] error, call the FormatMessage function, passing it an HMODULE handle to Wininet.dll, which can be obtained using the GetModuleHandle function.
MSDN 关于 System Error Codes (12000-15999) 的文档似乎与此矛盾(除非 FormatMessage()
在内部为您处理,这不会遵循 WinInet 文档):
The following list describes system error codes (errors 12000 to 15999). They are returned by the GetLastError function when many functions fail. To retrieve the description text for the error in your application, use the FormatMessage function with the FORMAT_MESSAGE_FROM_SYSTEM flag.
在FACILITY_ITF
(4)错误的情况下,HRESULT
是接口定义的,所以根本不能使用FormatMessage()
。但是您也许可以使用 GetErrorInfo()
instead, particularly if the implementing object supports the ISupportErrorInfo
界面。
windows 运行时 API 上的
HRESULT 的工作方式类似于 SetLastError()/GetLastError() mechanism, except that rather than storing the error code in the thread local storage, these APIs instead return the error code directly and store extended error information in thread local storage. Call GetRestrictedErrorInfo() to retrieve IRestrictedErrorInfo interface, and then call GetErrorDetails() 获取错误字符串。
使用它时要小心 - 您不得在接收失败的 HRESULT 和检索 IRestrictedErrorInfo 接口之间调用任何 Windows 运行时 API,因为它可以随时被覆盖(GetLastError() 存在相同的限制) . 设置受限错误信息的函数有两个:RoOriginateLanguageException() and RoOriginateError().
我不建议使用 FormatMessage(),除非您在没有可用的 IRestrictedErrorInfo 时将其用作后备:在大多数情况下,您不会从中获得合理的消息。