Jump to content

Download Manager


erifash
 Share

Recommended Posts

I got tired of all the other download managers I have found so I decided to write my own. I have the GUI completely done and a couple of other functions too. The only problem I am having is with incomplete downloads. I would like to be able to start a download on my thumb drive, pause the download, then complete it on a different computer. In other words, how can I handle incomplete downloads? Here is the GUI:

#NoTrayIcon
#include <GUIConstants.au3>
#include <GUIListView.au3>

Global Const $WM_NOTIFY = 0x004E
Global Const $NM_DBLCLK = -3

Opt("GUIResizeMode", 1)
Opt("GUIOnEventMode", 1)

_Exist("Download Manager")

Global $oErr = ObjEvent("AutoIt.Error", "_ErrorHandler")
$shell32 = @SystemDir & "\shell32.dll"

$gui = GUICreate("Download Manager", 540, 160, Default, Default, $WS_OVERLAPPEDWINDOW)

$start = GUICtrlCreateButton("Start", 0, 0, 20, 20, $BS_ICON)
GUICtrlSetImage(-1, $shell32, 176, 0)
GUICtrlSetTip(-1, "Start download")
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetOnEvent(-1, "_EventHandler")

$pause = GUICtrlCreateButton("Pause", 20, 0, 20, 20, $BS_ICON)
GUICtrlSetImage(-1, $shell32, 112, 0)
GUICtrlSetTip(-1, "Pause download")
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetOnEvent(-1, "_EventHandler")

$add = GUICtrlCreateButton("Add", 40, 0, 20, 20, $BS_ICON)
GUICtrlSetImage(-1, $shell32, 155, 0)
GUICtrlSetTip(-1, "Add new download")
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetOnEvent(-1, "_EventHandler")

$remove = GUICtrlCreateButton("Remove", 60, 0, 20, 20, $BS_ICON)
GUICtrlSetImage(-1, $shell32, 109, 0)
GUICtrlSetTip(-1, "Remove selected download")
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetOnEvent(-1, "_EventHandler")

$prefs = GUICtrlCreateButton("Preferences", 80, 0, 20, 20, $BS_ICON)
GUICtrlSetImage(-1, $shell32, 126, 0)
GUICtrlSetTip(-1, "Edit preferences")
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetOnEvent(-1, "_EventHandler")

$progress = GUICtrlCreateProgress(100, 0, 440, 20)
GUICtrlSetResizing(-1, $GUI_DOCKHEIGHT + $GUI_DOCKLEFT + $GUI_DOCKRIGHT)

$list = GUICtrlCreateListView("Name|Status|Remaining|Speed", 0, 20, 540, 120, $LVS_SHOWSELALWAYS, $LVS_EX_GRIDLINES)
GUICtrlSetResizing(-1, $GUI_DOCKBORDERS)
_GUICtrlListViewSetColumnWidth(-1, 0, 240)
_GUICtrlListViewSetColumnWidth(-1, 1, 80)
_GUICtrlListViewSetColumnWidth(-1, 2, 105)
_GUICtrlListViewSetColumnWidth(-1, 3, 90)

$status = GUICtrlCreateInput("0 downloading; 0 files; 0 KB/s total", 0, 140, 540, 20)
GUICtrlSetResizing(-1, $GUI_DOCKHEIGHT + $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKBOTTOM)

GUISetOnEvent($GUI_EVENT_CLOSE, "_EventHandler", $gui)
GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")

GUICtrlSetState($status, $GUI_DISABLE)
GUICtrlSetState($list, $GUI_FOCUS)
GUISetState()

While 1
   _ReduceMemory()
   Sleep(5000)
WEnd

Func WM_Notify_Events( $hWndGUI, $MsgID, $wParam, $lParam )
   #forceref $hWndGUI, $MsgID, $wParam
   Local $tagNMHDR, $event, $hwndFrom, $code
   $tagNMHDR = DllStructCreate("int;int;int", $lParam)
   If @error Then Return
   $event = DllStructGetData($tagNMHDR, 3)
   Select
      Case $wParam = $list
         Select
            Case $event = $NM_DBLCLK
               _ListEventHandler(_GUICtrlListViewGetItemText($list, _GUICtrlListViewGetSelectedIndices($list)))
         EndSelect
   EndSelect
   $tagNMHDR = 0
   $event = 0
   $lParam = 0
EndFunc

Func _EventHandler()
   Switch @GUI_CtrlId
      Case $GUI_EVENT_CLOSE
         Exit
      Case $start
         MsgBox(0, "Event", GUICtrlRead(@GUI_CtrlId))
      Case $pause
         MsgBox(0, "Event", GUICtrlRead(@GUI_CtrlId))
      Case $add
         MsgBox(0, "Event", GUICtrlRead(@GUI_CtrlId))
      Case $remove
         MsgBox(0, "Event", GUICtrlRead(@GUI_CtrlId))
      Case $prefs
         MsgBox(0, "Event", GUICtrlRead(@GUI_CtrlId))
   EndSwitch
