当前位置:  开发笔记 > 编程语言 > 正文

如何从GetLastError()返回的错误代码中获取错误消息?

如何解决《如何从GetLastError()返回的错误代码中获取错误消息?》经验,为你挑选了7个好方法。

在Windows API调用之后,如何以文本形式获取最后一条错误消息?

GetLastError() 返回一个整数值,而不是文本消息.



1> Jamin Grey..:
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
std::string GetLastErrorAsString()
{
    //Get the error message, if any.
    DWORD errorMessageID = ::GetLastError();
    if(errorMessageID == 0)
        return std::string(); //No error message has been recorded

    LPSTR messageBuffer = nullptr;
    size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);

    std::string message(messageBuffer, size);

    //Free the buffer.
    LocalFree(messageBuffer);

    return message;
}


这个实现的问题:`1``GetLastError`可能被称为太晚了.`2`没有Unicode支持.`3`在不实施异常安全保证的情况下使用异常.
我相信在这种情况下你实际上需要传递`(LPSTR)和messageBuffer`,否则FormatMessageA无法改变它的值以指向分配的缓冲区.
哦,哇,是的,这有点奇怪.它将如何修改指针?但是传递指针的地址(指向指针的指针),但将其转换为常规指针... Win32怪异.感谢您的抬头,将其修复在我自己的代码库中(以及我的答案).非常微妙的捕获.
不支持某些错误ID.例如,0x2EE7,ERROR_INTERNET_NAME_NOT_RESOLVED在调用FormatMessage时会导致新错误:0x13D,系统无法在%2的消息文件中找到消息号0x%1的消息文本.

2> LeviX..:

更新时间(11月13日),以考虑一些意见.

简单的例子:

wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
               NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
               buf, (sizeof(buf) / sizeof(wchar_t)), NULL);


@ Hi-Angel - 该示例假定您正在使用UNICODE定义进行编译.'FormatMessage'实际上是一个宏,可以扩展为Ansi/MBCS字符缓冲区的'FormatMessageA',或UTF16/UNICODE缓冲区的'FormatMessageW',具体取决于应用程序的编译方式.我冒昧地编辑上面的例子来显式调用与输出缓冲区类型(wchar_t)匹配的版本.
添加FORMAT_MESSAGE_IGNORE_INSERTS:"如果您无法控制格式字符串,则必须传递FORMAT_MESSAGE_IGNORE_INSERTS以防止%1导致问题." https://blogs.msdn.microsoft.com/oldnewthing/20071128-00/?p=24353

3> bk1e..:

MSDN有一些示例代码,演示如何使用FormatMessage()GetLastError()一起使用:检索Last-Error代码



4> Jonathan Gra..:

FormatMessage会将GetLastError的整数返回变为文本消息.



5> Vinay Sajip..:

通常,您需要使用FormatMessage从Win32错误代码转换为文本.

从MSDN 文档:

格式化消息字符串.该函数需要消息定义作为输入.消息定义可以来自传递给函数的缓冲区.它可以来自已加载模块中的消息表资源.或者调用者可以要求函数在系统的消息表资源中搜索消息定义.该函数基于消息标识符和语言标识符在消息表资源中查找消息定义.该函数将格式化的消息文本复制到输出缓冲区,处理任何嵌入的插入序列(如果请求).

FormatMessage的声明:

DWORD WINAPI FormatMessage(
  __in      DWORD dwFlags,
  __in_opt  LPCVOID lpSource,
  __in      DWORD dwMessageId, // your error code
  __in      DWORD dwLanguageId,
  __out     LPTSTR lpBuffer,
  __in      DWORD nSize,
  __in_opt  va_list *Arguments
);



6> IInspectable..:

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

