Link to home
Start Free TrialLog in
Avatar of spoowiz
spoowizFlag for United States of America

asked on

FtpGetFile not working.

I installed a VB program on an XP. It freezes at FtpGetFile function:

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

InternetConnect & InternetOpen are executing fine.
Help!!

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

Public Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" _
(ByVal sADB As String, ByVal lAccessType As Long, ByVal sProxyName As String, _
ByVal sProxyBypass As String, ByVal lFlags As Long) As Long
Avatar of spoowiz
spoowiz
Flag of United States of America image

ASKER

p.s. same installed program works on other XPs
we need more information :)
Avatar of [ fanpages ]
[ fanpages ]

Do calls to FtpFindFirstFile work following a successful call to InternetConnect?

Private Declare Function FtpFindFirstFile _
                         Lib "wininet.dll" _
                         Alias "FtpFindFirstFileA" _
                        (ByVal hFtpSession As Long, _
                         ByVal lpszSearchFile As String, _
                         lpFindFileData As udtWIN32_FIND_DATA, _
                         ByVal dwFlags As Long, _
                         ByVal dwContent As Long) As Long

Does your FTP server sit behind a firewall?  Do you need to access the FTP server via a Proxy Server?

Are you using an Active or Passive FTP connection?

Can you connect to the FTP server & perform the same commands using the MS-DOS Command Prompt?

BFN,

fp.

PS. Where udtWIN32_FIND_DATA is...

Private Const intMAX_PATH                               As Integer = 260

Private Type udtFILETIME
  lngLowDateTime                                         As Long
  lngHighDateTime                                        As Long
End Type

Private Type udtWIN32_FIND_DATA
  lngFileAttributes                                      As Long
  udtCreationTime                                        As udtFILETIME
  udtLastAccessTime                                      As udtFILETIME
  udtLastWriteTime                                       As udtFILETIME
  lngFileSizeHigh                                        As Long
  lngFileSizeLow                                         As Long
  lngReserved0                                           As Long
  lngReserved1                                           As Long
  strFilename                                            As String * intMAX_PATH
  strAlternate                                           As String * 14
End Type
ASKER CERTIFIED SOLUTION
Avatar of nffvrxqgrcfqvvc
nffvrxqgrcfqvvc

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
In the above depending on which file you are obtaining you need to change the dwflag to one of the following.

if it's a text file the you want ASCII
if it's a exe,zip etc.. you want BINARY
if your unsure then use UNKNOWN

Private Const FTP_TRANSFER_TYPE_UNKNOWN = &H0
Private Const FTP_TRANSFER_TYPE_ASCII = &H1
Private Const FTP_TRANSFER_TYPE_BINARY = &H2

So you would need to change the following line for different transferes.

Success = FtpGetFileA(mConn, RemoteFile, LocalFile, False, ByVal 0&, FTP_TRANSFER_TYPE_BINARY, DW_CONTEXT&)
'or
Success = FtpGetFileA(mConn, RemoteFile, LocalFile, False, ByVal 0&,FTP_TRANSFER_TYPE_ASCII, DW_CONTEXT&)
Hi egl1044,

Very useful code - thanks for sharing that.

Do you have corresponding code to PUT files to an FTP server, that you wouldn't mind sharing too?

BFN,

fp.
You can replace FtpGetFile with FtpPutFile API. Just remove the line FtpGetFile and make a call to FtpPutFile.

The above was written awhile ago, and I believe there is a bug in the WinInet functions FtpGetFile and FtpPutFile. Microsoft recommends the following FIX:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;312039

I have the example with FtpOpenFile somewere in my backups but I won't be around until tonight.
Thanks again.

I'll revise what you have provided already & go with that, but if you could post your entire code listing it may help (not only me, but) future searching of the PAQs.

:)

BFN,

fp.
Sure no problem fanpages
No rush, though... please don't go to any trouble; just when you have the time/opportunity.

Thanks.
Avatar of spoowiz

ASKER

