Announcement

Collapse
No announcement yet.

UnZip Options

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • UnZip Options

    Using the Windows Explorer built-in zip features I often zip up combinations of files and folders. I'd like something I can use in my Win10 app to unzip the content so I can automate and monitor the unzip process. I've actually posted a couple of threads on the topic myself, but they tended to focus on zipping, rather than unzipping.

    I've looked at various solutions in threads here, but can't say as I'had a Eureka! moment with any of them.

    If anyone has a strong feeling about what would be the simplest/minimal solution, I'm interested in hearing about it!

    I tried the shell code here, but the shellapi.inc file doesn't seem to be the same as the (unlisted) shell32.inc included by the code. I took the INC from another thread and it compiled, but didn't unzip the file. I'll be looking at it some more. Still. it holds promise. I'll have to test it some more.

    I tried the zlib code here, but it's not clear how to use it with a combination of files and folders.

    I tried the LiteUnZip DLL here. It unzipped a file/folder combination just fine. Pro: Allows monitoring, Very Minimal, Con: DLL required

    I'll keep looking some more ... feels like I've just scratched the surface of what has been discussed in the forums.










  • #2
    If my code calls out a function from a DLL, then that DLL must be available when my EXE starts, not just when my EXE makes its first call of the function. That's correct, isn't it?

    That means if I want to use a necessary DLL stored in my EXE, then I have to write my code to use LoadLibrary at run time, after I've extracted the DLL resource from the EXE. And, I'm guessing, that DLL cannot be deleted until I use FreeLibrary.

    Now that I ask, I think I've posted a demo of some of that. I'll go find it and see if I can post a example of the whole sequence - applied to the use of the liteunzip DLL.



    Comment


    • #3
      Well, I've run into a snag with demonstrating extraction and runtime use of the liteunzip.dll. Code and needed files are found here - lite_test.zip

      The code builds an EXE called "liteunzip.exe" which includes "test.zip" and liteunzip.dll" as resources, and puts it in the "test" subfolder. It is supposed to extract the resource files "test.zip" and "liteunzip.dll", then link to the DLL and then unzip "test.zip".

      Even though I use LoadLibrary and GetProcAddress to link to the DLL functions at run time , I still get this error on startup of the EXE, even before I try to load the DLL or make a call to the DLL functions.

      "The code execution cannot proceed because LITEUNZIP.DLL was not found. Reinstalling the program may fix this problem.
      I've done something wrong, but not sure what's wrong, but I know the issue is in the UnZipFilesAndFolders function, because if I comment it out, the rest of the code seems to work as expected.

      ... looking ... suggestions welcome ...

      Here's the test code ... (corresponds to the code mentioned earlier from Jose on using liteunzip) ...

      Code:
      'Compilable Example:
      #Compile Exe  "test\liteunzip.exe"
      #Dim All
      %Unicode = 1
      #Include "Win32API.inc"
      #Include "LITEZIP.INC"
      
      #Resource RcData, 1000, "test.zip"
      #Resource RcData, 1001, "liteunzip.dll"
      
      'copied out of litezip.inc
      Declare Function UnzipOpenFile   (ByRef hUnzip As Dword, ByRef szFilename As AsciiZ, ByRef szPassword As AsciiZ) As Dword
      Declare Function UnzipGetItem    (ByVal hUnzip As Dword, ByRef ze As ZIPENTRY) As Dword
      Declare Function UnzipItemToFile (ByVal hUnzip As Dword, ByRef szFilename As AsciiZ, ByRef ze As ZIPENTRY) As Dword
      Declare Function UnzipClose      (ByVal hUnzip As Dword) As Dword
      
      Enum Equates Singular
         IDC_Button
      End Enum
      
      Global hDlg,hLib As Dword
      Global add_Open, add_Get, add_File, add_Close As Dword
      
      Function PBMain() As Long
         Dialog New Pixels, 0, "LiteUnZip Test",300,300,300,100, %WS_OverlappedWindow To hDlg
         Control Add Button, hDlg, %IDC_Button,"Extract", 50,10,100,20
         Dialog Show Modal hDlg Call DlgProc
      End Function
      
      CallBack Function DlgProc() As Long
         Select Case Cb.Msg
            Case %WM_Command
               Select Case Cb.Ctl
                  Case %IDC_Button
                     ExtractDLLandZip              : ? "DLL and Zip extracted"
                     LoadLibraryAndLinkToFunctions : ? "Libary Loaded. Links Made to Functions"
                     UnZipFilesAndFolders          : ? "Files and Folders unzipped"
                     RemoveDLLandZip               : ? "DLL and Zip deleted"
               End Select
         End Select
      End Function
      
      Sub ExtractDLLandZip
         Local FileContent$
         FileContent$ = Resource$(RcData,1000)
         Open "test.zip" For Output As #1 : Print #1, FileContent$; : Close #1
         FileContent$ = Resource$(RcData,1001)
         Open "liteunzip.dll" For Output As #1 : Print #1, FileContent$; : Close #1
      End Sub
      
      Sub LoadLibraryAndLinkToFunctions
         hLib = LoadLibrary("liteunzip.dll")
         add_Open   = GetProcAddress(hLib, "UnzipOpenFileA")
         add_Get    = GetProcAddress(hLib, "UnzipGetItemA")
         add_File   = GetProcAddress(hLib, "UnzipItemToFileA")
         add_Close  = GetProcAddress(hLib, "UnzipClose")
      End Sub
      
      Sub UnZipFilesAndFolders
         Local hUnzip As Dword, ze As ZIPENTRY, numitems, idx As Dword, iResult As Long
         Call Dword add_Open Using UnzipOpenFile(hUnzip, "test.zip", ByVal %NULL) To iResult
         If hUnzip Then
            ze.Index = &HFFFFFFFF
            Call Dword add_Get Using UnzipGetItem(hUnzip, ze) To iResult
            numitems = ze.Index
            For idx = 0 To numitems - 1
               ze.Index = idx
               Call Dword add_Get Using UnzipGetItem(hUnzip, ze) To iResult
               Call Dword add_File Using UnzipItemToFile(hUnzip, ze.szName, ze) To iResult
               Dialog Set Text hDlg, "Items Unzipped: " + Str$(Idx)
            Next
            Call Dword add_Close Using UnzipClose(hUnzip) To iResult
         End If
      End Sub
      
      Sub RemoveDLLandZip
         FreeLibrary hLib
         If IsFile("test.zip")      Then Kill "test.zip
         If IsFile("liteunzip.dll") Then Kill "liteunzip.dll"
      End Sub

      Comment


      • #4
        The following may help narrow it down.
        Try #DEBUG DISPLAY ON with:
        Code:
        SUB UnZipFilesAndFolders
           LOCAL hUnzip AS DWORD, ze AS ZIPENTRY, numitems, idx AS DWORD, iResult AS LONG
           label1:
           CALL DWORD add_Open USING UnzipOpenFile(hUnzip, "test.zip", BYVAL %NULL) TO iResult
           label2:
           IF hUnzip THEN
              ze.Index = &HFFFFFFFF
              CALL DWORD add_Get USING UnzipGetItem(hUnzip, ze) TO iResult
              label3:
              numitems = ze.Index
              FOR idx = 0 TO numitems - 1
                 ze.Index = idx
                 CALL DWORD add_Get USING UnzipGetItem(hUnzip, ze) TO iResult
                 label4:
                 CALL DWORD add_File USING UnzipItemToFile(hUnzip, ze.szName, ze) TO iResult
                 label5:
                 DIALOG SET TEXT hDlg, "Items Unzipped: " + STR$(Idx)
              NEXT
              CALL DWORD add_Close USING UnzipClose(hUnzip) TO iResult
              label6:
           END IF
        END SUB
        Rod
        "To every unsung hero in the universe
        To those who roam the skies and those who roam the earth
        To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

        Comment


        • #5
          Hi Rodney!
          Thanks, but I still get the System Error message above, with no mention of the inserted labels.

          Commenting out all of the Call Using statements removes the initial runtime error, but of course, also does not let the EXE do what is intended.

          Comment


          • #6
            FYI, if I comment out the Call Using lines, and check the results of using GetProcAdresss, all of the pointers are non-zero.

            But because the System Error message is happening even before that Sub is executed, there seems to be something on startup going wrong - an attempt to load liteunzip.dll before my code tells it to load and before it's extracted from the EXE resources.

            I've run other, similar code, using Call Using with Kernel.dll, that works just fine. But this code with liteunzip.dll is not. I'm mis-understanding something, it would seem.

            Comment


            • #7
              Well, you can insert labels throughout the program which may help pinpoint the issue. 'Twas a stab in the dark.
              Rod
              "To every unsung hero in the universe
              To those who roam the skies and those who roam the earth
              To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

              Comment


              • #8
                Found something that seems to work. I renamed the Declared functions to names other than what was in the DLL.and adjusted the code to use the new names.

                My notes said the Declared functions can be the same as the functions in the DLL, but I guess my notes are wrong! I don't see where Help weighs in on the matter.

                Once I do that, the unzipping seems to take place as desired. Cool beans!

                Comment


                • #9
                  How did you rename the DECLAREd functions, via ALIAS?
                  Rod
                  "To every unsung hero in the universe
                  To those who roam the skies and those who roam the earth
                  To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

                  Comment


                  • #10
                    Hi Rodney,
                    Yes, I used the ALIAS as the Declare name at first, then simply added an X to the name to make it work (plus the X in the code lines as well). Here's the revised code ...

                    The light_test.zip file has been updated too.

                    Code:
                    'Compilable Example:
                    #Compile Exe  "test\liteunzip.exe"
                    #Dim All
                    
                    #Debug Display On
                    #Debug Error On
                    
                    %Unicode = 1
                    
                    #Include "Win32API.inc"
                    #Include "LITEZIP.INC"
                    
                    #Resource RcData, 1000, "test.zip"
                    #Resource RcData, 1001, "liteunzip.dll"
                    
                    'copied out of litezip.inc
                    Declare Function UnzipOpenFileX   (ByRef hUnzip As Dword, ByRef szFilename As AsciiZ, ByRef szPassword As AsciiZ) As Dword
                    Declare Function UnzipGetItemX    (ByVal hUnzip As Dword, ByRef ze As ZIPENTRY) As Dword
                    Declare Function UnzipItemToFileX (ByVal hUnzip As Dword, ByRef szFilename As AsciiZ, ByRef ze As ZIPENTRY) As Dword
                    Declare Function UnzipCloseX      (ByVal hUnzip As Dword) As Dword
                    
                    Enum Equates Singular
                       IDC_Button
                    End Enum
                    
                    Global hDlg,hLib As Dword
                    Global add_Open, add_Get, add_File, add_Close As Dword
                    
                    Function PBMain() As Long
                       Dialog New Pixels, 0, "LiteUnZip Test",300,300,300,100, %WS_OverlappedWindow To hDlg
                       Control Add Button, hDlg, %IDC_Button,"Extract", 50,10,100,20
                       Dialog Show Modal hDlg Call DlgProc
                    End Function
                    
                    CallBack Function DlgProc() As Long
                       Select Case Cb.Msg
                          Case %WM_Command
                             Select Case Cb.Ctl
                                Case %IDC_Button
                                   ExtractDLLandZip              : ? "DLL and Zip extracted"
                                   LoadLibraryAndLinkToFunctions : ? "Libary Loaded. Links Made to Functions"
                                   UnZipFilesAndFolders          : ? "Files and Folders unzipped"
                                   RemoveDLLandZip               : ? "DLL and Zip deleted"
                             End Select
                       End Select
                    End Function
                    
                    Sub ExtractDLLandZip
                       Local FileContent$
                       FileContent$ = Resource$(RcData,1000)
                       Open "test.zip" For Output As #1 : Print #1, FileContent$; : Close #1
                       FileContent$ = Resource$(RcData,1001)
                       Open "liteunzip.dll" For Output As #1 : Print #1, FileContent$; : Close #1
                    End Sub
                    
                    Sub LoadLibraryAndLinkToFunctions
                       hLib = LoadLibrary("liteunzip.dll")
                       add_Open   = GetProcAddress(hLib, "UnzipOpenFileA")   'Use ALIAS
                       add_Get    = GetProcAddress(hLib, "UnzipGetItemA")    'Use ALIAS
                       add_File   = GetProcAddress(hLib, "UnzipItemToFileA") 'Use ALIAS
                       add_Close  = GetProcAddress(hLib, "UnzipClose")       'Use ALIAS
                    End Sub
                    
                    Sub UnZipFilesAndFolders
                       Local hUnzip As Dword, ze As ZIPENTRY, numitems, idx As Dword, iResult As Long
                       Call Dword add_Open Using UnzipOpenFileX(hUnzip, "test.zip", ByVal %NULL) To iResult
                       If hUnzip Then
                          ze.Index = &HFFFFFFFF
                          Call Dword add_Get Using UnzipGetItemX(hUnzip, ze) To iResult
                          numitems = ze.Index
                          For idx = 0 To numitems - 1
                             ze.Index = idx
                             Call Dword add_Get Using UnzipGetItemX(hUnzip, ze) To iResult
                             Call Dword add_File Using UnzipItemToFileX(hUnzip, ze.szName, ze) To iResult
                             Dialog Set Text hDlg, "Items Unzipped: " + Str$(Idx)
                          Next
                          Call Dword add_Close Using UnzipCloseX(hUnzip) To iResult
                       End If
                    End Sub
                    
                    Sub RemoveDLLandZip
                       FreeLibrary hLib
                       If IsFile("test.zip")      Then Kill "test.zip
                       If IsFile("liteunzip.dll") Then Kill "liteunzip.dll"
                    End Sub

                    Comment


                    • #11
                      For those of you who just joined in, here's what the code above demonstrates:
                      1. Single EXE for distribution/installation of files and folders
                      2. The ZIP file containing the distribution files/folders and the DLL for unzipping that file are included in the EXE
                      3. Extract the DLL and ZIP
                      4. UnZip the ZIP file into the installation target folder
                      5. Number of files to unzip and number of files unzipped are monitored
                      6. Remove the DLL and ZIP when done

                      With embedded unzipping source code, the DLL file would go away.

                      The realtime # of files that have been unzipped can be used for a progress bar, although bytes extracted would probably be better. The size of the ZIP file would be the total bytes, then the size of each extracted file would be added and used to get a % complete. For this example, the install sequence is very quick, but for a larger number of files, the progress bar would be useful.

                      The code above does not ask for the uninstall location. That could be added.

                      If you know the list of files in the ZIP, you can put them into the EXE as individual resources, avoiding the need for the unZip code. However, the unZip DLL handles subfolders, significantly simplifying the installation code.

                      I'd read about folks doing something like this, just hadn't ever tried it myself.

                      I've only tried the one example contained in the download file. I'll test it out on other combinations of files/folders/installation target locations and see if any warts appear.

                      If anyone else knows of any issues with the approach, please speak up! I know from other threads that several of you have used similar techniques to create a single EXE installation file.

                      ... added... I've not included any code to remove any pre-existing files. On the first few tests, it seems that the DLL overwrites existing files. It would be appropriate to not remove pre-existing files, unless directed to do so by the user, because there may be user-generated files in the existing installation target folder.

                      Thanks, Jose for the liteunzip DLL example code, which is what I used in the unzip function of this example.

                      Comment


                      • #12
                        Has anyone found in Help where it talks about restrictions on the names of the template Functions? My notes say the template function name can be the same as the DLL function name, but I can't recall where that (incorrect) note came from.

                        I've always found it interesting that the Declare statements need not include the name of an argument.

                        Code:
                        This ...
                        Declare Function UnzipCloseX      (ByVal hUnzip As Dword) As Dword
                        can be replaced with this  ...
                        Declare Function UnzipCloseX      (ByVal Dword) As Dword
                        Having the argument name in the Declare is visually useful/convenient, but not required.

                        Comment


                        • #13
                          In the section on Creating Dynamic Link Libraries under An Example the following statement appears:
                          The ALIAS keyword is used to indicate the capitalization that PowerBASIC will assign the function. In Win32, all exported (and imported) Sub and Function names are case-sensitive. If the ALIAS keyword was omitted, PowerBASIC will capitalize the exported name and this could cause " Missing DLL entry point" errors if the calling code did not match the capitalization exactly.
                          This is the closest approach to the topic I can find and seems it might be referring to the issue you had.
                          Rod
                          "To every unsung hero in the universe
                          To those who roam the skies and those who roam the earth
                          To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

                          Comment


                          • #14
                            Hi Rod,

                            I think the issue was with the declaration of a 'Model" function. Needed to define the shape of the functions to be used from the Library which will be loaded when - "implementing run-time (explicit) dynamic linking of DLLs, rather than the more common load-time (implicit) linking".
                            This is described (kind of) in the USING section of the help topic for the CALL DWORD Statement..

                            Rgds, Dave

                            Comment


                            • #15
                              Dave,
                              You may be right, or it may be a combination of the features. The problem of disappeared apparently with the use of ALIAS. I haven't used the link to play with the code itself, which I may do later. I had not looked at the CALL DWORD-/-USING part of it, I'll study that too.
                              Rod
                              "To every unsung hero in the universe
                              To those who roam the skies and those who roam the earth
                              To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

                              Comment


                              • #16
                                Rodney,

                                The problem disappeared when I changed the template function names to something other than the ALIAS. Previously, I had made them both the same, thinking it did not matter.

                                Comment


                                • #17
                                  The proper native way to zip and unzip, not the scripting way.
                                  https://forum.powerbasic.com/forum/u...unaway-threads

                                  Here, you can have it in C++ and C# too. The C++ unzipwithshellitem shows a less code, simpler way to unzip only using newer Vista+ interaces, but you'll have to translate that to PB yourself
                                  Attached Files

                                  Comment


                                  • #18
                                    Gary,
                                    I did ask if you renamed the Declared functions(which worked) with ALIAS and you responded with "Yes, ...." and sometimes words that follow a comma get turned into ellipses.
                                    Re-reading your response I see there was more to it, .....!
                                    Rod
                                    "To every unsung hero in the universe
                                    To those who roam the skies and those who roam the earth
                                    To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

                                    Comment


                                    • #19
                                      Perhaps we were all on different pages( or out to lunch). I took the code from post #3 and tried it(I know I should have tried it before I posted my two cents worth). It didn't work.
                                      I changed "#COMPILE EXE "test\liteunzip.exe"" to "#COMPILE EXE "liteunzip.exe"" and it did.
                                      However, your changes allow you to retain the parent folder which may be more to your liking.
                                      Rod
                                      "To every unsung hero in the universe
                                      To those who roam the skies and those who roam the earth
                                      To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

                                      Comment


                                      • #20
                                        Hi Rodney,
                                        Yes, I had a subfolder "test" already. For anyone trying out the code, I should have put a test in for that folder, creating it if it did not exist.

                                        Comment

                                        Working...
                                        X