【问题标题】:Errors in Windows - DWORD (GetLastError) vs HRESULT vs LSTATUSWindows 中的错误 - DWORD (GetLastError) vs HRESULT vs LSTATUS
【发布时间】:2013-11-02 01:37:25
【问题描述】:

我正在使用 Win32 + WTL 进行一些编程,但我对可用的错误类型感到困惑。

一般来说,我想检查一个错误,并将其提供给 AtlGetErrorDescription(它调用 FormatMessage)。

我的问题是:

  1. 两者有什么区别:

    • DWORD,由GetLastError返回。
    • HRESULT,例如返回CAtlFile 包装器,它使用 HRESULT_FROM_WIN32DWORD 转换。
    • LSTATUS,由例如返回RegCreateKeyEx
  2. 我可以向FormatMessage 提供哪些类型的错误?它的签名表明它接受HRESULT,但是有很多例子是GetLastError的返回值直接传递给FormatMessage

【问题讨论】:

    标签: winapi error-handling wtl


    【解决方案1】:

    它们只是反映了 Windows 中使用的不同 API:

    • GetLastError() 返回一个 winapi 错误代码。一个从 1 开始的简单数字。它们通常映射自底层的原生 api 错误代码。像 ERROR_FILE_NOT_FOUND 是从 STATUS_OBJECT_NAME_NOT_FOUND 文件系统驱动程序错误代码映射的。 Winapi 错误代码在 WinError.h SDK 头文件中声明。您可以使用 FORMAT_MESSAGE_FROM_SYSTEM 选项从 FormatMessage() 获取描述性字符串。

    • HRESULT 是 COM 错误代码。它由三个基本部分组成,高位表示严重性,中间位编码指示错误来源的设备,低 16 位编码错误编号。 HRESULT_FROM_WIN32() 宏是一个辅助宏,用于将 winapi 错误代码映射到 COM 错误代码。它只是将严重性设置为“失败”,将设备代码设置为 7(winapi)并将错误代码复制到低位。有很多可能的 COM 错误代码,只有少数可以通过 FormatMessage() 转换为字符串。您应该使用 ISupportErrorInfo 接口询问 COM 服务器是否可以通过 IErrorInfo 提供错误描述。

    • LSTATUS 是模糊的,RegCreateEx 实际上返回 LONG,只是 winapi 错误代码。它确实会在一些 shell 包装函数中弹出,例如 SHGetValue()。我经常不清楚为什么 shell 团队会这样做。

    • 您的问题中未提及但值得注意的是本机 api 生成的错误代码。它们记录在 ntstatus.h SDK 标头中。 winapi 应该包装原生 api,但这些错误代码有时会在边缘窥视,特别是在异常情况下。大多数程序员都见过 0xc0000005 (STATUS_ACCESS_VIOLATION) 异常代码。 0xc00000fd 匹配此站点的名称。 FormatMessage() 可以将常见的转换为字符串,只要它不是驱动程序生成的自定义错误代码。有几个 API 使用这些类型的错误代码,即使它们在用户模式下运行。常见的例子是 WIC 和媒体基金会,否则没有强烈暗示他们为什么喜欢这种方式。获取此类错误代码的字符串需要使用带有 FORMAT_MESSAGE_FROM_HMODULE 选项的 FormatMessage。

    【讨论】:

    • 感谢您的详细解答。这是否意味着FormatMessage 可以同时处理GetLastError()HRESULT_FROM_WIN32(GetLastError())?另外,我不明白为什么有时 ATL 包装器会返回 WINAPI 错误代码(例如 CRegKey),有时会返回 HRESULT 代码(例如 CAtlFile)。是否可以将任一结果保留为 DWORD,并将错误(如果有)传递给 FormatMessage
    • ATL 主要面向 COM,因此看到它返回 COM 错误代码并不罕见。但是,是的,这并不一致。只需按返回错误类型查看差异。是的,除了 FormatMessage() 之外,你并没有另一个预言机给你一个字符串。
    • 您还没有回答FormatMessage 是否接受这两种错误消息。我想我会尝试一下 :) 另一个不便之处是他们有不同的方式来表示成功/失败 - ==ERROR_SUCCESSSUCCEEDED。所以也许除了坚持两者之一之外别无他法 - 因为AFAIK无法将HRESULT转换为WINAPI错误代码,我想我必须使用HRESULT。这太糟糕了,因为我不得不经常使用HRESULT_FROM_WIN32
    • ERROR_SUCCESS 是 0,S_OK 也是。 SUCCEEDED() 查找任何 HRESULT 值,即 >= 0,其中包括 S_FALSE (1),这不是错误。 GetLastError() 为错误返回一个非零值。 HRESULT 使用值 < 0 表示错误。要从 HRESULT 获取 win32 错误代码,您可以使用 HRESULT_CODE() 如果 HRESULT_FACILITY() 返回 FACILITY_WIN32 (7)。
    • 好吧,似乎可以将WINAPI 代码转换为HRESULTs,但反过来不行。然后我不明白微软的一个例子:us.codeforge.com/read/219594/MgSc.h__html。在那里,定义了内部调用WINAPICOM 函数的函数。但是,示例中的函数返回一个DWORD 错误代码,我理解为WINAPI。在实现中,可以看到许多(DWORD)SOME_HRESULT_CODE 类型的强制转换。是否有意义?为什么 API 不是反过来设计的?
    猜你喜欢
    • 2013-07-18
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-05
    相关资源
    最近更新 更多