【问题标题】:Handling WinAPI error return values处理 WinAPI 错误返回值
【发布时间】:2018-04-02 16:23:15
【问题描述】:

我目前正在学习与 WinAPI 相关的 C++。我正在努力为 WinAPI 函数提出有意义的错误处理策略。

问题:

大多数 WinAPI 函数在出现错误时都可以返回 0,但在许多情况下,我在 MSDN 上看不到任何关于什么可能导致此类错误以及如何解决/解决它的信息。以GetCursorPos为例:

如果成功则返回非零值,否则返回零值。要获取更多错误信息,请致电 GetLastError

(...)

输入桌面必须是调用GetCursorPos时的当前桌面。调用OpenInputDesktop判断当前桌面是否为输入桌面。如果不是,请使用 OpenInputDesktop 返回的 HDESK 调用 SetThreadDesktop 以切换到该桌面。

  • 如果我遵循 GetLastError 的路线,我会对该特定函数可能返回的错误感兴趣,以便我可以检查可以对它们执行的操作。但错误代码在此MSDN page 上仅根据错误编号分为 10 组,而没有任何说明在哪个组中列出了哪些错误。
  • 当我试图了解 OpenInputDesktop 如何帮助我使我的代码更加安全时,我再次发现:

如果函数失败,返回值为NULL。要获取扩展错误信息,请调用 GetLastError

总结一下:几乎WinAPI中的每个函数都可以返回值来确定错误的发生,我可以使用GetLastError获取错误何时发生的信息 功能。但是没有任何关于我可以预期什么样的错误以及解决这些错误的步骤的信息。

例子很多,GetWindowRect 也被广泛使用,MSDN 提供与GetCursorPos 相同的有限信息。

问题:

关于如何处理 WinAPI 函数错误返回值,是否有任何标准可以保留错误处理,而不是仅仅显示一个消息框并退出应用程序?谢谢!

【问题讨论】:

  • 如果同时使用 GetWindowRect 和 GetCursorPos,只有在其中一个 API 返回 FALSE 时才调用 GetLastError。
  • @Asesh 是的,但这只会让我了解发生了什么错误以及何时发生错误。 MSDN 关于可能发生的错误的资源非常有限,因此我可以更好地理解/决定在这种情况下我的代码应该做什么。
  • 除非给定 API 函数的文档明确说明返回的特定错误代码,否则您不能依赖特定错误,因为 ANY 错误可以退货。在这些情况下,您不应该尝试从它们中恢复,因为您无法提前知道它们失败的原因。您只能从已知错误中恢复。如果 API 对于给定操作的成功是必不可少的,那么您所能做的就是使操作失败,可选择记录错误,然后继续
  • 保留错误处理,不再只是显示消息框并退出应用程序 - 这取决于每个特定错误对您的应用程序的严重程度。在某些情况下,您可能会简单地跳过依赖于失败 API 的代码(例如 GUI 绘图代码),在其他情况下,您可能会记录错误但不通知用户,对于关键任务 API,您将另外显示错误消息到日志记录。我认为您的问题过于笼统,无法具体回答。
  • 问题基本上归结为:如何将控制从错误发现点转移到(潜在)错误处理点? C++ 为此使用了异常,std::system_error 在这种情况下是最合适的。这是必要的,因为您通常对发现错误时的影响一无所知。旧的“仅在特殊情况下使用例外”并没有给您带来任何好处,因为在您必须做出决定的时候,您无法评估这是否是特殊情况。

标签: c++ winapi error-handling standards getlasterror


【解决方案1】:

至于提前知道特定函数可以返回哪些可能的错误代码,恐怕微软很久以前就决定为所有函数维护这样的文档将过于繁琐和昂贵,作为一个 API 函数可以调用任意数量的其他 API 函数,这些函数又可以调用其他函数,依此类推。有时你很幸运,MSDN 文档会调用特定于该函数的错误代码,就像 ReadFile 的情况一样,但并非所有函数都如此。

话虽如此,处理GetLastError()返回的错误代码的标准方法是format them with FormatMessage

如果您为语言 ID 传递了 LANG_USER_DEFAULT,这将返回有时有用、有时不那么有用的错误消息,该错误消息采用用户选择的语言环境从错误代码中格式化。您可以向用户显示此消息。如果您想将其格式化为您自己的语言以用于记录目的,假设它是英语,您将传递 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) 作为语言 ID。

如果没有记录错误代码并且您在测试中没有遇到它们,这是您可以做的最好的事情:记录它们并获取日志以及附加到问题报告的其他调试信息。

【讨论】:

  • The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flagFormatMessage 的完整工作实现可以在 here 找到。
  • 你提到了ReadFile,它有一个让我烦恼的错误。从控制台读取时,文档说“如果您按 Ctrl+C,则调用成功,但 GetLastError 返回 ERROR_OPERATION_ABORTED”。从 Windows 8 开始,最后一个错误是 0,这与用户使用 Ctrl+Z 开始行以指示文件结束(即停止读取行、关闭 shell 等)无法区分。 ReadConsole 在这种情况下正确设置了错误,即使没有为此功能记录它;但是,它也需要手动实现 Ctrl+Z。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-18
  • 2016-06-25
  • 1970-01-01
  • 2018-05-26
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多