How to shows the progress of extracting files with ProgressBar ?

Just starting out? Need help? Post your questions and find answers here.
hoangdiemtinh
User
User
Posts: 97
Joined: Wed Nov 16, 2022 1:51 pm

How to shows the progress of extracting files with ProgressBar ?

Post by hoangdiemtinh »

I am new to PB.
My primary language is not US/UK. I am using Google Translate.

I have completed the exercise to Extract a file with 7Zip Standalone: https://www.7-zip.org/a/7z2406-extra.7z
But I am having trouble knowing where to start, as I need to display the extraction process in a Progress Bar.

Here, I can use "e" switch, I tried it but it causes an additional problem of "unable to extract file" if a folder exists with the same name as this file.

Please help.

Thanks.

Here is the code.

Code: Select all

CompilerIf #PB_Compiler_Thread = 0
  CompilerWarning "Enable thread safe option!"
CompilerEndIf

EnableExplicit

Enumeration Window
  #mainWindow
EndEnumeration

Enumeration #PB_Event_FirstCustomValue
  #MyEvent_7zip_Start
  #MyEvent_7zip_Doing
  #MyEvent_7zip_Finished
  #MyEvent_7zip_Validate
EndEnumeration

Enumeration Gadgets
  #Btn_Extract
  #Txt_Clock
  #Edit_1
  #StatusBar_1
  #Txt_1
EndEnumeration

Structure udtThreadControl
  ThreadID.i
  Window.i
  Event.i
EndStructure

Structure SEVEN7ZIP Extends udtThreadControl
  Init.i
  SevenFile.s
  ExitCode.i
  Output.s
  VersionS.s
  VersionI.i
  Password.s
  Flags.i
  ;
  nFiles.i
  FileList.s
  nFolders.i
  FolderList.s
  ;
  inFile.s
  outFolder.s
EndStructure

Global *thr7zip.SEVEN7ZIP = AllocateStructure(SEVEN7ZIP)
Global BayZip$ = GetTemporaryDirectory() + "s7zip.exe"

Procedure Set7ZipPassword(mk$)
  With *thr7zip
    \Password = mk$
  EndWith
EndProcedure

Procedure Set7ZipFlags(Flags.i)
  With *thr7zip
    \Flags = Flags
  EndWith
EndProcedure

