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

新手上路,请多包涵

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

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

原文由 Jena 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
1 个回答

解决方案

这是我使用 std::string/wstring 的最小 C++ 示例。

  • 适用于 Unicode 和 MBCS
  • 兼容 MSVC 6.0 -> VS2022 和 GCC/MinGW(使用 -lstdc++)。很可能也与 Clang 一起使用。
  • 不需要 C++11
  • 适用于 Windows XP 及更高版本。
 #include <windows.h>
#include <string>

typedef std::basic_string<TCHAR> String;

String errorMessage(DWORD dwError)
{
    LPTSTR lpBuffer = NULL;
    String ret = TEXT("");
    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, 0, (LPTSTR)&lpBuffer, 0, NULL))
        ret = String(lpBuffer);
    LocalFree(lpBuffer);
    return ret;
}

但是它没有任何错误检查,如果找不到指定的错误,它只会返回一个空字符串。如果愿意,您可以实现自己的错误检查。

为什么要浪费时间编写大量代码,而很少有代码会欺骗?


附加信息(您可以跳过此)

我为 dwLanguageId 传递了 0,因为它是正确的方法,因为其他答案没有注意到 MAKELANGID 宏已被弃用, 不应使用,因为它不一致并且对于某些语言根本不起作用。

以下是 Windows SDK 10.0.19041.0 (2020-05-12) 中 winnt.h 的摘录,说明了该问题:

 //
// ** DEPRECATED ** DEPRECATED ** DEPRECATED ** DEPRECATED ** DEPRECATED **
//
//  DEPRECATED: The LCID/LANGID/SORTID concept is deprecated, please use
//  Locale Names instead, eg: "en-US" instead of an LCID like 0x0409.
//  See the documentation for GetLocaleInfoEx.
//
//  A language ID is a 16 bit value which is the combination of a
//  primary language ID and a secondary language ID.  The bits are
//  allocated as follows:
//
//       +-----------------------+-------------------------+
//       |     Sublanguage ID    |   Primary Language ID   |
//       +-----------------------+-------------------------+
//        15                   10 9                       0   bit
//
//  WARNING:  This pattern is broken and not followed for all languages.
//            Serbian, Bosnian & Croatian are a few examples.
//
//  WARNING:  There are > 6000 human languages.  The PRIMARYLANGID construct
//            cannot support all languages your application may encounter.
//            Please use Language Names, such as "en".
//
//  WARNING:  There are > 200 country-regions.  The SUBLANGID construct cannot
//            represent all valid dialects of languages such as English.
//            Please use Locale Names, such as "en-US".
//
//  WARNING:  Some languages may have more than one PRIMARYLANGID.  Please
//            use Locale Names, such as "en-FJ".
//
//  WARNING:  Some languages do not have assigned LANGIDs.  Please use
//            Locale Names, such as "tlh-Piqd".
//
//  It is recommended that applications test for locale names rather than
//  attempting to construct/deconstruct LANGID/PRIMARYLANGID/SUBLANGID
//
//  Language ID creation/extraction macros:
//
//    MAKELANGID    - construct language id from a primary language id and
//                    a sublanguage id.
//    PRIMARYLANGID - extract primary language id from a language id.
//    SUBLANGID     - extract sublanguage id from a language id.
//
//  Note that the LANG, SUBLANG construction is not always consistent.
//  The named locale APIs (eg GetLocaleInfoEx) are recommended.
//
//  DEPRECATED: Language IDs do not exist for all locales
//
// ** DEPRECATED ** DEPRECATED ** DEPRECATED ** DEPRECATED ** DEPRECATED **
//

似乎这些信息还没有进入 MAKELANGID 的官方 MSDN 文档。

即使它确实工作正常,它也是一个更糟糕的选择,因为它试图在指定的 LangID 上找到错误字符串,并且只有一个 ID,如果它不存在则失败。改用 0 很可能至少会返回 something ,即使该错误未本地化为用户的语言。

引用 MSDN FormatMessageW

[输入] dwLanguageId

请求消息的语言标识符。如果 dwFlags 包含 FORMAT_MESSAGE_FROM_STRING,则忽略此参数。

如果您在此参数中传递特定 LANGID,则 FormatMessage 将仅返回该 LANGID 的消息。如果函数找不到该 LANGID 的消息,它将 Last-Error 设置为 ERROR_RESOURCE_LANG_NOT_FOUND。如果您传入零,则 FormatMessage 按以下顺序查找 LANGID 消息:

  1. 语言中立
  2. 线程 LANGID,基于线程的语言环境值
  3. 用户默认 LANGID,基于用户的默认语言环境值
  4. 系统默认 LANGID,基于系统默认语言环境值
  5. 美国英语

如果 FormatMessage 没有找到任何上述 LANGID 的消息,它会返回任何存在的语言消息字符串。如果失败,则返回 ERROR_RESOURCE_LANG_NOT_FOUND。

原文由 anzz1 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题