Thanks to the Internet's ever-increasing prominence in our world, we developers are constantly finding new and better ways to take advantage of its capabilities. Frequently, that means finding new ways to perform tasks on the Internet - pushing the limits to do something that hasn't been done before. At other times, we must find alternate paths to take advantage of functionality that's existed for years, such as file transfers using the File Transfer Protocol (FTP). FTP gives us the ability to send or receive all sorts of files across the Internet. Web browsers use underlying FTP functionality when downloading files. We can employ that same functionality in our Visual Basic applications to transfer files across the Internet or intranet by using the Microsoft Internet Transfer Control.
| Properties | Description |
| Password | The password you use when connecting with the FTP server. |
| StillExecuting | Specifies whether a command is still being processed. |
| URL | The URL of the FTP server. |
| Username | User name to use to log into the FTP server. |
| Methods | Description |
| Execute | Initiates an asynchronous command/connection. |
| GetChunk | Reads data from the buffer. |
| OpenURL | Initiates a synchronous command/connection. |
| Events | Description |
| StateChanged | Fires whenever the control state has changed, for example, when a response is received from the FTP server. |
Performing Transfers
To perform FTP transfers, you must follow a few basic steps. First, you define the FTP server you want to attach to. You can specify the FTP site in two ways: using the RemoteHost and RemotePort properties or via the URL property. For simplicity's sake, we'll use the URL property:
Inet1.URL = txtURL
Inet1.UserName = txtUsername
Inet1.Password = txtPassword
Since we're going to be dealing strictly with FTP connections, we'll set the Protocol property accordingly, as follows:
Inet1.Protocol = icFTP
We'll want to execute these commands when we make our first connection to the FTP server. We use the cmdConnect command button to establish this connection, so the code will go to the server. At the same time, when we make this first FTP connection, we'll also retrieve the list of files available on the FTP server. We'll see how to do this next.
Executing Gets Things Done
You'll use the Execute method to send all commands to the FTP site through the control. The syntax of the Execute method is
Inet1.Execute URL, Operation, Data, _
RequestHeaders
Asynchronous Processing
When you're using the Execute method, keep in mind that all its operations are asynchronous. This means that when you tell the control to perform an operation, it starts the operation but returns control back to the application. The control will handle all communications back and forth, based on the properties and commands you've given it. When the operation is completed, the control will notify the application. If you use the OpenURL method, the control makes a synchronous connection and executes the command. However, control doesn't return until the command finishes executing. This more straightforward approach is somewhat simpler to program. Since the asynchronous approach is more flexible--and therefore preferable--we'll use it exclusively here.
Our discussion of the asynchronous approach would be incomplete without mentioning the StillExecuting property. This property identifies when the control is in the middle of performing some operation. If you need to perform an operation that requires several commands, you'll start the first command, loop until the control has stopped processing the command (i.e., StillExecuting is False), then move on to the next operation, as follows:
Inet1.Execute txtURL, "get MyFile.txt"
Do
DoEvents
Loop While Inet1.StillExecuting
Sub Inet1.StateChanged(ByVal State As Integer)
Select Case State
Case icResponseCompleted
`put your code here
End Select
End Sub
Creating The Sample Project
The first step is to begin a new EXE project in VB5. Build a form similar to that shown in Figure A. As you can see, the form should include TextBox controls for the target URL, user name, and password. You'll also need to provide a way to display both local and remote files. Our example uses the DirListBox, DriveListBox, and FileListBox controls for the local files, and a standard ListBox control to display the remote files. Finally, you must add a CommandButton to establish the initial connection. After that, our work with the list boxes will be complete. Table B shows the controls to add to the form, as well as some key properties.
Table B: Controls to add to the form
| Control | Property | Setting |
| Form | Caption | File Transfer |
| TextBox | Name | txtURL |
| TextBox | Name | txtUserName |
| TextBox | Name | txtPassword |
| DriveListBox | Name | drvLocal |
| DirListBox | Name | dirLocal |
| FileListBox | Name | filLocal |
| ListBox | Name | lstRemoteFiles |
| CommandButton | Name | cmdConnect |
| Caption | Connect |
As the name implies, the Connect button will connect to the designated FTP site and retrieve a list of files. To accomplish this, put the following code in the cmdConnect_Click event:
Public Sub cmdConnect_Click()
Inet1.URL = txtURL
Inet1.UserName = txtUserName
Inet1.Password = txtPassword
Inet1.Protocol = icFTP
`Use constant to identify that
`we're getting a directory listing.
`We'll use it in the
`Inet1_StateChanged Event.
iLastFTP = ftpDIR
Inet1.Execute Inet1.URL, "DIR"
End Sub
Once we have the list of files, we can let the user upload files to (or download files from) the FTP site. Since downloading files is more common, let's consider this example first. We download files by executing the FTP command Get. The syntax of the command is Get file1 file2, where file1 is the name of the file on the FTP site and file2 is the name you want the file to have locally. File2 can include path information as well. The GetFiles() function in Listing A demonstrates how to issue the command and retrieve the file.
Similarly, if you want to upload a file to the FTP site (assuming you have write privileges at the site), you use the FTP command Put. The syntax of the command is Put file1 file2, where file1 is the local filename (which can include the path) and file2 is the name the file will have on the FTP site. The PutFiles() function in Listing A demonstrates this process. Please note that you'll have a problem to work around. The FTP Command Line doesn't allow spaces in the filename or path. To solve this problem, you can take one of the following steps:
1. Use relative paths when specifying local files (which is the option we used in the sample program).
2. Place quotation marks (Chr(34)) around the full path and filename (such as C:\My FTP Files\TestFile.txt) in the ftp command.
3. Use the 8.3-character directory name
4. Don't allow spaces in directory names.
With a little work, our application can allow the user to select multiple files to transfer in one operation. Of course, the application will need to issue an Execute command for each transfer. Then, we must test the StillExecuting property to determine whether the control has finished executing that command. Once it's complete, we can loop back and send the command again for the second file. We can continue this process for as many files as necessary.
Known Bugs And Issues
You should be aware of several issues that exist with the current versions of the control. These issues vary depending on which version you're using. In the version that ships with VB 5 (version 5.00.3714), the control sends all filenames as uppercase when you're sending or receiving files. If you're hitting an Internet Information Server (IIS) using NT/DOS file settings, case doesn't matter, since the filenames aren't case-sensitive. However, if you're hitting a UNIX server, it's extremely important, since UNIX filenames are case-sensitive. The result is that any files you send will be named in all uppercase, and you won't be able to retrieve files that have lowercase letters in their names.
Fortunately, Microsoft is aware of this conflict (see the Microsoft Knowledge Base article support.microsoft.com/support/kb/articles/Q168/7/66.asp for more information) and has corrected it in Service Pack 2 for Visual Studio. However, the SP2 control (version 5.01.4319) introduces an even worse problem.
In the SP2 version of the control, you can't log in to any server, other than a strictly anonymous server (such as ftp://ftp.microsoft.com). User names and passwords are sent incorrectly to the FTP server. (See the Microsoft Knowledge Base article support.microsoft.com/support/kb/articles/Q173/2/65.asp for more details.)
Finally, Microsoft released Service Pack 3 (http://msdn.microsoft.com/vstudio/sp/vs6sp3/default.asp) in early December 1997, correcting these problems.
Code For Core Functionality
Add the following to a form:
Private Const ftpDIR As Integer = 0
Private Const ftpPUT As Integer = 1
Private Const ftpGET As Integer = 2
Private Const ftpDEL As Integer = 3
Private iLastFTP As Integer
Private Sub cmdConnect_Click()
On Error GoTo ConnectError
Inet1.URL = txtURL
Inet1.UserName = txtUserName
Inet1.Password = txtPassword
Inet1.Protocol = icFTP
iLastFTP = ftpDIR
Inet1.Execute Inet1.URL, "DIR"
End Sub
Private Sub Inet1_StateChanged(ByVal _
State As Integer)
Select Case State
Case icNone
sbFTP.Panels("status").Text = ""
Case icResolvingHost
sbFTP.Panels("status").Text
=
"Resolving Host"
Case icHostResolved
sbFTP.Panels("status").Text _
= "Host
Resolved"
Case icConnecting
sbFTP.Panels("status").Text _
=
"Connecting..."
Case icConnected
sbFTP.Panels("status").Text _
=
"Connected!"
Case icRequesting
sbFTP.Panels("status").Text _
=
"Requesting..."
Case icRequestSent
sbFTP.Panels("status").Text _
= "Request
Sent"
Case icReceivingResponse
sbFTP.Panels("status").Text _
=
"Receiving Response..."
Case icResponseReceived
sbFTP.Panels("status").Text _
=
"Response Received!"
Case icDisconnecting
sbFTP.Panels("status").Text _
=
"Disconnecting..."
Case icDisconnected
sbFTP.Panels("status").Text _
=
"Disconnected"
Case icError
sbFTP.Panels("status").Text _
= "Error!
" & Trim(CStr( _
Inet1.ResponseCode)) & _
": "
& Inet1.ResponseInfo
Case icResponseCompleted
sbFTP.Panels("status").Text _
=
"Response Completed!"
ReactToResponse iLastFTP
End Select
End Sub
Public Function _
ReactToResponse(ByVal _
iLastCommand As Integer) As Long
Select Case iLastCommand
Case ftpDIR
ShowRemoteFileList
Case ftpPUT
MsgBox
"File Sent from " & CurDir()
Case ftpGET
MsgBox
"File Received "& "in " & CurDir()
Case ftpDEL
End Select
End Function
Public Function ShowRemoteFileList() As Long
Dim sFileList As String
Dim sTemp As String
Dim p As Integer
sTemp = Inet1.GetChunk(1024)
Do While Len(sTemp) > 0
DoEvents
sFileList = sFileList & sTemp
sTemp = Inet1.GetChunk(1024)
Loop
lstRemoteFiles.Clear
Do While sFileList > ""
DoEvents
p = InStr(sFileList, vbCrLf)
If p > 0 Then
lstRemoteFiles.AddItem
Left(sFileList, p - 1)
If
Len(sFileList) > (p + 2) Then
sFileList = Mid(sFileList, p + 2)
Else
sFileList = ""
End If
Else
lstRemoteFiles.AddItem sFileList
sFileList
= ""
End If
Loop
End Function
Code For Core Functionality Part 2
'Continued:
Public Function GetFiles(sFileList As String) As
Long
Dim sFile As String
Dim sTemp As String
Dim p As Integer
iLastFTP = ftpGET
sTemp = sFileList
Do While sTemp > ""
DoEvents
p = InStr(sTemp, "|")
If p Then
sFile =
Left(sTemp, p - 1)
sTemp =
Mid(sTemp, p + 1)
Else
sFile =
sTemp
sTemp =
""
End If
Inet1.Execute Inet1.URL,
"GET " & sFile & _
"
" & sFile
'wait until this execution is done
`before going to next file
Do
DoEvents
Loop Until Not _
Inet1.StillExecuting
Loop
iLastFTP = ftpDIR
Inet1.Execute Inet1.URL, "DIR"
End Function
Public Function PutFiles(sFileList As String) As
Long
Dim sFile As String
Dim sTemp As String
Dim p As Integer
iLastFTP = ftpPUT
sTemp = sFileList
Do While sTemp > ""
DoEvents
p = InStr(sTemp, "|")
If p Then
sFile =
Left(sTemp, p - 1)
sTemp =
Mid(sTemp, p + 1)
Else
sFile =
sTemp
sTemp =
""
End If
Inet1.Execute Inet1.URL,
"PUT" & sFile & _
"
" & sFile
'wait until this execution is done
`before going to next file
Do
DoEvents
Loop Until Not
Inet1.StillExecuting
Loop
iLastFTP = ftpDIR
Inet1.Execute Inet1.URL, "DIR"
End Function
Private Sub dirLocal_Change()
filLocal.Path = dirLocal.Path
End Sub
Private Sub drvLocal_Change()
dirLocal.Path = drvLocal.Drive
End Sub
Private Sub filLocal_DragDrop(Source _
As Control, X As Single, Y As
Single)
'receiving files from FTP site.
Dim I As Integer
Dim sFileList As String
If TypeOf Source Is ListBox Then
For i = 0 _
To
Source.ListCount - 1
If
Source.Selected(i) Then
sFileList = _
sFileList & _
Source.List(i) & "|"
End If
Next
End If
If Len(sFileList) > 0 Then
'strip off the last pipe
sFileList = Left(sFileList, _
Len(sFileList) - 1)
GetFiles sFileList
End If
End Sub
Private Sub _
filLocal_MouseDown(Button As _
Integer, Shift As Integer, X As _
Single, Y As Single)
filLocal.Drag vbBeginDrag
End Sub
Private Sub filLocal_MouseUp(Button _
As Integer, Shift As Integer, _
X As Single, Y As Single)
filLocal.Drag vbEndDrag
End Sub
Code For Core Functionality Part 3
'Continued:
Private Sub _
lstRemoteFiles_DragDrop(Source _
As Control, X As Single, Y As Single)
Dim I As Integer
Dim sFileList As String
If TypeOf Source Is FileListBox Then
For i = 0 To Source.ListCount - 1
If
Source.Selected(i) Then
sFileList = sFileList & _
Source.List(i) & "|"
End If
Next
End If
If Len(sFileList) > 0 Then
'strip off the last pipe
sFileList = Left(sFileList, _
Len(sFileList) - 1)
PutFiles sFileList
End If
End Sub
Private Sub _
lstRemoteFiles_KeyDown(KeyCode _
As Integer, Shift As Integer)
If KeyCode = vbKeyDelete Then
Inet1.Execute Inet1.URL,
"DEL " & _
lstRemoteFiles.List( _
lstRemoteFiles.ListIndex)
Do
DoEvents
Loop While Inet1.StillExecuting
End If
iLastFTP = ftpDIR
Inet1.Execute Inet1.URL, "DIR"
End Sub
Private Sub _
lstRemoteFiles_MouseDown(Button _
As Integer, Shift As Integer, )
X As Single, Y As Single)
lstRemoteFiles.Drag vbBeginDrag
End Sub
Private Sub lstRemoteFiles_MouseUp(Button As _
Integer, Shift As Integer, _
X As Single, Y As Single)
lstRemoteFiles.Drag vbEndDrag
End Sub
Conclusion
As the Internet's importance grows in our daily lives, we must make our applications more Internet-aware. Actually, the Internet offers several solutions to some potential problems--the challenge is to take advantage of the existing capabilities to meet those challenges. If you need to transfer files between two Internet sites, the Internet Transfer Control offers a quick solution. In this article, we've shown you how to use the control in your applications. We've also pointed out a couple of bugs to work around.