Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

FTP file using INET control

Status
Not open for further replies.

jadams0173

Technical User
Feb 18, 2005
1,210
I'm using the INET control to FTP a zip ranging in size from 5K to 5MB(CAD drawings). The FTP works on the small files I've tried but after reading some posts here, I am curious to know if this method is reliable and acceptable. One post by Strongm suggested the State Change event could have some issues so I didn't use it. That said is there a way to show the progress of the upload? I won't be doing any download at this time(unless thats what is need to verify the file upload). Also can you tell the INET to upload in binary? I'll post back when the threads I've read and the code I'm using in just a bit.
 
Here is some of the threads I've read through:
thread222-1383045 which links to this thread222-1126722 and this thread708-970319

This makes me wonder if the INET is the way to use it based on Bob's last post thread222-1373125

I can't find the one where Strongm references the state change event. Here is how I'm currectly uploading the file.

Code:
Function FTPFile() As Boolean

Set INET2 = CreateObject("InetCtls.Inet")

With INET2
    .URL = "ftp://ftp.xxxx.com/"
    .UserName = "xxxxxx"
    .Password = "xxxxxxxx"
    .Execute , "CD htdocs/work"
    FinishCmd
    
    'PUT path to file to upload file name after upload
    .Execute "", "PUT " & FileNameAndPath & " " & FileNameOnly
    
    FinishCmd
End With
    INET2.Execute , "CLOSE"
    
Set INET2 = Nothing

End Function
Public Sub FinishCmd()
    Do While INET2.StillExecuting
        DoEvents
    Loop
End Sub



How can I verify the upload was ok?
 
I've used it successfully for small files. I ran into a problem with multi-megabyte files - it never finished the download. I'm now doing it in vb.net and don't have any problems.

To verify the upload, you can do a size command, then compare the file size with your local file. You will need to use the GetChunk routine to retrieve the size.

Also, the inet control only works in binary mode.




"I think we're all Bozos on this bus!" - Firesign Theatre [jester]
 
Thanks ArtieChoke for the info. I'm also having issues with a space in the path.

ex.

.Execute "", "PUT C:\Temp\My File\name.txt Name.txt" doesn't work.

I've tried replacing the space with %20 and that doesn't work. If I remove the space between My and file it works?

I'm currently looking to use the code in bobrodes post in thread708-970319 but keep getting an error returned from err.lastdll.
 
Yep, spaces in the path don't work, since a space is the separator between the command and file name, so it gets confused. I've never had any luck with spaces in the file path.

"I think we're all Bozos on this bus!" - Firesign Theatre [jester]
 
Here's a class I wrote to do ftp using the inet control. I used a timer because sometimes the control wouldn't recognize a timeout or other failure and just hang.

Code:
Dim curFile As Integer
Dim errors As Boolean
Dim ftpFiles(3000) As String
Dim numFtpFiles As Integer
Dim outFile As Integer
Dim inboundDir As String
Dim outboundDir As String
Dim outFileName As String
Dim sizeData As String
Dim startTime As Long
Dim system As dirTypes
Dim timeoutMinutes As Integer

'   Number of minutes to kill program if it runs this long

Const ProgramTimeout = 10

Enum ftpStates
    ftpCD
    ftpClose
    ftpConnect
    ftpDelete
    FTPDir
    ftpGet
    ftpPut
    ftpSize
End Enum

'   These values determine how to parse off file names from the different system's
directories

Enum dirTypes
    dirUNIX = 1
    dirWindows
End Enum

Private ftpIsConnected As Boolean
Private ftpState As Integer
Private ftpError As Boolean
Private WithEvents inetFTP As Inet
Attribute inetFTP.VB_VarHelpID = -1
Private WithEvents timClock As VB.Timer
Attribute timClock.VB_VarHelpID = -1

'************************************************************************
'   Properties
'************************************************************************

Property Get fileSize() As Long

    If sizeData <> "" Then
        fileSize = CLng(sizeData)
    Else
        fileSize = -1
    End If
    
End Property

Property Let FTPSystem(sys As dirTypes)

    system = sys
    
End Property

Property Let InboundDirectory(doh As String)

    inboundDir = doh
    If Right(inboundDir, 1) <> "\" Then inboundDir = inboundDir + "\"
    
End Property

Property Get NextFile() As String

    If curFile + 1 > numFtpFiles Then
        NextFile = ""
    Else
        curFile = curFile + 1
        NextFile = ftpFiles(curFile)
    End If

End Property

