Ever wanted to use the dialog box that appears when you do file operations
in Explorer? Well, it is not that hard to work, and can be used to provide some very neat
little features for your application. One little warning before we go too much further:
you can easily use this function to delete entire directories without any confirmation; I
recommend that you create some temporary directories that you can play about with, rather
than destroying any useful directories.
All the dialog boxes are based around one function, SHFileOperation. It is
very easy to use, and only has one parameter, a SHFILEOPSTRUCT user-defined type. Here are
the declarations that you will need:
Public Declare Function SHFileOperation Lib _ "shell32.dll" Alias "SHFileOperationA" _ (lpFileOp As Any) As LongPublic Declare Sub _ SHFreeNameMappings Lib _ "shell32.dll" (ByVal hNameMappings As Long) Public Declare Sub CopyMemory Lib "KERNEL32" _ Alias "RtlMoveMemory" (hpvDest As Any, hpvSource _ As Any, ByVal cbCopy As Long)Public Type SHFILEOPSTRUCT hwnd As Long wFunc As FO_Functions pFrom As String pTo As String fFlags As FOF_Flags fAnyOperationsAborted As Long hNameMappings As Long lpszProgressTitle As String 'only used if FOF_SIMPLEPROGRESS End Type Public Enum FO_Functions FO_MOVE = &H1 FO_COPY = &H2 FO_DELETE = &H3 FO_RENAME = &H4 End Enum Public Enum FOF_Flags FOF_MULTIDESTFILES = &H1 FOF_CONFIRMMOUSE = &H2 FOF_SILENT = &H4 FOF_RENAMEONCOLLISION = &H8 FOF_NOCONFIRMATION = &H10 FOF_WANTMAPPINGHANDLE = &H20 FOF_ALLOWUNDO = &H40 FOF_FILESONLY = &H80 FOF_SIMPLEPROGRESS = &H100 FOF_NOCONFIRMMKDIR = &H200 FOF_NOERRORUI = &H400 FOF_NOCOPYSECURITYATTRIBS = &H800 FOF_NORECURSION = &H1000 FOF_NO_CONNECTED_ELEMENTS = &H2000 FOF_WANTNUKEWARNING = &H4000 End Enum Public Type SHNAMEMAPPING pszOldPath As String pszNewPath As String cchOldPath As Long cchNewPath As Long End Type
Calling is not quite as easy as it looks: the API function expects the UDT
to be byte aligned, but VB aligns the UDT in double byte boundaries. Therefore, we must
use a small workaround to get it to work properly:
Public Function SHFileOP(ByRef lpFileOp _ As SHFileOpStruct) As Long ' This uses a method suggested at MSKB to ' ensure that all parameters are passed correctly ' Call this wrapper rather than the API function ' directly Dim result As Long Dim lenFileop As Long Dim foBuf() As Byte lenFileop = LenB(lpFileOp) ReDim foBuf(1 To lenFileop) ' the size of the structure. ' Now we need to copy the structure into a byte array Call CopyMemory(foBuf(1), lpFileOp, lenFileop) ' Next we move the last 12 bytes by 2 to byte align the data Call CopyMemory(foBuf(19), foBuf(21), 12) result = SHFileOperation(foBuf(1)) SHFileOP = result End Function
Call this function instead of the API one, and it will correct the
problem, then make the call.
This is how the SHFILEOPSTRUCT works:
hwnd: a window handle of the owner of the dialog box. You should
set this to the hwnd of the form that is calling the box, although, you can set it to 0,
so that the desktop is the owner.
– FO_COPY – Copies the files specified in the pFrom member to the location
specified in the pTo member.
– FO_DELETE – Deletes the files specified in pFrom. (pTo is ignored.)
– FO_MOVE – Moves the files specified in pFrom to the location specified in pTo.
– FO_RENAME – Renames the files specified in pFrom.
pFrom: A string containing the names of the sources files and
directories. Separate multiple names by nulls (vbNullChar) and finish with two nulls. It
is important to remember this.
pTo: A string containing the name of the destination file or
directory. If only files are specified in pFrom, you can specify specific names in pTo,
again separated by nulls and ended with a double null.
fFlags: Flags that control the file operation. This member can be a
combination of the following flags, combined using the Or operator:
– FOF_ALLOWUNDO – Preserve Undo information, if possible.
– FOF_CONFIRMMOUSE – Not currently implemented.
– FOF_FILESONLY – Perform the operation on files only if a wildcard file name (*.*)
– FOF_MULTIDESTFILES – The pTo member specifies multiple destination files (one for
each source file) rather than one directory where all source files are to be deposited.
– FOF_NOCONFIRMATION – Respond with Yes to All for any dialog box that is
– FOF_NOCONFIRMMKDIR – Does not confirm the creation of a new directory if the
operation requires one to be created.
– FOF_NOCOPYSECURITYATTRIBS – Do not copy NT file Security Attributes.
– FOF_NOERRORUI – No user interface will be displayed if an error occurs.
– FOF_NORECURSION – Do not recurse directories (i.e. only operate on the
directories specified in pFrom, and not any subdirectories).
– FOF_RENAMEONCOLLISION – Give the file being operated on a new name in a move,
copy, or rename operation if a file with the target name already exists.
– FOF_SILENT – Does not display a progress dialog box.
– FOF_SIMPLEPROGRESS – Displays a progress dialog box but does not show the file
– FOF_WANTMAPPINGHANDLE – If FOF_RENAMEONCOLLISION is specified, the hNameMappings
member will be filled in if any files were renamed.
These two only apply in Internet Explorer 5 Environments:
– FOF_NO_CONNECTED_ELEMENTS – Do not operate on connected elements
– FOF_WANTNUKEWARNING – During delete operations, warn if
permanently deleting instead of placing in recycle bin (partially overrides FOF_NOCONFIRMATION)
fAnyOperationsAborted: Value that contains 0 if the operation was
not cancelled, otherwise, it contains a non-zero number.
hNameMappings: Handle to a file name mapping object that contains
an array of SHNAMEMAPPING structures. Each structure contains the old and new path names
for each file that was moved, copied, or renamed. This member is used only if the fFlags
member includes the FOF_WANTMAPPINGHANDLE flag. The handle must be freed by using the
SHFreeNameMappings function. The exact use of this is beyond the depth of this article.
lpszProgressTitle – A string to use as the title of a progress dialog box.
This member is used only if fFlags includes the FOF_SIMPLEPROGRESS flag.
For example to back up your documents and VB programs to a backup folder,
you could use this code:
Dim lret As Long Dim fileop As SHFILEOPSTRUCT With fileop .hwnd = 0 .wFunc = FO_COPY .pFrom = "C:Program FilesDevStudioVBMy Programs" & _ vbNullChar & "C:My Documents" & vbNullChar & vbNullChar .pTo = "c:Backup of Documents" & vbNullChar & vbNullChar .lpszProgressTitle = "Please wait, backing up..." .fFlags = FOF_SIMPLEPROGRESS Or FOF_RENAMEONCOLLISION End With lret = SHFileOp(fileop) If result <> 0 Then ' Operation failed MsgBox Err.LastDllError 'Show the error returned from the API. Else If fileop.fAnyOperationsAborted <> 0 Then MsgBox "Operation Failed" End If End If
To send this directory to the recycle bin when it is too old, you could
use this code:
Dim lret As Long Dim fileop As SHFILEOPSTRUCT With fileop .hwnd = 0 .wFunc = FO_DELETE .pFrom = "c:Backup of Documents" & vbNullChar & vbNullChar .lpszProgressTitle = "Please wait, backing up..." .fFlags = FOF_SIMPLEPROGRESS Or FOF_ALLOWUNDO End With lret = SHFileOp(fileop) If result <> 0 Then ' Operation failed MsgBox Err.LastDllError 'Show the error returned from the API. Else If fileop.fAnyOperationsAborted <> 0 Then MsgBox "Operation Failed" End If End If
That just about wraps up the SHFileOperation function. Have an experiment
and a play about with it, and before long you will have the wonderful progress dialog box
seamlessly integrated into your application.
If you have any comments/suggestions/questions, please email me.