Welcome to shell: revealed Sign in | Join | Help
in Search

Shell Blog

Common Questions Concerning the SHFileOperation API: Part 1

Over the years, I have seen many questions being asked on newsgroups and developer forums concerning the SHFileOperation API.  This API allows developers to perform file operations such as Copy, Move, Rename and Delete as well as provide rich UI for confirmation, error and progress dialogs. 

The API uses a struct named SHFILEOPSTRUCT, which contains many members and possible flags/values for those members.  As a consequence, there are many dark corners of the API that need better clarification.  While the documentation on MSDN contains helpful nuggets of information, I wanted to address some of the more commonly asked questions in this multi-part blog entry. 

Part 1:  Why does SHFileOperation return incorrect error codes that have nothing to do with what actually went wrong?

The newsgroups are filled with developers asking questions such as: "SHFileOperation returned error code 117 which maps to ERROR_INVALID_CATEGORY.   This doesn't make any sense!"

In the context of Win32 - that developer is correct.  The description for ERROR_INVALID_CATEGORY in winerror.h is: "The IOCTL call made by the application program is not correct."  What in the world does SHFileOperation have to do with IOCTL errors???   Absolutely nothing.  SHFileOperation isn't returning ERROR_INVALID_CATEGORY.  In this example it is actually returning DE_OPCANCELLED (0x75).  Don't bother searching for what DE_OPCANCELLED is.  It's not documented. 

Many of the error codes returned from SHFileOperation are either old DOS codes from the pre- Win32 era, or custom error codes defined in the copy engine for the old File Manager.  The SHFileOperation API was created from this code and first appeared in Windows 95/NT 4.  At the time, changing the error codes was not foreseen as a priority.  The problem that we see today is that these error codes overlap with those defined in winerror.h.  Other Shell APIs behave the same way.  For example, the ShellExecute API documentation states that any return code lower than 32 is an error.  Above that, it succeeded.  These are old DOS error codes as well.

For reference, below is a table of the error codes returned from SHFileOperation along with their corresponding description.

Error Code

Value

Description

DE_SAMEFILE

0x71

Source and destination file are the same

DE_MANYSRC1DEST

0x72

Multiple paths were specified in the source of the operation, but only one destination path

DE_DIFFDIR

0x73

Rename operation was specified but the destination path is a different directory.  Use move instead.

DE_ROOTDIR

0x74

Source is a root directory, cannot be moved or renamed

DE_OPCANCELLED

0x75

Operation was cancelled by the user (or silently cancelled if the specified flags were supplied to SHFileOperation)

DE_DESTSUBTREE

0x76

The destination is a sub-tree of the source

DE_ACCESSDENIEDSRC

0x78

Security problems on source

DE_PATHTOODEEP

0x79

The source or destination path exceeded or would exceed MAX_PATH

DE_MANYDEST

0x7A

Operation involved multiple destination paths which can fail in the case of a move operation

DE_INVALIDFILES

0x7C

The paths in the source or destination were invalid

DE_DESTSAMETREE

0x7D

Source and destination have the same parent folder.

DE_FLDDESTISFILE

0x7E

The destination path is to an existing file

DE_FILEDESTISFLD

0x80

The destination path is to an existing folder

DE_FILENAMETOOLONG

0x81

The name of the file exceeds MAX_PATH

DE_DEST_IS_CDROM

0x82

Destination is a Read-Only CDRom, possibly unformatted

DE_DEST_IS_DVD

0x83

Destination is a Read-Only DVD, possibly unformatted

DE_DEST_IS_CDRECORD

0x84

Destination is a Recordable (AudioL) CDRom, possibly unformatted

DE_FILE_TOO_LARGE

0x85

The file involved in the operation is too large for the destination media or file system

DE_SRC_IS_CDROM

0x86

Source is a Read-Only CDRom, possibly unformatted

DE_SRC_IS_DVD

0x87

Source is a Read-Only DVD, possibly unformatted

DE_SRC_IS_CDRECORD

0x88

Source is a Recordable (AudioL) CDRom, possibly unformatted

DE_ERROR_MAX

0xB7

MAX_PATH was exceeded during the operation.

Generic Error

0x402 

An unknown error occurred. This is typically due to invalid paths in the source or destination. This error does not occur on Vista and greater.

ERRORONDEST

0x10000 

An unspecified error occurred on the destination.

DE_ROOTDIR|ERRORONDEST 

0x10074 

Destination is a root directory, cannot be renamed

Correcting this error code overlap at this point is simply not practical.  Too many applications are written to expect these specific error codes.  Changing SHFileOperation to return valid winerror.h defined error codes could break these applications.    Please note that the above error codes are subject to change (as they have in previous versions of Windows) and I want to stress that there is NO OFFICIAL SUPPORT FOR THESE ERROR CODES.  As MSDN calls out:  Your code should only check if SHFileOperation returned zero or non-zero.  I only call them out here to add some clarity for those developers debugging their code.  If you want to know for sure why an operation failed you will have to roll your own operations engine.

The silver lining to this story is that in Vista a new interface has been written to allow developers to move away from SHFileOperation's confusing error codes to correctly mapped HRESULT values.  That interface is IFileOperation and will be the topic of later posts.

Published Monday, September 11, 2006 2:53 AM by chrdavis

Comments

 

erangi said:

What a glorious post! This is actually the only documentation of those return values on the Web. What a rare situation for such a commonly used function.

Now, I've happily added all those codes to my application, hoping that it would give me some clue about what's failing the function. When I reproduced the problem, the return code was 32, which is not one of the error codes described... 32 was also the LastError code (as reported by @err, GetLastError wasn't used...), and it actually did make some sense - I was trying to move a folder that contained an open file. From your post I understand it is possible that an internal function SHFileOperation calls will set the last error variable, but why would SHFO itself return that code?

October 3, 2006 8:58 AM
 

chrdavis said:

You should not be relying on GetLastError to return you anything meaningful about the error that occurred.  It is only luck that the last error and the error returned from SHFileOperation were the same error code.

There seems to be some misunderstanding about this post.  SHFileOperation will return valid error codes that map to the correct values in winerror.h for most cases.  It is only in a few cases that I called out in this post where the values overlap those in winerror.h and can lead to some confusion.  

erangi - in your case you get back error code 32 - which maps to ERRROR_NOT_SUPPORTED or ERROR_SHARING_VIOLATION (more likely the latter) from winerror.h.  Use the error lookup tool in Visual Studio or call FormatMessage with the error code returned to get the description.  If the error code matches one of the values I called out, you will have to special case your error handling if you want to give a meaningful error message to the user.

Please see my second post on SHFileOperation in this blog which outlines the most common errors in using the API.  

October 3, 2006 2:17 PM
 

erangi said:

Reading the list of error messages, something looks a bit strange...

There are two error messages that refer to the use of DVD. According to Wiki, the first DVD players were introduced (in Japan) on 1996, and it took them several more years to get to the first personal computers. So, is this some late addition, or is it a smart prediction? if the former, why would anyone add a DE message after winerror was introduced? if the later, it's a pitty those prediction abilities hadn't been used to predict winerror.h as well... ;-)

November 1, 2006 5:06 AM
Anonymous comments are disabled
Powered by Community Server, by Telligent Systems © 2006 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks | Privacy Statement.