Property Let OutboundDirectory(doh As String)

    outboundDir = doh
    If Right(outboundDir, 1) <> "\" Then outboundDir = outboundDir + "\"

End Property

Property Get UNIX()

    UNIX = dirUNIX
    
End Property

'************************************************************************
'   Public routines
'************************************************************************

Public Function Connected() As Boolean

    Connected = ftpIsConnected
    
End Function

Public Function DoFTPCD(cdDir As String) As Integer

    DoFTPCD = DoFTPCommand("cd " + cdDir, ftpCD)

End Function

Public Function DoFTPClose() As Integer

    DoFTPClose = DoFTPCommand("close", ftpClose)
    ftpIsConnected = False

End Function

Public Function DoFTPDelete(fname As String) As Integer

    DoFTPDelete = DoFTPCommand("delete " + fname, ftpCD)

End Function

Public Function DoFTPDir(Optional mask As String = "*.*") As Integer

'   Retrieve all files (no directories) in the current directory
'   No path information is included

    DoFTPDir = DoFTPCommand("dir " + mask, FTPDir)
    curFile = 0

End Function

Public Function DoFTPGet(fname As String) As Integer

    DoFTPGet = DoFTPCommand("get " + fname + " " + inboundDir + fname, ftpGet)

End Function

Public Function DoFTPPut(fname As String) As Integer

    DoFTPPut = DoFTPCommand("put " + outboundDir + fname + " " + fname, ftpPut)

End Function

Public Function InitFTP(net As Inet, tc As VB.Timer, url As String, userid As String,
_
password As String, Optional numRetries As Integer = 3, Optional retryTime = 30, _
Optional timeout As Integer = ProgramTimeout) As Integer

'   Uses the internet transfer control to ftp files

    Dim i As Integer
    Dim fname As String
    Dim t As Long
    
    On Error Resume Next
    
    errors = False
    system = dirUNIX
    InitFTP = -1
    Set inetFTP = net
    Set timClock = tc
    
'   Initialize the timer

    timeoutMinutes = timeout
    timClock.Enabled = False
    timClock.Interval = 60000

'   Connect to the ftp site
'   Timeout is in seconds

    inetFTP.Protocol = icFTP
    inetFTP.RequestTimeout = 60
    inetFTP.url = url
    inetFTP.UserName = userid
    inetFTP.password = password
    
'   Try up to numRetries times to get a connection
'   Delay a user-defined interval in seconds between retries, since a connection failure
'   may return immediately rather than be timed-out

    On Error Resume Next
    For i = 1 To numRetries
        DoFTPCommand "", ftpConnect
        If Err.Number <> 0 Then
            If Err.Number = icTimeout Or Err.Number = icConnectFailed Then
                
'   Cancel the command and delay

                t = Timer
                Do While Timer < t + retryTime
                    DoEvents
                Loop
            Else
                Err.Raise Err.Number, , Err.Description
                Exit Function
            End If
        Else
            Exit For
        End If
    Next
    If Err.Number = icTimeout Or Err.Number = icConnectFailed Then
        Err.Raise Err.Number, , Err.Description + vbNewLine + "On retry number " +
CStr(i) + _
        " with an interval of " + CStr(retryTime) + " seconds"
        Exit Function
    End If
    InitFTP = 0
    ftpIsConnected = True

End Function

Public Sub Ping(url As String)

'   Ping the ftp site
'   Just start a command with a ping an wait a few seconds for it to finish

    Shell "ping " + url, vbMinimizedNoFocus
    startTime = Timer
    Do While Timer < startTime + 5
        DoEvents
    Loop

End Sub

'************************************************************************
'   Control events
'************************************************************************

Private Sub timClock_Timer()

'   Kill program if it runs too long
    
    If Timer > startTime + timeoutMinutes * 60 Then
        timClock.Interval = 0
        ftpError = True
        Exit Sub
    End If

End Sub

'************************************************************************
'   Private routines
'************************************************************************

Function DoFTPCommand(Command As String, mode As ftpStates) As Integer

'   Do the ftp command and set the mode for processing
'   Allow for testing without being connected - ftp commands will just be ignored

    If Not ftpIsConnected And mode <> ftpConnect Then
        DoFTPCommand = 0
        Exit Function
    End If

    On Error Resume Next

'   Set a timer to cancel program if it gets hung up except on connect, which has
'   it's own time-out
'   ALWAYS enabling timer - program has been hanging...

