dba key graphicdatabase advisors graphic
Beetle to Home

How to create an FTP client within Access

By William Hindman,Darren Dick, and Jim Lawrence


Demo File: How to create an FTP client within Access download sample MDB file   Print this Page

 

Demo file, How to create an FTP client within Access download

 

This application includes a number of very interesting components via a Common File Dialog:

 

  • Selecting a file from directories
  • Opening folders
  • Hiding Windows
  • Playing sounds
  • Using the FTP client

 

The one key module that will be discussed in this article is the Class exposing the FTP client.

 

To use a FTP client you’ll need a good understanding of the API functions within the ‘wininet.dll’. This DLL is a very important program and many Microsoft key applications are designed around it. Without it, programs like Outlook, Internet Explorer, and FTP would not function.

 

Here is a class module created to expose these features. First the declaration section:

 

 

Option Compare Database

Option Explicit

 

'''''''''''''''''''''''''''''''

'Member Variables

'''''''''''''''''''''''''''''''

Private m_ProxyName     As String

Private m_RemoteDir     As String

Private m_RemoteFile    As String

Private m_NewFileName   As String

Private m_LocalFile     As String

Private m_ServerName    As String

Private m_UserName      As String

Private m_Password      As String

Private m_TransferType  As Long

Private m_FileSpec      As String

'

'''''''''''''''''''''''''''''''

'Collections

'''''''''''''''''''''''''''''''

Public FileNames As New Collection

'

'''''''''''''''''''''''''''''''

'Private Variables

'''''''''''''''''''''''''''''''

Private m_hFTP As Long  'Handle to the FTP session

Private m_hCon As Long  'Handle to the server connection

'

'''''''''''''''''''''''''''''''

'Private Constants

'''''''''''''''''''''''''''''''

Private Const mc_AGENTNAME = "FTP Class"

'

'''''''''''''''''''''''''''''''

'Error values (See the RaiseError routine)

'''''''''''''''''''''''''''''''

Private Const errOpenFTP      As String = "1;Call to InternetOpen failed."

Private Const errOpenCon      As String = "2;Call to InternetConnect failed."

Private Const errGetFile      As String = "3;Call to FtpGetFile failed. (FILE NOT PRESENT IN DIRECTORY)"

Private Const errPutFile      As String = "4;Call to FtpPutFile failed."

Private Const errDelFile      As String = "5;Call to FtpDeleteFile failed."

Private Const errRenFile      As String = "6;Call to FtpRenameFile failed."

Private Const errGetDir       As String = "7;Call to FtpGetCurrentDirectory failed."

Private Const errSetDir       As String = "8;Call to FtpSetCurrentDirectory failed." & vbCrLf & "(FILE NOT FOUND IN REMOTE DIRECTORY - or REMOTE DIRECTORY DOES NOT EXIST)"

Private Const errCreateDir    As String = "9;Call to FtpCreateDirectory failed."

Private Const errFindFirst    As String = "10;Call to FtpFindFirstFile failed."

Private Const errFindNext     As String = "11;Call to InternetFindNextFile failed."

Private Const errDelDir       As String = "12;Call to FtpRemoveDirectory failed."

Private Const errNotOpen      As String = "13;FTP session not open. Call OpenFTP first."

Private Const errNotConnected As String = "14;Not connected to a server. Call OpenServer first."

Private Const errNoServer     As String = "15;No Server Name specified."

Private Const errNoLocalFile  As String = "16;No Local File specified."

Private Const errNoRemoteFile As String = "17;No Remote File specified."

'

'''''''''''''''''''''''''''''''

'API Declarations

'''''''''''''''''''''''''''''''

Private Const MAX_PATH = &H104

'

Private Const INTERNET_INVALID_PORT_NUMBER = &H0

Private Const INTERNET_SERVICE_FTP = &H1

Private Const INTERNET_OPEN_TYPE_DIRECT = &H1

Private Const INTERNET_OPEN_TYPE_PROXY = &H3

Private Const INTERNET_FLAG_RELOAD = &H80000000

Private Const INTERNET_FLAG_PASSIVE = &H8000000

'

Private Const FTP_TRANSFER_TYPE_ASCII = &H0

Private Const FTP_TRANSFER_TYPE_BINARY = &H1

'

Private Const NO_ERROR = &H0

Private Const ERROR_NO_MORE_FILES = &H12

Private Const ERROR_INTERNET_EXTENDED_ERROR = &H2EE3

'

Private Type FILETIME

    dwLowDateTime  As Long

    dwHighDateTime As Long