I'll try your code later, egl1044.
More info:
1. Other XPs use same code and can download so I don't think it's the firewall
2. I noticed that the program references C:\windows\system32\shdocvw.oca which doesn't exist on "problem" pc. Think this is needed? I will put it there and test and let you know.
Avatar of spoowiz

ASKER

egl - your code worked. thanks.
As I use other wininet functions such as ftpdeletefile, so i tried to compare and see the difference.
Started to work by changing
        Public Const INTERNET_INVALID_PORT_NUMBER = 0
        Public Const INTERNET_SERVICE_FTP = 1
        nFlag = 0
        hConnection = InternetConnect(hOpen, vServer, INTERNET_INVALID_PORT_NUMBER, _
                vUser, vPswd, INTERNET_SERVICE_FTP, nFlag, 0)
to
        hConnection = InternetConnect(hOpen, vServer, 21, _
                vUser, vPswd, 1, FTP_PASSIVE&, DW_CONTEXT&)

I wonder if you can tell me why it's been working fine all these months on Win2000 and WinXP PCs. And didn't work on this particular XP pc. (I checked that it has service pack 2). Wel... all other winXP is Pro edition, this one's Home edition. Does that matter?
thanks
Hi,

Are you now using a different FTP server, or has the administrator of the service changed the FTP site?

The Port Number ("Invalid" = 0 vs. explicitly stating 21) can be discounted.

The site may have changed to Passive connections only.

BFN,

fp.
Avatar of spoowiz

ASKER

