#include <APIConstants.au3>
#include <File.au3>
#include <StaticConstants.au3>
Dim $arrayCmdLin,$iPID,$sizeSelect,$widthWind
; файл список в кодировке WIN (1251). У меня он содержит одну строку (но может быть и несколько):
; x:\1
; в этой папке различные файлы и подпапки с файлами общим размером около 50 МБ
$fileList=@ScriptDir&"\List.txt"
; путь и имя выходного архива
$nameArchv="x:\"&@HOUR&"_"&@MIN&"_"&@SEC&"_test.7z"
; путь к архиватору
$p7z='C:\Program Files\7-Zip\'
; вспомогательные переменные для сжатия
$mtd='LZMA2'; метод сжатия
$dct=8; словарь в МБ
$comline7z='-scsWIN -mmt2 -m0=BCJ2 -m1='&$mtd&':d'&$dct&'m -m2='&$mtd&':d21 -m3='&$mtd&':d21 -mb0:1 -mb0s1:2 -mb0s2:3'
; расчет размера выделенных папок\файлов
_FileReadToArray($fileList,$arrayCmdLin)
For $i=1 To $arrayCmdLin[0]
If StringInStr(FileGetAttrib($arrayCmdLin[$i]),'D') Then
$sizeSelect+=DirGetSize($arrayCmdLin[$i])
Else
$sizeSelect+=FileGetSize($arrayCmdLin[$i])
EndIf
Next
;************************************************************************************
$Title='Архивирование папок/файлов'
$Text='Размер выделенных папок/файлов|' _
&StringRegExpReplace($sizeSelect,'(\A\d{1,3}(?=(\d{3})+\z)|\d{3}(?=\d))','\1 ')&@LF& _
'Выбранный размер словаря (МБ)|'&$dct&@LF& _
'Выбранный метод сжатия|'&$mtd&@LF& _
'Имя архива|'&StringRegExpReplace($nameArchv,'^.*\\','')&@LF&@LF& _
'Для прерывания архивирования нажмите клавишу ESC'&@LF& _
'Свернуть/развернуть окно можно, нажав клавишу F11'
HotKeySet("{ESC}","_ESC_1")
HotKeySet('{F11}','_F11_1')
$hGuiWin=GUICreate('',0,0)
Opt('MouseCoordMode',2)
GUISetFont(8.5,800,0,'Tahoma')
GUICtrlCreateLabel('',0,0)
; расчет размеров окна
$array=StringSplit($Text,@LF,2)
$heightWind=UBound($array)*16+20
For $i In $array
$Width=_GetTabbedStringSizeEx(-1,$i)
If $Width > $widthWind Then $widthWind=$Width
Next
$widthWind +=20
; создание окна
$hGuiWin=GUICreate($Title,$widthWind+6,$heightWind+67,-1,-1,$WS_SYSMENU,-1)
GUISetFont(8.5,400,0,'Tahoma')
; вывод текста
For $i=0 To UBound($array)-1
$subline=StringSplit($array[$i],'|',1)
If $i < UBound($array)-3 Then
GUICtrlCreateLabel($subline[1],50,10+16*$i,_GetTabbedStringSizeEx(-1,$subline[1]),20)
If $subline[0] > 1 Then
$Width=_GetTabbedStringSizeEx(-1,$subline[2])
GUICtrlCreateLabel($subline[2],$widthWind-$Width-10,10+16*$i,$Width,20,$SS_RIGHT)
EndIf
Else
GUICtrlCreateLabel($subline[1],10,10+16*$i,_GetTabbedStringSizeEx(-1,$subline[1]),20)
GUICtrlSetColor(-1,0xff0000)
GUICtrlSetFont(-1,8.5,800)
EndIf
Next
; вывод иконки и звука
GUICtrlCreateIcon('user32.dll',4+100,10,10)
DllCall('user32.dll','int','MessageBeep','int',0x40)
; прогрессбар и процент архивирования
$Progress=GUICtrlCreateProgress(10,$heightWind-5,$widthWind-20,20,1)
$Label=GUICtrlCreateLabel('0%',-1,$heightWind+20,$widthWind-20,20,1)
GUICtrlSetFont(-1,-1,800)
GUISetState(BitAND(@SW_DISABLE,@SW_SHOW),$hGuiWin)
; запуск процесса архивирования
$errr = _7zRead('"'&$p7z&'7z.exe" a "'&$nameArchv&'" @"'&$fileList&'" '&$comline7z,$Progress,$Label)
If $errr <> '' Then MsgBox(1+256+48,'Ошибка 7-Zip',$errr)
GUIDelete($hGuiWin)
Exit
;=======================================================================
;main UDF ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Function: _7zRead
; Description: Reads progress from 7zip window and sets control data
; Parameters: $sCmd = 7zip Commandline to be executed
; $iProgress = ControlID of Progress Control to be updated
; $iStatic = ControlID of a Static Control (label, button etc pp) to be updated
; $nShow = [optional] Flag for 7zip window, default is @SW_HIDE
; Author: jennico, basic script by valik
Func _7zRead($sCmd, $iProgress, $iStatic, $nShow=@SW_HIDE)
$iPID=Run($sCmd,"",$nShow)
ProcessWait($iPID)
; Open the 7-Zip percent reader.
Local $hPercent=Open7ZipPercent($iPID)
Local $opercent=-1
; Loop on the process existence.
While ProcessExists($iPID)
; Read the percent and update the progress bar.
Local $nPercent=Read7ZipPercent($hPercent)
If $nPercent >= 0 And $opercent <> $nPercent Then
GUICtrlSetData($iProgress,$nPercent)
GUICtrlSetData($iStatic,$nPercent&"%")
$opercent=$nPercent
Else
Sleep(50)
EndIf
WEnd
Local $OutLastLine = StringStripWS(_Read7Ziptxt($hPercent), 2)
; Cleanup.
If UBound($hPercent)=4 Then
; Detach the console
DllCall('Kernel32.dll','int',"FreeConsole")
; Destroy the handle
$hPercent=0
EndIf
If StringInStr($OutLastLine,'Everything is Ok') <> 1 Then Return $OutLastLine
Return ''
EndFunc ;==>_7zRead
;internal helper functions ++++++++++++++++++++++++++++++++++++++++++++++++++++
Func Open7ZipPercent($pid)
; Try to attach to the console of the PID.
; Return 0 on failure.
If _AttachConsole($pid)=0 Then Return 0
; The user should treat this as an opaque handle, but internally it contains a handle and some structures.
Local $vHandle[4]
$vHandle[0]=_GetStdHandle(-11) ; STDOUT Handle
$vHandle[1]=DllStructCreate("short dwSizeX;short dwSizeY;short dwCursorPositionX;short dwCursorPositionY;short wAttributes;short Left;short Top;short Right;short Bottom;short dwMaximumWindowSizeX;short dwMaximumWindowSizeY") ; Screen Buffer structure
$vHandle[2]=DllStructCreate("dword[4]") ; Data buffer
$vHandle[3]=DllStructCreate("short Left;short Top;short Right;short Bottom") ; SMALL_RECT structure
; Return the handle on success.
Return $vHandle
EndFunc ;==>Open7ZipPercent
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
Func _Read7Ziptxt(ByRef $vHandle, $Nline=-1)
; Basic sanity check to validate the handle.
Local $exit_txt=""
If UBound($vHandle)=4 Then
; Try to get the screen buffer information.
If _GetConsoleScreenBufferInfo($vHandle[0],$vHandle[1]) Then
For $s = 0 To 19
; Load the SMALL_RECT with the projected text position.
DllStructSetData($vHandle[3],"Left",$s*4)
DllStructSetData($vHandle[3],"Top",DllStructGetData($vHandle[1],"dwCursorPositionY")+$Nline)
DllStructSetData($vHandle[3],"Right",80)
DllStructSetData($vHandle[3],"Bottom",DllStructGetData($vHandle[1],"dwCursorPositionY")+$Nline)
; Read the console output.
If _ReadConsoleOutput($vHandle[0],$vHandle[2],$vHandle[3]) Then
; Читаем 4 символа
For $i = 0 To 3
Local $pCharInfo=DllStructCreate("wchar UnicodeChar;short Attributes", _
DllStructGetPtr($vHandle[2])+($i*4))
; Append the character.
$exit_txt &=DllStructGetData($pCharInfo,"UnicodeChar")
Next
EndIf
Next
EndIf
EndIf
; On failure we return -1 which is obviously not a valid percentage.
Return $exit_txt
EndFunc ;==>_Read7Ziptxt
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
Func Read7ZipPercent(ByRef $vHandle)
; Basic sanity check to validate the handle.
If UBound($vHandle)=4 Then
; Try to get the screen buffer information.
If _GetConsoleScreenBufferInfo($vHandle[0],$vHandle[1]) Then
; Load the SMALL_RECT with the projected text position.
DllStructSetData($vHandle[3],"Left",DllStructGetData($vHandle[1],"dwCursorPositionX")-4)
DllStructSetData($vHandle[3],"Top",DllStructGetData($vHandle[1],"dwCursorPositionY"))
DllStructSetData($vHandle[3],"Right",DllStructGetData($vHandle[1],"dwCursorPositionX"))
DllStructSetData($vHandle[3],"Bottom",DllStructGetData($vHandle[1],"dwCursorPositionY"))
; Read the console output.
If _ReadConsoleOutput($vHandle[0],$vHandle[2],$vHandle[3]) Then
; This variable holds the output string.
Local $sPercent=""
; We iterate over 3 characters because that's all we read.
For $i = 0 To 3
Local $pCharInfo=DllStructCreate("wchar UnicodeChar;short Attributes", _
DllStructGetPtr($vHandle[2])+($i*4))
; Append the character.
$sPercent &=DllStructGetData($pCharInfo,"UnicodeChar")
Next
; Ensure we read a valid percentage. If so return the cast to a number.
If StringRight($sPercent,1)="%" Then Return Number($sPercent,4)
EndIf
EndIf
EndIf
; On failure we return -1 which is obviously not a valid percentage.
Return -1
EndFunc ;==>Read7ZipPercent
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
Func _GetStdHandle($nHandle)
Local $aRet=DllCall('Kernel32.dll','hwnd',"GetStdHandle",'dword',$nHandle)
If @error Then Return SetError(@error,@extended,-1)
Return $aRet[0]
EndFunc ;==>_GetStdHandle
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
Func _AttachConsole($nPid)
Local $aRet=DllCall('Kernel32.dll','int',"AttachConsole",'dword',$nPid)
If @error Then Return SetError(@error,@extended,False)
Return $aRet[0]
EndFunc ;==>_AttachConsole
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
Func _GetConsoleScreenBufferInfo($hConsoleOutput,$pConsoleScreenBufferInfo)
Local $aRet=DllCall('Kernel32.dll','int',"GetConsoleScreenBufferInfo",'hwnd',$hConsoleOutput,'ptr', _
_SafeGetPtr($pConsoleScreenBufferInfo))
If @error Then Return SetError(@error,@extended,False)
Return $aRet[0]
EndFunc ;==>_GetConsoleScreenBufferInfo
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
Func _ReadConsoleOutput($hConsoleOutput,$pBuffer,$pSmallRect);,65540,0,
; We lie about the types for the COORD structures. Since they are the size of an int we expect a packed
; int. Otherwise we may crash or just pass garbage.
Local $aRet=DllCall('Kernel32.dll','int',"ReadConsoleOutputW",'ptr',$hConsoleOutput, _
'ptr',_SafeGetPtr($pBuffer),'int',65540, 'int',0, _
'ptr',_SafeGetPtr($pSmallRect))
If @error Then SetError(@error,@extended,False)
Return $aRet[0]
EndFunc ;==>_ReadConsoleOutput
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
Func _SafeGetPtr(Const ByRef $PTR)
Local $_ptr=DllStructGetPtr($PTR)
If @error Then $_ptr=$PTR
Return $_ptr
EndFunc ;==>_SafeGetPtr
;=======================================================================
; вспомогательные функции для тестового окна
;=======================================================================
Func _ESC_1()
ProcessClose($iPID)
Beep(1000,500)
Do
$err=FileDelete($nameArchv)
Until $err
Exit
EndFunc ;==>_ESC_1
Func _F11_1()
If BitAnd(WinGetState($hGuiWin),16) Then
GUISetState(@SW_RESTORE,$hGuiWin)
Else
GUISetState(@SW_MINIMIZE,$hGuiWin)
EndIf
Beep(1000,200)
EndFunc ;==> _F11_1()
Func _GetTabbedStringSizeEx($CtrlID,$sString)
Local $tTM= DllStructCreate('long;long;long;long;long;long;long;long;long;long;long;wchar;wchar;wchar;wchar;byte;byte;byte;byte;byte')
Local $pTM=DllStructGetPtr($tTM)
Local $tData=DllStructCreate('long;long')
Local $pData=DllStructGetPtr($tData)
If Not IsHWnd($CtrlID) Then $CtrlID=GUICtrlGetHandle($CtrlID)
Local $Ret=DllCall('user32.dll','ptr','GetDC','hwnd',$CtrlID)
Local $hDC=$Ret[0]
$Ret=DllCall('user32.dll','ptr','SendMessageW','hwnd',$CtrlID,'uint',0x0031,'wparam',0,'lparam',0)
$Ret=DllCall('gdi32.dll','ptr','SelectObject','hwnd',$hDC,'ptr',$Ret[0])
Local $hSv=$Ret[0]
$Ret=DllCall('gdi32.dll','int','GetTextMetricsW','hwnd',$hDC,'ptr',$pTM)
Local $Tab=8*DllStructGetData($tTM,6)
DllStructSetData($tData,1,$Tab)
$Ret=DllCall('user32.dll','dword','GetTabbedTextExtentW','hwnd',$hDC,'wstr',$sString,'int',StringLen($sString), _
'int',1,'ptr',$pData)
If $hSv Then DllCall('gdi32.dll','ptr','SelectObject','hwnd',$hDC,'ptr',$hSv)
If $hDC Then DllCall('user32.dll','int','ReleaseDC','hwnd',$CtrlID,'hwnd',$hDC)
Return BitAND($Ret[0],0xFFFF)
EndFunc ;==>_GetTabbedStringSizeEx