Jump to content


Photo

DllCall: Basic FTP Functions


  • Please log in to reply
30 replies to this topic

#1 olfen

olfen
  • Members
  • 115 posts

Posted 10 June 2006 - 05:57 PM

Not heavily tested. Feel free to revise and add more.
I think the call to InternetOpenA needs refinement regarding the proxy settings. I don't have the knowledge to do so.

/*
http://msdn.microsoft.com/library/en-us/wininet/wininet/ftp_sessions.asp
http://msdn.microsoft.com/library/en-us/wininet/wininet/internetopen.asp
http://msdn.microsoft.com/library/en-us/wininet/wininet/internetconnect.asp
*/

FtpCreateDirectory(DirName) {
global ic_hInternet
r := DllCall("wininet\FtpCreateDirectoryA", "uint", ic_hInternet, "str", DirName)
If (ErrorLevel != 0 or r = 0)
return 0
else
return 1
}

FtpRemoveDirectory(DirName) {
global ic_hInternet
r := DllCall("wininet\FtpRemoveDirectoryA", "uint", ic_hInternet, "str", DirName)
If (ErrorLevel != 0 or r = 0)
return 0
else
return 1
}

FtpSetCurrentDirectory(DirName) {
global ic_hInternet
r := DllCall("wininet\FtpSetCurrentDirectoryA", "uint", ic_hInternet, "str", DirName)
If (ErrorLevel != 0 or r = 0)
return 0
else
return 1
}

FtpPutFile(LocalFile, NewRemoteFile="", Flags=0) {
;Flags:
;FTP_TRANSFER_TYPE_UNKNOWN = 0 (Defaults to FTP_TRANSFER_TYPE_BINARY)
;FTP_TRANSFER_TYPE_ASCII = 1
;FTP_TRANSFER_TYPE_BINARY = 2
If NewRemoteFile=
NewRemoteFile := LocalFile
global ic_hInternet
r := DllCall("wininet\FtpPutFileA"
, "uint", ic_hInternet
, "str", LocalFile
, "str", NewRemoteFile
, "uint", Flags
, "uint", 0) ;dwContext
If (ErrorLevel != 0 or r = 0)
return 0
else
return 1
}

FtpGetFile(RemoteFile, NewFile="", Flags=0) {
;Flags:
;FTP_TRANSFER_TYPE_UNKNOWN = 0 (Defaults to FTP_TRANSFER_TYPE_BINARY)
;FTP_TRANSFER_TYPE_ASCII = 1
;FTP_TRANSFER_TYPE_BINARY = 2
If NewFile=
NewFile := RemoteFile
global ic_hInternet
r := DllCall("wininet\FtpGetFileA"
, "uint", ic_hInternet
, "str", RemoteFile
, "str", NewFile
, "int", 1 ;do not overwrite existing files
, "uint", 0 ;dwFlagsAndAttributes
, "uint", Flags
, "uint", 0) ;dwContext
If (ErrorLevel != 0 or r = 0)
return 0
else
return 1
}

FtpGetFileSize(FileName, Flags=0) {
;Flags:
;FTP_TRANSFER_TYPE_UNKNOWN = 0 (Defaults to FTP_TRANSFER_TYPE_BINARY)
;FTP_TRANSFER_TYPE_ASCII = 1
;FTP_TRANSFER_TYPE_BINARY = 2
global ic_hInternet
fof_hInternet := DllCall("wininet\FtpOpenFileA"
, "uint", ic_hInternet
, "str", FileName
, "uint", 0x80000000 ;dwAccess: GENERIC_READ
, "uint", Flags
, "uint", 0) ;dwContext
If (ErrorLevel != 0 or fof_hInternet = 0)
return -1

FileSize := DllCall("wininet\FtpGetFileSize", "uint", fof_hInternet, "uint", 0)
DllCall("wininet\InternetCloseHandle",  "UInt", fof_hInternet)
return, FileSize
}


FtpDeleteFile(FileName) {
global ic_hInternet
r :=  DllCall("wininet\FtpDeleteFileA", "uint", ic_hInternet, "str", FileName)
If (ErrorLevel != 0 or r = 0)
return 0
else
return 1
}

FtpRenameFile(Existing, New) {
global ic_hInternet
r := DllCall("wininet\FtpRenameFileA", "uint", ic_hInternet, "str", Existing, "str", New)
If (ErrorLevel != 0 or r = 0)
return 0
else
return 1
}

FtpOpen(Server, Port=21, Username=0, Password=0 ,Proxy="", ProxyBypass="") {
IfEqual, Username, 0, SetEnv, Username, anonymous
IfEqual, Password, 0, SetEnv, Password, anonymous

If (Proxy != "")
AccessType=3
Else
AccessType=1
;#define INTERNET_OPEN_TYPE_PRECONFIG                    0   // use registry configuration
;#define INTERNET_OPEN_TYPE_DIRECT                       1   // direct to net
;#define INTERNET_OPEN_TYPE_PROXY                        3   // via named proxy
;#define INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY  4   // prevent using java/script/INS

global ic_hInternet, io_hInternet, hModule
hModule := DllCall("LoadLibrary", "str", "wininet.dll")

io_hInternet := DllCall("wininet\InternetOpenA"
, "str", A_ScriptName ;lpszAgent
, "UInt", AccessType
, "str", Proxy
, "str", ProxyBypass
, "UInt", 0) ;dwFlags

If (ErrorLevel != 0 or io_hInternet = 0) {
FtpClose()
return 0
}

ic_hInternet := DllCall("wininet\InternetConnectA"
, "uint", io_hInternet
, "str", Server
, "uint", Port
, "str", Username
, "str", Password
, "uint" , 1 ;dwService (INTERNET_SERVICE_FTP = 1)
, "uint", 0 ;dwFlags
, "uint", 0) ;dwContext

If (ErrorLevel != 0 or ic_hInternet = 0)
return 0
else
return 1
}

FtpClose() {
global ic_hInternet, io_hInternet, hModule
DllCall("wininet\InternetCloseHandle",  "UInt", ic_hInternet)
DllCall("wininet\InternetCloseHandle",  "UInt", io_hInternet)
DllCall("FreeLibrary", "UInt", hModule)
}
Edit 20071020: Added global hModule in FtpOpen and FtpClose

#2 Chris

Chris
  • Administrators
  • 10727 posts

Posted 10 June 2006 - 08:37 PM

For most purposes, this method seems superior to the FileAppend + Ftp method. Thanks for posting it.

#3 corrupt

corrupt
  • Members
  • 2558 posts

Posted 10 June 2006 - 10:21 PM

Thanks :) . Very handy.

#4 Thalon

Thalon
  • Members
  • 641 posts

Posted 11 June 2006 - 08:04 AM

For general use this is a great solution I was searching for!

