jennico

_7zRead UDF

3 posts in this topic

#1 ·  Posted (edited)

Lots of people have been looking for a way to read out and display the contents of the the 7zip cmd window.

while there is no problem to read out the "7z t " and "7z l " commands by stdoutread, there is no easy way to get the text from the "7z a" (add to archive) command.

finally i found a tricky solution written by valik (Screen_Scrape). at least it is able to read out the compression progress percentage. the script is deeply hidden in the chat forum. i was so glad about it that i built a little UDF around it. working perfectly.

you can run the script as .au3 or #include it, but it cannot be run from SciTe.

;Global UDF Constants +++++++++++++++++++++++++++++++++++++++++++++++++++++++

Global Const $STD_INPUT_HANDLE = -10
Global Const $STD_OUTPUT_HANDLE = -11
Global Const $STD_ERROR_HANDLE = -12
Global Const $INVALID_HANDLE_VALUE = -1
Global Const $_CONSOLE_SCREEN_BUFFER_INFO = "short dwSizeX; short dwSizeY;short dwCursorPositionX; short dwCursorPositionY; short wAttributes;short Left; short Top; short Right; short Bottom; short dwMaximumWindowSizeX; short dwMaximumWindowSizeY" 
Global Const $_COORD = "short X; short Y" 
Global Const $_CHAR_INFO = "wchar UnicodeChar; short Attributes" 
Global Const $_SMALL_RECT = "short Left; short Top; short Right; short Bottom" 
Global Const $K32 = "Kernel32.dll", $INT = "int", $HWN = "hwnd", $PTR = "ptr", $DWO = "dword" 

;main UDF ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

;   Function:       _7zRead
;   Description:    Reads progress from 7zip window and sets control data
;   Parameters:     $sCmd = 7zip Commandline to be executed
;                   $iProgress = [optional] ControlID of Progress Control to be updated (if none, use "")
;                   $sProgress = [optional] 1 if Progress Bar Window has to be updated, "" if not
;                   $sProgressSubText = [optional] 1 if Progress Bar Subtext to be written, "" if not
;                   $iStatic = [optional] ControlID of a Static Control (label, button etc pp) to be updated (if none, use "")
;                   $iStaticText = [optional] Text for $iStatic, the percentage will be added
;                   $nShow = [optional] Flag for 7zip window, default is @SW_HIDE
;   Author:         jennico, basic script by valik

Func _7zRead($sCmd, $iProgress="", $sProgress="", $sProgressSubText="", $iStatic="", $iStaticText="", $nShow = @SW_HIDE)
    $iPID = Run($sCmd, "", $nShow)
    ProcessWait($iPID)
    If $iStatic Then GUICtrlSetData($iStatic, $iStaticText & "0%")
    Local $hPercent = Open7ZipPercent($iPID), $opercent = -1
    While ProcessExists($iPID)
        Local $nPercent = Read7ZipPercent($hPercent)
        If $nPercent >= 0 And $opercent <> $nPercent Then
            If $sProgressSubText Then $sProgressSubText = $nPercent
            If $sProgress Then ProgressSet($nPercent, $nPercent & "%")
            If $iProgress Then GUICtrlSetData($iProgress, $nPercent)
            If $iStatic Then GUICtrlSetData($iStatic, $iStaticText & $nPercent & "%")
            $opercent = $nPercent
        Else
            Sleep(50)
        EndIf
    WEnd
    Close7ZipPercent($hPercent)
EndFunc   ;==>_7zRead

;internal helper functions ++++++++++++++++++++++++++++++++++++++++++++++++++++

Func Open7ZipPercent($pid)
    If _AttachConsole($pid) = 0 Then Return
    Local $vHandle[4]
    $vHandle[0] = _GetStdHandle($STD_OUTPUT_HANDLE)
    $vHandle[1] = DllStructCreate($_CONSOLE_SCREEN_BUFFER_INFO)
    $vHandle[2] = DllStructCreate("dword[4]")
    $vHandle[3] = DllStructCreate($_SMALL_RECT)
    Return $vHandle
EndFunc   ;==>Open7ZipPercent

Func Close7ZipPercent(ByRef $vHandle)
    If UBound($vHandle) <> 4 Then Return False
    DllCall($K32, $INT, "FreeConsole")
    $vHandle = 0
    Return True
EndFunc   ;==>Close7ZipPercent

Func Read7ZipPercent(ByRef $vHandle)
    If UBound($vHandle) = 4 Then
        Local Const $hStdOut = $vHandle[0]
        Local Const $pConsoleScreenBufferInfo = $vHandle[1]
        Local Const $pBuffer = $vHandle[2]
        Local Const $pSmallRect = $vHandle[3]
        If _GetConsoleScreenBufferInfo($hStdOut, $pConsoleScreenBufferInfo) Then
            DllStructSetData($pSmallRect, "Left", DllStructGetData($pConsoleScreenBufferInfo, "dwCursorPositionX") - 4)
            DllStructSetData($pSmallRect, "Top", DllStructGetData($pConsoleScreenBufferInfo, "dwCursorPositionY"))
            DllStructSetData($pSmallRect, "Right", DllStructGetData($pConsoleScreenBufferInfo, "dwCursorPositionX"))
            DllStructSetData($pSmallRect, "Bottom", DllStructGetData($pConsoleScreenBufferInfo, "dwCursorPositionY"))
            If _ReadConsoleOutput($hStdOut, $pBuffer, $pSmallRect) Then
                Local $sPercent = ""
                For $i = 0 To 3
                    Local $pCharInfo = DllStructCreate($_CHAR_INFO, DllStructGetPtr($pBuffer) + ($i * 4))
                    $sPercent &= DllStructGetData($pCharInfo, "UnicodeChar")
                Next
                If StringRight($sPercent, 1) = "%"  Then Return Number($sPercent)
            EndIf
        EndIf
    EndIf
    Return -1
