Page 1 of 1

WININET Problem. Please Help.

Posted: Mon Jun 18, 2007 2:40 pm
by AndyMK
Hi, im accessing an FTP server from PB4.02 using the WININET API. Everything works except listing files in a directory. The first time i run the list code, it works but any time after that during the same session, it does not. I will post some basic/messy code to show what i am doing. Help would be much appreciated. Thanks.

Code: Select all

#INTERNET_SERVICE_FTP=1
#INTERNET_OPEN_TYPE_DIRECT=1
#FTP_PORT=21
#FTP_TRANSFER_ASCII=1
#FTP_TRANSFER_BINARY=2
Proxy.s=""
ProxyBypass.s=""
ServerName.s="demosite.homeftp.net"
UserName.s="vac"
Password.s="vac"
acc$="Home"

If OpenWindow(0, 0, 0, 210, 150, "BlahBlah", #PB_Window_ScreenCentered)

event=WaitWindowEvent()
gadget=EventGadget()
etype=EventType()

hInternet=InternetOpen_("FTP",#INTERNET_OPEN_TYPE_DIRECT,Proxy,ProxyBypass,0)
If hInternet
hConnect=InternetConnect_(hInternet,ServerName,#FTP_PORT,UserName,Password,#INTERNET_SERVICE_FTP,0,0)
If hConnect

Repeat
WindowEvent()
Delay(1000)

hFind=FtpFindFirstFile_(hConnect,"*.jpg",@FTPFile.WIN32_FIND_DATA,0,0) 
If hFind 
  Find=1 
  Debug PeekS(@FTPFile\cFileName) ;Directories
  While Find 
    Find=InternetFindNextFile_(hFind,@FTPFile) 
    If Find 
      Debug PeekS(@FTPFile\cFileName) ;Files
    EndIf      
  Wend
EndIf 

ForEver

InternetCloseHandle_(hInternet)
EndIf
EndIf
EndIf
Most of the code was taken from Purearea Code Archives.

Posted: Mon Jun 18, 2007 3:52 pm
by Trond
Read this: http://msdn2.microsoft.com/En-US/library/aa384146.aspx
It says it can only be used once (!).

Posted: Mon Jun 18, 2007 4:15 pm
by AndyMK
How strange? I have some code in BlitzPlus using the same WININET API that works refreshing the directory during the same session... Oh well.. Thanks for the reply.

Posted: Mon Jun 18, 2007 4:27 pm
by Trond
Can you post the blitz code?

Posted: Mon Jun 18, 2007 4:29 pm
by Flype
Hello,

you should use file attribute to recognize if it is a directory or a file :

Code: Select all

hFile\dwFileAttributes & #FILE_ATTRIBUTE_DIRECTORY

Posted: Mon Jun 18, 2007 5:20 pm
by maw
Actually, if you really read the MSDN page you notice that you can only have one instance of FtpFindFirstFile() per FTP-session. So all you have to do is close the handle once you are done with the FtpFindFirstFile(), then you should be able to start another.

So, do a InternetCloseHandle() on the handle you get from the FtpFindFirstFile() before trying to run it again.

Posted: Mon Jun 18, 2007 6:21 pm
by AndyMK
maw, tried it and still nothing. The only way so far is to disconnect from the server and reconnect.

Here is a chunk of code from Blitz doing exactly what maw explained.

Code: Select all

Function FTPGetFileList(remoteDirectory$="")
	Delete Each ftpfile	
	If remoteDirectory$ = "" Then remoteDirectory$ = gCurrentDirectory$
	lpFindFileData = CreateBank (320) 
	hInternet = FtpFindFirstFile(ghFTPSession,remoteDirectory$,lpFindFileData,INTERNET_FLAG_RELOAD,0)	
	If hInternet = 0 
		FreeBank lpFindFileData
		If GetLastError() = ERROR_NO_MORE_FILES Then Return succeeded ;no files or subdirectories
		Return failed	
	EndIf	

	;Iterate through the files in the directory and store each in a type.
	Repeat
		ftpfile.ftpfile = New ftpfile	
		ftpfile\directory$ = remoteDirectory$
		ftpfile\fileName$ = ReadAPIString$(lpFindFileData,44)
		If PeekInt(lpFindFileData,0) = 16 Then ftpfile\typeOfFile = 2 ;directory (FILE_ATTRIBUTE_DIRECTORY)
		If PeekInt(lpFindFileData,0) = 128 Then ftpfile\typeOfFile = 1 ;file (FILE_ATTRIBUTE_NORMAL)
		ftpfile\sizeofFile = PeekInt(lpFindFileData,32)	 ;nFileSizeLow is enough, accurate for files < 2.1 gigs (that's huge)	
	Until InternetFindNextFile(hInternet,lpFindFileData) = 0

	result = InternetCloseHandle(hInternet) 
	FreeBank lpFindFileData	
	Return succeeded
End Function

Posted: Mon Jun 18, 2007 6:39 pm
by AndyMK
Ok, maw was right, it does work.

Code: Select all

Procedure.l FTPInit() 
  ProcedureReturn InternetOpen_("FTP",1,"","",0) 
EndProcedure 

Procedure.l FTPConnect(hInternet,Server.s,User.s,Password.s,port.l) 
  ProcedureReturn InternetConnect_(hInternet,Server,port,User,Password,1,0,0) 
EndProcedure 

Procedure.l FTPDir(hConnect.l) 
  hFind=FtpFindFirstFile_(hConnect,"*.*",@FTPFile.WIN32_FIND_DATA,0,0) 
  If hFind 
    Find=1 
    Debug PeekS(@FTPFile\cFileName) ;Directories
    While Find 
      Find=InternetFindNextFile_(hFind,@FTPFile) 
      If Find 
        Debug PeekS(@FTPFile\cFileName) ;Files
      EndIf      
    Wend
    InternetCloseHandle_(hFind) 
  EndIf 
EndProcedure 

Procedure.l FTPSetDir(hConnect.l,Dir.s) 
  ProcedureReturn FtpSetCurrentDirectory_(hConnect,Dir) 
EndProcedure 

Procedure.l FTPCreateDir(hConnect.l,Dir.s) 
  ProcedureReturn FtpCreateDirectory_(hConnect,Dir) 
EndProcedure 

Procedure.l FTPDownload(hConnect.l,Source.s,Dest.s) 
  ProcedureReturn FtpGetFile_(hConnect,Source,Dest,0,0,0,0) 
EndProcedure 

Procedure.l FTPUpload(hConnect.l,Source.s,Dest.s) 
  ProcedureReturn FtpPutFile_(hConnect,Source,Dest,0,0) 
EndProcedure 

Procedure.l FTPClose(hInternet.l) 
  ProcedureReturn InternetCloseHandle_(hInternet) 
EndProcedure 
  

hInternet=FTPInit() 
If hInternet  
  
  hConnect=FTPConnect(hInternet,"demosite.homeftp.net","vac","vac",21) 
  If hConnect 
  While Not hFind
    FTPDir(hConnect) 
    Delay(5000)
  Wend
  EndIf 
EndIf
Thanks :)

Posted: Mon Jun 18, 2007 6:42 pm
by maw
Works here, it retrieves the filelist every second without disconnecting:

Code: Select all

#INTERNET_SERVICE_FTP=1
#INTERNET_OPEN_TYPE_DIRECT=1
#FTP_PORT=21
#FTP_TRANSFER_ASCII=1
#FTP_TRANSFER_BINARY=2
Proxy.s=""
ProxyBypass.s=""
ServerName.s="demosite.homeftp.net"
UserName.s="vac"
Password.s="vac"
acc$="Home"


If OpenWindow(0, 0, 0, 210, 150, "BlahBlah", #PB_Window_ScreenCentered)

	event=WaitWindowEvent()
	gadget=EventGadget()
	etype=EventType() 
	
	hInternet=InternetOpen_("FTP",#INTERNET_OPEN_TYPE_DIRECT,Proxy,ProxyBypass,0)
	
	If hInternet
		
		Repeat
			hConnect=InternetConnect_(hInternet,ServerName,#FTP_PORT,UserName,Password,#INTERNET_SERVICE_FTP,0,0)
			If hConnect
				hFind=FtpFindFirstFile_(hConnect,"*.jpg",@FTPFile.WIN32_FIND_DATA,0,0)
				If hFind
				  Find=1
				  Debug PeekS(@FTPFile\cFileName) ;Directories
				  While Find
				    Find=InternetFindNextFile_(hFind,@FTPFile)
				    If Find
				      Debug PeekS(@FTPFile\cFileName) ;Files
				    EndIf     
				  Wend
				EndIf
				InternetCloseHandle_(hConnect)
			EndIf
			While WindowEvent() : Wend
			Delay(1000)
		ForEver
	
	EndIf
EndIf
Edit: Damnit, I also need to code faster :lol:

Posted: Mon Jun 18, 2007 10:01 pm
by Flype
don't know if this can help but here is one way of examining recursively a ftp folder (using linked list).

Code: Select all

;============================================

EnableExplicit

#FTP_TRANSFER_ASCII  = 1
#FTP_TRANSFER_BINARY = 2

#INTERNET_SERVICE_FTP = 1
#INTERNET_OPEN_TYPE_DIRECT = 1

Import "shlwapi.lib"
  StrFormatByteSize64A(Size.q, *BufStr, BufSize.l) 
EndImport

Procedure.s StrByteSize(nBytes.q)
  
  Protected string.s{64}
  
  If StrFormatByteSize64A(nBytes, @string, 64)
    ProcedureReturn PeekS(@string, -1, #PB_Ascii)
  EndIf
  
EndProcedure

;============================================

Structure FILESIZE
  High.l
  Low.l
EndStructure
Structure WIN32_FIND_DATA_2
  dwFileAttributes.l
  ftCreationTime.FILETIME
  ftLastAccessTime.FILETIME
  ftLastWriteTime.FILETIME
  nFileSizeLow.l
  nFileSizeHigh.l
  dwReserved0.l
  dwReserved1.l
  cFileName.s{260} ; replaced by fixed string
  cAlternate.s{14} ; replaced by fixed string
  dummy.w
EndStructure

Macro FtpOpen(Proxy = "", ProxyBypass = "")
  InternetOpen_("FTP", #INTERNET_OPEN_TYPE_DIRECT, Proxy, ProxyBypass, 0)
EndMacro
Macro FtpClose(hInternet)
  InternetCloseHandle_(hInternet)
EndMacro
Macro FtpConnect(hInternet, Host, User, Pwd, Port = 21)
  InternetConnect_(hInternet, Host, Port, User, Pwd, #INTERNET_SERVICE_FTP, 0, 0)
EndMacro
Macro FtpDisconnect(hConnect)
  InternetCloseHandle_(hConnect)
EndMacro

;============================================

Procedure.l FtpListAll(hConnect.l, folder.s = "/", depth.l = 0)
  
  Protected hFind.l, Size.q, NewList find.WIN32_FIND_DATA_2()
  
  If FtpSetCurrentDirectory_(hConnect, folder) And AddElement(find())
    hFind = FtpFindFirstFile_(hConnect, 0, find(), 0, 0)
    If hFind 
      While AddElement(find()) And InternetFindNextFile_(hFind, find()) 
        ; Delay(1) 
      Wend
      InternetCloseHandle_(hFind)
      DeleteElement(find())
    EndIf
  EndIf
  
  ForEach find()
    If find()\dwFileAttributes & #FILE_ATTRIBUTE_DIRECTORY
      AddGadgetItem(0, -1, "[DIR] " + find()\cFileName, 0, depth)
      FtpListAll(hConnect, folder + find()\cFileName + "/", depth + 1)
    Else
      PokeL(@Size + 4, find()\nFileSizeLow)
      PokeL(@Size + 0, find()\nFileSizeHigh)
      AddGadgetItem(0, -1, "[FILE] " + find()\cFileName + " (" + StrByteSize(Size) + ")", 0, depth)
    EndIf
  Next
  
EndProcedure

;============================================

Define ftp.l, conn.l

If OpenWindow(0, 0, 0, 640, 480, "Ftp", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
  
  If CreateGadgetList(WindowID(0))
    TreeGadget(0, 10, 10, 620, 460, #PB_Tree_AlwaysShowSelection)
  EndIf
  
  ftp = FtpOpen()
  If ftp
    conn = FtpConnect(ftp, "localhost", "user", "pwd")
    If conn
      FtpListAll(conn, "/") ; <---- recursive proc
      FtpDisconnect(conn)
    EndIf
    FtpClose(ftp)
  EndIf
  
  Repeat
    Select WaitWindowEvent() 
      Case #PB_Event_CloseWindow: Break
      Case #PB_Event_SizeWindow:  ResizeGadget(0, #PB_Ignore, #PB_Ignore, WindowWidth(0)-20, WindowHeight(0)-20)
    EndSelect
  ForEver
  
EndIf

;============================================