ftp server is unchanged
all other PCs are still working properly with previous code (active connection) (altho, i don't know what the difference is between active and passive connection)
Taken from [ http://en.wikipedia.org/wiki/File_Transfer_Protocol ]:

"FTP is commonly run on two ports, 20 and 21, and runs exclusively over TCP. The FTP server listens on port 21 for incoming connection from FTP clients. A connection on this port forms the control stream, on which commands are passed to the FTP server.

For the actual file transfer to take place, a different connection is required. Depending on the transfer mode, the client (active mode) or the server (passive mode) can listen for the incoming data connection. Before file transfer begins, the client and server also negotiate the port of the data connection. In case of active connections (where the server connects to the client to transfer data), the server binds on port 20 before connecting to the client. For passive connections, there is no such restriction."

---

From [ http://searchnetworking.techtarget.com/sDefinition/0,290660,sid7_gci512897,00.html ]:

"Passive FTP (sometimes referred to as PASV FTP because it involves the FTP PASV command) is a more secure form of data transfer in which the flow of data is set up and initiated by the File Transfer Program (FTP) client rather than by the FTP server program. Separate FTP client programs, such as WS_FTP Pro, usually allow the user to select passive FTP. Most Web browsers (which act as FTP clients) use passive FTP by default because corporations prefer it as a safety measure. As a general rule, any coprorate firewall server, which exists in order to protect an internal network from the outside world, recognizes input from the outside only in response to user requests that were sent out requesting the input. The use of passive FTP ensures all data flow initiation comes from inside the network rather than from the outside."

---

See also [ http://slacksite.com/other/ftp.html ]:

"Active FTP vs. Passive FTP, a Definitive Explanation"

"...Active FTP is beneficial to the FTP server admin, but detrimental to the client side admin. The FTP server attempts to make connections to random high ports on the client, which would almost certainly be blocked by a firewall on the client side.

Passive FTP is beneficial to the client, but detrimental to the FTP server admin. The client will make both connections to the server, but one of them will be to a random high port, which would almost certainly be blocked by a firewall on the server side."

---

Has the client PC recently had a firewall or anti-virus software package installed?

Or, is the client PC's IP address known to the server filewall?

BFN,

fp.
Avatar of spoowiz

ASKER

no new firewall or anti-vrus software.
Again, whatever it is, it is uniquen to this one pc.
How is it connected to your network?

Does it go via a different router or hub than everything else?

And... OK... let's extend the software question to: Has this PC had anything installed upon it recently (i.e. around the time the FTP client interface ceased functioning as per all the other client PCs)?
I couldn't find the backup so I just re-wrote a simple example.
Might have some errors, if so let me know didn't do any  major testing

'--- module1.bas ---

Option Explicit

    '// CreateFileW
    Private Const Generic_Read  As Long = &H80000000
    Private Const Generic_Write As Long = &H40000000
    Private Const Create_Always As Long = 2
    Private Const Open_Existing As Long = 3
    '// InternetConnectW
    Private Const INTERNET_SERVICE_FTP  As Long = 1
    Private Const INTERNET_FLAG_PASSIVE As Long = &H8000000
    '// FtpOpenFileW
    Private Const FTP_TRANSFER_TYPE_UNKNOWN As Long = &H0
   
    '// Transfer Rates
    Public Enum Rate
        [1 KB] = 1024
        [2 KB] = 1024 * 2
        [5 KB] = 1024 * 5
        [8 KB] = 1024 * 8
        [16 KB] = 1024 * 16
    End Enum
   
    Private Declare Function InternetOpenW Lib "wininet.dll" ( _
        ByVal lpszAgent As Long, _
        ByVal dwAccessType As Long, _
        ByVal lpszProxyName As Long, _
        ByVal lpszProxyBypass As Long, _
        ByVal dwFlags As Long) As Long
   
    Private Declare Function InternetSetStatusCallback Lib "wininet.dll" ( _
        ByVal hInternet As Long, _
        ByVal lpfnInternetCallback As Long) As Long
 
    Private Declare Function InternetConnectW Lib "wininet.dll" ( _
        ByVal hConnect As Long, _
        ByVal lpszServerName As Long, _
        ByVal nServerPort As Long, _
        ByVal lpszUsername As Long, _
        ByVal lpszPassword As Long, _
        ByVal dwService As Long, _
        ByVal dwFlags As Long, _
        ByVal dwContext As Long) As Long
 
    Private Declare Function CreateFileW Lib "kernel32.dll" ( _
        ByVal lpFileName As Long, _
        ByVal dwDesiredAccess As Long, _
        ByVal dwShareMode As Long, _
        ByVal lpSecurityAttributes As Long, _
        ByVal dwCreationDisposition As Long, _
        ByVal dwFlagsAndAttributes As Long, _
        ByVal hTemplateFile As Long) As Long
       
    Private Declare Function InternetReadFile Lib "wininet.dll" ( _
        ByVal hFile As Long, _
        ByVal sBuffer As Long, _
        ByVal lNumBytesToRead As Long, _
        lNumberOfBytesRead As Long) As Long
   
    Private Declare Function InternetWriteFile Lib "wininet.dll" ( _
        ByVal hFile As Long, _
        ByVal sBuffer As Long, _
        ByVal lNumBytesToWite As Long, _
        dwNumberOfBytesWritten As Long) As Long

    Private Declare Function InternetCloseHandle Lib "wininet.dll" ( _
        ByVal hInternet As Long) As Long
   
    Private Declare Function CloseHandle Lib "kernel32" ( _
        ByVal hObject As Long) As Long

    Private Declare Function WriteFile Lib "kernel32" ( _
        ByVal hFile As Long, _
        ByVal lpBuffer As Any, _
        ByVal nNumberOfBytesToWrite As Long, _
        lpNumberOfBytesWritten As Long, _
        ByVal lpOverlapped As Long) As Long

    Private Declare Function ReadFile Lib "kernel32" ( _
        ByVal hFile As Long, _
        ByVal lpBuffer As Any, _
        ByVal nNumberOfBytesToRead As Long, _
        lpNumberOfBytesRead As Long, _
        ByVal lpOverlapped As Any) As Long
   
    Private Declare Function FtpOpenFileW Lib "wininet.dll" ( _
      ByVal hConnect As Long, _
      ByVal lpszFileName As Long, _
      ByVal dwAccess As Long, _
      ByVal dwFlags As Long, _
      ByVal dwContext As Long) As Long

    Private Declare Function FtpSetCurrentDirectoryW Lib "wininet.dll" ( _
        ByVal hConnect As Long, _
        ByVal lpszDirectory As Long) As Long
       
    Private Declare Function FtpCreateDirectoryW Lib "wininet.dll" ( _
        ByVal hConnect As Long, _
        ByVal lpszDirectory As Long) As Long
   
    Private Declare Function FtpDeleteFileW Lib "wininet.dll" ( _
        ByVal hConnect As Long, _
        ByVal lpszFileName As Long) As Long
   
    Private Declare Function FtpRemoveDirectoryW Lib "wininet.dll" ( _
        ByVal hConnect As Long, _
        ByVal lpszDirectory As Long) As Long
       
    Private Declare Function FtpRenameFileW Lib "wininet.dll" ( _
        ByVal hConnect As Long, _
        ByVal lpszExisting As Long, _
        ByVal lpszNew As Long) As Long

    Dim FTPOpen        As Long
    Dim FTPConn        As Long      '// HINTERNET Connection HANDLE
    Dim FTPHandle      As Long      '// FtpOpenFileW HINTERNET HANDLE
   
    Dim FileHandle     As Long      '// CreateFileW HANDLE

    Dim DATA_BUFFER()  As Byte
   
    Dim BytesRead      As Long
    Dim BytesWritten   As Long

Public Sub FtpConnect( _
    ByVal server As String, _
    ByVal user As String, _
    ByVal password As String, _
    ByVal port As Long)

 FTPOpen = InternetOpenW(0&, 1, 0&, 0&, 0&)
 
 Call InternetSetStatusCallback(FTPOpen, AddressOf INTERNET_STATUS_CALLBACK)

 FTPConn = InternetConnectW(FTPOpen, _
        StrPtr(server), _
        port, _
        StrPtr(user), _
        StrPtr(password), _
        INTERNET_SERVICE_FTP, _
        INTERNET_FLAG_PASSIVE, _
        2)

End Sub

Public Sub FtpDisconnect()
    InternetCloseHandle (FTPConn)
    InternetCloseHandle (FTPOpen)
End Sub

Public Sub ChangeDirectory(ByVal FtpDirectory As String)
    FtpSetCurrentDirectoryW FTPConn, StrPtr(FtpDirectory)
End Sub

Public Sub CreateDirectory(ByVal FtpDirectory As String)
    FtpCreateDirectoryW FTPConn, StrPtr(FtpDirectory)
End Sub

Public Sub DeleteFile(ByVal FtpFile As String)
    FtpDeleteFileW FTPConn, StrPtr(FtpFile)
End Sub

Public Sub RemoveDirectory(ByVal FtpDirectory As String)
    FtpRemoveDirectoryW FTPConn, StrPtr(FtpDirectory)
End Sub

Public Sub RenameFile(ByVal Existing As String, ByVal Renamed As String)
    FtpRenameFileW FTPConn, StrPtr(Existing), StrPtr(Renamed)
End Sub

Public Sub DownloadFile( _
    ByVal LocalFile As String, _
    ByVal ServerFile As String, _
    ByVal Transfer As Rate)

    FileHandle = CreateFileW(StrPtr(LocalFile), _
        Generic_Write, _
        ByVal 0&, _
        ByVal 0&, _
        Create_Always, _
        0&, _
        ByVal 0&)
   
    FTPHandle = FtpOpenFileW(FTPConn, _
        StrPtr(ServerFile), _
        Generic_Read, _
        FTP_TRANSFER_TYPE_UNKNOWN, _
        2)
   
    ReDim DATA_BUFFER(Transfer)
   
    Do
    If InternetReadFile(FTPHandle, ByVal VarPtr(DATA_BUFFER(0)), Transfer, BytesRead) Then
    Call WriteFile(FileHandle, _
            ByVal VarPtr(DATA_BUFFER(0)), _
            BytesRead, _
            BytesWritten, _
            0&)
    Else
        Exit Do
    End If
    Loop While BytesRead > 0
   
    InternetCloseHandle FTPHandle
    CloseHandle FileHandle
    Erase DATA_BUFFER
   
End Sub

Public Sub UploadFile( _
    ByVal LocalFile As String, _
    ByVal ServerFile As String, _
    ByVal Transfer As Rate)

    FileHandle = CreateFileW(StrPtr(LocalFile), _
            Generic_Read, _
            ByVal 0&, _
            ByVal 0&, _
            Open_Existing, _
            0&, _
            ByVal 0&)
           
    FTPHandle = FtpOpenFileW(FTPConn, _
            StrPtr(ServerFile), _
            Generic_Write, _
            FTP_TRANSFER_TYPE_UNKNOWN, _
            2)
           
    ReDim DATA_BUFFER(Transfer)
   
    Do
    If ReadFile(FileHandle, ByVal VarPtr(DATA_BUFFER(0)), Transfer, BytesRead, 0&) Then
      Call InternetWriteFile(FTPHandle, _
            ByVal VarPtr(DATA_BUFFER(0)), _
            BytesRead, _
            BytesWritten)
        Else
        Exit Do
    End If
    Loop While BytesRead > 0
   
    InternetCloseHandle FTPHandle
    CloseHandle FileHandle
    Erase DATA_BUFFER

End Sub

Public Sub INTERNET_STATUS_CALLBACK( _
    ByVal hInternet As Long, _
    ByVal dwContext As Long, _
    ByVal dwInternetStatus As Long, _
    ByVal lpvStatusInformation As Long, _
    ByVal dwStatusInformationLength As Long)

DoEvents

End Sub




'--- Form ----

Option Explicit

Private Sub Command1_Click()

Call FtpConnect("ftp.host.com", "user", "password", 21)

'ChangeDirectory "BIN"
'CreateDirectory "TESTING"
'RemoveDirectory "TESTING"
'RenameFile "calc.exe", "calcnew.exe"
'DeleteFile "calcnew.exe"

'Call UploadFile("c:\windows\system32\calc.exe", "calc.exe", [8 KB])
'Call DownloadFile("c:\calc.exe", "calc.exe", [8 KB])

Call FtpDisconnect

End Sub
Thanks for taking the time with your code, egl1044.

I'll look into this in more depth today.

spoowiz: you've accepted a comment made by egl1044; which is fine... but not come back to me regarding my queries on your follow-up issue.

Is this no longer a problem?


BFN,

fp.
Avatar of spoowiz

ASKER

fanpages - i closed this because I got the program to work - even tho I don't understand why. I didn't think it was right to keep it open to have the ancillary question unanswered.
As for your questions, everything was exactly the same with all PCs except this one PC and I thought that I had said so, so I didn't think it needed to be repeated.
I thank you for your attempt to find out the cause, but I'm now satisfied with result. I'm afraid I won't find the "real" cause, unfortunately - don't have the time either to pursue.
Thanks all.
Yes, you did say everything was exactly the same... hence my last set of queries.  Thanks for coming back to me to say that you don't have the time to investigate.  I have many open questions with comments left standing because people feel defeated but don't let me know; so I appreciate your time telling me.

Glad you resolved your initial problem too.

BFN,

fp.
Avatar of spoowiz

ASKER

fanpages - i hope you don't misunderstand me... I feel grateful for experts like you who take the time to answer questions for folks like us. somestimes, when the major problem is resolved, i like to know the cause, if possible, quickly, but not it takes a long time. for this one, it seemed like there was no quick answer so i felt best to abondon the "cause" portion.
I just don't like seeing a problem unresolved and, from previous questions, it does get annoying when people stop contributing without saying so.

No offence taken.  Please do not feel the need to apologise.

If the issue reoccurs, please raise another question (and reference this one for background information for any further Expert to review).

Thanks.

BFN,

fp.