Put basic FTP functionality in your VB applications

Adding simple send/receive FTP functionality to a Visual Basic application isn't difficult. Lamont Adams shows you how to do it.

I once saw a demo of a commercial banking application that could update itself on the fly. As the user moved around the interface, the app would use a live Internet connection to check the company's FTP server for new versions of components that required frequent updates, such as those having to do with legal compliance, an area in a constant state of change in the banking industry. Of course, this made for a pretty slow user experience at times, but it seemed to me to be a sound idea in principle. Putting together and sending updated software to customers on a semiregular basis occupied a large chunk of our time at that particular company, so this seemed like the proverbial Holy Grail.

While live updating may be impractical for a variety of reasons, FTP services offer a simple way to give an application access to frequently updated data files in very widely distributed systems. In this article, I'll go over an easy way to implement FTP functionality in Microsoft Visual Basic 6 using wininet.dll. I’ll also provide you with a class library, SimpleFTP, that can give an application simple file-level put and get functionality.

High-level Internet functions
WinInet is a library of high-level functions that allow you to easily access Internet resources through either HTTP or FTP connections. You could use Winsock to do all of the same things, but WinInet is written to allow for proxy servers, DNS services, and dynamic IP addressing. You don't have to do it all yourself, which should cut down on aspirin use around the office. The only two caveats are:
  • WinInet is only officially supported on Intel-based machines. There may or may not be an AMD-centric version—I wasn't able to confirm or deny this while researching this article.
  • The WinInet functions are for use on client applications only and shouldn’t be used in applications that will be run as Windows Services.

Guided tour of the WinInet library
The SimpleFTP class library makes use of five main WinInet functions: InternetOpen, InternetConnect, InternetCloseHandle, FTPPutFile, and FTPGetFile. Let's look at each of these in turn.

InternetOpen opens an Internet session on behalf of a particular application and returns a session handle needed to open a connection to an Internet server. It must be called before any of the other WinInet functions can be used, but don't be fooled into thinking that it actually connects the machine to the Internet, as in opening a dialup connection. Instead it simply allocates the internal resources the library needs to manage itself and any server connections you may make later. The declare statement for InternetOpen is:
Public Declare Function InternetOpen Lib "wininet.dll" _
Alias "InternetOpenA" (ByVal sAgent As String, _
ByVal lAccessType As Long, ByVal sProxyName As String, _
ByVal sProxyBypass As String, ByVal lFlags As Long) As Long

After opening an Internet session with InternetOpen, you can call InternetConnect to open a connection to a given server. InternetConnect returns a connection handle that is used with other functions that interact with the server. The declare statement for InternetConnect looks like:
Public Declare Function InternetConnect Lib "wininet.dll"_
Alias "InternetConnectA" (ByVal hInternetSession As Long,_
ByVal sServerName As String, ByVal nServerPort As Integer,_
ByVal sUsername As String, ByVal sPassword As String, _
ByVal lService As Long, ByVal lFlags As Long, _
ByVal lContext As Long) As Long

A few of those arguments bear some special attention:
  • As you may have guessed, hInternetSession is the session handle returned by InternetOpen.
  • The sServerName argument can be either an IP address or domain name; DNS conversion is performed automatically if needed.
  • Because this function can open any of several different kinds of connections, lService tells the library what kind of service it’s communicating with and which default port it should communicate on if you don't specify a port with the nServerPort argument.

Ok, so you've opened connections to all these servers. Now how do you close them? Pass the connection (or session) handle to InternetCloseHandle, which takes care of closing the actual connections and freeing any resources used by them.
Public Declare Function InternetCloseHandle Lib "wininet.dll" _
(ByVal hInet As Long) As Integer

Finally, we have FTPGetFile and FTPPutFile, which are used to download and upload files from and to an FTP server. These are both high-level, easy-to–use functions, taking care of creating a new file on the appropriate end and streaming the file's data to or from the server. FTPGetFile includes an option to cancel the transfer if the local destination file already exists (pass True for fFailIfExists.
Public Declare Function FtpGetFile Lib "wininet.dll"_
Alias "FtpGetFileA" (ByVal hFtpSession As Long, _
ByVal lpszRemoteFile As String, _
ByVal lpszNewFile As String,
ByVal fFailIfExists As Boolean, _
ByVal dwFlagsAndAttributes As Long, _
ByVal dwFlags As Long, _
ByVal dwContext As Long) As Boolean
Public Declare Function FtpPutFile Lib "wininet.dll" _
Alias "FtpPutFileA" (ByVal hFtpSession As Long, _
ByVal lpszLocalFile As String, _
ByVal lpszRemoteFile As String, _
ByVal dwFlags As Long, _
ByVal dwContext As Long) As Boolean

Get to the good stuff!
I've put the source for the SimpleFTP class up in Listing A, and an associated utility module called modAPI can be found in Listing B. To use it, your application first needs to open a connection to an FTP server via the OpenConnection method, which internally handles the business of obtaining an Internet session handle. Anonymous access is possible by passing "anonymous" for the strUser parameter.

The actual dirty work of sending and receiving files is performed in the class' GetFile and PutFile methods, which you can set to automatically close Internet sessions and connections for you after a transfer via the Boolean AutoCloseInet and AutoCloseFTP properties. Rudimentary error handling is also provided: If either method returns false, check the ErrorInfo property for the last few responses sent by the FTP server. This can help you diagnose the problem.

As advertised by its name, SimpleFTP provides only very simple FTP functionality. Among the other useful features it lacks are the ability to retrieve a directory listing from the FTP server, the ability to delete or rename remote files, and support for passive FTP. To learn how to add support for these missing items, plus a bit more, check out the second installment in this series, coming soon to a Builder site near you.




Editor's Picks