[VBInet]

An internet client project

Sunday, Novermber 5, 2000

VBInet is an unfinished VB6 project. It provides FTP client functionality for applications. I don't work on it anymore, but it is being continued in .NET (it's the first project that I have seriously ported, using the upgrade wizard, and spending another couple of days on it to get it running).

Since the project is available for download at this site, I though I might as well write a bit about it.

Concepts

We're talking about a single-threaded ActiveX DLL here. Everything is based on the Windows internet API. I've restricted my efforts on synchronous operations only, for the known threading issues that come up in classic VB.

You'll find many constants from the API in there, even if they're not needed. This can save you some typing if you want to write your own internet client stuff. Many constants live in enums (while that doesn't add any type safety, you can use IntelliSense to your advantage).

There is an object model arround the remote file system, mainly a CFtpFolder and a CFtpFile class (along with collections). Otherwise, you can define connection using CFtpServer objects. The actual connection info is provided by CUrl objects. There's a singleton root object called InetConnection (exposed as a property in a MultiUse class).

Last but not least, there a caching mechanism that stores remote file system info, as well as general connection information, in an XML files for offline viewing. This functionality is availably via the CInetConnection class.

Details

The CInetConnection class lets you access the FTP servers collection, register a callback interface, perform some general methods (like checking online status or attempting a connection to the internet), or show a dialog for entering general connection info (such as proxy information). You can also fire a dialog that lets the user define connections to an FTP site (which will be persisted via XML). Mainly, CInetConnection encapsulates the root internet handle for the client application (you can call methods such as Connect, but note that this will be done automatically by sub objects as needed; there is a usage counting mechanism). Because the overall object model uses many circular references, you need to clean up when the library's functionality is no longer needed (call the Dispose method).

CFtpServer defines a connection to an FTP site, with information such as a friendly name, a description, and connection info (provided by the CUrl class). It has methods that establish an FTP connection (which, again, need not be called explicitly; but if you call them, you need to disconnect later). The initial remote directory (as specified by the path parameter of the accompanying URL) is accessible as an CFtpFolder via the RootFolder property.

The CUrl class lets you parse a URL string. It will also translate internet shortcuts (these are the *.url files used for Internet Explorer's favorites) of any type (not just FTP); but you can also provide the individual components of a URL. In addition to a standard URL, this class allows you to name additional users (see the CUser class) per instance - this is handy when several users connect to the same FTP server, allowing for some normalization of the connection data. The CUrl class provides a logon dialog that shows the user names. It's possible to persists user info via XML (note that passwords are not encrypted). The CUrl can be used without the other classes as well.

Once one or more FTP servers have been set up, you call the Update method on the RootFolder of the respective server object. This will enable the appropriate connections. You'll be notified if you implement the IStatusCallback interface. Every folder has an NFtpFolders collection for subdirectories, and an NFtpFiles collecion for files. Items are listed in alphabetical order, but that's up to the remote host. You can upload files using the PutFile method; for downloads, use the GetFile method of the CFtpFile class.

Internals

The DLL uses a single callback function. It would have been possible to use different callback functions for different operations, but with the object-oriented approach I've taken, the main challenge is to map callback to the objects that an operations is performed on; therefore, simply using different callback functions is not a solution.

At first, I thought I might use the dwContext parameter (passing back application-defined data) in a bitwise fashion, faking bit shifting using multiplication and division, or even CopyMemory. However, this approach turned out to be too limited for storing all the information needed.

So I created the CContext class, which holds references to the CFtpServer, CFtpFolder, and CFtpFile objects involved in an operation, as well an ID for the kind of operation performed. I could have hacked and converted the reference to the CContext object to a raw pointer using the ObjPtr function, but that would have been unnecessarily dangerous. So all CContext instances are stored in a collecion, and a context ID (a Long) is used a as a key. The context ID is passed to the API, which returns it with the callback function, allowing the library to retrieve the CContext object. Here's the callback function:

Sub InetStatusCallback(ByVal hInet As Long, _
                       ByVal dwContext As Long, _
                       ByVal dwInternetStatus As InternetStates, _
                       ByVal lpvStatusInfo As Long, _
                       ByVal dwStatusInfoLength As Long)
On Error GoTo hell
    ' create info object
    Dim status As New CStatusInfo, ctxt As CContext
    Set ctxt = InetConnection.Contexts.Item(dwContext)
    status.Create hInet, ctxt, dwInternetStatus, _
                  lpvStatusInfo, dwStatusInfoLength
    ' call internet connection (will pass it on)
    InetConnection.InetStatusCallback status
    Exit Sub
hell:
End Sub

The singleton CInetConnection instance will call the server in question, which will in turn forward the call to the right CFtpFolder and CFtpFile instances. The context information is also available from the CStatusInfo class, which is passed to the IStatusCallback interface's methods.

State of the project: Missing features

You can observe the functionality discussed above in the test project that comes with the download: It works OK (like a Beta, I'd say). Of course, there's more to an FTP client. These are the most glaring ommissions: