如何在程序运行时获取Visual Studio中NetworkDirect HRESULT状态码的错误文本?
Windows状态常量转人类可读错误信息的实现方案
问题背景
尝试将Windows状态常量(如STATUS_ACCESS_VIOLATION、ND_ACCESS_VIOLATION)转换为可读错误信息时,使用_com_error的ErrorMessage()方法仅能正确处理COM标准HRESULT(如E_FAIL),其他状态码均返回"Unknown error",但Visual Studio监视窗口能显示正确描述,需要在运行时获取这些文本。
原代码及输出
原代码
#include <Windows.h> #include <comdef.h> #include <iostream> // from ndstatus.h #define ND_ACCESS_VIOLATION ((HRESULT)0xC0000005L) #define ND_INVALID_PARAMETER_3 ((HRESULT)0xC00000F1L) int main() { const HRESULT hr1 = E_FAIL; std::cout << _com_error(hr1).ErrorMessage() << std::endl; const HRESULT hr2 = STATUS_ACCESS_VIOLATION; std::cout << _com_error(hr2).ErrorMessage() << std::endl; const HRESULT hr3 = ND_ACCESS_VIOLATION; std::cout << _com_error(hr3).ErrorMessage() << std::endl; const HRESULT hr4 = ND_INVALID_PARAMETER_3; std::cout << _com_error(hr4).ErrorMessage() << std::endl; }
输出结果
Unspecified error Unknown error 0xC0000005 Unknown error 0xC0000005 Unknown error 0xC00000F1
问题原因
_com_error仅针对COM定义的HRESULT设计,无法识别NTSTATUS转换而来的HRESULT(如STATUS_*系列、ND_*系列)。Visual Studio监视窗口能正确显示是因为它调用了系统底层的错误信息查询接口。
解决方案:使用FormatMessage函数
Windows API的FormatMessage可以从系统错误资源中提取所有NTSTATUS和HRESULT对应的描述文本。以下是实现代码:
#include <Windows.h> #include <iostream> #include <string> // from ndstatus.h #define ND_ACCESS_VIOLATION ((HRESULT)0xC0000005L) #define ND_INVALID_PARAMETER_3 ((HRESULT)0xC00000F1L) std::wstring GetErrorText(HRESULT hr) { wchar_t* msgBuffer = nullptr; // 处理NTSTATUS转HRESULT的情况:如果是0xC0000000开头的HRESULT,直接用原始DWORD值查询 DWORD status = (hr & 0xFFFFF000) == 0xC0000000 ? static_cast<DWORD>(hr) : HRESULT_CODE(hr); DWORD result = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&msgBuffer), 0, nullptr ); if (result == 0) { // 系统无对应描述时,返回十六进制错误码 wchar_t hexBuffer[32]; swprintf_s(hexBuffer, L"Unknown error 0x%08X", hr); return hexBuffer; } std::wstring errorMsg(msgBuffer); LocalFree(msgBuffer); // 移除末尾的换行符,优化输出格式 if (!errorMsg.empty() && errorMsg.back() == L'\n') { errorMsg.pop_back(); if (!errorMsg.empty() && errorMsg.back() == L'\r') { errorMsg.pop_back(); } } return errorMsg; } int main() { const HRESULT hr1 = E_FAIL; std::wcout << GetErrorText(hr1) << std::endl; const HRESULT hr2 = STATUS_ACCESS_VIOLATION; std::wcout << GetErrorText(hr2) << std::endl; const HRESULT hr3 = ND_ACCESS_VIOLATION; std::wcout << GetErrorText(hr3) << std::endl; const HRESULT hr4 = ND_INVALID_PARAMETER_3; std::wcout << GetErrorText(hr4) << std::endl; return 0; }
代码说明
- 类型适配:针对
0xC0000000开头的HRESULT(本质是NTSTATUS),直接使用原始DWORD值查询;普通HRESULT则提取错误码部分。 - FormatMessage参数:
FORMAT_MESSAGE_ALLOCATE_BUFFER:让系统自动分配存储错误信息的缓冲区FORMAT_MESSAGE_FROM_SYSTEM:从系统内置的错误资源中读取描述文本FORMAT_MESSAGE_IGNORE_INSERTS:跳过格式化占位符,避免额外参数处理
- 资源管理:使用
LocalFree释放系统分配的缓冲区,防止内存泄漏 - 文本优化:移除错误信息末尾的换行符,让输出更整洁
预期输出
Unspecified error Access violation Access violation Invalid parameter 3
内容的提问来源于stack exchange,提问作者bers
相关产品推荐
相关产品推荐

