Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

UrlDownloadToFile Progress


  • Please log in to reply
57 replies to this topic
bmcclure
  • Members
  • 774 posts
  • Last active: Jan 04 2014 10:44 PM
  • Joined: 24 Nov 2007
This function is a slightly modified version of Sean's original RegisterCallback version. The problem is the function never ends and just hands indefinitely.

The file downloads successfully, the download window closes successfully, but something never ends.
SW_Download(pUrl,pFile,pTitle="",pGuiNum="") {
	global
	If pGuiNum {
		GuiNum = %pGuiNum%:
		Gui, %GuiNum%Default
	}
	If Not pTitle
		pTitle := SubStr(pFile,InStr(pFile,"\","-1")+1)
	thisDownloadSW := SW_Create("Downloading " . pTitle,300,125,pGuiNum) ; Create the window
	;Gui, Add, Text, x8 y27 w280 h60 +backgroundtrans, Downloading %pTitle%
	Gui, Add, Progress, w280 h30 x8 y27 background424242 c282828 vSWDLprogress
	Gui, Add, Text, xp y+10 h30 +backgroundtrans vSWDLtext1, %pTitle% - 
	Gui, Add, Text, x+5 yp h30 +backgroundtrans w150 vSWDLtext2,
	SW_Show()
	Gui, -Resize
	VarSetCapacity(vt, 4*11), nParam = 31132253353
	Loop, Parse, nParam
		NumPut(RegisterCallback("SW_DownloadProgress", "Fast", A_LoopField, A_Index-1), vt, 4*(A_Index-1))
	DllCall("urlmon\URLDownloadToFileA", "Uint", 0, "str", pUrl, "str", pFile, "Uint", 0, "UintP", &vt)
	WinWaitClose,% "ahk_id " . SteamWin%thisDownloadSW%WinID
	Return 1
}

SW_DownloadProgress(pthis, nProgress = 0, nProgressMax = 0, nStatusCode = 0, pStatusText = 0)
{
	global
	If (A_EventInfo = 6) {
		GuiControl,,SWDLprogress,% p := 100 * nProgress//nProgressMax
		GuiControl,,SWDLtext2,%nProgress% of %nProgressMax%
		If (p = 100)
			WinClose,% "ahk_id " . SteamWin%thisDownloadSW%WinID
	}
	Return 0
}

Update: OK, actually, it's the WinWaitClose that never ends. But I don't understand it... the download window is successfully closed with WinClose, and WinWaitClose uses the exact same ahk_id for the title. Oh well, I guess the issue is unrelated to the download--thanks for the cool script!

Update 2: Odd, not even this works:
Loop
		IfWinNotExist,% "ahk_id " . SteamWin%thisDownloadSW%WinID
			Break
	Return 1

Something else in this download script must be stopping this from working. If I remove the code that's supposed to wait for the window, the function completes, but it completes immediately without waiting. If I try and wait for the window, it waits indefinitely even after the window is closed. Hmm...

I even tried setting a global variable in the DownloadProgress function when the download completes, and waiting for that variable in the main script. But it never stops waiting, even after the variable should be set. This is odd behavior. Could the callback or DllCall be somehow responsible?

Without waiting for the window to close, or setting a variable upon completion, I don't know how to know when the download is complete. Not to mention, is that going to mean I can't wait for any more windows in the remainder of my script? This is confusing.

Murp-e
  • Members
  • 531 posts
  • Last active: Sep 27 2011 11:44 AM
  • Joined: 12 Jan 2007
Would winkill or Process, close, PID-or-Name do any good?

bmcclure
  • Members
  • 774 posts
  • Last active: Jan 04 2014 10:44 PM
  • Joined: 24 Nov 2007
Using WinKill doesn't seem to correct the issue, it's still indefinitely waiting for the already-killed window for some reason. It's like whatever changes I make from within the callback function aren't seen afterwards by the rest of the script. But I could be completely wrong about that. WinWaitClose shouldn't care how the window was closed as long as it stops existing.

Murp-e
  • Members
  • 531 posts
  • Last active: Sep 27 2011 11:44 AM
  • Joined: 12 Jan 2007
What about:
WinGetText, OutputVar, ahk_pid %myPID%

if errorlevel

 break


Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
You don't need to wait, the DllCall() will not return until the download is completed.

bmcclure
  • Members
  • 774 posts
  • Last active: Jan 04 2014 10:44 PM
  • Joined: 24 Nov 2007
D'oh!

Thanks Sean, I didn't realize that. So I can potentially close the window immediately after the DLL call then I take it. Nice.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Thanks again, Sean. This is a great convenience.
I slightly modified your code to create unobtrusive tray-tip like progress:

DetectHiddenWindows, On

url:="http://www.pinellascounty.org/fbg/images/wildlife/Tree_Frog_lg.jpg"
splitpath,url,ofn
file := A_Temp "\" ofn
MsgBox, % file "`n" url
If Download( url, file ) 
 Runwait, Rundll32.exe %A_Windir%\system32\shimgvw.dll`,ImageView_Fullscreen %file%

Return


Download( url, file ) {
  static _init
  global _cu
  Splitpath,file, _dFile
  if ! init
{ RegRead,SysNot,HKCU,AppEvents\Schemes\Apps\.Default\SystemNotification\.Current 
  Transform, SysNot, deref, %sysnot% 
  SysGet, m, MonitorWorkArea, 1
  y:=(mBottom-52-2),x:=(mRight-330-2),init:=1,VarSetCapacity(vt,4*11),nPar:="31132253353"
  Loop, Parse, nPar
     NumPut(RegisterCallback("DL_Progress","Fast",A_LoopField,A_Index-1),vt,4*(A_Index-1))
} VarSetCapacity(_cu,255),DllCall("shlwapi\PathCompactPathExA",Str,_cu,Str,url,UInt,50) 
  Progress,Hide CWFAFAF7 CT000020 CB445566 x%x% y%y% w330 h52 B1 FS8 WM700 WS700 FM8 ZH12 ZY3 C11,,%_cu%,AutoHotkeyProgress,Tahoma
  WinSet,Transparent,180,AutoHotkeyProgress
  SoundPlay, %SysNot%
  re:=DllCall("urlmon\URLDownloadToFileA", Uint,0, Str,url,Str,file,Uint,0,UintP,&vt)
  SoundPlay, %SysNot%
  Progress, Off
Return re=0 ? 1 : 0
} 
DL_Progress( pthis, nP=0, nPMax=0, nSC=0, pST=0 ) {
  global _cu
  If (A_EventInfo=6) 
{ Progress, Show
  Progress, % (P:=100*nP//nPMax),% "Downloading:     " Round(np/1024,1) " Kb / " 
            .  Round(npmax/1024) " Kb    [ " p "`% ]",%_cu%
} Return 0
}

