Using Explorer's File Copy Dialog Box

Tuesday Nov 19th 2002 by John Percival

Using Explorer's File Copy Dialog Box

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
End Enum

Public Enum FOF_Flags
End Enum

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 (*.*) is specified.
- 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 displayed.
- 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 names.
- 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

With fileop
.hwnd = 0
.wFunc = FO_COPY
.pFrom = "C:\Program Files\DevStudio\VB\My Programs" & _
vbNullChar & "C:\My Documents" & vbNullChar & vbNullChar
.pTo = "c:\Backup of Documents" & vbNullChar & vbNullChar
.lpszProgressTitle = "Please wait, backing up..."
End With

lret = SHFileOp(fileop)

If result <> 0 Then ' Operation failed
MsgBox Err.LastDllError 'Show the error returned from the API.
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

With fileop
.hwnd = 0
.wFunc = FO_DELETE
.pFrom = "c:\Backup of Documents" & vbNullChar & vbNullChar
.lpszProgressTitle = "Please wait, backing up..."
End With

lret = SHFileOp(fileop)

If result <> 0 Then ' Operation failed
MsgBox Err.LastDllError 'Show the error returned from the API.
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.

Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved