Jump to content

_7zRead UDF


jennico
 Share

Recommended Posts

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

 

Link to comment
Share on other sites

  • 1 month later...

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

Edited by MrCreatoR

 

Spoiler

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...

Spoiler

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

Link to comment
Share on other sites

  • 5 months later...

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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...