// This functions fills a caller-defined character buffer (pBuffer)
// of max length (cchBufferLength) with the human-readable error message
// for a Win32 error code (dwErrorCode).
// 
// Returns TRUE if successful, or FALSE otherwise.
// If successful, pBuffer is guaranteed to be NUL-terminated.
// On failure, the contents of pBuffer are undefined.
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 
#include 
#include 
#include 
typedef std::basic_string String;

String GetErrorMessage(DWORD dwErrorCode)
{
    LPTSTR psz{ nullptr };
    const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
                                         | FORMAT_MESSAGE_IGNORE_INSERTS
                                         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                                       NULL, // (not used with FORMAT_MESSAGE_FROM_SYSTEM)
                                       dwErrorCode,
                                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                       reinterpret_cast(&psz),
                                       0,
                                       NULL);
    if (cchMsg > 0)
    {
        // Assign buffer to smart pointer with custom deleter so that memory gets released
        // in case String's c'tor throws an exception.
        auto deleter = [](void* p) { ::HeapFree(::GetProcessHeap(), 0, p); };
        std::unique_ptr ptrBuffer(psz, deleter);
        return String(ptrBuffer.get(), cchMsg);
    }
    else
    {
        auto error_code{ ::GetLastError() };
        throw std::system_error( error_code, std::system_category(),
                                 "Failed to retrieve error message string.");
    }
}

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


这些实现提供了对现有答案的以下改进:

完整的示例代码,而不仅仅是对要调用的API的引用.

提供C和C++实现.

适用于Unicode和MBCS项目设置.

将错误代码作为输入参数.这很重要,因为线程的最后一个错误代码仅在明确定义的点上有效.输入参数允许调用者遵循记录的合同.

实现适当的异常安全.与隐式使用异常的所有其他解决方案不同,如果在构造返回值时抛出异常,则此实现不会泄漏内存.

正确使用FORMAT_MESSAGE_IGNORE_INSERTS旗帜.有关详细信息,请参阅FORMAT_MESSAGE_IGNORE_INSERTS标志的重要性.

与其他一些答案不同,正确的错误处理/错误报告会默默地忽略错误.


这个答案已经从Stack Overflow Documentation中收录.以下用户对该示例做出了贡献:stackptr,Ajay,Cody Gray♦,IInspectable.



7> rboy..:

如果您使用的是c#,则可以使用以下代码:

using System.Runtime.InteropServices;

public static class WinErrors
{
    #region definitions
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr LocalFree(IntPtr hMem);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern int FormatMessage(FormatMessageFlags dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer, uint nSize, IntPtr Arguments);

    [Flags]
    private enum FormatMessageFlags : uint
    {
        FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100,
        FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200,
        FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000,
        FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000,
        FORMAT_MESSAGE_FROM_HMODULE = 0x00000800,
        FORMAT_MESSAGE_FROM_STRING = 0x00000400,
    }
    #endregion

    /// 
    /// Gets a user friendly string message for a system error code
    /// 
    /// System error code
    /// Error string
    public static string GetSystemMessage(int errorCode)
    {
        try
        {
            IntPtr lpMsgBuf = IntPtr.Zero;

            int dwChars = FormatMessage(
                FormatMessageFlags.FORMAT_MESSAGE_ALLOCATE_BUFFER | FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM | FormatMessageFlags.FORMAT_MESSAGE_IGNORE_INSERTS,
                IntPtr.Zero,
                (uint) errorCode,
                0, // Default language
                ref lpMsgBuf,
                0,
                IntPtr.Zero);
            if (dwChars == 0)
            {
                // Handle the error.
                int le = Marshal.GetLastWin32Error();
                return "Unable to get error code string from System - Error " + le.ToString();
            }

            string sRet = Marshal.PtrToStringAnsi(lpMsgBuf);

            // Free the buffer.
            lpMsgBuf = LocalFree(lpMsgBuf);
            return sRet;
        }
        catch (Exception e)
        {
            return "Unable to get error code string from System -> " + e.ToString();
        }
    }
}

推荐阅读
勤奋的瞌睡猪_715
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有