But be shure not to use this with your ftp-settings in a freeware (or similar).
2 days ago I heard from a game that updates it's highscore via FTP.
A friend of me was asked to test the game from the author and sent him back servername, username and even password for full access!
The password was encrypted, but this is no problem even for low-level-debugger. (The game isn't online any more until finishing development ^^)

Thalon

#5 Veovis

Veovis
  • Members
  • 389 posts

Posted 11 June 2006 - 09:19 PM

LOL

#6 olfen

olfen
  • Members
  • 115 posts

Posted 12 June 2006 - 04:33 PM

I fully agree with your security related objections, Thalon.
But even if the hardcoded access data were protected by means of encryption or even anti-debugging code (which is not an obstacle for some people), it still would be easy enough to sniff the relevant data using a network protocol analyzer.

#7 PhiLho

PhiLho
  • Fellows
  • 6850 posts

Posted 12 June 2006 - 04:54 PM

I suppose that's why SFTP was invented...

#8 olfen

olfen
  • Members
  • 115 posts

Posted 12 June 2006 - 05:06 PM

I suppose that's why SFTP was invented...

Good guess :wink:

As for anti-debugging: This will detect OllyDbg and probably some others:
;http://msdn.microsoft.com/library/en-us/debug/base/isdebuggerpresent.asp
r := DllCall("IsDebuggerPresent")
IfEqual, r, 0, MsgBox No debugger present.
IfEqual, r, 1, MsgBox Debugger detected.

Edit: Google references tell me that many debuggers can be hidden from this function, so can OllyDbg :?

#9 Ace_NoOne

Ace_NoOne
  • Members
  • 299 posts

Posted 27 December 2006 - 10:11 AM

Great job, olfen; very useful!

I just noticed that a return value of 1 means success while 0 means failure.
ErrorLevel values are usually the other way round; any special reason for choosing to do it this way?

#10 Elevator_Hazard

Elevator_Hazard
  • Members
  • 297 posts

Posted 27 May 2007 - 01:42 PM

Although this post is a little old, can someone show me an example usage that would work? Like no variables in the params so I know what the domain name should look like and such, because I always get confused about that. Of course you can omit the password, I just need to know how to work it.

#11 Ace_NoOne

Ace_NoOne
  • Members
  • 299 posts

Posted 27 May 2007 - 07:17 PM

can someone show me an example usage that would work?

Sure; below are three essential (though very simple) routines, pulled from my FtpUploader script, which makes heavy use of these functions. I've also included some sample values for the variables used; that should give you everything you need to get started.
; sample values
FtpHost = autohotkey.net
FtpPort = 21
FtpUsername = AhkH4x0r
FtpPassword = Ahk1337
localFile = C:\FtpTest.txt
remoteFile = test/FtpTest.txt

; establish connection to FTP server
connect:
	FtpConnection := FtpOpen(FtpHost, FtpPort, FtpUsername, FtpPassword)
	If (FtpConnection != 1)
	{
		MsgBox, Error connecting to FTP server.
		GoSub, quit
	}
Return

; upload file
uploadFile:
    ; establish connection to FTP server
	GoSub, connect
	; store file on FTP server
	fileTransfer := FtpPutFile(localFile, remoteFile)
	If (fileTransfer != 1)
	{
		MsgBox, Error uploading file.
		GoSub, quit
	}
	; close connection
	FtpClose()
	; confirmation message
	MsgBox, Upload complete.
	; terminate script
	GoSub, quit
Return

; download file
downloadFile:
    ; establish connection to FTP server
	GoSub, connect
	; retrieve file from FTP server
	fileTransfer := FtpGetFile(remoteFile, localFile)
	If (fileTransfer != 1)
	{
		MsgBox, Error downloading file.
		GoSub, quit
	}
	; close connection
	FtpClose()
	; confirmation message
	MsgBox, Download complete.
	; terminate script
	GoSub, quit
Return
HTH.


PS: That "Windows XP Scream" logo in your sig is awesome! (Though hotlinking it, that's evil... :p )

#12 Elevator_Hazard

Elevator_Hazard
  • Members
  • 297 posts

Posted 28 May 2007 - 02:30 PM

Oops I forgot to say thanks yesterday. Thanks :D It really helped. And I didn't want to discredit the people who used that picture that is my siggy :D

Again thanks.

#13 Helpy

Helpy
  • Guests

Posted 28 May 2007 - 03:45 PM

And I didn't want to discredit the people who used that picture that is my siggy :D

I am not sure to understand this sentence.
Anyway, what Ace_NoOne meant is that you get the picture directly from apcmag.com site, which is stealing their bandwidth.

Even worse, this picture is quite heavy: 32KB, compare to size of most other avatars here. Sometime the loading of a topic is slow down because you posted there. Seriously (I am on broadband, not on dialup!).

#14 Elevator_Hazard

Elevator_Hazard
  • Members
  • 297 posts

Posted 28 May 2007 - 04:53 PM

Oopsies... I'll change it to .gif and put it on some site of mine. Thanks for bringing this up.

#15 Helpy

Helpy
  • Guests

Posted 28 May 2007 - 09:06 PM

Aha, much better, thanks. I really can sense the difference in download time. It seems AHK isn't a very fast server (but good enough, mind you).
Sorry, olfen, for being off topic, although netiquette is an important aspect of the Web, so not far from FTP, somehow...