:)

Edit:

Snapshot of TNA -
Posted Image[/list]

trik
  • Members
  • 1317 posts
  • Last active: Jun 11 2010 11:48 PM
  • Joined: 15 Jul 2007
Sean, when I first saw this, I sort of brushed it off thinking it was just another boring function I could never hope to understand. Now I have learned to completely read the title before passing through. I greatly appreciate you making this.

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

I have two questions about urlmon\URLDownloadToFile progress method

1) It returns the file from cache when available.. Can we force the download?
2) It does not download webpages
for eg: <!-- m -->http://www.autohotke...pic.php?t=19475<!-- m --> (this topic)
or <!-- m -->http://msdn.microsof...ibrary/ms775133<!-- m -->
and returns 0x800401E4

Please help!

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

1) It returns the file from cache when available.. Can we force the download?

I don't think making URLDownloadToFile do so will be simple. Use instead URLDownloadToCacheFile with BINDF_GETNEWESTVERSION flag.
sUrl := "http://www.autohotkey.com/download/AutoHotkeyInstall.exe" 
sFile := A_Temp . "\AutoHotkeyInstall.exe"
VarSetCapacity(sCache,260*2) ; assuming UNICODE build

DllCall("urlmon\URLDownloadToCacheFileW", "Ptr", 0, "Str", sUrl, "Str", sCache, "UInt", VarSetCapacity(sCache)//2, "UInt", [color=red]BINDF_GETNEWESTVERSION[/color]:=0x10, "Ptr*", &vt)
FileCopy, %sCache%, %sFile%

2) It does not download webpages
for eg: <!-- m -->http://www.autohotke...pic.php?t=19475<!-- m --> (this topic)
or <!-- m -->http://msdn.microsof...ibrary/ms775133<!-- m -->
and returns 0x800401E4

It's Invalid Syntax error. What did you use as URL?
MK_E_SYNTAX = 0x800401E4 ; Invalid Syntax


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

I don't think making URLDownloadToFile do so will be simple. Use instead URLDownloadToCacheFile with BINDF_GETNEWESTVERSION flag.


er.. Seeing the parameters, I am unable to guess how to pass that flag to the function.
Guess, I am stuck with UrlDownLoadToFile... I could workaround calling UrlDownloadToFile twice, first to find and delete the cache file and then do the download.

It's Invalid Syntax error. What did you use as URL?

MK_E_SYNTAX = 0x800401E4 ; Invalid Syntax


I am able to reproduce it with your code. The only alteration I have in my code is the return type for urlmon\UrlDownloadToFile

sUrl  := "http://www.autohotkey.com/forum/viewtopic.php?t=19475"
sFile := A_ScriptDir "\post.htm"

Progress, % "M W" . A_ScreenWidth//2, 0, 0 of 0
VarSetCapacity(vt, 4*11), nParam = 31132253353
Loop, Parse, nParam
   NumPut(RegisterCallback("DownloadProgress", "Fast", A_LoopField, A_Index-1), vt, 4*(A_Index-1))

Res := DllCall("urlmon\URLDownloadToFileA", "Uint", 0, "str", sUrl, "str", sFile, "Uint", 0, "UintP", &vt, [color=red]UInt[/color] )
Progress, Off
SetFormat, Integer, hex
MsgBox, % Res+0

DownloadProgress(pthis, nProgress = 0, nProgressMax = 0, nStatusCode = 0, pStatusText = 0)
{
   If A_EventInfo = 6
   Progress, % p := 100 * nProgress//nProgressMax, %p%, % nProgress . " of " . nProgressMax
   Return 0
}


Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
It worked fine with AHK_L UNICODE 64bit build. The code with the official AHK will be:
sUrl  := "http://www.autohotkey.com/forum/viewtopic.php?t=19475" 
sFile := A_ScriptDir "\post.htm"

Progress, % "M W" . A_ScreenWidth//2, 0, 0 of 0
VarSetCapacity(vt, 4*11), nParam = 31132253353
Loop, Parse, nParam
   NumPut(RegisterCallback("DownloadProgress", "Fast", A_LoopField, A_Index-1), vt, 4*(A_Index-1))

hr := DllCall("urlmon\URLDownloadToCacheFileA", "UInt", 0, "Str", sUrl, "Str", sCache, "UInt", VarSetCapacity(sCache,260), "UInt", BINDF_GETNEWESTVERSION:=0x10, "UInt*", &vt, "UInt")
If hr = 0
    FileMove, %sCache%, %sFile%, 1
MsgBox % hr "|" sCache

DownloadProgress(pthis, nProgress = 0, nProgressMax = 0, nStatusCode = 0, pStatusText = 0)
{
    If A_EventInfo = 6
    Progress, % p := 100 * nProgress//nProgressMax, %p%, % nProgress . " of " . nProgressMax
    Return 0
}


Uberi
  • Moderators
  • 1119 posts
  • Last active: May 02 2015 06:05 PM
  • Joined: 23 Aug 2010

It worked fine with AHK_L UNICODE 64bit build. The code with the official AHK will be:

sUrl  := "http://www.autohotkey.com/forum/viewtopic.php?t=19475" 
sFile := A_ScriptDir "\post.htm"

Progress, % "M W" . A_ScreenWidth//2, 0, 0 of 0
VarSetCapacity(vt, 4*11), nParam = 31132253353
Loop, Parse, nParam
   NumPut(RegisterCallback("DownloadProgress", "Fast", A_LoopField, A_Index-1), vt, 4*(A_Index-1))

hr := DllCall("urlmon\URLDownloadToCacheFileA", "UInt", 0, "Str", sUrl, "Str", sCache, "UInt", VarSetCapacity(sCache,260), "UInt", BINDF_GETNEWESTVERSION:=0x10, "UInt*", &vt, "UInt")
If hr = 0
    FileMove, %sCache%, %sFile%, 1
MsgBox % hr "|" sCache

DownloadProgress(pthis, nProgress = 0, nProgressMax = 0, nStatusCode = 0, pStatusText = 0)
{
    If A_EventInfo = 6
    Progress, % p := 100 * nProgress//nProgressMax, %p%, % nProgress . " of " . nProgressMax
    Return 0
}


I believe the line:

VarSetCapacity(vt, 4*11), nParam = 31132253353

Should be:

VarSetCapacity(vt, 4*11), nParam := 31132253353

Unless I'm mistaken? Nice script, by the way.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Again: URLDownloadToCacheFileA() did not download webpages for me in IE 6.0.2900 in XP SP3
But I found the culprit. Using DllCall( "ole32\CoInitialize", UInt,0 ) does the trick, again
urlmon\URLDownloadToFile() also works now, with CoInitialize() added.
Many Many Thanks!... For the quick reply and especially for URLDownloadToCacheFileA()

:D :D :D

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

I believe the line:

VarSetCapacity(vt, 4*11), nParam = 31132253353
Should be:
VarSetCapacity(vt, 4*11), nParam := 31132253353

In v1.0.46.01+, when a comma is followed immediately by a variable and an equal sign, that equal sign is automatically treated as an assignment (:=). For example, all of the following are assignments: x:=1, y=2, a=b=c

Anyway, I don't recommend this practice, IMO, one of the most confusing syntaxes in AHK.