isual Basic applications are becoming more connected, and developers are trying to Web-enable their applications by supporting HTTP or FTP. Often this requires using the Microsoft Internet Transfer control or a third party control, but all of the functionality can be achieved through the use of the WinInet API without the need of a form to host the control.
This solution will present the FTP functionality of the WinInet API and provide a wrapper to this API so that you can easily add FTP support to your applications.
Built into Windows are several APIs that allow you to develop rich networking applications. Two that are available to Visual Basic developers are the Win32 Internet API (WinInet) and the WinSock API. These two APIs are encapsulated in the Microsoft Internet Transfer control and the Winsock control, but they do not offer all of the flexibility that working with the API does.
The WinInet API was designed to abstract three Internet protocols, HTTP, FTP, and Gopher; making it easier for developers to build Internet-enabled applications. WinInet exposes many functions for Web-enabling your applications. Some of the functions that exist in the API are:
- InternetConnect – Opens a FTP, Gopher, or HTTP session to a given site.
- InternetReadFile – Reads data from a handle on a site.
- InternetWriteFile – Writes data to an open Internet file.
- FTPGetFile – Retrieves a file from a FTP site and saves it locally.
- FTPRenameFile – Renames a file on a FTP site.
Now let’s go into detail on the FTP functions that the WinInet API exposes and create a wrapper class to allow you to easily add FTP support without the use of ActiveX controls.
FTP API Functions
The WinInet API exposes 12 functions that allow developers to manipulate and navigate files and directories on a FTP site. In addition there are several functions that provide session management for opening and closing handles to a site. When working with the WinInet API, there is a sequence of events that occur over an over. This sequence is:
1. Initialize the WinInet API by calling the InternetOpen function
2. Connect to a site and retrieve a handle to the open connection by using the InternetConnect function
3. Navigate through the site and manipulate files and directories
4. Close the connection
To make this more concrete, let’s download a file from Microsoft’s FTP site using the WinInet API. The code for downloading ls-lr.zip from the root directory would be:
hInternet = InternetOpen("DevX Sample", _INTERNET_OPEN_TYPE_DIRECT, vbNullString, vbNullString, _INTERNET_FLAG_NO_CACHE_WRITE) hConnect = InternetConnect(hInternet, "ftp.Microsoft.com", _INTERNET_DEFAULT_FTP_PORT, _ "", "", INTERNET_SERVICE_FTP, _ INTERNET_FLAG_EXISTING_CONNECT Or INTERNET_FLAG_PASSIVE, _&H0) lRes = FtpGetFile(hConnect, "ls-lr.zip", "c:ls-lr.zip", _False, FILE_ATTRIBUTE_ARCHIVE, _ FTP_TRANSFER_TYPE_UNKNOWN, 0&) lRes = InternetCloseHandle(hConnect) lRes = InternetCloseHandle(hInternet)
To get a better understanding of what is happening, let’s take a closer look at each function.
The first function to be called is the InternetOpen function. This initializes the internal state of the WinInet API. The declaration of the InternetOpen method is:
Public Declare Function InternetOpen Lib “wininet.dll” _
Alias "InternetOpenA" _ (ByVal lpszAgent As String, _ ByVal dwAccessType As Long, _ ByVal lpszProxyName As String, _ ByVal lpszProxyBypass As String, _ ByVal dwFlags As Long) As Long
The following table describes each of the parameters.
|lpszAgent||Sets the user agent string that is passed to the server during each call.|
|dwAccessType||Determines what access will be used, either direct connection or through a proxy.|
|lpszProxyName||Lists the names of the proxy servers to use.|
|lpszProxyBypass||Lists the names of clients that should not use a proxy server.|
|dwFlags||Flags for setting asynchronous requests and caching support.|
Table 1: Parameters for the InternetOpen function
InternetOpen returns a handle that is used in subsequent calls into the WinInet API. You will only have to call this function once and store the handle in a variable.
After initializing the WinInet DLL, you must retrieve a handle to an FTP session. This is accomplished using the InternetConnect function. The handle that you receive will be used in all of the subsequent calls to manipulate files and directories and navigate through the FTP site. The InternetConnect function is passed connection information like the site you are connecting to and the user’s name and password. In addition, the type of connection is specified. In the following case we are opening a FTP session:
hConnect = InternetConnect(hInternet, "ftp.Microsoft.com", INTERNET_DEFAULT_FTP_PORT, _ sUserName, sPassword, INTERNET_SERVICE_FTP, _ INTERNET_FLAG_EXISTING_CONNECT Or INTERNET_FLAG_PASSIVE, &H0)
With the connection handle you can start manipulating file and directories on the FTP site.
The WinInet API exposes several functions that allow you to manipulate files and directories and to navigate through a FTP site. The following table lists all of the functions.
|FtpCreateDirectory||Creates a new directory on the FTP site|
|FtpGetCurrentDirectory||Retrieves the current directory|
|FtpRemoveDirectory||Deletes a directory and all sub items from the FTP site|
|FtpSetCurrentDirectory||Changes the current directory|
|FtpDeleteFile||Deletes a file from the FTP site|
|FtpFindFirstFile||Searches the current directory of a FTP site for files and subdirectories|
|FtpGetFile||Downloads a file from a FTP site to the local machine|
|FtpGetFileSize||Retrieves the size of a file from the FTP site|
|FtpOpenFile||Opens a handle to a file on the FTP for reading and writing|
|FtpPutFile||Uploads a file to the FTP site|
|FtpRenameFile||Renames a file on the FTP site|
|FtpCommand||Provides an interface for sending FTP commands to the FTP server|
Table 2: FTP functions within the WinInet API
All of these functions take a handle to an Internet connection and specific information on the file or directory to manipulate. All of the declarations for these functions can be found in the WinInetAPI.bas file in the source code.
WinInet FTP Class
As with most APIs it is often easier to think about and work with the API if it is wrapped in a class module. The accompanying source code contains one class module that exposes the FTP functionality of the WinInet API. By encapsulating the functionality within a class module, most of the details of the underlying API can be removed from client application. To demonstrate this, we will download the same ls-lr.zip from Microsoft’s FTP site:
Dim oFTP As New clsFTP oFTP.OpenConnection "ftp.Microsoft.com", "", "", "" oFTP.DownloadFile "ls-lr.zip", "C:" oFTP.CloseConnection Set oFTP = Nothing
The class can be used to perform most interactions with an FTP site such as navigating through the directory structure, enumerating files and directories, and manipulating the file and directories. You can download the code by clicking here.
Limitations of WinInet
The WinInet API was not designed to scale for high-stress, high-volume server environments. It was designed to provide FTP, HTTP, and Gopher functionality for Internet Explorer. Because it was designed as a client application, the uses registry values contained in the HKEY_CURRENT_USER hive are not available if you are running the WinInet API from NT services such as IIS. In addition, the WinInet API limits the number of concurrent connections to a single server to just two connections. This is in agreement with the HTTP specification. To accomplish networking tasks on a server you will need to use the WinSock API or third party components that were designed for this task.
The future Is VB.NET
One of the main goals behind the .NET initiative is to provide a common platform that all programming languages can use to develop enterprise applications. To accomplish this, Microsoft has developed a framework that all applications can use. The framework is organized into namespaces and one of the namespaces is System.Net. This namespace contains a set of classes that allow you to add networking to your applications.
The System.Net namespace is divided into three layers of abstraction. At the highest level is the request and response layer. This provides developers with a simple mechanism for requesting and receiving data from an Internet site. Below the request and response layer is the application protocols level. This level consists of HTTP, TCP, and UDP classes for directly working with these protocols. Lastly, there is the transport layer, which provides access to the windows sockets.
FTP support was not added to the Beta 1 for Visual Studio .NET, but the following example will show how you can use the System.Net classes to make a Web request using the request/response layer:
Imports System.NetDim oWebRequest As WebRequestDim oWebResponse As WebResponseDim oStreamReader As StreamReaderDim Buffer(1024) As CharDim BytesRead As IntegerDim Length As Integer = 1024oWebRequest = WebRequestFactory.Create( _"http://www.goamerica.net/index.html")oWebResponse = oWebRequest.GetResponse()oStreamReader = new StreamReader(oWebRequest.GetResponseStream(), _Encoding.ASCII)Bytesread = oStreamReader.Read(Buffer, 0, Length)Do While (BytesRead > 0) Console.Write(Buffer, 0, BytesRead) BytesRead = oStreamReader.Read(Buffer, 0 , Length)LoopoStreamReader.Close
As you can see, the .NET framework provides a very simple interface for Web-enabling your applications. Beyond this, the .NET framework removes the need for making calls to many of the other APIs in Windows by providing most of the functionality in class structures. The main difference between System.Net namespace and the WinInet API is that the .NET classes are designed to work in a high-stress environment so you can use them in all your applications.