我正在将我的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);
答案 0 :(得分:3)
Windows运行时API上的HRESULT类似于SetLastError() / GetLastError()机制,除了不是将错误代码存储在线程本地存储中,而是直接返回错误代码并存储扩展错误线程本地存储中的信息。调用GetRestrictedErrorInfo()来检索IRestrictedErrorInfo接口,然后在其上调用GetErrorDetails()以获取错误字符串。
使用时要小心 - 在接收失败的HRESULT和检索IRestrictedErrorInfo接口之间不能调用任何Windows运行时API,因为它可以随时被覆盖(GetLastError()存在同样的限制。有两个函数可以设置受限制的错误信息:RoOriginateLanguageException()和RoOriginateError()。
我建议不要使用FormatMessage(),除非你在没有IRestrictedErrorInfo时使用它作为后备:在大多数情况下,你不会从中得到合理的信息。
答案 1 :(得分:2)
MSDN描述了HRESULT
的一般格式:
如何将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文档中所述:
MSDN关于System Error Codes (12000-15999)的文档似乎与此相矛盾(除非要获取[Internet]错误的错误文本,请调用FormatMessage函数,将HMODULE句柄传递给Wininet.dll,这可以使用GetModuleHandle函数获取。
WinInet.dll
在内部为您处理此问题,但不会遵循WinInet文档):
以下列表描述了系统错误代码(错误12000到15999)。当许多函数失败时,它们由GetLastError函数返回。要在应用程序中检索错误的描述文本,请使用带有FORMAT_MESSAGE_FROM_SYSTEM标志的FormatMessage函数。
如果FormatMessage()
(4)错误,则FACILITY_ITF
是接口定义的,因此您根本无法使用HRESULT
。但您可能会使用GetErrorInfo()
,尤其是在实现对象支持ISupportErrorInfo
接口的情况下。