EndFunc

Func _ListEventHandler( $text )
   $text = StringSplit($text, "|")
   If @error or $text[1] = "" Then Return
   MsgBox(0, "Event", $text[1])
EndFunc

Func _ErrorHandler()
   MsgBox(0x41030, "COM Error", "Intercepted COM Error :" & @CRLF & @CRLF & _
      "err.description is: " & @TAB & $oErr.description & @CRLF & _
      "err.windescription:" & @TAB & $oErr.windescription & @CRLF & _
      "err.number is: " & @TAB & Hex($oErr.number, 8) & @CRLF & _
      "err.lastdllerror is: " & @TAB & $oErr.lastdllerror & @CRLF & _
      "err.scriptline is: " & @TAB & $oErr.scriptline & @CRLF & _
      "err.source is: " & @TAB & $oErr.source & @CRLF & _
      "err.helpfile is: " & @TAB & $oErr.helpfile & @CRLF & _
      "err.helpcontext is: " & @TAB & $oErr.helpcontext _
   )
   SetError(1)
EndFunc

Func _Exist( $str, $fatal = 1 )
   Local $h = DllCall("kernel32.dll", "int", "CreateMutex", "int", 0, "long", 1, "str", StringReplace($str, "\", "..")), $l = DllCall("kernel32.dll", "int", "GetLastError")
   If $l[0] = 183 and $fatal Then Exit
   SetError($l[0])
   Return $h[0]
EndFunc

Func _Error( $sText, $iFatal = 0, $sTitle = "Error", $iOpt = 0x41030 )
   Local $ret = MsgBox($iOpt, $sTitle, $sText)
   If $iFatal Then Exit
   Return SetError(1, 0, $ret)
EndFunc

Func _ReduceMemory( $pid = -1, $psapi = "psapi.dll", $kernel32 = "kernel32.dll" )
   If $pid = -1 Then
      Local $ret = DllCall($psapi, "int", "EmptyWorkingSet", "long", -1)
   Else
      Local $hwnd = DllCall($kernel32, "int", "OpenProcess", "int", 0x1F0FFF, "int", 0, "int", $pid)
      Local $ret = DllCall($psapi, "int", "EmptyWorkingSet", "long", $hwnd[0])
      DllCall($kernel32, "int", "CloseHandle", "int", $hwnd[0])
   EndIf
   Return $ret[0]
EndFunc

Func _ByteFormat( $bytes, $decimal = 0 )
   Local $i = 0, $word[5] = [" B", " KB", " MB", " GB", " TB"]
   While $bytes < 1024
      $bytes /= 1024
   WEnd
   Return Round($bytes, $decimal) & $word[$i]
EndFunc

Thanks! :whistle:

Link to comment
Share on other sites

@lod3n: Thanks for that bit of information, it helped a lot. :lmao:

I wanted to do it in pure AutoIt so I discovered that "partial content" is already built into the HTTP protocol. I scripted a small tcp listener set to port 80 and used a download manager to try and download an imaginary "file" off my imaginary "server." Here is the header that it sent:

GET /woot.txt HTTP/1.0

Referer: http://x.x.x.x/woot.txt

Range: bytes=0-

User-Agent: Web Download

Host: x.x.x.x

Pragma: no-cache

I decided to give this header a test run so I wrote a script to start/resume a download of a large file (123 MB). Here it is:

; try to start (or resume) the download of
; http://61.74.68.173/GIS/Gunbound_GIS_WC_545.exe
; which is 123 MB in size so it should be good for testing

$file = @ScriptDir & "\Gunbound_GIS_WC_545.exe"
If FileExists($file) Then
    $bytes = FileGetSize($file)
Else
    $bytes = 0
EndIf

TCPStartup()

$conn = TCPConnect("61.74.68.173", 80)
If $conn = -1 or @error Then Exit

$h  = "GET /GIS/Gunbound_GIS_WC_545.exe HTTP/1.0" & @CRLF
$h &= "Referer: http://61.74.68.173/GIS/Gunbound_GIS_WC_545.exe" & @CRLF
$h &= "Range: bytes=" & $bytes & "-" & @CRLF
$h &= "User-Agent: AutoIt3" & @CRLF
$h &= "Host: " & @IPAddress1 & @CRLF
$h &= "Pragma: no-cache" & @CRLF
$h &= @CRLF
TCPSend($conn, $h)

$listen = TCPListen(@IPAddress1, 80)

While 1
    $sock = TCPAccept($listen)
    If $sock > -1 Then
        $data = ""
        While not @error
            FileWrite($file, $data)
            $data = TCPRecv($sock, 2048)
        WEnd
        TCPCloseSocket($sock)
    EndIf
    Sleep(50)
WEnd

... and it doesn't work :evil:

If anyone would care to try and help me fix this it would be great! ;)

EDIT: Nevermind, I figured it out.

Edited by erifash
Link to comment
Share on other sites

  • 2 months later...
  • 2 months later...
  • 2 years later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...