'    If mode <> ftpConnect Then timClock.Enabled = True
    timClock.Enabled = True
    startTime = Timer

    ftpError = False
    ftpState = mode
    inetFTP.Execute , Command
    While inetFTP.StillExecuting And Not ftpError
         DoEvents
    Wend
    timClock.Enabled = False
    
    If (inetFTP.ResponseCode <> 18 And inetFTP.ResponseCode <> 0) Or ftpError Or Err.Number
<> 0 Then
    
'   An error occurred during the command, get from server

        If inetFTP.ResponseCode <> 18 And inetFTP.ResponseCode <> 0 Then
            Err.Raise inetFTP.ResponseCode, "DoFTPCommand", inetFTP.ResponseInfo
        ElseIf Err.Number = 0 Then
            Err.Raise 9999, "DoFTPCommand", "Unknown error or time-out during FTP
command"
        End If
        DoFTPCommand = -1
    Else
        FTPComplete
        DoFTPCommand = 0
    End If
    
End Function

Public Sub FTPComplete()

    Dim tmpData As Variant
    Dim dirData As String
    Dim strEntry As String
    Dim i As Long
    Dim k As Long
    Dim s As Long
    Dim doh As String

    On Error Resume Next
    Select Case ftpState
        Case FTPDir:
            dirData = ""
            Do
                tmpData = inetFTP.GetChunk(4096, icString)
                If Len(tmpData) = 0 Then Exit Do
                DoEvents
                dirData = dirData + tmpData
            Loop
            numFtpFiles = 0
            
            If dirData <> "" Then
                Select Case system
                    Case dirUNIX
                        For i = 1 To Len(dirData) - 1
                             k = InStr(i, dirData, vbCrLf)        ' We don't want
CRLF
                             strEntry = Mid(dirData, i, k - i)
                             If Right(strEntry, 1) = "/" And Trim(strEntry) <> ""
Then
                                numFtpFiles = numFtpFiles + 1
                                ftpFiles(numFtpFiles) = strEntry
                             End If
                             i = k + 1
                             DoEvents
                        Next i
                    Case dirWindows
                        For i = 1 To Len(dirData) - 1
                             k = InStr(i, dirData, vbCrLf)        ' We don't want
CRLF
                             strEntry = Mid(dirData, i, k - i)
                             If Trim(strEntry) <> "" Then
                                numFtpFiles = numFtpFiles + 1
                                ftpFiles(numFtpFiles) = strEntry
                             End If
                             i = k + 1
                             DoEvents
                        Next i
                End Select
            End If
        Case ftpSize:

'   Return the file size

            tmpData = inetFTP.GetChunk(1024, icString)
            sizeData = ""
            If Len(tmpData) > 0 Then sizeData = tmpData
    End Select

End Sub

Sub GetFileList(path As String, ext As String, files() As String, nfiles As Integer)

'   Get a list of files from a directory without the extension

    Dim fname As String, cpos As Integer

    nfiles = 0
    fname = Dir(path + "*." + ext)
    Do While fname <> ""
        nfiles = nfiles + 1
        files(nfiles) = fname
        fname = Dir
    Loop

End Sub

"I think we're all Bozos on this bus!" - Firesign Theatre [jester]
 
Thanks for the code ArtieChoke. I give it a try! :)
 
My first thought is piffle!

I think a lot of people try to fight VB too hard, and the communication components (Winsock, Inet, MSComm controls) in particular. Most of the headaches come from trying to do asynchronous operations... synchronously.

The use of DoEvents() with these components is always suspicious.


One thing to be watchful for is that HTTP and FTP transfers can time out or terminate early. You can fiddle with the timeouts or watch for them externally.

People also get tangled up trying to chain operations with FTP. Calling Inet.Execute inside of the StateChanged handler is generally doomed to failure. I suspect this is another place where people go badly wrong.

For that matter there seems to be an unhealthy distrust of VB's Timer control. Go figure!


Here's an example that shows one way to chain FTP operations using Inet.Execute FTP DIR Inet.zip. It's a bit clumsy to include here as inline code.

This example simply logs on, changes the directory, does a DIR and displays the results, and CLOSEs the FTP session. It would be easy to have it perform a series of uploads or downloads with minor alterations. You just enter the host, user, PW, and directory and click "Get Dir" and it performs the steps listed above in sequence.

It was a quick demo so it may have warts, but it illustrates the basic idea.
 
Thanks for the code on the inet control. I have decided to use the WinInet.dll in BobRodes' post in thread thread708-970319

A little research also landed me the calls to change the directory on the ftp server along with all the other methods that are associated with the WinInet.dll.

Here is the site that was most helpful to me with WinInet.dll


 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top