End Type

'

Private Type WIN32_FIND_DATA

    dwFileAttributes As Long

    ftCreationTime   As FILETIME

    ftLastAccessTime As FILETIME

    ftLastWriteTime  As FILETIME

    nFileSizeHigh    As Long

    nFileSizeLow     As Long

    dwReserved0      As Long

    dwReserved1      As Long

    cFileName        As String * MAX_PATH

    cAlternate       As String * 14

End Type

'

Private Declare Function FtpCreateDirectory Lib "wininet.dll" _

    Alias "FtpCreateDirectoryA" (ByVal hFtpSession As Long, ByVal lpszDirectory As String) As Boolean

   

Private Declare Function FtpDeleteFile Lib "wininet.dll" _

    Alias "FtpDeleteFileA" (ByVal hFtpSession As Long, ByVal lpszFileName As String) As Boolean

   

Private Declare Function FtpFindFirstFile Lib "wininet.dll" Alias "FtpFindFirstFileA" _

    (ByVal hFtpSession As Long, ByVal lpszSearchFile As String, _

    lpFindFileData As WIN32_FIND_DATA, ByVal dwFlags As Long, ByVal dwContent As Long) As Long

   

Private Declare Function FtpGetCurrentDirectory Lib "wininet.dll" Alias "FtpGetCurrentDirectoryA" _

    (ByVal hFtpSession As Long, ByVal lpszBuffer As String, lpdwBufferLength As Long) As Boolean

   

Private 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

   

Private 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

   

Private Declare Function FtpRemoveDirectory Lib "wininet.dll" _

    Alias "FtpRemoveDirectoryA" (ByVal hFtpSession As Long, ByVal lpszDirectory As String) As Boolean

   

Private Declare Function FtpRenameFile Lib "wininet.dll" Alias "FtpRenameFileA" _

    (ByVal hFtpSession As Long, ByVal lpszExistFile As String, ByVal lpszNewFile As String) As Boolean

   

Private Declare Function FtpSetCurrentDirectory Lib "wininet.dll" Alias "FtpSetCurrentDirectoryA" _

    (ByVal hFtpSession As Long, ByVal lpszDirectory As String) As Boolean

 

Private Declare Function InternetCloseHandle Lib "wininet.dll" _

    (ByVal hInet As Long) As Integer

 

Private 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

 

Private Declare Function InternetFindNextFile Lib "wininet.dll" Alias "InternetFindNextFileA" _

    (ByVal hFind As Long, lpvFindData As WIN32_FIND_DATA) As Long

 

Private Declare Function InternetGetLastResponseInfo Lib "wininet.dll" Alias "InternetGetLastResponseInfoA" _

    (lpdwError As Long, ByVal lpszBuffer As String, lpdwBufferLength As Long) As Boolean

 

Private 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

 

A staggering array of features is exposed within the previous declaration section. These features give the class the capabilities to do the following:

 

  • Attach to a remote FTP server
  • Add and delete
  • Navigate through the directories
  • Get, put and delete files

 

To set up the Class the private and public properties must be created. The Private Properties are only accessible within the class and the Public properties can be accessed externally. The Let properties can acquire information and the Get properties can receive and store information.

 

There is a Let/Get property for each of the FTP client requirements: Server name, username, password, type of access, type of transfer, and names of files to send or receive.

 

 

'''''''''''''''''''''''''''''''

'Properties

'''''''''''''''''''''''''''''''

Public Property Get ProxyName() As String

   

    ProxyName = m_ProxyName

 

End Property

 

Public Property Let ProxyName(NewData As String)

   

    m_ProxyName = NewData

 

End Property

 

Public Property Get RemoteDir() As String

   

    RemoteDir = m_RemoteDir

 

End Property

 

Public Property Let RemoteDir(NewData As String)

   

    m_RemoteDir = NewData

 

End Property

 

Public Property Get RemoteFile() As String

   

    RemoteFile = m_RemoteFile

 

End Property

 

 

 

Public Property Let RemoteFile(NewData As String)

   

    m_RemoteFile = NewData

 

End Property

 

Public Property Get LocalFile() As String

   

    LocalFile = m_LocalFile

 

End Property

 

Public Property Let LocalFile(NewData As String)

   

    m_LocalFile = NewData

 

End Property

 

Public Property Let NewFileName(NewData As String)

   

    m_NewFileName = NewData

 

End Property

 

Public Property Get ServerName() As String

   

    ServerName = m_ServerName

 

End Property

 

