Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

UrlDownloadToFile - Saving download to default name?


  • Please log in to reply
13 replies to this topic
  • Guests
  • Last active:
  • Joined: --
I'm using a function to download files, but the names of the files are wrong. Example:
UrlDownloadToFile, URL, FileName%version%.rar
I can't use the variable for the version name. Problem is, I need to download many different versions and save the files with the correct names.

Is there no way of doing this? If the URL is visited the file is automatically downloaded and is called "FileName vVersionName.rar". Is there no way of downloading from a URL without specifying the name of the file (assuming I can't use variables for the version)?

EzBlue
  • Members
  • 27 posts
  • Last active: Aug 15 2011 01:05 PM
  • Joined: 14 Feb 2011
Most likely, you should be writing
%URL%
and to make sure your filepath is correct,
FilePath := "FileName " version ".rar"
so...
URLDownloadToFile, %URL%, %FilePath%


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

If the URL is visited the file is automatically downloaded and is called "FileName vVersionName.rar". Is there no way of downloading from a URL without specifying the name of the file (assuming I can't use variables for the version)?


Instead, we may find the filename with a few DllCall()s and then use it with URLDownloadToFile. I am willing to discuss it if you register/log-on.

garry
  • Spam Officer
  • 3219 posts
  • Last active: Sep 20 2018 02:47 PM
  • Joined: 19 Apr 2005
( sorry, maybe not understand problem )
mosttime I use splitpath ( rename extension later )
SetWorkingDir %A_ScriptDir%
url1 =http://kurse.wienerborse.at/teledata_php/prices/dispatch_list.php?TYPE=P
     SplitPath,url1,name, dir, ext, name_no_ext, drive
F1=%A_scriptdir%\%name_no_ext%.txt

Splashimage,,b w600 h30  CWteal m9 b fs10 zh0,DOWNLOAD >>> %URL1%
UrlDownloadToFile,%URL1%,%F1%
Splashimage, off
exitapp


malcev
  • Members
  • 73 posts
  • Last active: Jan 28 2016 08:05 PM
  • Joined: 19 May 2011
Instead, we may find the filename with a few DllCall()s and then use it with URLDownloadToFile.

 

Could You please tell how it is possible?



Bruttosozialprodukt
  • Members
  • 457 posts
  • Last active: Oct 18 2015 08:47 AM
  • Joined: 20 Oct 2012

Try:

Download("http://ahkscript.org/download/ahk-u32.zip")
Download("http://ahkscript.org/download/1.1/AutoHotkeyHelp.zip")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Download(url) {
    If (!InStr(url,"://"))
        url := "http://" . url
    SplitPath, url, fileName
    UrlDownloadToFile, %url%, %fileName%
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


malcev
  • Members
  • 73 posts
  • Last active: Jan 28 2016 08:05 PM
  • Joined: 19 May 2011

I mean if I have link on file like this:

https://docs.google....LWhYVHYwanJLS3c



Bruttosozialprodukt
  • Members
  • 457 posts
  • Last active: Oct 18 2015 08:47 AM
  • Joined: 20 Oct 2012

This is gonna be tricky. The URL uses an (afaik) unusual method to specify the filename.
Well, I took the time, give this a try:

Download("https://docs.google.com/uc?export=download&id=0B7FildjsrNkILWhYVHYwanJLS3c")
Download("http://ahkscript.org/download/ahk-u32.zip")


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Download(url) {
    If (!InStr(url,"://"))
        url := "http://" . url
    WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    WebRequest.Open("GET", url)
    WebRequest.Send()
    
    ComObjError(false)
    cdHeader := WebRequest.GetResponseHeader("Content-Disposition")
    ComObjError(true)
    
    If (cdHeader) {
        RegexMatch(cdHeader, "filename=""([^""]+)""", match)
        fileName := match1
        
        ADODBObj := ComObjCreate("ADODB.Stream")
        ADODBObj.Type := 1
        ADODBObj.Open()
        ADODBObj.Write(WebRequest.ResponseBody)
        ADODBObj.SaveToFile(fileName, 2)
        ADODBObj.Close()
    } Else {
        SplitPath, url, fileName
        UrlDownloadToFile, %url%, %fileName%
    }
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

For me it worked fine for both URLs.
When you download very big files (bigger than your free RAM), then you might get problems with such downloads from google.



malcev
  • Members
  • 73 posts
  • Last active: Jan 28 2016 08:05 PM
  • Joined: 19 May 2011

Thank You!

I modified Your script, because with this link it did not work.

http://avatars-fast....-gA65dkojGA/y90

Download("http://avatars-fast.yandex.net/get-direct/R85qdm4hRHr-gA65dkojGA/y90")

Download(url) {
   If (!InStr(url,"://"))
       url := "http://" . url
   WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
   ComObjError(false)
   WebRequest.Open("GET", url)
   WebRequest.Send()
   cdHeader := WebRequest.GetResponseHeader("Content-Disposition")
   If (cdHeader)
   {
      RegexMatch(cdHeader, "filename=""([^""]+)""", match)
      fileName := match1
   }
   Else
   {
      SplitPath, url, fileName, , ext
      if (ext = "")
      {
         ext := WebRequest.GetResponseHeader("Content-Type")
         if (ext != "")
            filename := filename "." SubStr(ext, InStr(ext, "/")+1)
      }
   }
   UrlDownloadToFile, %url%, %fileName%
}


garry
  • Spam Officer
  • 3219 posts
  • Last active: Sep 20 2018 02:47 PM
  • Joined: 19 Apr 2005
thank you , works fine , just added old idea ( command splashimage ) to see it working

Bruttosozialprodukt
  • Members
  • 457 posts
  • Last active: Oct 18 2015 08:47 AM
  • Joined: 20 Oct 2012

@malcev It's a good point to not do the download per se with WinHttpRequest.

For the mime type you will likely get in trouble though because it doesn't always contain the actual extension.

E.g: application/octet-stream stands for .exe

There is a nice registry key that contains most of the mime types, check this:

Download("http://avatars-fast.yandex.net/get-direct/R85qdm4hRHr-gA65dkojGA/y90")

Download(url) {
    If (!InStr(url,"://"))
        url := "http://" . url
    WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    WebRequest.Open("GET", url)
    WebRequest.Send()
    ComObjError(false)
    cdHeader := WebRequest.GetResponseHeader("Content-Disposition")
    If (cdHeader) {
        RegexMatch(cdHeader, "filename=""([^""]+)""", match)
        fileName := match1
    } Else {
        SplitPath, url, fileName, , ext
        If (!ext) {
           mimeType := WebRequest.GetResponseHeader("Content-Type")
           If (mimeType) {
               RegRead, ext, HKEY_CLASSES_ROOT, MIME\Database\Content Type\%mimeType%, Extension
               filename := filename ext
           }
        }
    }
    ComObjError(true)
    UrlDownloadToFile, %url%, %fileName%
}

Another way to determine the extension could be a DllCall to Urlmon.dll\FindMimeFromData, but this requires the file to be already downloaded and it's also really complicated.



malcev
  • Members
  • 73 posts
  • Last active: Jan 28 2016 08:05 PM
  • Joined: 19 May 2011

It was not good idea to download file through only UrlDownloadToFile.
Because in that  case we download file 2 times.

The question is - how to download big files with WinHttpRequest?

May be to download file in chunks.

I found the next code on VBS, but I cannot convert it to AHK. :(

http://stackoverflow...-using-vbscript
Now the script is like this:

Download("http://avatars-fast.yandex.net/get-direct/R85qdm4hRHr-gA65dkojGA/y90")
Download("https://docs.google.com/uc?export=download&id=0B7FildjsrNkILWhYVHYwanJLS3c")
 
Download(url) {
   If (!InStr(url,"://"))
      url := "http://" . url
   WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
   ComObjError(false), WebRequest.Open("GET", url), WebRequest.Send()
   If (cdHeader := WebRequest.GetResponseHeader("Content-Disposition"))
      RegexMatch(cdHeader, "filename=""(?<name>[^""]+)""", file)   
   Else
   {
      SplitPath, url, fileName, , ext
      if (ext = "" && ctHeader := WebRequest.GetResponseHeader("Content-Type"))
      {
         RegRead, ext, HKEY_CLASSES_ROOT, MIME\Database\Content Type\%ctHeader%, Extension
         filename := filename ext
      }      
   }
   StreamToFile(WebRequest.ResponseStream, fileName), WebRequest := ""
}
 
StreamToFile(Stream, fileName)  {
   If (ComObjType(Stream) != 0xD)  
      Return 0
   pIStream := ComObjQuery(Stream, "{0000000c-0000-0000-C000-000000000046}")
   oFile := FileOpen(fileName, "w")
   While (cbRead != 0)   
      VarSetCapacity(Buffer, 8192)
      , DllCall(NumGet(NumGet(pIStream + 0) + 3 * A_PtrSize)
      , "ptr", pIStream, "ptr", &Buffer, "uint", 8192, "ptr*", cbRead)
      , oFile.RawWrite(&Buffer, cbRead)
   Return 1, ObjRelease(pIStream), oFile.Close()      
}


Bruttosozialprodukt
  • Members
  • 457 posts
  • Last active: Oct 18 2015 08:47 AM
  • Joined: 20 Oct 2012

Usually you would do a HEAD request instead of GET in this case, but when you do that, you won't get the Content-Disposition header.

I think that httpRequest.ahk is able to downlaod the file through a buffer sothat it won't overload your RAM:

http://www.autohotke...hk-lunicodex64/

If you want to do it yourself you might wanna check out the winhttp api. I wrote this function a while ago (big creadits to RHCP who teached me a lot about DllCalls):

HttpRequest(url,method:="",headers:="",ByRef body:="",proxy:="",pExcludeList:="",httpVersion:="",sessionOptions:="",requestOptions:="") {
    ;Makes working with the msdn functions easier
    static LPCWSTR:="UPTR"
    static DWORD:="UInt"
    static LPCVOID:="UPTR"
    static LPDWORD:="UPTR"
    static HINTERNET:="UPTR"
    static INTERNET_PORT:="UShort"
    static DWORD_PTR:="UPTR"
    static LPVOID:="UPTR"
    static NULL := 0
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Not supported so far
    asynch := False
    VarSetCapacity(callbackValue,A_PtrSize)
    ;;;;;;;;;;;;;;;;;;;;;
    
    ;Crack URL to use it's segments in the upcomming DllCalls
    VarSetCapacity(myStruct,60,0)
    numput(60,myStruct,0,"Uint") ; this dll function requires this to be set
    numput(1,myStruct,8,"Uint") ; SchemeLength
    numput(1,myStruct,20,"Uint") ; HostNameLength
    ;numput(1,myStruct,32,"Uint") ; UserNameLength
    ;numput(1,myStruct,40,"Uint") ; PasswordLength
    numput(1,myStruct,48,"Uint") ; UrlPathLength
    numput(1,myStruct,56,"Uint") ; ExtraInfoLength
    DllCall("Winhttp.dll\WinHttpCrackUrl","PTR",&url,"UInt",StrLen(url),"UInt",0,"PTR",&myStruct)
    
    scheme := StrGet(NumGet(myStruct,4,"Ptr"),NumGet(myStruct,8,"UInt"))
    ;userName := StrGet(NumGet(myStruct,28,"Ptr"),NumGet(myStruct,32,"UInt"))
    ;password := StrGet(NumGet(myStruct,36,"Ptr"),NumGet(myStruct,40,"UInt"))
    hostName := StrGet(NumGet(myStruct,16,"Ptr"),NumGet(myStruct,20,"UInt"))
    port := NumGet(myStruct,24,"Int")
    urlPath := StrGet(NumGet(myStruct,44,"Ptr"),NumGet(myStruct,48,"UInt"))
    extraInfo := StrGet(NumGet(myStruct,52,"Ptr"),NumGet(myStruct,56,"UInt"))
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Make the url parts usable
    If (scheme = "https") {
        port := (port) ? port : 443
        https := True
    } Else 
        https := False
    
    resource := urlPath . extraInfo
    ;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Parse headers and convert them to be usable
    addHeaders := ""
    acceptedTypes := []
    For header, value in headers 
    {
        If (header = "User-Agent")
            userAgent := value
        Else If (header = "Referer")
            referrer := value
        Else If (header = "Accept") {
            Loop, parse, acceptedTypes, `;
                acceptedTypes.Insert(value)
        } Else If (header = "Content-Length")
            bodySize := value
        Else
            addHeaders .= header . ": " . value . "`r`n"
    }
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Parse proxy exclude list and make it usable
    proxyBypassString := ""
    Loop, % pExcludeList.MaxIndex()
        proxyBypassString .= pExcludeList[A_Index] . ";"
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Initialize WinHttp application
    hSession := DllCall("Winhttp.dll\WinHttpOpen"
                       ,LPCWSTR,&userAgent
                       ,DWORD, (proxy) ? 3 : 1
                       ,LPCWSTR,&proxy
                       ,LPCWSTR,(pExcludeList) ? pExcludeList : NULL
                       ,DWORD,asynch)    
    If (!hSession)
        Return % {Body:"",Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"WinHttp initialization failed"} ;Msgbox,, hSession, LastError: %A_LastError%`nErrorLevel: %ErrorLevel%
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Set session options
    For optionKey, optionValue in sessionOptions
    {
        oResult := DllCall("Winhttp.dll\WinHttpSetOption"
               ,HINTERNET,hConnect
               ,DWORD,optionKey
               ,LPVOID,&optionValue
               ,DWORD,StrLen(optionValue))
        If !(oResult)
            Return % {Body:"",Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Setting session option #" . A_Index . " failed"}
    }
    ;;;;;;;;;;;;;;;;;;;;
    
    ;Specify target server
    hConnect := DllCall("Winhttp.dll\WinHttpConnect"
                       ,HINTERNET,hSession
                       ,LPCWSTR,&hostName
                       ,INTERNET_PORT,port
                       ,DWORD,0)    
    If (!hConnect)
        Return % {Body:"",Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Creating connect handle failed"} ;Msgbox,, hConnect, LastError: %A_LastError%`nErrorLevel: %ErrorLevel%
    ;;;;;;;;;;;;;;;;;;;;;;
    
    ;Create request handle
    hRequest := DllCall("Winhttp.dll\WinHttpOpenRequest"
                      ,HINTERNET,hConnect
                      ,LPCWSTR,(method) ? &method : NULL
                      ,LPCWSTR,(resource) ? &resource : NULL
                      ,LPCWSTR,(httpVersion) ? &httpVersion : NULL
                      ,LPCWSTR,(referrer) ? &referrer : NULL
                      ,LPCWSTR,(acceptedTypes.MaxIndex()) ? &acceptedTypes : NULL
                      ,DWORD,(https) ? 0x00800000 : NULL)
    If (!hRequest)
        Return % {Body:"",Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Creating request handle failed"} ;Msgbox,, hRequest, LastError: %A_LastError%`nErrorLevel: %ErrorLevel%
    ;;;;;;;;;;;;;;;;;;;;;;
    
    ;Set request options
    For optionKey, optionValue in requestOptions
    {
        oResult := DllCall("Winhttp.dll\WinHttpSetOption"
               ,HINTERNET,hConnect
               ,DWORD,optionKey
               ,LPVOID,&optionValue
               ,DWORD,StrLen(optionValue))
        If !(oResult)
            Return % {Body:"",Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Setting request option #" . A_Index . " failed"}
    }
    ;;;;;;;;;;;;;;;;;;;;
    
    ;Send request to server
    bResults := DllCall("Winhttp.dll\WinHttpSendRequest"
                       ,HINTERNET,hRequest
                       ,LPCWSTR,&addHeaders
                       ,DWORD,StrLen(addHeaders)
                       ,LPVOID,&body
                       ,DWORD,(bodySize) ? bodySize : StrLen(body)*2
                       ,DWORD,(bodySize) ? bodySize : StrLen(body)*2
                       ,DWORD_PTR,&callbackValue)
    If (!bResults)
        Return % {Body:"",Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Sending the request failed"} ; Msgbox,, bResults 1, LastError: %A_LastError%`nErrorLevel: %ErrorLevel%
    ;;;;;;;;;;;;;;;;;;;;;;
    
    ;Receive server response
    bResults := DllCall("Winhttp.dll\WinHttpReceiveResponse"
                       ,HINTERNET,hRequest
                       ,LPVOID,NULL)        
    If (!bResults)
        Return % {Body:"",Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Receiving server response failed"} ; Msgbox,, bResults 1, LastError: %A_LastError%`nErrorLevel: %ErrorLevel%
    ;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Receive the response body
    responseBody := ""
    VarSetCapacity(dwDownloaded,8)
    Loop {
        dwSize := 0
        If (!DllCall("Winhttp.dll\WinHttpQueryDataAvailable"
                    ,HINTERNET,hRequest
                    ,LPDWORD,&dwSize)) {
            Return % {Body:"",Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Getting info about available response data failed"} ;Msgbox,, hRequest, LastError: %A_LastError%`nErrorLevel: %ErrorLevel%
        } Else
            dwSize := Asc(dwSize)
        
        If (!dwSize)
            Break
        
        VarSetCapacity(pszOutBuffer,Asc(dwSize)+1,0)
        If (!DllCall("Winhttp.dll\WinHttpReadData"
                    ,HINTERNET,hRequest
                    ,LPVOID,&pszOutBuffer
                    ,DWORD,dwSize
                    ,LPDWORD,&dwDownloaded)) {
            MsgBox % "error:" A_LastError
        } Else {
            Loop, % Asc(dwDownloaded)
                responseBody .= Chr(NumGet(&pszOutBuffer,A_Index-1,"UChar"))
        }
        
        If (!dwDownloaded)
            break
            
     If (dwSize <= 0)
      Break
    }
    ;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Receive response headers
    dwSize := 0
    bResults := DllCall("Winhttp.dll\WinHttpQueryHeaders"
           ,HINTERNET,hRequest
           ,DWORD,22 ;raw
           ,LPCWSTR, NULL
           ,LPVOID, NULL
           , "UIntP", dwSize
           ;,LPDWORD, &dwSize
           ,LPDWORD, NULL)

    If (!bResults && A_LastError != 122) ; allow function to proceed if it was a buffer size error
        Return % {Body:responseBody,Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Getting the size of the response headers failed"} 
    If (A_LastError = 122) { ;buffer too small
        ;lpOutBuffer := new WCHAR[dwSize/sizeof(WCHAR)]

        VarSetCapacity(lpOutBuffer, dwSize, 0) 
        bResults := DllCall("Winhttp.dll\WinHttpQueryHeaders"
                          ,HINTERNET,hRequest
                          ,DWORD,22 ;raw
                          ,LPCWSTR,NULL
                          ,LPVOID, &lpOutBuffer
                          ,"UIntP", dwSize
                          ,LPDWORD, NULL)
    }
    If (!bResults)
        Return % {Body:responseBody,Headers:{},StatusCode:0,StatusText:"",HttpVersion:"",Error:"Receiving responseheaders failed"} ;Msgbox,, hRequest, LastError: %A_LastError%`nErrorLevel: %ErrorLevel%
    
    VarSetCapacity(lpOutBuffer, -1) ; update the internal string length - otherwise script will crash
    ;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;Parse received statusline and request headers
    responseHeaders := Object()
    requestLine := Array()
    Loop, parse, lpOutBuffer, `n, `r
    {
        If (!A_LoopField)
            Continue
        If (A_Index = 1) {
            Loop, parse, A_LoopField, %A_Space%
                requestLine[A_Index] := A_LoopField
        } Else
            responseHeaders.Insert(SubStr(A_LoopField,1,InStr(A_LoopField,": ")-1), SubStr(A_LoopField,InStr(A_LoopField,": ")+2))
    }
    responseHttpVersion := requestLine[1]
    statusCode := requestLine[2]
    statusText := requestLine[3]
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    If (A_LastError || ErrorLevel)
        Return % {Body:responseBody,Headers:responseHeaders,StatusCode:statusCode,StatusText:statusText,HttpVersion:responseHttpVersion,Error:"An error occurred"} ;Msgbox,, hRequest, LastError: %A_LastError%`nErrorLevel: %ErrorLevel%
    
    Return % {Body:responseBody,Headers:responseHeaders,StatusCode:statusCode,StatusText:statusText,HttpVersion:responseHttpVersion,Error:""}
}

You won't be able to save binary data with it, but it shows how you can retrive the responsebody in a loop with a buffer.
But this is really complicated stuff and right now I don't have the time to find out what exactly you would need to change.
The functions are documented here: http://msdn.microsof...7(v=vs.85).aspx
You might also want to check out the C++ examples on the site.



malcev
  • Members
  • 73 posts
  • Last active: Jan 28 2016 08:05 PM
  • Joined: 19 May 2011

by serzh82saratov and teadrinker.

url = http://ahkscript.org/download/ahk-install.exe
 
MsgBox % Download(url)
Return

Download(Location)
{
    Global Path, FullSize, KBSize
    Info := HttpQueryInfo(Location, 22)  
    RegexMatch(Info, ".*? (.*?)\R", stat)
    If !InStr(stat1, "200 OK")
        Return "Error: " stat1
    RegexMatch(Info, "\RContent-Disposition: .*?filename=""(?<D>.*?)""", C)   
    If CD !=  
        Path := CD
    Else
    {
        SplitPath, Location, FileName, , Ext, NameNoExt
        RegexMatch(Info, "\RContent-Type: (.*?/(.*?))\R", CT)   
        RegRead, ExtMIME, HKEY_CLASSES_ROOT, MIME\Database\Content Type\%CT1%, Extension  
        If (ExtMIME != "")
           Path := NameNoExt ExtMIME
        Else If (Ext = "" && CT2 != "")
            Path := NameNoExt "." CT2
        Else
            Path := FileName
    }
    If !Path
        Return "Error: Path not found"  
    RegexMatch(Info, "\RContent-Length: (?<L>.*?)\R", C), FullSize := CL
    MsgBox % Path "`n`n" KBSize := Floor(FullSize/1024) "KB"
    SetTimer, GetSize, 100
    UrlDownloadToFile, %Location%, %Path%   
    SetTimer, GetSize, -1
    Progress, Hide
    Return "Complete"
}

GetSize:
    FSize := FileOpen(Path, "r").Length
    Percent := Floor((FSize / FullSize) * 100)  
    Progress, %Percent%, %Percent%`% Complete, Downloading...
        , % Floor(FSize/1024) "KB / " KBSize " || " Path
    Return
 
Esc::   
    ExitApp

HttpQueryInfo(URL, QueryInfoFlag=21, Proxy="", ProxyBypass="")
{
   hModule := DllCall("LoadLibrary", "str", "wininet.dll", Ptr)
   AccessType := Proxy = "" ? 1 : 3
   
   Loop 1
   {
      Error := 1
      if !io_hInternet := DllCall("wininet\InternetOpen", "str", "", "uint", AccessType, "str", Proxy, "str", ProxyBypass, "uint", 0, Ptr) ;dwFlags
         break
      
      if !iou_hInternet := DllCall("wininet\InternetOpenUrl", Ptr, io_hInternet, "str", url, "str", "", "uint", 0, "uint", 0x80000000, "uint", 0)
         break
      
      VarSetCapacity(buffer_len, 4, 0)
      Loop
      {         
         if A_Index = 3
            break 2
         
         VarSetCapacity(buffer, NumGet(&buffer_len+0, "UInt"))
         hqi := DllCall("wininet\HttpQueryInfo", Ptr, iou_hInternet, "uint", QueryInfoFlag, Ptr, &buffer, Ptr, &buffer_len, "uint", 0)
      } Until hqi
      Error := ""
   }
   
   DllCall("wininet\InternetCloseHandle",  Ptr, iou_hInternet)
   DllCall("wininet\InternetCloseHandle",  Ptr, io_hInternet)
   DllCall("FreeLibrary", Ptr, hModule)
   
   Return, Error ? -1 : StrGet(&buffer)
}