Nikolas92 Posted August 19, 2017 Share Posted August 19, 2017 (edited) Hi, i am trying to make copying directory to show progress bar, but function _WinAPI_CopyFileEx randomly fails with error 87. Could someone help me find what is causing this error? expandcollapse popup; www.autoitscript.com/forum/topic/158598-dllcallbackregister-with-non-freezing-gui-volatile-example ; www.autoitscript.com/forum/topic/153104-scriptdir-returns-trailing-slash #NoTrayIcon #RequireAdmin #include <File.au3> #include <Constants.au3> #include <GUIConstants.au3> #include <WinAPI.au3> #include <WinAPIFiles.au3> #include <WinAPIShPath.au3> #include <WinAPIShellEx.au3> #include <Security.au3> Opt("WinWaitDelay", 0) Opt("MouseClickDelay", 0) Opt("MouseClickDownDelay", 0) Opt("MouseClickDragDelay", 0) Opt("SendKeyDelay", 0) Opt("SendKeyDownDelay", 0) Opt("WinTitleMatchMode", 3) Opt("GUIOnEventMode", 1) FileChangeDir(StringRegExpReplace(@ScriptDir, '\\+$', '')) If $CmdLine[0] = 0 Then MsgBox($MB_OK, 'Info', 'Drag files and folders on ' & @ScriptName & ' to test copying with progress bar.') Exit EndIf Global Const $SID_ALL_APP_PACKAGES_GROUP = 'S-1-15-2-1' Global $MetroGroupExist = False Global $AccountInfo = _Security__LookupAccountSid($SID_ALL_APP_PACKAGES_GROUP) If IsArray($AccountInfo) Then $MetroGroupExist = True Global $hProgressProc = DllCallbackRegister('_ProgressProc', 'bool', 'uint64;uint64;uint64;uint64;dword;dword;handle;handle;ptr') Global $FailedToCopyList = '' Global $Folders[1] = [1] Global $Files[1] = [1] Global $TotalSize = 0 Global $CopiedSize = 0 Global $TargetDirCreated = False Global $Drive, $Directory, $Name, $Extension Global $GuiName = 'Copying files and folders...' Global $MainGui = GUICreate($GuiName, 250, 59, (@DesktopWidth-250)/2-35, 0, BitOR($WS_CAPTION, $WS_SYSMENU)) Global $progressbar = GUICtrlCreateProgress(5, 5, 240, 20, $PBS_SMOOTH) Global $CurrentActivity = GUICtrlCreateLabel('', 5, 27, 240, 30, BitOR($SS_CENTER, $BS_MULTILINE)) GUISetOnEvent($GUI_EVENT_CLOSE, '_AllExit', $MainGui) GUICtrlSetFont($CurrentActivity, 9, 0, 0, "Verdana") GUICtrlSetData($CurrentActivity, 'Calculating total size...') GUISetState(@SW_SHOW, $MainGui) $aCmdLine = _WinAPI_CommandLineToArgv($CmdLineRaw) For $i = 1 to $aCmdLine[0] $Path = $aCmdLine[$i] If StringRight($Path, 1) = '\' or StringRight($Path, 1) = '"' Then $Path = StringTrimRight($Path, 1) If not StringInStr(FileGetAttrib($Path), "D") Then $Files[0] += 1 ReDim $Files[$Files[0]] $Files[$Files[0] - 1] = $Path $iSize = _GetFileSize($Path) If $iSize <> -1 Then $TotalSize = $TotalSize + $iSize Else $Folders[0] += 1 ReDim $Folders[$Folders[0]] $Folders[$Folders[0] - 1] = $Path $iSize = DirGetSize($Path) $TotalSize = $TotalSize + $iSize EndIf Next If UBound($Folders) - 1 > 0 Then For $i = 1 to UBound($Folders) - 1 _MultiFileCopy($Folders[$i], @DesktopDir & '\test') Next EndIf If UBound($Files) - 1 > 0 Then For $i = 1 to UBound($Files) - 1 _MultiFileCopy($Files[$i], @DesktopDir & '\test') Next EndIf GUISetState(@SW_HIDE, $MainGui) If $FailedToCopyList <> '' Then MsgBox($MB_OK, 'Info', 'Failed to copy:' & @CRLF & $FailedToCopyList) Exit Volatile Func _AllExit() GUIDelete(@GUI_WinHandle) Exit EndFunc Volatile Func _ProgressProc($iTotalFileSize, $iTotalBytesTransferred, $iStreamSize, $iStreamBytesTransferred, $iStreamNumber, $iCallbackReason, $hSourceFile, $hDestinationFile, $pData) $iPercent = (($CopiedSize+$iTotalBytesTransferred)/$TotalSize)*100 GUICtrlSetData($progressbar, Round($iPercent)) If $iTotalBytesTransferred = $iTotalFileSize Then $CopiedSize = $CopiedSize + $iTotalFileSize EndFunc Func _GetFileSize($sPath) $hFile = _WinAPI_CreateFileEx('\\.\' & $sPath, $OPEN_EXISTING, 0, BitOR($FILE_SHARE_READ, $FILE_SHARE_WRITE), BitOR($FILE_FLAG_BACKUP_SEMANTICS, $FILE_FLAG_OPEN_REPARSE_POINT)) $sSize = _WinAPI_GetFileSizeEx($hFile) _WinAPI_CloseHandle($hFile) Return $sSize EndFunc Func _MultiFileCopy($sSourcePath, $sTargetDir, $RemoveTargetIfExist = False, $CreateSourceRootFolderInTarget = True) Local $sDrive, $sDir, $sFileName, $sExtension _PathSplit($sTargetDir, $sDrive, $sDir, $sFileName, $sExtension) $sTargetDrive = $sDrive If $TargetDirCreated = False Then If $RemoveTargetIfExist = True and DriveGetDrive($sTargetDrive) <> 'CDROM' Then _DeleteTarget($sTargetDir) _WinAPI_CreateDirectory($sTargetDir) $TargetDirCreated = True EndIf _PathSplit($sSourcePath, $sDrive, $sDir, $sFileName, $sExtension) Switch _WinAPI_PathIsDirectory($sSourcePath) Case False If _WinAPI_FileExists($sSourcePath) = True Then GUICtrlSetData($CurrentActivity, 'Copying file ' & $sFileName & $sExtension & '...') If _WinAPI_FileExists($sTargetDir & '\' & $sFileName & $sExtension) = True and DriveGetDrive($sTargetDrive) <> 'CDROM' Then _DeleteTarget($sTargetDir & '\' & $sFileName & $sExtension) _CopyFileProc($sSourcePath, $sTargetDir & '\' & $sFileName & $sExtension) Else Return SetError(1, 0, False) EndIf Case $FILE_ATTRIBUTE_DIRECTORY $sTarget = $sTargetDir If $CreateSourceRootFolderInTarget = True Then If ($sFileName & $sExtension) <> '' Then $sTargetDir = $sTargetDir & '\' & $sFileName & $sExtension Else $sTargetDir = $sTargetDir & '\Drive ' & StringUpper(StringReplace($sDrive, ':', '')) EndIf EndIf If ($sFileName & $sExtension) <> '' Then GUICtrlSetData($CurrentActivity, 'Copying folder ' & $sFileName & $sExtension & '...') Else GUICtrlSetData($CurrentActivity, 'Copying drive ' & StringUpper($sDrive) & '...') EndIf If _WinAPI_PathIsDirectory($sTargetDir) = $FILE_ATTRIBUTE_DIRECTORY Then If ($sTarget <> $sTargetDir or ($RemoveTargetIfExist = True and $TargetDirCreated = False)) and DriveGetDrive($sTargetDrive) <> 'CDROM' Then _DeleteTarget($sTargetDir) EndIf _MultiFileCopyDirProc($sSourcePath, $sTargetDir) $aFolderList = _FileListToArrayRec($sSourcePath, '*', $FLTAR_FOLDERS, $FLTAR_RECUR, $FLTAR_SORT, $FLTAR_FULLPATH) If IsArray($aFolderList) Then For $i = 1 to $aFolderList[0] _MultiFileCopyDirProc($aFolderList[$i], $sTargetDir & '\' & StringReplace($aFolderList[$i], $sSourcePath & '\', '')) Next EndIf EndSwitch Return True EndFunc Func _DeleteTarget($sTarget) _WinAPI_ShellFileOperation($sTarget, '', $FO_DELETE, BitOR($FOF_NOCONFIRMATION, $FOF_NOERRORUI, $FOF_SILENT, $FOF_NO_UI)) If @extended = 120 Then _SubinaclFull($sTarget) _WinAPI_ShellFileOperation($sTarget, '', $FO_DELETE, BitOR($FOF_NOCONFIRMATION, $FOF_NOERRORUI, $FOF_SILENT, $FOF_NO_UI)) EndIf If @error Then Return False Return True EndFunc Func _MultiFileCopyDirProc($sSourcePath, $sTargetDir) _WinAPI_CreateDirectory($sTargetDir) $aFileList = _FileListToArrayRec($sSourcePath, '*', $FLTAR_FILES, $FLTAR_NORECUR, $FLTAR_NOSORT, $FLTAR_FULLPATH) If IsArray($aFileList) Then For $j = 1 to $aFileList[0] _CopyFileProc($aFileList[$j], $sTargetDir & '\' & StringReplace($aFileList[$j], $sSourcePath & '\', '')) Next EndIf EndFunc Func _CopyFileProc($sSourceFile, $sTargetFile) $result = _WinAPI_CopyFileEx($sSourceFile, $sTargetFile, BitOR($COPY_FILE_ALLOW_DECRYPTED_DESTINATION, $COPY_FILE_COPY_SYMLINK, $COPY_FILE_NO_BUFFERING), DllCallbackGetPtr($hProgressProc)) If _WinAPI_GetLastError() = 5 Then _SubinaclFull($sSourceFile) $result = _WinAPI_CopyFileEx($sSourceFile, $sTargetFile, BitOR($COPY_FILE_ALLOW_DECRYPTED_DESTINATION, $COPY_FILE_COPY_SYMLINK, $COPY_FILE_NO_BUFFERING), DllCallbackGetPtr($hProgressProc)) EndIf If $result = False Then $FailedToCopyList = $FailedToCopyList & $sSourceFile & ' (error ' & _WinAPI_GetLastError() & ')' & @CRLF $iSize = _GetFileSize($sSourceFile) If $iSize <> -1 Then $CopiedSize = $CopiedSize + $iSize $iPercent = ($CopiedSize/$TotalSize)*100 GUICtrlSetData($progressbar, Round($iPercent)) EndIf EndIf EndFunc Func _SubinaclFull($sPath, $recurse = True) $MetroGroupAce = '' If $MetroGroupExist = True Then $MetroGroupAce = ' /GRANT="ALL APPLICATION PACKAGES"=R' If StringRight($sPath, 1) <> '\' Then $sPath = $sPath & '\' $PathForSubinacl = StringTrimRight(StringReplace($sPath, @WindowsDir & '\System32\', @WindowsDir & '\Sysnative\'), 1) RunWait(StringRegExpReplace(@WorkingDir, '\\+$', '') & '\subinacl.exe' & ' /nostatistic /noverbose /file "' & $PathForSubinacl & '" /GRANT=System=F /GRANT=Administrators=F /GRANT=Users=F /GRANT=Everyone=F /GRANT=' & @UserName & '=F' & $MetroGroupAce & ' /SETOWNER=Everyone', '', @SW_HIDE) If $recurse = True and StringInStr(FileGetAttrib(StringTrimRight($sPath, 1)), "D") Then RunWait(StringRegExpReplace(@WorkingDir, '\\+$', '') & '\subinacl.exe' & ' /nostatistic /noverbose /subdirectories "' & $PathForSubinacl & '\*" /GRANT=System=F /GRANT=Administrators=F /GRANT=Users=F /GRANT=Everyone=F /GRANT=' & @UserName & '=F' & $MetroGroupAce & ' /SETOWNER=Everyone', '', @SW_HIDE) EndFunc Edited August 19, 2017 by Nikolas92 Link to comment Share on other sites More sharing options...
Nikolas92 Posted August 20, 2017 Author Share Posted August 20, 2017 Bump. What parameter of _WinAPI_CopyFileEx is invalid (error 87)? thanks Link to comment Share on other sites More sharing options...
Simpel Posted August 20, 2017 Share Posted August 20, 2017 Hi. Call _WinAPI_GetLastError() to get extended error information. Conrad SciTE4AutoIt = 3.7.3.0 AutoIt = 3.3.14.2 AutoItX64 = 0 OS = Win_10 Build = 19044 OSArch = X64 Language = 0407/german H:\...\AutoIt3\SciTE H:\...\AutoIt3 H:\...\AutoIt3\Include (H:\ = Network Drive) Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. Link to comment Share on other sites More sharing options...
Nikolas92 Posted August 20, 2017 Author Share Posted August 20, 2017 6 minutes ago, Simpel said: Hi. Call _WinAPI_GetLastError() to get extended error information. Conrad Thats already in example. How would I know otherwise what error number is? Link to comment Share on other sites More sharing options...
Simpel Posted August 20, 2017 Share Posted August 20, 2017 Sorry, currently no AutoIt to test. What I meant is: _WinAPI_GetLastErrorMessage() - this is mostly explaining I hope this is the right function, Conrad SciTE4AutoIt = 3.7.3.0 AutoIt = 3.3.14.2 AutoItX64 = 0 OS = Win_10 Build = 19044 OSArch = X64 Language = 0407/german H:\...\AutoIt3\SciTE H:\...\AutoIt3 H:\...\AutoIt3\Include (H:\ = Network Drive) Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. Link to comment Share on other sites More sharing options...
Nikolas92 Posted August 20, 2017 Author Share Posted August 20, 2017 16 minutes ago, Simpel said: Sorry, currently no AutoIt to test. What I meant is: _WinAPI_GetLastErrorMessage() - this is mostly explaining I hope this is the right function, Conrad I already tried that too and result was that some parameter is incorrect. Link to comment Share on other sites More sharing options...
Nikolas92 Posted August 21, 2017 Author Share Posted August 21, 2017 bump Link to comment Share on other sites More sharing options...
benched42 Posted August 25, 2017 Share Posted August 25, 2017 When I want to show a progress bar while copying files and/or directories, I use Yashied's Copy UDF. I've used it to write a script that we us internally where I work to copy all data from one machine to a storage device and notifies the user of any folders in the root of C: that are not standard (so they might be copied as well) Who lied and told you life would EVER be fair? 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