Public Property Let ServerName(NewData As String)

   

    m_ServerName = NewData

 

End Property

 

Public Property Get UserName() As String

   

    UserName = m_UserName

 

End Property

 

Public Property Let UserName(NewData As String)

   

    m_UserName = NewData

 

End Property

 

Public Property Get PASSWORD() As String

   

    PASSWORD = m_Password

 

End Property

 

 

Public Property Let PASSWORD(NewData As String)

   

    m_Password = NewData

 

End Property

 

Public Property Get TransferType() As String

   

    TransferType = IIf(m_TransferType = FTP_TRANSFER_TYPE_BINARY, "BINARY", "ASCII")

 

End Property

 

Public Property Let TransferType(NewData As String)

   

    m_TransferType = IIf(UCase(Left(NewData, 3)) = "BIN", FTP_TRANSFER_TYPE_BINARY, FTP_TRANSFER_TYPE_ASCII)

 

End Property

 

Public Property Get FileSpec() As String

   

    FileSpec = m_FileSpec

 

End Property

 

Public Property Let FileSpec(NewData As String)

   

    m_FileSpec = NewData

 

End Property

 

 

The next section is the Class methods. These private and public functions perform most of the duties required by the Class. First the opening methods:

 

 

Private Sub Class_Initialize()

'Set property defaults

 

    m_RemoteDir = "."

    m_RemoteFile = vbNullString

    m_LocalFile = vbNullString

    m_NewFileName = vbNullString

    m_UserName = vbNullString

    m_Password = vbNullString

    m_ProxyName = vbNullString

    m_ServerName = vbNullString

    m_TransferType = FTP_TRANSFER_TYPE_BINARY

   

End Sub

 

 

Before further processing is done the Class_Initialize methods clears all the Public variables. The initialization is performed automatically when an Instant of the Class is created.

 

 

Public Sub OpenFTP(Optional pProxyName)

'Initiate FTP session

 

    'Handle optional parameters

    If Not IsMissing(pProxyName) Then m_ProxyName = pProxyName

    '

    If Len(m_ProxyName) Then

        m_hFTP = InternetOpen(mc_AGENTNAME, INTERNET_OPEN_TYPE_PROXY, _

            m_ProxyName, vbNullString, 0)

    Else

        m_hFTP = InternetOpen(mc_AGENTNAME, INTERNET_OPEN_TYPE_DIRECT, _

            vbNullString, vbNullString, 0)

    End If

   

    If m_hFTP = 0 Then RaiseError errOpenFTP

 

End Sub

 

 

If Proxy settings are used the information can either be set or retrieved from the Properties.

 

 

Public Sub OpenServer(Optional pServerName, Optional pUserName, Optional pPassword)

    'Establish connection to server

 

    'If FTP session not initiated

    If m_hFTP = 0 Then RaiseError errNotOpen

    '

    'Handle optional parameters

    If Not IsMissing(pServerName) Then m_ServerName = pServerName

    If Not IsMissing(pUserName) Then m_UserName = pUserName

    If Not IsMissing(pPassword) Then m_Password = pPassword

    '

    'Handle empty properties

    If Len(m_ServerName) = 0 Then RaiseError errNoServer

    '

    'The following are translated to:

    '  UserName: Anonymous

    '  Password: default email address

    'by the API, if nulls passed

    If Len(m_UserName) = 0 Then m_UserName = vbNullString

    If Len(m_Password) = 0 Then m_Password = vbNullString

    '

    m_hCon = InternetConnect(m_hFTP, m_ServerName, INTERNET_INVALID_PORT_NUMBER, m_UserName, m_Password, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0)

   

    If m_hCon = 0 Then RaiseError errOpenCon

   

End Sub

 

 

The above code checks that all the required parameters are provided or have been set previously so a connection to the FTP server can be made.

 

 

Public Sub OpenServer(Optional pServerName, Optional pUserName, Optional pPassword)

    'Establish connection to server

 

    'If FTP session not initiated

    If m_hFTP = 0 Then RaiseError errNotOpen

    '

    'Handle optional parameters

    If Not IsMissing(pServerName) Then m_ServerName = pServerName

    If Not IsMissing(pUserName) Then m_UserName = pUserName

    If Not IsMissing(pPassword) Then m_Password = pPassword

    '

    'Handle empty properties

    If Len(m_ServerName) = 0 Then RaiseError errNoServer

    '

    'The following are translated to:

    '  UserName: Anonymous

    '  Password: default email address

    'by the API, if nulls passed

    If Len(m_UserName) = 0 Then m_UserName = vbNullString

    If Len(m_Password) = 0 Then m_Password = vbNullString

    '

    m_hCon = InternetConnect(m_hFTP, m_ServerName, INTERNET_INVALID_PORT_NUMBER, m_UserName, m_Password, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0)

   

    If m_hCon = 0 Then RaiseError errOpenCon

   