EndFunc   ;==>Read7ZipPercent

Func _GetStdHandle($nHandle)
    Local $aRet = DllCall($K32, $HWN, "GetStdHandle", $DWO, $nHandle)
    If @error Then Return SetError(@error, @extended, $INVALID_HANDLE_VALUE)
    Return $aRet[0]
EndFunc   ;==>_GetStdHandle

Func _AttachConsole($nPid)
    Local $aRet = DllCall($K32, $INT, "AttachConsole", $DWO, $nPid)
    If @error Then Return SetError(@error, @extended, False)
    Return $aRet[0]
EndFunc   ;==>_AttachConsole

Func _GetConsoleScreenBufferInfo($hConsoleOutput, $pConsoleScreenBufferInfo)
    Local $aRet = DllCall($K32, $INT, "GetConsoleScreenBufferInfo", $HWN, $hConsoleOutput, $PTR, _SafeGetPtr($pConsoleScreenBufferInfo))
    If @error Then Return SetError(@error, @extended, False)
    Return $aRet[0]
EndFunc   ;==>_GetConsoleScreenBufferInfo

Func _ReadConsoleOutput($hConsoleOutput, $pBuffer, $pSmallRect);, 65540, 0,
    Local $aRet = DllCall($K32, $INT, "ReadConsoleOutputW", $PTR, $hConsoleOutput, $INT, _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


;example GUI +++++++++++++++++++++++++++++++++++++++++++++++++++++++
#include <WindowsConstants.au3>
#include <EditConstants.au3>

$gui = GUICreate("", 400, 189, Default, Default, BitOR($WS_POPUP, $WS_BORDER), $WS_EX_TOPMOST)
$Edit = GUICtrlCreateEdit("", 4, 4, 394, 156, BitOR($WS_VSCROLL, $ES_READONLY))
GUICtrlSetBkColor(-1, 0)
GUICtrlSetColor(-1, 0xFFFFFF)
GUICtrlSetFont(-1, 9, 800)
$Progress = GUICtrlCreateProgress(4, 162, 394, 25, 1)
GUICtrlSetColor(-1, 0xF200)
$Label = GUICtrlCreateLabel("", 4, 167, 394, 20, 1)
GUICtrlSetFont(-1, 9, 800)
GUICtrlSetBkColor(-1, -2)

GUISetState()
HotKeySet("{ESC}", "_Exit")
ProgressOn("7zipRead Example GUI", "Compressing", "", -1, @DesktopHeight / 2 - 200, 16)

GUICtrlSetData($Edit, "Press <ESC> to abort", 1)

$Folder = FileSelectFolder("Please Choose Directory to be Compressed" & @CRLF & "(Folder should contain several subs and some 100 MB)", @HomeDrive, 0, @HomeDrive, $gui)
If StringRight($Folder, 2) = ":\"  Then $Folder = StringTrimRight($Folder, 1)

Dim $t, $search = FileFindFirstFile($Folder & "\*.*")
Do
    $t &= FileFindNextFile($search) & "|" 
Until @error
FileClose($search)

$FileList = StringSplit(StringTrimRight($t, 2), "|")
$Archiv = @HOUR & "_" & @MIN & "_" & @SEC & "_test.zip" 

For $i = 1 To $FileList[0]
    GUICtrlSetData($Edit, @CRLF & "...compressing  " & $Folder & "\" & $FileList[$i] & "  " & $i & " of " & $FileList[0] & " ...", 1)
    ProgressSet(0, "", "Compressing " & $Folder & "\" & $FileList[$i])
    _7zRead("7z a -tzip " & $Archiv & " " & FileGetShortName($Folder & "\" & $FileList[$i]) & " -x!Thumbs.db", $Progress, 1, 1, $Label, $Folder & "\" & $FileList[$i] & "  =>  ", @SW_SHOW)
    GUICtrlSetData($Edit, " OK", 1)
Next

ProgressSet(100,"100%")
GUICtrlSetData($Progress,100)
GUICtrlSetData($Label,$Folder&"  =>  100%")

Dim $t="",$x = Run("7z l " & $Archiv & " -r", "", @SW_SHOW, 6)
While @error = 0
    $t &= StdoutRead($x)
WEnd

GUICtrlSetData($Edit,@CRLF&@CRLF&$t,1)
    
While 1
    Sleep(20)
WEnd

Func _Exit()
    ProcessClose("7z.exe")
    Exit
EndFunc   ;==>_Exit

cheers j.

Edit: updated example. it is better to pass FileGetShortName because of the spaces in file path. even better it would be to use @ComSpec with '' ...... i know ..... :P

Edit2: inserted a sleep to avoid cpu load.

Edited by jennico

Spoiler

I actively support Wikileaks | Freedom for Julian Assange ! | Defend freedom of speech ! | Fight censorship ! | I will not silence.OixB7.jpgDon't forget this IP: 213.251.145.96

 

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Thanks, good UDF, definitly will use it ^_^

Edited by MrCreatoR

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

AutoIt is simple, subtle, elegant. © AutoIt Team

Share this post


Link to post
Share on other sites

Thanks, good UDF.

can use for makecab.exe?

Share this post


Link to post
Share on other sites

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