Win32 API 将错误代码转换为消息字符串

示例

GetLastError返回数字错误代码。要获取描述性错误消息(例如,显示给用户),可以调用FormatMessage:

// 此函数填充调用者定义的字符缓冲区(pBuffer)
// 最大长度(cchBufferLength)与人类可读的错误消息
// Win32错误代码(dwErrorCode)。
// 
// 如果成功,则返回TRUE,否则返回FALSE。
// 如果成功,则保证pBuffer为NUL终止。
// 失败时,pBuffer的内容未定义。
BOOL GetErrorMessage(DWORD dwErrorCode, LPTSTR pBuffer, DWORD cchBufferLength)
{
    if (cchBufferLength == 0)
    {
        return FALSE;
    }

    DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                 NULL,  /* (not used with FORMAT_MESSAGE_FROM_SYSTEM) */
                                 dwErrorCode,
                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                 pBuffer,
                                 cchBufferLength,
                                 NULL);
    return (cchMsg > 0);
}

C ++中,可以通过使用std::string类来大大简化接口:

#include <Windows.h>
#include <exception>
#include <stdexcept>
#include <memory>
#include <string>
typedef std::basic_string<TCHAR> String;

String GetErrorMessage(DWORD dwErrorCode)
{
    LPTSTR psz = NULL;
    const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
                                         | FORMAT_MESSAGE_IGNORE_INSERTS
                                         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                                       NULL, // (不适用于FORMAT_MESSAGE_FROM_SYSTEM)
                                       dwErrorCode,
                                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                       reinterpret_cast<LPTSTR>(&psz),
                                       0,
                                       NULL);
    if (cchMsg > 0)
    {
        // 使用自定义删除器将缓冲区分配给智能指针,以便释放内存
        // 万一String的c'tor抛出异常。
        auto deleter = [](void* p) { ::HeapFree(::GetProcessHeap(), 0, p); };
        std::unique_ptr<TCHAR, decltype(deleter)> ptrBuffer(psz, deleter);
        return String(ptrBuffer.get(), cchMsg);
    }
    else
    {
        throw std::runtime_error("检索错误消息字符串失败。");
    }
}

注意:这些功能也适用于HRESULT值。只需将第一个参数从更改为DWORD dwErrorCode即可HRESULT hResult。其余代码可以保持不变。