End Sub

 

 

The above Method uses the standard set of Properties to access the FTP server. If an error is not raised to the caller, routine processing continues.

 

Below is a standard set of Methods for handling files. They get, put, rename and delete files from the FTP server:

 

 

Public Sub GetFile(Optional pRemoteDir, Optional pRemoteFile, _

                   Optional pLocalFile, Optional pTransferType)

    'Retrieve a file from server

    'pTransferType accepts "ASCII" or "BINARY"

 

    'Bail out if server connection not established

    If m_hCon = 0 Then RaiseError errNotConnected

    '

    'Handle optional parameters

    If Not IsMissing(pRemoteDir) Then m_RemoteDir = pRemoteDir

    If Not IsMissing(pRemoteFile) Then m_RemoteFile = pRemoteFile

    If Not IsMissing(pLocalFile) Then m_LocalFile = pLocalFile                                        

    If Not IsMissing(pTransferType) Then Me.TransferType = pTransferType

    '

    'Handle empty properties

    If Len(m_RemoteDir) = 0 Then m_RemoteDir = "."

    If Len(m_RemoteFile) = 0 Then RaiseError errNoRemoteFile

    If Len(m_LocalFile) = 0 Then RaiseError errNoLocalFile

    If Len(m_TransferType) = 0 Then Me.TransferType = "BINARY"

    '

    'Change directory on server

    Me.SetDir m_RemoteDir

    '

    If FtpGetFile(m_hCon, m_RemoteFile, m_LocalFile, False, _

      INTERNET_FLAG_RELOAD, m_TransferType, 0) = False Then

       

        RaiseError errGetFile

   

    End If

       

End Sub

 

Public Sub PutFile(Optional pRemoteDir, Optional pRemoteFile, _

                   Optional pLocalFile, Optional pTransferType)

 

    'Transmit a file to server

    'pTransferType accepts "ASCII" or "BINARY"

 

    'Bail out if server connection not established

    If m_hCon = 0 Then RaiseError errNotConnected

    '

    'Handle optional parameters

    If Not IsMissing(pRemoteDir) Then m_RemoteDir = pRemoteDir

    If Not IsMissing(pRemoteFile) Then m_RemoteFile = pRemoteFile

    If Not IsMissing(pLocalFile) Then m_LocalFile = pLocalFile

    If Not IsMissing(pTransferType) Then Me.TransferType = pTransferType

    '

    'Handle empty properties

    If Len(m_RemoteDir) = 0 Then m_RemoteDir = "."

    If Len(m_RemoteFile) = 0 Then RaiseError errNoRemoteFile

    If Len(m_LocalFile) = 0 Then RaiseError errNoLocalFile

    If Len(m_TransferType) = 0 Then Me.TransferType = "BINARY"

    '

    'Change directory on server

    Me.SetDir m_RemoteDir

    '

    If FtpPutFile(m_hCon, m_LocalFile, m_RemoteFile, m_TransferType, 0) = False Then

       

        RaiseError errPutFile

   

    End If

       

End Sub

 

Public Sub DelFile(Optional pRemoteDir, Optional pRemoteFile)

'Delete a file on server

 

    'Bail out if server connection not established

    If m_hCon = 0 Then RaiseError errNotConnected

    '

    'Handle optional parameters

    If Not IsMissing(pRemoteDir) Then m_RemoteDir = pRemoteDir

    If Not IsMissing(pRemoteFile) Then m_RemoteFile = pRemoteFile

    '

    'Handle empty properties

    If Len(m_RemoteDir) = 0 Then m_RemoteDir = "."

    If Len(m_RemoteFile) = 0 Then RaiseError errNoRemoteFile

    '

    'Change directory on server

    Me.SetDir m_RemoteDir

    '

    If FtpDeleteFile(m_hCon, m_RemoteFile) = False Then

        RaiseError errDelFile

    End If

       

End Sub

 

