llewxam Posted September 15, 2009 Posted September 15, 2009 expandcollapse popupAutoItSetOption("TrayIconHide",1) #include <GUIConstantsEx.au3> ;needed for $GUI_EVENT_CLOSE, $GUI_DISABLE, $GUI_UNCHECKED #include <String.au3> ;needed for _StringAddThousandsSep #include <WindowsConstants.au3> ;needed for $DT_End_Ellipsis which trims the path&file name to fit $fileinfo and $copyinfo #include <Array.au3> ;needed for _ArrayDisplay #include <ListboxConstants.au3> Global $sourcelist, $synced, $howmany, $howbig, $newprofilelist $temp = "" ;$temp is all file names & relative paths, see below; done to avoid _ArrayAdd $failedlist = "" ;this is to store the file names that failed to sync $loaded = 0 ;if a profile is loaded this is set to 1, then you will not be asked to save it as a profile $howmany = 0 ;total file count of the source directory $synced = 0 ;counts how many files needed to be synced $failed = 0 ;counts how many files failed to sync $main = GUICreate("File Syncer", 400, 335) ;main window $box=GUICtrlCreateGraphic(195,317,380,2) ; <--------------------------------------------| GUICtrlSetGraphic($box, $GUI_GR_COLOR, 0xa8a8a8) ; <--| GUICtrlSetGraphic($box, $GUI_GR_MOVE, 1,1) ; <--| GUICtrlSetGraphic($box, $GUI_GR_LINE,199,1) ; <--| $maxadsoft=GUICtrlCreateLabel("MaxImuM AdVaNtAgE SofTWarE(C) 2009",195,320,380,20) ; <--| GUICtrlSetColor($maxadsoft,0xa8a8a8) ; <--------------------------------------------| $sourcemsg = GUICtrlCreateLabel("", 10, 10, 380, 20) ;shows file count for current sync job $sourceinfo = GUICtrlCreateLabel("", 140, 10, 380, 20) ;shows file count for current sync job $syncedinfo = GUICtrlCreateLabel("", 260, 10, 380, 20) ;just adds a message when sync has started $fileinfo = GUICtrlCreateLabel("", 10, 70, 380, 20, $DT_END_ELLIPSIS) ;shows current file name $fileprog = GUICtrlCreateLabel("", 10, 90, 380, 20) ;shows current file number & total file count $copyprogress = GUICtrlCreateProgress(10, 130, 380, 20) ;progress bar for current file copy $progressbar = GUICtrlCreateProgress(10, 200, 380, 20) ;progress bar for total files $sourceinput = GUICtrlCreateInput("Type The Source Or Browse Above", 10, 260, 180) ;input box for source path $targetinput = GUICtrlCreateInput("Type The Target Or Browse Above", 210, 260, 180) ;input box for target path $sourcebutton = GUICtrlCreateButton("Source", 60, 230, 80) ;button for FileSelectFolder for source path $targetbutton = GUICtrlCreateButton("Target", 260, 230, 80) ;button for FileSelectFolder for target path $gobutton = GUICtrlCreateButton("GO", 120, 285, 80) ;start $loadprofile=GUICtrlCreateButton("Profiles",200,285,80) ;button to load a saved profile GUISetState(@SW_SHOW, $main) ;done setting up GUI Dim $AccelKeys[1][2] = [["{ENTER}", $gobutton]] ;sets Enter to start sync GUISetAccelerators($AccelKeys) ;sets Enter to start sync Do $msg = GUIGetMsg() ;get mouse/keyboard actions If $msg = $sourcebutton Then GUICtrlSetData($sourceinput, FileSelectFolder("Select folder to sync", "")) ;set source If $msg = $targetbutton Then GUICtrlSetData($targetinput, FileSelectFolder("Select where to place the files", "", 1)) ;set target if $msg = $loadprofile then profiles() ;load/delete a profile $msg="" ;when profiles() is exited $msg must be cleared or the app tries to close EndIf if $msg = $gobutton Then If FileExists(GUICtrlRead($sourceinput)) and GUICtrlRead($targetinput)<>"" and GUICtrlRead($targetinput)<>"Type The Target Or Browse Above" then ;check that the source path exists, and that a target path has been specified ExitLoop ;if the above criteria are met then leave the setup and get some work done :) Else if not FileExists(GUICtrlRead($sourceinput)) then msgbox(48,"Bad Source!","The source path does not exist!") ;warning if GUICtrlRead($targetinput)="" or GUICtrlRead($targetinput)="Type The Target Or Browse Above" then msgbox(48,"No Target!","The target path has not been set yet!") ;warning endif EndIf If $msg = $gui_event_close Then Exit ;quit Until 1 = 2 ControlFocus("", "", $gobutton) ;done so when all of the buttons are disabled the focus will be on a non-functional control GUICtrlSetState($sourcebutton, $gui_disable) ; <-----------------------| GUICtrlSetState($targetbutton, $gui_disable) ; | GUICtrlSetState($gobutton, $gui_disable) ; | shut off the buttons once the sync has started GUICtrlSetState($loadprofile, $gui_disable) ; | GUICtrlSetState($sourceinput, $gui_disable) ; | GUICtrlSetState($targetinput, $gui_disable) ; <-----------------------| $basedir = GUICtrlRead($sourceinput) ;set $basedir to source path $target = GUICtrlRead($targetinput) ;set $target to target path if $loaded=0 then ;if this is not a previously loaded profile $profile=msgbox(4,"Save Sync?","Would you like to save the Source and Target as a profile?") ;wanna save this profile? if $profile=6 then ;yes $nameit=GUICreate("Profile Name?",225,50) ;window title to save profile name $profilename=GUICtrlCreateInput("",5,5,185) ;input box for the profile name $accept=GUICtrlCreateButton("OK",190,5,25) ;accept button GUISetState(@sw_show,$nameit) ;done setting up GUI Dim $AccelKeys[1][2] = [["{ENTER}", $accept]] ;set Enter to accept GUISetAccelerators($AccelKeys) ;set Enter to accept Do $msg = GUIGetMsg() ;get mouse/keyboard actions If $msg = $accept Then ;OK $thename=GUICtrlRead($profilename) ;assign the name of the profile ExitLoop ;done EndIf Until 1 = 2 GUIDelete($nameit) ;remove the profile name window $currentprofiles=RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\MaxImuM Advantage","Sync") ;get the current saved profiles if $currentprofiles<>"" then $currentprofiles=$currentprofiles&"*" ;if there are preexisting profile add * delimiter RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\MaxImuM AdVaNtAgE","Sync","REG_SZ",$currentprofiles&$thename&"*"&$basedir&"*"&$target) ;add the new profile EndIf EndIf $trimamount = StringLen($basedir) + 1 ;used to remove the source path from the file names GUICtrlSetData($sourcemsg,"Enumerating Source Files: ") ; $begin = TimerInit() ;start the timer $pause = GUICtrlCreateCheckbox("Pause", 175, 150) ;pause, then option to quit job during operation (GUI button overlap) theheart($basedir) ;theheart() is the folder recursion routine GUICtrlSetData($sourcemsg, "Finished Enumeration: " & _StringAddThousandsSep($howmany)) ;sets the total file count from the source path GUICtrlDelete($sourceinfo) $sourcelist = StringSplit($temp, Chr(1)) ;$temp is all file names & relative paths, see below; done to avoid _ArrayAdd GUICtrlSetData($syncedinfo, "Checking For Files To Sync") ;message that work has started ;$pause = GUICtrlCreateCheckbox("Pause", 175, 150) ;pause, then option to quit job during operation (GUI button overlap) $total = $sourcelist[0] - 1 ;should have the same result as $howmany For $lookatsource = 1 To $total ;start with the first file found, go down the line... While GUICtrlRead($pause) == 1 ;look for the pause button $quit=msgbox(36,"Paused","Quit Now?") if $quit=6 then exit ;yes if $quit=7 then GUICtrlSetState($pause,$gui_unchecked) ;no, so uuncheck the box WEnd GUICtrlSetData($fileinfo, $sourcelist[$lookatsource]) ;show file name GUICtrlSetData($fileprog, "(" & _StringAddThousandsSep($lookatsource) & "/" & _StringAddThousandsSep($total) & ")") ;show progress GUICtrlSetData($progressbar, $lookatsource / $total * 99) ;I use 99 cuz I hate seeing a full progress bar when something isn't done yet!!! If Not FileExists($target & "\" & $sourcelist[$lookatsource]) Then ;file does need to be synced $copied=_CopyWithProgress($basedir & "\" & $sourcelist[$lookatsource], $target & "\" & $sourcelist[$lookatsource]) ;copy the file if $copied=1 then $synced += 1 ;file synced, increment the synced file count if $copied=0 then ;file did not sync properly $failedlist=$failedlist&$basedir & "\" & $sourcelist[$lookatsource]&"*" ;add the file name to the list of failures $failed+=1 ;increment the failed counter EndIf EndIf Next $seconds=TimerDiff($begin) / 1000 if $seconds<60 then $time=round($seconds,2) $type=" Seconds" Else $time=round($seconds/60,2) $type=" Minutes" EndIf MsgBox(0, "Finished in " & _StringAddThousandsSep($time)&$type, "Synced " & _StringAddThousandsSep($synced) & " files with "&$failed&" errors.") ;shos some stats when done if $failed>0 then $showfailed=msgbox(4,"See Failed?","Do you want to see the files that failed?") if $showfailed=6 Then StringTrimRight($failedlist,1) ;take off the trailing * delimeter $failedarray=StringSplit($failedlist,"*") ;break up the list of failed files $failedwindow=GUICreate("Failed Files",@DesktopWidth,300) ;to display the failed files $failedlist=GUICtrlCreateList("",5,5,@DesktopWidth-10,290) ;to display the failed files GUISetState(@sw_show,$failedwindow) ;done setting up GUI for $show=1 to $failed GUICtrlSetData($failedlist,$failedarray[$show]) ;list the failed files Next Do $msg=GUIGetMsg() if $msg=$gui_event_close then exit ;when the failed window is closed, quit the program until 1=2 ; _ArrayDisplay($failedarray,"Failed Files") EndIf EndIf Exit Func profiles() $currentprofiles=RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\MaxImuM Advantage","Sync") ;get list of current profiles if $currentprofiles="" Then msgbox(48,"No Profiles!","There are no profiles to load!") Else $selectprofile=GUICreate("Select A Profile",200,202) $showprofiles=GUICtrlCreateList("",5,5,190,170) $selectprofilebutton=GUICtrlCreateButton("Load",5,171,60) $profiledelete=GUICtrlCreateButton("Delete",135,171,60) GUISetState(@sw_show,$selectprofile) GUICtrlSetState($showprofiles,$gui_disable) $profilelist=StringSplit($currentprofiles,"*") for $cycle=1 to $profilelist[0] step 3 GUICtrlSetData($showprofiles,$profilelist[$cycle]) Next GUICtrlSetState($showprofiles,$gui_enable) EndIf Do $msg = GUIGetMsg() if $msg=$gui_event_close Then ExitLoop EndIf If $msg = $selectprofilebutton Then $selectedprofile=GUICtrlRead($showprofiles) for $cycle=1 to $profilelist[0] if $profilelist[$cycle]=$selectedprofile Then GUICtrlSetData($sourceinput,$profilelist[$cycle+1]) GUICtrlSetData($targetinput,$profilelist[$cycle+2]) ExitLoop EndIf Next $loaded=1 ExitLoop EndIf If $msg = $profiledelete Then $selectedprofile=GUICtrlRead($showprofiles) $reallydelete=msgbox(4,"Really Delete?","Are you sure you want to delete the """&$selectedprofile&""" profile?") if $reallydelete=6 Then for $cycle=1 to $profilelist[0] if $profilelist[$cycle]<>$selectedprofile Then $newprofilelist=$newprofilelist&$profilelist[$cycle]&"*" Else $cycle+=2 EndIf Next $len=StringLen($newprofilelist) $newprofilelist=stringmid($newprofilelist,1,$len-1) RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\MaxImuM Advantage","Sync","REG_SZ",$newprofilelist) $newprofilelist="" ExitLoop EndIf EndIf Until 1 = 2 GUIDelete($selectprofile) EndFunc Func theheart($basedir) While GUICtrlRead($pause) == 1 ;look for the pause button $quit=msgbox(36,"Paused","Quit Now?") if $quit=6 then exit ;yes if $quit=7 then GUICtrlSetState($pause,$gui_unchecked) ;no, so uuncheck the box WEnd $basesearch = FileFindFirstFile($basedir & "\*.*") If $basesearch == -1 Then Return 0 ; specified folder is empty! While @error <> 1 $basefile = FileFindNextFile($basesearch) ; skip these If $basefile == "." Or $basefile == ".." Or $basefile == "" Then ContinueLoop EndIf ; if it's a dir then call this function again (nesting the function is clever ;) $formattedfile = $basedir & "\" & $basefile If StringInStr(FileGetAttrib($formattedfile), "D") > 0 Then theheart($formattedfile) Else ; Files we need to deal with $filename = StringTrimLeft($formattedfile, $trimamount) $temp = $temp & $filename & Chr(1) ;makes a string with all results mashed together $howmany += 1 GUICtrlSetData($sourceinfo,_StringAddThousandsSep($howmany)) EndIf WEnd FileClose($basesearch) Return 1 EndFunc ;==>theheart Func _CopyWithProgress($inSource, $inDest) ; Function to copy a file showing a realtime progress bar ; ; By Paul Niven (NiVZ) ; ; 05/11/2008 ; ; Parameters: ; ; $inSource - Full path to source file ; $inDest - Full path to Target file (structure will be created if it does not exist ; ; Returns 0 if copy is successful and 1 if it fails ; ; ; Updates: ; ; 06/11/2008 - Now shows SOURCE and DEST on seperate lines while copying ; - Now uses Kernal32 and DllCallBackRegister to provide faster copying ; Kernal32 and DllCallBackRegister taken from _MultiFileCopy.au3 ; See: http://www.autoit.de/index.php?page=Thread&postID=58875 If Not IsDeclared("callback") Then Local $callback = DllCallbackRegister('__Progress', 'int', 'uint64;uint64;uint64;uint64;dword;dword;ptr;ptr;str') If Not IsDeclared("ptr") Then Local $ptr = DllCallbackGetPtr($callback) $DestDir = StringLeft($inDest, StringInStr($inDest, "\", "", -1)) If Not FileExists($DestDir) Then DirCreate($DestDir) $ret = DllCall('kernel32.dll', 'int', 'CopyFileExA', 'str', $inSource, 'str', $inDest, 'ptr', $ptr, 'str', '', 'int', 0, 'int', 0) If $ret[0] <> 0 Then ; Success Return 1 Else ; Fail Return 0 EndIf EndFunc ;==>_CopyWithProgress Func __Progress($FileSize, $BytesTransferred, $StreamSize, $StreamBytesTransferred, $dwStreamNumber, $dwCallbackReason, $hSourceFile, $hTargetFile, $lpData) GUICtrlSetData($copyprogress, Round($BytesTransferred / $FileSize * 100, 0)) EndFunc ;==>__Progress While running and working on a large copy, if the GUI is clicked on or if another window is opened and covers this and is then minimized, basically any interruption/interaction the GUI goes mental. Is there a way to make the GUI refresh every 100ms or something? Or a flag to keep it alive? I can't lock the GUI or the progressbar will not work. Also, is this just being caused by the _CopyWithProgress? Like, while that routine is busy the GUI isn't active? Thanks Ian My projects: IP Scanner - Multi-threaded ping tool to scan your available networks for used and available IP addresses, shows ping times, resolves IPs in to host names, and allows individual IPs to be pinged. INFSniff - Great technicians tool - a tool which scans DriverPacks archives for INF files and parses out the HWIDs to a database file, and rapidly scans the local machine's HWIDs, searches the database for matches, and installs them. PPK3 (Persistent Process Killer V3) - Another for the techs - suppress running processes that you need to keep away, helpful when fighting spyware/viruses. Sync Tool - Folder sync tool with lots of real time information and several checking methods. USMT Front End - Front End for Microsoft's User State Migration Tool, including all files needed for USMT 3.01 and 4.01, 32 bit and 64 bit versions. Audit Tool - Computer audit tool to gather vital hardware, Windows, and Office information for IT managers and field techs. Capabilities include creating a customized site agent. CSV Viewer - Displays CSV files with automatic column sizing and font selection. Lines can also be copied to the clipboard for data extraction. MyDirStat - Lists number and size of files on a drive or specified path, allows for deletion within the app. 2048 Game - My version of 2048, fun tile game. Juice Lab - Ecigarette liquid making calculator. Data Protector - Secure notes to save sensitive information. VHD Footer - Add a footer to a forensic hard drive image to allow it to be mounted or used as a virtual machine hard drive. Find in File - Searches files containing a specified phrase.
wraithdu Posted September 15, 2009 Posted September 15, 2009 (edited) AutoIt is single threaded. So if you enter a long and laborious processing routine where Sleep() is not called (GuiGetMsg() has sleep built in / MsgBox() does not cause this problem, etc there are other exceptions), then your app cannot process any window messages (GUI updates and other stuff). If this goes on for long enough (5-10 seconds maybe?) Windows thinks the program has hung and you get the whitish GUI and the (Not Responding) window title. If your app must do long processing tasks, and you're only using AutoIt, then you're out of luck. Other programming languages get around this by putting the interface code into another thread, or the processing into another thread. Obviously AutoIt cannot do this. If you have written the processing functions yourself, try to build in a short sleep somewhere so the GUI can process window messages, and see if that helps. EDIT - Can you post a smaller script showing your problem? Edited September 15, 2009 by wraithdu
llewxam Posted September 15, 2009 Author Posted September 15, 2009 Thanks for your reply. I wrote this sync script but did not write the _CopyWithProgress function. I don't think that I can do anything with that function, it's above my understanding As for a shorter script, I've experienced it on other apps I've written and kinda thought it was something to do with AutoIt's threads. Soooooo, I guess it just is what it is. If I get VERY ambitious I may look in to some of the multithreading threads in General Help, maybe something can be done to multithread this app. Thanks again!! Ian My projects: IP Scanner - Multi-threaded ping tool to scan your available networks for used and available IP addresses, shows ping times, resolves IPs in to host names, and allows individual IPs to be pinged. INFSniff - Great technicians tool - a tool which scans DriverPacks archives for INF files and parses out the HWIDs to a database file, and rapidly scans the local machine's HWIDs, searches the database for matches, and installs them. PPK3 (Persistent Process Killer V3) - Another for the techs - suppress running processes that you need to keep away, helpful when fighting spyware/viruses. Sync Tool - Folder sync tool with lots of real time information and several checking methods. USMT Front End - Front End for Microsoft's User State Migration Tool, including all files needed for USMT 3.01 and 4.01, 32 bit and 64 bit versions. Audit Tool - Computer audit tool to gather vital hardware, Windows, and Office information for IT managers and field techs. Capabilities include creating a customized site agent. CSV Viewer - Displays CSV files with automatic column sizing and font selection. Lines can also be copied to the clipboard for data extraction. MyDirStat - Lists number and size of files on a drive or specified path, allows for deletion within the app. 2048 Game - My version of 2048, fun tile game. Juice Lab - Ecigarette liquid making calculator. Data Protector - Secure notes to save sensitive information. VHD Footer - Add a footer to a forensic hard drive image to allow it to be mounted or used as a virtual machine hard drive. Find in File - Searches files containing a specified phrase.
wraithdu Posted September 15, 2009 Posted September 15, 2009 I looked up the CopyFileEx function, and this is exactly your problem. AutoIt sits waiting for the DllCall() to return and does not process window messages, causing the 'stuck' GUI. I had this same problem with a file hashing (MD5, SHA, etc) app I wrote. I ended up modifying the hash.dll source and writing my own helper DLL to thread the hash calls. Then I could use WaitForSingleObject() in a loop to know when the process had finished in my main app, while still allowing the GUI to update via short Sleep() calls. It worked really well. Frankly, I'm surprised the progress bar actually updates, since that would imply that window messages are getting through, at least to some degree. Maybe I'll play with this function some time.
wraithdu Posted September 15, 2009 Posted September 15, 2009 I looked at the original function, and this happens there as well with really big files, esp if you click on the progress box during the copy. The _MultiFileCopy script will have the same issue for a really big file for the same reason. That script copies files one by one, so if none are too big, then you won't get this problem since the script is active. I've noticed this happens most with blocked DllCall() calls.
llewxam Posted September 15, 2009 Author Posted September 15, 2009 Thanks for the extra info Ian My projects: IP Scanner - Multi-threaded ping tool to scan your available networks for used and available IP addresses, shows ping times, resolves IPs in to host names, and allows individual IPs to be pinged. INFSniff - Great technicians tool - a tool which scans DriverPacks archives for INF files and parses out the HWIDs to a database file, and rapidly scans the local machine's HWIDs, searches the database for matches, and installs them. PPK3 (Persistent Process Killer V3) - Another for the techs - suppress running processes that you need to keep away, helpful when fighting spyware/viruses. Sync Tool - Folder sync tool with lots of real time information and several checking methods. USMT Front End - Front End for Microsoft's User State Migration Tool, including all files needed for USMT 3.01 and 4.01, 32 bit and 64 bit versions. Audit Tool - Computer audit tool to gather vital hardware, Windows, and Office information for IT managers and field techs. Capabilities include creating a customized site agent. CSV Viewer - Displays CSV files with automatic column sizing and font selection. Lines can also be copied to the clipboard for data extraction. MyDirStat - Lists number and size of files on a drive or specified path, allows for deletion within the app. 2048 Game - My version of 2048, fun tile game. Juice Lab - Ecigarette liquid making calculator. Data Protector - Secure notes to save sensitive information. VHD Footer - Add a footer to a forensic hard drive image to allow it to be mounted or used as a virtual machine hard drive. Find in File - Searches files containing a specified phrase.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now