Procedure Load7zip()
  Define iFileNr.i, iResult.i
  DeleteFile(BayZip$, #PB_FileSystem_Force)
  iFileNr = CreateFile(#PB_Any, BayZip$)
  If iFileNr
    iResult = WriteData(iFileNr, ?file_7zip, ?file_7zip_end - ?file_7zip)
    Debug "Bytes: " + iResult
    CloseFile(iFileNr)
    Delay(500)
  EndIf
EndProcedure

Procedure.i __7Zip_Run(exx.s, Parameter.s = "", Directory.s = "")
  Protected PID.i = #Null
  With *thr7zip
    \ExitCode = 0
    \Output = ""
    PID = RunProgram(exx, Parameter, Directory, #PB_Program_Hide | #PB_Program_Open | #PB_Program_Read)
    If (PID)
      While (ProgramRunning(PID))
        While (AvailableProgramOutput(PID))
          \Output + ReadProgramString(PID, #PB_UTF8) + #LF$ ; Phải là #PB_UTF8
        Wend
        Delay(1)
      Wend
      \ExitCode = ProgramExitCode(PID)
      CloseProgram(PID)
    EndIf
  EndWith
  ProcedureReturn (Bool(PID))
EndProcedure

Procedure Reset7Zip()
  With *thr7zip
    \Password = ""
    \Flags = #Null
  EndWith
EndProcedure

Procedure.s Get7ZipVersion()
  With *thr7zip
    If (\Init)
      ProcedureReturn (\VersionS)
    Else
      ProcedureReturn ("")
    EndIf
  EndWith
EndProcedure

Procedure.i Get7ZipBuildNumber()
  With *thr7zip
    If (\Init)
      ProcedureReturn (\VersionI)
    Else
      ProcedureReturn (0)
    EndIf
  EndWith
EndProcedure

Procedure.i Examine7ZipFiles(Archive$)
  Protected Result.i = 0
  With *thr7zip
    If (\Init)
      If (FileSize(Archive$) >= 0)
        Protected Param$ = "l"
        Param$ + " " + #DQUOTE$ + Archive$ + #DQUOTE$
        If (\Password)
          Param$ + " -p" + \Password
        EndIf
        If (__7Zip_Run(\SevenFile, Param$, GetPathPart(Archive$)))
          If (\ExitCode = 0)
            Protected Lines.i = 1 + CountString(\Output, #LF$)
            \nFiles     = 0
            \FileList   = ""
            \nFolders   = 0
            \FolderList = ""
            Protected i.i
            Protected InList.i = #False
            Protected NameOffset.i
            For i = 1 To Lines
              Protected Line.s = StringField(\Output, i, #LF$)
              If (InList)
                If (Left(Line, 19) = "-------------------")
                  Break
                Else
                  If (Mid(Line, 21, 1) = "D")
                    \FolderList + #LF$ + Mid(Line, NameOffset)
                    \nFolders + 1
                  Else
                    \FileList + #LF$ + Mid(Line, NameOffset)
                    \nFiles + 1
                  EndIf
                EndIf
              Else
                If Right(Line, 6) = "  Name"
                  NameOffset = Len(Line) - 4 + 1
                ElseIf (Left(Line, 19) = "-------------------")
                  InList = #True
                EndIf
              EndIf
            Next i
            \FileList = Mid(\FileList, 2)
            \FolderList = Mid(\FolderList, 2)
            Result = #True
          EndIf
        EndIf
      EndIf
    EndIf
  EndWith
  ProcedureReturn (Result)
EndProcedure

Procedure.i Get7ZipFileCount()
  ProcedureReturn (*thr7zip\nFiles)
EndProcedure

Procedure.s Get7ZipFileList()
  ProcedureReturn (*thr7zip\FileList)
EndProcedure

Procedure AllocateString(String.s) ; Result = Pointer
  Protected *mem.string = AllocateStructure(String)
  If *mem
    *mem\s = String
  EndIf
  ProcedureReturn *mem
EndProcedure

Procedure.s FreeString(*mem.string) ; Result String
  Protected r1.s
  If *mem
    r1 = *mem\s
    FreeStructure(*mem)
  EndIf
  ProcedureReturn r1
EndProcedure

Procedure StartThread(*Data.udtThreadControl, *Procedure)
  If Not IsThread(*Data\ThreadID)
    *Data\ThreadID = CreateThread(*Procedure, *Data)
  EndIf
  ProcedureReturn *Data\ThreadID
EndProcedure

Procedure FreeThread(*Data.udtThreadControl, Wait = 1000)
  If IsThread(*Data\ThreadID)
    If WaitThread(*Data\ThreadID, Wait) = 0
      KillThread(*Data\ThreadID)
    EndIf
  EndIf
  FreeStructure(*Data)
EndProcedure

Procedure.i Extract7ZipFile(Archive$, Dest$ = "")
  Protected.i Result = #False
  With *thr7zip
    If (\Init)
      If FileSize(Archive$) > 0
        If Len(Dest$) < 3
          Dest$ = GetCurrentDirectory() + "temp"
        EndIf
        Protected Param$ = "x -y -aoa"
        Param$ + " "   + #DQUOTE$ + Archive$ + #DQUOTE$
        Param$ + " -o" + #DQUOTE$ + Dest$ + #DQUOTE$
        If (\Password)
          Param$ + " -p" + #DQUOTE$ + \Password + #DQUOTE$
        EndIf
        If (__7Zip_Run(\SevenFile, Param$, GetPathPart(Archive$)))
          If (\ExitCode = 0)
            Result = #True
          EndIf
        EndIf
      EndIf
    EndIf
  EndWith
  ProcedureReturn (Result)
EndProcedure

Procedure.i Init7Zip(exx.s = "")
  With *thr7zip
    If (Not \Init)
      If (exx = "")
        exx = BayZip$
      EndIf
      If (__7Zip_Run(exx))
        Protected ii.i = FindString(\Output, "7-Zip (a) ", 1, #PB_String_NoCase)
        If (ii)
          \SevenFile = BayZip$
          \VersionS = StringField(Trim(Mid(\Output, ii + 10)), 1, " ")
          \VersionI = Round(100.0 * ValF(\VersionS), #PB_Round_Nearest)
          Reset7Zip()
          \Init = #True
          Debug "VersionS: " +  \VersionS
          Debug "VersionI: " +  \VersionI
        EndIf
      EndIf
    EndIf
    ProcedureReturn (\Init)
  EndWith
EndProcedure

Procedure Thread7Zip(*Data.SEVEN7ZIP)
  Protected sdata$, doc_7zip_fullpath$, fullpath_to_extract$, mk$
  With *Data
    doc_7zip_fullpath$ = \inFile
    fullpath_to_extract$ = \outFolder
    mk$ = \Password
    If FileSize(doc_7zip_fullpath$) = -1
      sdata$ = "Không tìm thấy Tài nguyên."
      PostEvent(#MyEvent_7zip_Finished, #mainWindow, 0, 0, AllocateString(sdata$))
    EndIf
    If FileSize(doc_7zip_fullpath$) > 0
      Load7zip()      
      If (Init7Zip())
        Protected FileList$, zFile$
        Protected.i i, n
        Set7ZipPassword(mk$)
        If (Examine7ZipFiles(doc_7zip_fullpath$))
          n = Get7ZipFileCount()
          FileList$ = Get7ZipFileList()
          For i = 1 To n
            zFile$ = StringField(FileList$, i, #LF$)
            If FileSize(RTrim(fullpath_to_extract$, "\") + "\" + zFile$) >= 0
              sdata$ = "Xóa tập tin: " + zFile$
              PostEvent(#MyEvent_7zip_Doing, #mainWindow, 0, 0, AllocateString(sdata$))
              ;MessageRequester("file", RTrim(fullpath_to_extract$, "\") + "\" + zFile$)
              DeleteFile(RTrim(fullpath_to_extract$, "\") + "\" + zFile$, #PB_FileSystem_Force)
            EndIf
            If FileSize(RTrim(fullpath_to_extract$, "\") + "\" + zFile$) = -2
              sdata$ = "Xóa thư mục: " + zFile$
              PostEvent(#MyEvent_7zip_Doing, #mainWindow, 0, 0, AllocateString(sdata$))
              ;MessageRequester("thư mục", RTrim(fullpath_to_extract$, "\") + "\" + zFile$)
              DeleteDirectory(RTrim(fullpath_to_extract$, "\") + "\" + zFile$, "", #PB_FileSystem_Force | #PB_FileSystem_Recursive)
            EndIf
          Next i
          sdata$ = "Trích xuất Tài nguyên..."
          PostEvent(#MyEvent_7zip_Start, #mainWindow, 0, 0, AllocateString(sdata$))
          If Extract7ZipFile(doc_7zip_fullpath$, fullpath_to_extract$)
            sdata$ = "Trích xuất Tài nguyên thành công."
            PostEvent(#MyEvent_7zip_Finished, #mainWindow, 0, 0, AllocateString(sdata$))
          EndIf
        Else
          sdata$ = "Sai mật khẩu."
          PostEvent(#MyEvent_7zip_Finished, #mainWindow, 0, 0, AllocateString(sdata$))
        EndIf
      Else
        sdata$ = "Không thể khởi tạo Bộ giải nén."
        PostEvent(#MyEvent_7zip_Start, #mainWindow, 0, 0, AllocateString(sdata$))
      EndIf
      Reset7Zip()
      RunProgram("taskkill", "/F /IM " + #DQUOTE$ + \SevenFile + #DQUOTE$, "", #PB_Program_Wait| #PB_Program_Hide)
      DeleteFile(\SevenFile, #PB_FileSystem_Force)
    EndIf
  EndWith
EndProcedure

Procedure DoExtract(*dt.SEVEN7ZIP, doc_7zip_fullpath$, fullpath_to_extract$, pw$)
  If Not IsThread(*dt\ThreadID)
    With *dt
      \inFile = doc_7zip_fullpath$
      \outFolder = fullpath_to_extract$
      \Password = pw$
      StartThread(*dt, @Thread7Zip())
    EndWith
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

Declare.i update_clock(ii)

Procedure.i update_clock(ii)
  Repeat
    SetGadgetText(#Txt_Clock, FormatDate("%hh:%ii:%ss", Date()))
    Delay(500)
  ForEver
EndProcedure

Procedure StatusBar_mainWindow()
  CreateStatusBar(#StatusBar_1, WindowID(#mainWindow))
  AddStatusBarField(70)
  AddStatusBarField(430)
  StatusBarText(#StatusBar_1, 0, "Progress: ", #PB_StatusBar_BorderLess)
  StatusBarProgress(#StatusBar_1, 1, 3)
EndProcedure

Procedure Resize_mainWindow()
  Protected mainWindow_WidthIni = 500, mainWindow_HeightIni = 180
  Protected ScaleX.f, ScaleY.f
  ScaleX = WindowWidth(#mainWindow) / mainWindow_WidthIni : ScaleY = WindowHeight(#mainWindow) / mainWindow_HeightIni
  ResizeGadget(#Txt_1, ScaleX * 10, ScaleY * 10, ScaleX * 50, ScaleY * 25)
  ResizeGadget(#Txt_CLOCK, ScaleX * 65, ScaleY * 10, ScaleX * 60, ScaleY * 25)
  ResizeGadget(#Btn_Extract, ScaleX * 410, ScaleY * 10, ScaleX * 80, ScaleY * 30)
  ResizeGadget(#Edit_1, ScaleX * 10, ScaleY * 50, ScaleX * 480, ScaleY * 90)
EndProcedure

Procedure Open_mainWindow(X = 0, Y = 0, Width = 500, Height = 180)
  OpenWindow(#mainWindow, X, Y, Width, Height, "Shows the progress of extracting 7z files with ProgressBar", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
  TextGadget(#Txt_1, 10, 10, 50, 25, "Clock:", #SS_CENTERIMAGE)
  TextGadget(#Txt_CLOCK, 65, 10, 60, 25, "8:18:18", #PB_Text_Center | #SS_CENTERIMAGE)
  ButtonGadget(#Btn_Extract, 410, 10, 80, 30, "Extract")
  EditorGadget(#Edit_1, 10, 50, 480, 90)
  AddGadgetItem(#Edit_1, -1, "Action Log...")
  StatusBar_mainWindow()
  CreateThread(@update_clock(),0)
  BindEvent(#PB_Event_SizeWindow, @Resize_mainWindow(), #mainWindow)
  PostEvent(#PB_Event_SizeWindow, #mainWindow, 0)
EndProcedure

Open_mainWindow()

;- Main Program
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      FreeThread(*thr7zip)
      Break
    Case #MyEvent_7zip_Start
      SetGadgetText(#Edit_1, FreeString(EventData()))
    Case #MyEvent_7zip_Doing
      SetGadgetText(#Edit_1, FreeString(EventData()))
    Case #MyEvent_7zip_Finished
      SetGadgetText(#Edit_1, FreeString(EventData()))
    Case #MyEvent_7zip_Validate
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #Btn_Extract
          If Not IsThread(*thr7zip\ThreadID)
            DoExtract(*thr7zip, "D:\my-files\a1.7z", "D:\ab c\d ef", "mypass")
          EndIf
      EndSelect
  EndSelect
ForEver

DataSection
  file_7zip:
  IncludeBinary "7za.exe"
  file_7zip_end:
EndDataSection
PC: Windows 10 x64, 8GB RAM. PB ver: 6.x
--
I love PB5 vs PB6 :)
infratec
Always Here
Always Here
Posts: 7662
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to shows the progress of extracting files with ProgressBar ?

Post by infratec »

As usual:

define the ProgressBarGadget() in the main programm and set the values via PostEvent from the thread.
You can also set the end value of the bar via a PostEvent()
hoangdiemtinh
User
User
Posts: 97
Joined: Wed Nov 16, 2022 1:51 pm

Re: How to shows the progress of extracting files with ProgressBar ?

Post by hoangdiemtinh »

Thank @infratec.

As switch "e", I can count the number of files/folders in the 7z package by using "Get7ZipFileCount". From there, it's easy to set a value for ProgressBar.
Here, only switch "x" can be used...

How can I know the number of bytes extracted, something like that...
Take the total number of bytes (un-compressed), subtract this number of bytes....
PC: Windows 10 x64, 8GB RAM. PB ver: 6.x
--
I love PB5 vs PB6 :)
Post Reply