tags:

views:

504

answers:

2

I'm writing some C++ code that needs to call the CopyFileEx function. The documentation for CopyFileEx, like most other WIN32 functions, says:

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Which is all well and good - however does anyone know where I can find a list of the error codes that a specific API function may return via GetLastError? In this case I want to handle different error conditions in different ways but without a list of the error codes for this function I'm going to be reduced to generating the error conditions I want to handle just to see what error code is prodcued or going through the system error codes from numbers 0 to 15999 trying to guess which ones might apply!

Edit: Here is a little more context to help explain the issue and why I want to know if there is a definitive list of error codes that can be returned by a function anywhere.

The code will be used as part of a Windows service so while there are users they won't always be there to respond to errors. I need to be able to distinguish between errors that don't need reporting every time, if a file is locked I'm just to re-try it again later. If I don't have permissions to read a particular file I can log the problem and carry on, if the destination directory is unreadable or is full then I want the service to stop and to trigger a reporting process that will atrract the attention of a user.

Without a comprehensive list of the ways that CopyFileEx can fail I'm finding it hard to do this.

+3  A: 

There is a list of Windows error codes here but it doesn't specify the errorcodes per API call. Still, the MSDN site does provide a lot of useful information about most API methods, including the possible error codes they could return.

The FormatMessage function can be used to translate an error to the proper error message, taking the current Windows language into account. Often, displaying such an error message should be enough. You'd only want to add logic for errors that you might expect and even then you'd just want to show an error message.

When reading about CopyFileEx, you will read the following beyond the part about getting the GetLastError() call:

Remarks

This function fails with ERROR_ACCESS_DENIED if the destination file already exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_READONLY attribute set.

When encrypted files are copied using CopyFileEx, the function attempts to encrypt the destination file with the keys used in the encryption of the source file. If this cannot be done, this function attempts to encrypt the destination file with default keys. If both of these methods cannot be done, CopyFileEx fails with an ERROR_ENCRYPTION_FAILED error code. If you want CopyFileEx to complete the copy operation even if the destination file cannot be encrypted, include the COPY_FILE_ALLOW_DECRYPTED_DESTINATION as the value of the dwCopyFlags parameter in your call to CopyFileEx.

Basically, those are the errors you could normally expect. All others should just result in an error message to the user.

(And I hate it when this site translates the underscores to something else...)

Workshop Alex
In this case I do need to do a bit more than just display an error. The program needs to take different actions but not knowing which errors the function can generate makes it hard to know how it can fail and what recovery actions I might need to take.
Jackson
The Remarks section does list 2 errors that the function might return; but I don't think it is a comprehensive list of errors. I can think of many other errors that could occurr, no source file, no space on the destination, source file is locked, source is open in another process, no permission to write to target directory... A comprehensive error list for this function is really what I'm after.
Jackson
When a file is locked or open or if there's not enough disk space, there will always be a need to tell the user about the problem, since only the user could solve it. Still, error codes in the range of 0 to 499 are related to the file system and some more possible errors. These would be the most important errors in case op copying files.
Workshop Alex
+3  A: 

Microsoft doesn't give a list of all error codes an API might return for the simple reason that the list may change over time and various implementations of Windows, installed drivers or simple oversight (APIs often return errors caused by other APIs called within the one you called).

Sometimes the docs call out specific errors that are of particular interest for users of that API, but in general they will not has a definitive complete list of errors. Nor should they, which is unfortunate, but is a fact of life.

I sympathize with your plight - there are many times I would have liked this kind of information so I could have a better idea of how to handle problems that should be anticipated - particularly those that have a reasonable recovery path. Usually I try to deal with this by testing to find the failure behavior of the APIs, and I'd like to avoid that because it's a pain and it doesn't help much with ensuring that I've covered all the scenarios or against future differences.

However, covering all the scenarios (with a comprehensive list of error codes) or protecting against future changes is really an impossible goal. Consider how Microsoft might have to manage documenting all possble error codes in Win32:

Say the Win32 API has only 2 functions: foo() and bar(). foo() might generate its own error, ERROR_FOO and bar() might generate its own error, ERROR_BAR. However, foo() calls bar(), so foo() might also return ERROR_BAR if its call to bar() returns that error.

The docs reflect the following:

  • foo() may retun either ERROR_FOO or ERROR_BAR
  • bar() may return ERROR_BAR

Now, when API v2 is released, bar() has been extended to also return ERROR_BAZ. for something the size of this API it's simple to manage that the docs for bar() need to be updated to add the new error code (however, note that for an API as large as the real Win32 and an organization as large as MS, the same might not be true, but lets assume it is).

However, the guy adding the new error to bar() has no direct visibility to the fact the foo()'s behavior has also changed in terms of what errors it might return. In an API small as this, it's probably not a big deal - in something like Win32 it would be a mess. Now throw in the fact that Win32 can be dependant on 3rd party code (drivers, plug-ins, COM objects, etc) and the task is now pretty near impossible.

Actually that's not necessarily a great example, since if the error codes were part of the contract of an API ERROR_BAZ should have never come into the picture.

So here's another scenario: the API has an OpenObject() function that can return ERROR_NO_MEMORY or ERROR_NOT_FOUND. When this system was first developed, it had no concept of security (say like MS-DOS), but a new release adds access controls. Now we'd like OpenObject() to be able to return ERROR_ACCESS_DENIED, but it can't because that would change the contract, so a new API OpenObjectEx() is added to deal with that situation. There are at least 2 problems here:

  • You'll get an explosion of APIs over time that really add little or no value over the old APIs
  • what should happen to a legacy application that calls the old OpenObject() API and fails because of access restrictions? Neither of the contracted error returns would tell the truth about what the problem is.

This problem is one of the reasons that exception specifications (in C++ or Java) are considered by many to have been a bad idea.

Michael Burr
I understand what you saying; but I just think it's lazyness on Microsofts part. I've always considered the error codes from a function to be almost as much a part of the function definition as the meaning of the parameters it takes; it's something which if it's changed can break working code.
Jackson
I've updated my answer to give an example of why this probably shouldn't be considered lazyness on MS's part.
Michael Burr
Still not convined here :-) If (and I have) I was writing a library for a 3rd party to use and I said; these functions return some errors but I'm not going to tell you what they are I'd expect my customer to less than pleased. For the WIN32 API it would not be a trivial task - however as it's the basis for a significant proportion of the worlds code it might be nice if the largest software company in existance made the effort.
Jackson
well, it's certainly not a hard and fast thing (for example, many very knowlegable people disagree about exception specifications), but I'd be willing to bet that these are the kinds of things that MS would cite as a rationale. For example, MS has a big problem just with people relying on undocumented behaviors not changing - documenting a more or less unchangable set of errors would really hamper their ability to update the system (even if just to fix bugs).
Michael Burr