Public Sub RenFile(Optional pOldName, Optional pNewName)

    'Rename a file on server

 

    'Bail out if server connection not established

    If m_hCon = 0 Then RaiseError errNotConnected

    '

    'Handle optional parameters

    If Not IsMissing(pOldName) Then m_RemoteFile = pOldName

    If Not IsMissing(pNewName) Then m_NewFileName = pNewName

    '

    'Handle empty properties

    If Len(m_RemoteFile) = 0 Then RaiseError errNoRemoteFile

    If Len(m_NewFileName) = 0 Then m_NewFileName = m_RemoteFile

    '

    'Change directory on server

    Me.SetDir m_RemoteDir

    '

    If FtpRenameFile(m_hCon, m_RemoteFile, m_NewFileName) = False Then

        RaiseError errRenFile

    End If

       

End Sub

 

                                                                                                                                                                        

The next set of Methods manage the FTP server by providing navigation through the directories, acquiring and display files within those directories and allow the remote user to create and delete directories.

 

 

Public Sub CreateDir(Optional pRemoteDir)

    'Create directory on server

 

    'Bail out if server connection not established

    If m_hCon = 0 Then RaiseError errNotConnected

    '

    'Handle optional parameters

    If Not IsMissing(pRemoteDir) Then m_RemoteDir = pRemoteDir

    '

    'Handle empty properties

    If Len(m_RemoteDir) = 0 Then m_RemoteDir = "."                                            

    '

    If FtpCreateDirectory(m_hCon, m_RemoteDir) = False Then

        RaiseError errCreateDir

    End If

       

End Sub

 

Public Sub DelDir(Optional pRemoteDir)

    'Delete directory on server

 

    'Bail out if server connection not established

    If m_hCon = 0 Then RaiseError errNotConnected

    '

    'Handle optional parameters

    If Not IsMissing(pRemoteDir) Then m_RemoteDir = pRemoteDir

    '

    'Handle empty properties

    If Len(m_RemoteDir) = 0 Then m_RemoteDir = "."

    '

    If FtpRemoveDirectory(m_hCon, m_RemoteDir) = False Then

        RaiseError errDelDir

    End If

       

End Sub

 

Public Sub GetFileNames(Optional pRemoteDir, Optional pFileSpec)

    'Fill the FileNames collection with list

    'of files matching pFileSpec from server's

    'current directory

 

    Dim hFind As Long

    Dim LastErr As Long

    Dim fData As WIN32_FIND_DATA

   

    '

    'Bail out if server connection not established

    If m_hCon = 0 Then RaiseError errNotConnected

    '

    'Handle optional parameters

    If Not IsMissing(pRemoteDir) Then m_RemoteDir = pRemoteDir

    If Not IsMissing(pFileSpec) Then m_FileSpec = pFileSpec

    '

    'Handle empty properties

    If Len(m_RemoteDir) = 0 Then m_RemoteDir = "."

    If Len(m_FileSpec) = 0 Then m_FileSpec = "*.*"

    '

    'Change directory on server

    Me.SetDir m_RemoteDir

    '

    'Find first file matching FileSpec

    fData.cFileName = String(MAX_PATH, 0)

    'Obtain search handle if successful

    hFind = FtpFindFirstFile(m_hCon, m_FileSpec, fData, 0, 0)

 

 

    LastErr = Err.LastDllError

    If hFind = 0 Then

        'Bail out if reported error isn't end-of-file-list

        If LastErr <> ERROR_NO_MORE_FILES Then

            RaiseError errFindFirst

        End If

        'Must be no more files

        Exit Sub

    End If

    '

    'Reset variable for next call

    LastErr = NO_ERROR

    '

    'Add filename to the collection

    FileNames.Add Left(fData.cFileName, _

        InStr(1, fData.cFileName, vbNullChar, vbBinaryCompare) - 1)

    Do

        'Find next file matching FileSpec

        fData.cFileName = String(MAX_PATH, 0)

        If InternetFindNextFile(hFind, fData) = False Then

            LastErr = Err.LastDllError

            If LastErr = ERROR_NO_MORE_FILES Then

                'Bail out if no more files

                Exit Do

            Else

                'Must be a 'real' error

                InternetCloseHandle hFind

                RaiseError errFindNext

            End If

        Else

            'Add filename to the collection

            FileNames.Add Left(fData.cFileName, _

                InStr(1, fData.cFileName, vbNullChar, vbBinaryCompare) - 1)

       End If

    Loop

    '

    'Release the search handle

    InternetCloseHandle hFind

 

End Sub

 

Public Sub ClearFileNames()

'Clear contents of FileNames collection

 

    Dim itm As Long

    '

    With FileNames

        For itm = 1 To .Count

            .Remove 1

        Next

    End With