Wednesday, August 5, 2009

How to File Copy, Move, and Delete Files in VB.Net Using Windows Functionality

Ever wonder how to copy, move and delete files in VB.Net? Well, in this article I will show you how to do it.

Before, in VB6, we have the FileCopy and Kill statements. FileCopy simply locks up your program until the copy is performed, which makes it pretty difficult to give the user feedback as to what your program is doing. Likewise, the Kill statement banishes a file to a Black Hole with no chance of revival.

Now, in VB.Net, due to the object-oriented methodology, you can easily construct a little class that handles these functions for you. Thus, the EnhancedFileOps class will handle this for you.

Using the EnhancedFileOps Class

The most logical method of designing the EnhancedFileOps class would have been to inherit a new class from the existing File class. Unfortunately, this isn’t possible because the File class is marked as NonInheritable, which means that you cannot create a new class under it. Instead, you should create a base class (which inherits right from System.Object) that does the work.

The API (Application Programming Interface) call that handles both file copying (with Progress Dialog) and moving files to Recycle Bin is called SHFileOperation. It takes as its lone parameter a structure called SHFileOpStruct. The declaration for the function and the structure are shown here:

Private Declare Function SHFileOperation_

Lib “Shell32.dll” Alias “SHFileOperationA” (ByRef _

lpFileOp As SHFILEOPSTRUCT) As Integer

Structure SHFILEOPSTRUCT

Public hwnd As Integer

Public wFunc As Integer

Public pFrom As String

Public pTo As String

Public fFlags As Integer

Public fAnyOperationsAborted As Integer

Public hNameMappings As Integer

Public lpszProgressTitle As Integer

End Structure

There are also a fair amount of private constants declared in the class, which represent constants placed into various fields of the SHFileOpStruct.

Sending a File to the Recycle Bin

To send a file to Recycle Bin, you make the API call with the wFunc parameter set to FO_DELETE, and the fFlags parameter set to FOF_ALLOWUNDO, as shown here:

Public Function SendToRecycleBin() As Boolean

Dim sOP As New SHFILEOPSTRUCT()

With sOP

.hwnd = FhWnd.ToInt32

.wFunc = FO_DELETE

.pFrom = FFilename & Chr(0) & Chr(0)

.fFlags = FOF_ALLOWUNDO

End With

Return(SHFileOperation(sOP) = 0)

End Function

Note that the pFrom parameter requires termination in two nulls, written as chr(0) in VB-speak. The reason for this is that the SHFileOperation API call can actually work on more than one file at a time. To process multiple files, you fill the pFrom parameter with each filename separated by single nulls, and then you end the whole file list with two nulls. My example class does not take advantage of the multiple file functionality, but it would be easy enough to add in.

Take special note of the last line in the function, as there are a few different little tricks going on there. The first is that VB.Net functions can return their value by using the special keyword Return. Older versions of VB required assigning a value to a variable whose name was the function name (this was a big pain when you decided to change the function name but forgot to change the result assignment at the bottom).

The second little trick is a programmer’s preference that we can use to compress the code into fewer lines. The last line of code is exactly equivalent to the following statement block:

iResult = SHFileOperation(sOP)

If iResult = 0 Then

Return True

Else

Return False

End If

This block is a bit easier to read, perhaps, but it takes six lines of code, whereas the replacement takes a single line. The trick here is to note that (SHFileOperation(sOP) = 0) is itself a Boolean expression---that is, it has a value of True or False. If the SHFileOperation API call returns 0, then the expression is true. If the API call returns non-zero, then the expression is false. Instead of writing all that out, we find it easier to compress it on one line. We call the function, compare the result to 0, and return the result of that comparison as the result of my SendToRecycleBin function.

Copying or Moving a File

Copying (or moving) a file using the API call is equally simple. In addition to the pFrom parameter that specifies the source, you must also fill in the pTo parameter, which gives the destination. This is usually a folder name, as shown here:

Private Function InternalCopy(ByVal cDestination _

As String, ByVal bMove As Boolean) As Boolean

Dim sOP As New SHFILEOPSTRUCT()

With sOP

.hwnd = FhWnd.ToInt32

If bMove Then

.wFunc = FO_MOVE

Else

.wFunc = FO_COPY

End If

.pFrom = FFilename & Chr(0) & Chr(0)

.pTo = cDestination & Chr(0) & Chr(0)

.fFlags = FOF_SIMPLEPROGRESS Or _

FOF_FILESONLY Or FOF_NOCONFIRMMKDIR

End With

Return (SHFileOperation(sOP) = 0)

End Function

We made this function a private function because it handles both the moving and copying of large files, based on the second function parameter. We then created easy-to-read methods named CopyWithProgress and MoveWithProgress that in turn call this private function.

The function itself simply sets up the API structure and makes the call. Note the FOF_SIMPLEPROGRESS constant as part of the fFlags parameter---that’s what displays the progress dialog when large files are copied.

The example application allows you to pick a file, which it copies to hard coded folder C:\tempvb when a button is clicked. Select a large file (100MB files are pretty commonplace these days on many hard drives) to make sure you see the progress dialog in action. The second button on the form deletes this newly copied file by placing it in the Recycle Bin.

I want to give thanks to Matt Tagliaferri for the explanation and samples.

No comments:

Post a Comment