CopyFileEx会出现什么错误代码?

时间:2009-09-04 09:47:50

标签: c++ winapi

我正在编写一些需要调用CopyFileEx函数的C ++代码。像大多数其他WIN32函数一样,CopyFileEx的文档说:

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

哪一切都很好 - 但有谁知道我在哪里可以找到特定API函数可能通过GetLastError返回的错误代码列表?在这种情况下,我想以不同的方式处理不同的错误条件,但是没有错误代码列表这个函数我将被简化为生成我想要处理的错误条件只是为了看什么错误代码产生或通过系统错误代码从数字0到15999试图猜测哪些可能适用!

编辑:这里有一个更多的上下文来帮助解释这个问题以及为什么我想知道是否有一个确定的错误代码列表可以由函数在任何地方返回。

代码将用作Windows服务的一部分,因此虽然有用户,但他们并不总是在那里响应错误。我需要能够区分每次都不需要报告的错误,如果文件被锁定我只是稍后再重新尝试一次。如果我没有读取特定文件的权限,我可以记录问题并继续,如果目标目录不可读或已满,那么我希望服务停止并触发报告过程,这将吸引注意力用户。

如果没有CopyFileEx失败方式的全面列表,我发现很难做到这一点。

3 个答案:

答案 0 :(得分:6)

Microsoft没有提供API可能返回的所有错误代码的列表,原因很简单,因为列表可能会随着时间的推移而发生变化,Windows的各种实现,安装的驱动程序或简单的监督(API通常会返回由其他API引起的错误)在你打电话的那个内。)

有时,文档会调出特定于该API用户特别感兴趣的错误,但通常它们不会有明确的完整错误列表。它们也不应该是不幸的,但这是生活中的事实。

我同情你的困境 - 很多时候我会喜欢这种信息,所以我可以更好地了解如何处理应该预料到的问题 - 特别是那些有合理恢复路径的问题。通常我会尝试通过测试找到API的失败行为来处理这个问题,我想避免这种情况,因为它很痛苦,并且确保我已经涵盖了所有场景或未来差异。

但是,覆盖所有方案(包含错误代码的完整列表)或防范未来的更改实际上是一个不可能实现的目标。考虑一下Microsoft如何管理在Win32中记录所有可能的错误代码:

假设Win32 API只有两个功能:foo()bar()foo()可能会生成自己的错误,ERROR_FOObar()可能会生成自己的错误ERROR_BAR。但是,foo()会调用bar(),因此foo()如果对ERROR_BAR的调用返回该错误,bar()也可能会返回foo()

文档反映了以下内容:

  • ERROR_FOO可以重新调整ERROR_BARbar()
  • ERROR_BAR可能会返回bar()

现在,当API v2发布时,ERROR_BAZ已扩展为还返回bar()。对于这个API大小的东西,它很容易管理bar()的文档需要更新以添加新的错误代码(但是,请注意,对于像真正的Win32这样大的API和像MS一样大的组织,同样可能不是真的,但我们假设它是)。

但是,向foo()添加新错误的人无法直接了解ERROR_BAZ的行为在可能返回的错误方面也发生了变化。在这个小的API中,它可能不是什么大问题 - 在像Win32这样的东西中它会是一团糟。现在抛出Win32可以依赖于第三方代码(驱动程序,插件,COM对象等)的事实,现在几乎不可能完成任务。

实际上,这不一定是一个很好的例子,因为如果错误代码是API OpenObject()合同的一部分,那么它应该永远不会出现。

所以这是另一种情况:API有一个ERROR_NO_MEMORY函数,可以返回ERROR_NOT_FOUNDOpenObject()。当这个系统最初开发时,它没有安全概念(比如MS-DOS),但是新版本增加了访问控制。现在我们希望ERROR_ACCESS_DENIED能够返回OpenObjectEx(),但它不能,因为这会改变合同,因此添加了一个新的API OpenObject()来处理这种情况。这里至少有两个问题:

  • 随着时间的推移,您将获得大量的API,这些API实际上几乎没有增加旧API的价值
  • 调用旧{{1}} API并因访问限制而失败的旧应用程序会发生什么情况?这些合同错误的回复都不会说明问题的真相。

这个问题是许多人认为异常规范(在C ++或Java中)不是一个坏主意的原因之一。

答案 1 :(得分:3)

有一个Windows error codes here列表,但它没有指定每个API调用的错误代码。尽管如此,MSDN站点确实提供了大量有关大多数API方法的有用信息,包括可能返回的错误代码。

FormatMessage函数可用于将错误转换为正确的错误消息,并考虑当前的Windows语言。通常,显示这样的错误消息应该足够了。您只想为可能出现的错误添加逻辑,即使这样您只想显示错误消息。

在阅读CopyFileEx时,您将阅读以下有关获取GetLastError()调用的内容:

  

<强>说明

     

如果目标文件已存在并且设置了FILE_ATTRIBUTE_HIDDEN或FILE_ATTRIBUTE_READONLY属性,则此函数将失败并显示ERROR_ACCESS_DENIED。

     

使用CopyFileEx复制加密文件时,该函数会尝试使用加密源文件中使用的密钥加密目标文件。如果无法执行此操作,则此函数会尝试使用默认密钥加密目标文件。如果无法完成这两种方法,则CopyFileEx将失败并显示ERROR_ENCRYPTION_FAILED错误代码。如果您希望CopyFileEx完成复制操作,即使目标文件无法加密,也请在调用CopyFileEx时将COPY_FILE_ALLOW_DECRYPTED_DESTINATION包含为dwCopyFlags参数的值。

基本上,这些是您通常可以预期的错误。所有其他应该只是向用户发出错误消息。

(当本网站将下划线翻译成其他内容时,我讨厌它...)

答案 2 :(得分:1)

CopyFileEx最终由一系列设备驱动程序处理,一些是由Microsoft编写的,一些可能不是,设备驱动程序返回任意NTSTATUS代码,该代码被转换为Win32错误代码。由于它可以是返回此NTSTATUS的自定义驱动程序,因此Microsoft无法保证您的任何信息。

CopyFileEx可以为您提供“短而甜”的列表的唯一方法是,如果CopyFileEx将详细的错误代码更改为一些简单的错误代码 - 即它会为所有其他错误返回ERROR_ACCESS_DENIED,ERROR_SHARING_VIOLATION或ERROR_GEN_FAILURE(即它将隐藏隐藏错误代码背后的所有其他错误)。我们不希望那样,不是吗?

更新:就合同而言,用户代码应该处理CopyFileEx失败(即返回FALSE时)。用户代码可以通过在失败时查询GetLastError来处理零个或多个特定错误代码。

用户代码很少能够实际处理错误代码。试图处理所有这些当然不是最好的做法。如果用户代码具有针对特定错误代码执行的特定操作,则应执行此操作。否则,唯一与错误代码有关的方法是向用户指示或记录它(请参阅FormatMessage),否则将其视为不透明值。

正如我所说,最好的做法是说你应该自己处理失败 - 因此,你可能做出的回滚更改,内存分配等等。像'finally'子句和C ++ RAII这样的东西在这里可以大有帮助。