Vakari Posted March 21, 2008 Share Posted March 21, 2008 I've been creating a bunch of random GUIs just to mess around and help me think of better ways to make useful programs later on. I'm currently playing with a simple program to copy a file from one place to another. What I had originally wanted to do was start a filecopy, display a progress bar, and inform the user the copy was complete. I've found a few Filecopy-Progress bar scripts floating around on the boards, but they are for folder copying and multiple files. The last one I tried technically worked as far as the progress bar went, but if you only copied one file, the destiation file always ended up getting corrupted. I was looking to copy a single file and show progress. The reason why is because the file can be anywhere up to 50MB, copying across a really slow network share. A progress bar staying at 1% and then jumping to 100% 2 minutes later is rather unhelpful. So what I decided to do was provide the user some random form of visual feedback to show that it was actually doing something. I settled on using radio buttons in a row (Why? I don't know, just wanted to see how one would go about doing it). So ultimately, I want this to display the animation while the file is being copied, and stop when the copy is complete. expandcollapse popup#Include <GUIConstants.au3> $ThisApp = "Update Tool" $App = GUICreate($ThisApp, 400, 200, @DesktopWidth / 2 - 200, @DesktopHeight / 2 - 100, $WS_POPUPWINDOW) $Button_Update = GUICtrlCreateButton("Update", 50, 145, 75, 35) $Button_Close = GUICtrlCreateButton("Close", 275, 145, 75, 35) $Input_Status = GUICtrlCreateInput("Click update to download the latest version", 75, 100, 250, 20, $ES_CENTER + $ES_READONLY) $Source = "C:\Test\From\Spreadsheet.xls" $Destination = "C:\Test\To\Spreadsheet.xls" $X = 50 $Y = 60 $Z = 1 $Buttons = 21 Global $Radio[$Buttons + 1] = [0] GUISetState() For $i = 1 To $Buttons Sleep(20) $Radio[$i] = GUICtrlCreateRadio("", $X, $Y) GUICtrlSetState($Radio[$i], $GUI_DISABLE) $X = $X + 300 / $Buttons If $Z = 1 Then $Y = $Y - 1 $Z = 0 Else $Z = 1 EndIf Next While 1 $msg = GUIGetMsg() If $msg = $Button_Close Then Exit If $msg = $Button_Update Then $Z = 0 GUICtrlSetState($Button_Update, $GUI_DISABLE) GUICtrlSetData($Input_Status, "Downloading") ;FileCopy($Source, $Destination, 1) While $Z < 3 ; While file is copying... possible? GUICtrlSetState($Radio[$Buttons], $GUI_DISABLE) For $i = 1 To $Buttons If GUIGetMsg() = $Button_Close Then Abort() GUICtrlSetState($Radio[$i], $GUI_ENABLE + $GUI_CHECKED) If $i - 1 <> 0 Then GUICtrlSetState($Radio[$i - 1], $GUI_DISABLE + $GUI_UNCHECKED) EndIf Sleep(50) Next $Z = $Z + 1 WEnd GUICtrlSetState($Button_Update, $GUI_ENABLE) GUICtrlSetData($Input_Status, "Update Complete") EndIf WEnd Func Abort() MsgBox(262160, "Warning", "Update Aborted", 2) Exit EndFunc While it would be nice of some sort of progress bar to display the actual progress, I'm not really looking to do that here (Though it would be nice to know how later on) A shorter way to describe it, if you don't care about the poorly written code above, would be: FileCopyAndStartTheNextLineOfCodeBeforeTheFileIsFinished($Source, $Dest) While FileIsCopying MiscProgressDisplay Wend Exit Hmm, that's even worse =) Anyway, if anyone has any advice or a slap in the face for me, feel free to let me know. Any input would be appreciated. Link to comment Share on other sites More sharing options...
Aassdd Posted March 21, 2008 Share Posted March 21, 2008 So you basically want a progress bar?http://www.autoitscript.com/forum/index.ph...hl=progress+barhttp://www.autoitscript.com/forum/index.ph...hl=progress+bar Link to comment Share on other sites More sharing options...
monoceres Posted March 21, 2008 Share Posted March 21, 2008 I don't think you can do what you try to accomplish with the FileCopy() function, the easiest way I can see is that you read the file into your script (binary) and then write the file att the destination, that way you can see how much of the copying has been completed. Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
Aassdd Posted March 21, 2008 Share Posted March 21, 2008 Or Do ... Until FileGetSize("path") = FileGetSize("path") Link to comment Share on other sites More sharing options...
monoceres Posted March 21, 2008 Share Posted March 21, 2008 Doesn't FileCopy() pause the script? Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
monoceres Posted March 21, 2008 Share Posted March 21, 2008 Anyways here's an axample how you can copy one file with progress: $filehandle = FileOpen("source.file",16) ; Open in read + binary mode $output = FileOpen("destination.file",17); Open in write + binary mode $chunksize=100 ; How many bytes the script will read at a time $size = FileGetSize("source.file") $i=0 Do $data = FileRead($filehandle,$chunksize) If $data <>"" Then FileWrite($output,$data) $i+=$chunksize ConsoleWrite(Round($i/$size*100)&" %"&@CRLF) ; Output progress in console Until $data="" Apples292 1 Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
Aassdd Posted March 21, 2008 Share Posted March 21, 2008 I'm not sure but take a look a look at the links I gave you. Link to comment Share on other sites More sharing options...
Vakari Posted March 21, 2008 Author Share Posted March 21, 2008 @ Aassdd - Thank you for the links and the time you spent to located them. I understand (a little anyway) about creating and using Progress bars. I'd like to figure out how to get a progress bar involved with another function that generally pauses the script, such as FileCopy(). I didn't test anything with the Do/Until idea you posted, but should the 'Until' syntax be : Until FileGetSize($Source) = FileGetSize($Destination) ? I would imagine it would only go through one cycle since the example you posted would always be true. If you assumed I'd understand this is what you meant anway, then I apologize heh. I'm still an AutoIT noob, unfortunately. @ monoceres - Thanks so much for that small script. I tested it out and it seems to work great. I'll slap it into my test script to see what I can come up with then I'll throw it on here incase you'd like to take a look at it. Thanks again, both of you, for your time and help. Link to comment Share on other sites More sharing options...
Aassdd Posted March 21, 2008 Share Posted March 21, 2008 Until FileGetSize($Source) = FileGetSize($Destination) ^ yes sorry. Link to comment Share on other sites More sharing options...
FreeFry Posted March 21, 2008 Share Posted March 21, 2008 (edited) You could use something like this: Func _FileCopyEx($s_File, $s_newFile) Local $SHFILEOPSTRUCT = DllStructCreate("hwnd hwnd;uint wFunc;ptr pFrom;ptr pTo;int fFlags;int fAnyOperationsAborted;hwnd hNameMappings;ptr lpszProgressTitle") Local $SHFILEOPSTRUCT_From = DllStructCreate("char pFrom[" & StringLen($s_File)+2 & "]") DllStructSetData($SHFILEOPSTRUCT_From, "pFrom", $s_File) Local $SHFILEOPSTRUCT_To = DllStructCreate("char pTo[" & StringLen($s_newFile)+2 & "]") DllStructSetData($SHFILEOPSTRUCT_To, "pTo", $s_newFile) DllStructSetData($SHFILEOPSTRUCT, "wFunc", 2) ; FO_COPY = 2 DllStructSetData($SHFILEOPSTRUCT, "pFrom", DllStructGetPtr($SHFILEOPSTRUCT_From)) DllStructSetData($SHFILEOPSTRUCT, "pTo", DllStructGetPtr($SHFILEOPSTRUCT_To)) Local $i_State = DllCall("shell32.dll", "int", "SHFileOperation", "ptr", DllStructGetPtr($SHFILEOPSTRUCT)) $SHFILEOPSTRUCT = 0 If Not $i_State[0] Then SetError(1) Return 0 EndIf SetError(0) Return 1 EndFuncoÝ÷ ÙKØî²Ùbëazz+©EW¢ºÚ"µÍÑ[PÛÜQ^ ØÜ [È ][ÝÉÌLÛ^Y[K ][ÝËØÜ [È ][ÝÉÌLÛ^Y[WØÛÜK ][ÝÊ Edited March 21, 2008 by FreeFry Link to comment Share on other sites More sharing options...
monoceres Posted March 21, 2008 Share Posted March 21, 2008 @ monoceres - Thanks so much for that small script. I tested it out and it seems to work great. I'll slap it into my test script to see what I can come up with then I'll throw it on here incase you'd like to take a look at it.Just increase the chunksize to at least 128 kB otherwise copying will be painfully slow, and good luck! Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
Vakari Posted March 21, 2008 Author Share Posted March 21, 2008 (edited) expandcollapse popup#Include <GUIConstants.au3> $ThisApp = "Update Tool" $App = GUICreate($ThisApp, 400, 150, @DesktopWidth / 2 - 200, @DesktopHeight / 2 - 100, $WS_POPUPWINDOW) $Button_Update = GUICtrlCreateButton("Update", 50, 105, 75, 35) $Button_Close = GUICtrlCreateButton("Close", 275, 105, 75, 35) $Input_Status = GUICtrlCreateInput("Click update to download the latest version", 75, 45, 250, 20, $ES_CENTER + $ES_READONLY) $Label_Speed = GUICtrlCreateLabel("Update Speed :", 25, 77) $Input_Speed = GUICtrlCreateInput("", 105, 75, 70, 20, $ES_CENTER + $ES_READONLY) $Label_Percent = GUICtrlCreateLabel(": % Complete", 300, 77) $Input_Percent = GUICtrlCreateInput("", 225, 75, 70, 20, $ES_CENTER + $ES_READONLY) $ProgressBar = GUICtrlCreateProgress(10, 10, 380, 20, $PBS_SMOOTH) $SourceFile = "C:\Test\From\Spreadsheet.xls" $DestFile = "C:\Test\To\Spreadsheet.xls" Local $TimeToCopy, $DLSpeed, $TotalTime = 0 GUISetState() While 1 $msg = GUIGetMsg() If $msg = $Button_Close Then Exit If $msg = $Button_Update Then If FileExists($SourceFile) Then FileDelete($DestFile) $Source = FileOpen($SourceFile, 16); Open in read + binary mode $Destination = FileOpen($DestFile, 17); Open in write + binary mode $SourceSize = FileGetSize($SourceFile) $DataToRead = $SourceSize * .01;50000; How many bytes the script will read at a time $DataCopied = 0 $Data = "." $PercentComplete = 0 GUICtrlSetState($Button_Update, $GUI_DISABLE) GUICtrlSetData($Input_Status, "Downloading Update - " & Int($SourceSize / 1000) & "KB") $TimeToCopy = TimerInit() While $Data <> "" If GUIGetMsg() = $Button_Close Then Abort() $Data = FileRead($Source, $DataToRead) If $Data <> "" Then FileWrite($Destination, $Data) $DataCopied += $DataToRead $TotalTime = Round(TimerDiff($TimeToCopy) / 1000, 2) $DLSpeed = Round(($DataCopied / Round(TimerDiff($TimeToCopy) / 1000, 2)) / 1000, 1) GUICtrlSetData($Input_Speed, $DLSpeed & "KBps") $PercentComplete = Int($DataCopied / $SourceSize * 100) GUICtrlSetData($ProgressBar, $PercentComplete) GUICtrlSetData($Input_Percent, $PercentComplete) Sleep(1) If $Data = "" Then ExitLoop WEnd FileClose($Source) FileClose($Destination) GUICtrlSetState($Button_Update, $GUI_ENABLE) GUICtrlSetData($Input_Status, "Update completed after " & $TotalTime & " seconds") ConsoleWrite($TotalTime & " seconds to update" & @CR) $TotalTime = 0 $TimeToCopy = 0 Else ConsoleWrite($SourceFile & " does not exist. Aborting" & @CR) EndIf EndIf WEnd Func Abort() MsgBox(262160, "Warning", "Update Aborted", 2) FileClose($Source) FileClose($Destination) FileDelete($DestFile) Exit EndFunc ;==>Abort $DataToRead = $SourceSize * .01 : I replaced your $chunksize variable with $DataToRead (To keep my brain from hurting too much). I set this so that I could at least see the progress bar movement, instead of instantly going from 1% to 100%, depending on file size. I doubt I would use this value in the actual program. I tested it with many different file types and didn't experience corruption, so I'm quite happy with its performance. The math I used to calculate download speed is inaccurate due to rounding, and 1000 bytes not really being 1KB. It was just another thing I thought I would try to play with and display to the user. There was one oddity I found: The original script that you posted does not care if the destination file already exists. I added the FileDelete before to get rid of it before any copying took place. What I was finding was that if you ran the program once, you would successfully copy Spreadsheet.xls to the destination, yay. If you ran it again without deleting the old destination file, it would still run flawlessly, but then Windows would report the filesize to be double what it was before. If you ran it again, it would still run without errors, but now Windows would show the filesize to be triple the original size. I ran this 10 times on a 3 MB spreadsheet as a test, and it ended up being 30MB in the destination folder! The good news is, once you actually open the file, it works properly as expected. When it is closed, Windows reports the original file size as 3MB. I'm on Win2k here at work, but I don't know if it is OS specific. Refreshing the view of the folder did not fix the filesize display, I had to actually open the file that I copied, then close it. Thanks again for your help, Aassdd and monoceres. This really helped me a lot. And FreeFry, I had already finished up this script before I came back to the forums, so give me some time and I'll see what I can do/learn from the code you posted. Though I must admit, I haven't touched any functions directly related to Dll's, so it may be a while =) But I do thank you for reading and posting. Edited March 21, 2008 by Vakari Link to comment Share on other sites More sharing options...
FreeFry Posted March 21, 2008 Share Posted March 21, 2008 my example uses the same functions that windows uses when it copies files, i like it. Link to comment Share on other sites More sharing options...
Tom42 Posted March 22, 2008 Share Posted March 22, 2008 You could use something like this: Func _FileCopyEx($s_File, $s_newFile) Local $SHFILEOPSTRUCT = DllStructCreate("hwnd hwnd;uint wFunc;ptr pFrom;ptr pTo;int fFlags;int fAnyOperationsAborted;hwnd hNameMappings;ptr lpszProgressTitle") Local $SHFILEOPSTRUCT_From = DllStructCreate("char pFrom[" & StringLen($s_File)+2 & "]") DllStructSetData($SHFILEOPSTRUCT_From, "pFrom", $s_File) Local $SHFILEOPSTRUCT_To = DllStructCreate("char pTo[" & StringLen($s_newFile)+2 & "]") DllStructSetData($SHFILEOPSTRUCT_To, "pTo", $s_newFile) DllStructSetData($SHFILEOPSTRUCT, "wFunc", 2) ; FO_COPY = 2 DllStructSetData($SHFILEOPSTRUCT, "pFrom", DllStructGetPtr($SHFILEOPSTRUCT_From)) DllStructSetData($SHFILEOPSTRUCT, "pTo", DllStructGetPtr($SHFILEOPSTRUCT_To)) Local $i_State = DllCall("shell32.dll", "int", "SHFileOperation", "ptr", DllStructGetPtr($SHFILEOPSTRUCT)) $SHFILEOPSTRUCT = 0 If Not $i_State[0] Then SetError(1) Return 0 EndIf SetError(0) Return 1 EndFuncoÝ÷ ÙKØî²Ùbëazz+©EW¢ºÚ"µÍÑ[PÛÜQ^ ØÜ [È ][ÝÉÌLÛ^Y[K ][ÝËØÜ [È ][ÝÉÌLÛ^Y[WØÛÜK ][ÝÊ This is wonderful, Is there anyway to make it overwrite the file without asking for permission Link to comment Share on other sites More sharing options...
rasim Posted March 22, 2008 Share Posted March 22, 2008 More examples Link to comment Share on other sites More sharing options...
FreeFry Posted March 22, 2008 Share Posted March 22, 2008 This is wonderful, Is there anyway to make it overwrite the file without asking for permission Yep there is, it requires just a little modification to the function(I haven't bothered adding a simple parameter for it yet, as this win api function takes alot of parameters..): Func _FileCopyEx($s_File, $s_newFile) Local $SHFILEOPSTRUCT = DllStructCreate("hwnd hwnd;uint wFunc;ptr pFrom;ptr pTo;int fFlags;int fAnyOperationsAborted;hwnd hNameMappings;ptr lpszProgressTitle") Local $SHFILEOPSTRUCT_From = DllStructCreate("char pFrom[" & StringLen($s_File)+2 & "]") DllStructSetData($SHFILEOPSTRUCT_From, "pFrom", $s_File) Local $SHFILEOPSTRUCT_To = DllStructCreate("char pTo[" & StringLen($s_newFile)+2 & "]") DllStructSetData($SHFILEOPSTRUCT_To, "pTo", $s_newFile) DllStructSetData($SHFILEOPSTRUCT, "wFunc", 2) ; FO_COPY = 2 DllStructSetData($SHFILEOPSTRUCT, "pFrom", DllStructGetPtr($SHFILEOPSTRUCT_From)) DllStructSetData($SHFILEOPSTRUCT, "pTo", DllStructGetPtr($SHFILEOPSTRUCT_To)) DllStructSetData($SHFILEOPSTRUCT, "fFlags", 16) ; <---- Added Local $i_State = DllCall("shell32.dll", "int", "SHFileOperation", "ptr", DllStructGetPtr($SHFILEOPSTRUCT)) $SHFILEOPSTRUCT = 0 If Not $i_State[0] Then SetError(1) Return 0 EndIf SetError(0) Return 1 EndFunc That will answer yes to any dialogs that would pop up. Link to comment Share on other sites More sharing options...
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