Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

7zip 7-zip32.dll Library without commandline [AHK_L]


  • Please log in to reply
25 replies to this topic
shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006
Now we can have all the features of 7za.exe (the command-line version of 7-zip, using a third-party dll (7-zip32.dll). Supports 7z, gzip, zip, bzip2, tar, iso and udf archive formats.
The superior speed and compression of 7-zip can be called with AHK and it can work in the background (both the -hide parameter and RegisterCallBack method are supported - see examples included.)
This dll is based on the latest 7-zip (version 9.20)

Also, no need to go figure out the command line 8). The options can easily be set with the Object.opt properties (see doc).

Discovered way back in this post and also here. Anyway, here is the library.

► Download Library:7-zip32.7z + Dll: Official Site/AHK.netDocumentation

Reference:
Dll Site: <!-- m -->http://www.madobe.ne...er/index-e.html<!-- m -->
Dll API : <!-- m -->http://www.madobe.ne...zip32api-en.txt<!-- m -->
Dll Japanese site: <!-- m -->http://www.csdinc.co...ib/7-zip32.html<!-- m -->
7-zip cmdline reference: <!-- m -->http://sevenzip.sour...jp/chm/cmdline/<!-- m -->

Basic Example
/* Function: Basic 7-zip32.dll library example
   Requires: 7Zip.ahk (include or in Std Library) and AHK_L
   URL: http://www.autohotkey.com/forum/viewtopic.php?t=69249
*/
If !( o7z := 7Zip_Init() )
  Quit("Failed loading 7-zip32.dll library")
o7z.opt.Hide := 1  ;You can enable it to hide process dialog
  
MsgBox % 7Zip_GetVersion()

FileSelectFile,sArcFile, S16,,Create archive as..,Archives (*.zip; *.7z; *.bzip2; *.tar; *.iso; *.udf; *.gzip)
FileSelectFolder, sFolder,,0,Select folder to archive

MsgBox % 7Zip_Add(sArcFile, sFolder)  ;Add to archive
MsgBox % 7Zip_List(sArcFile)          ;List files in archive

FileSelectFolder, sFolder,,3,Select folder to extract to
o7z.opt.Output := sFolder                     ;Set output folder
MsgBox % 7Zip_Extract(sArcFile)       ;Extract files

7Zip_Close()
ExitApp

Quit(Msg) {
  MsgBox % Msg
  ExitApp
}
#Include 7zip.ahk

Basic Callback Example:
/* Function: Example Add files to archive with callback
   Requires: 7Zip.ahk (include or in Std Library) and AHK_L
   URL: http://www.autohotkey.com/forum/viewtopic.php?t=69249
*/

gui, +LastFound
hMyWnd := WinExist()
o7z := 7Zip_Init()
o7z.opt.Hide := 1  ;Required for callback mode

FileSelectFile,sArcFile, S16,,Create archive as..,Archives (*.zip; *.7z; *.bzip2; *.tar; *.iso; *.udf; *.gzip)
FileSelectFolder, sFolder,,0,Select folder to archive

If !7Zip_SetOwnerWindowEx("Fn_ARCHIVERPROC", hMyWnd)
  Quit("Could not create callback")

7Zip_Add(sArcFile, sFolder, hMyWnd)
Sleep 100
While !7Zip_ProcessComplete
  Sleep 200
MsgBox, Archive created successfully!

FileSelectFolder, sFolder,,3,Select folder to extract to
o7z.opt.Output := sFolder

r := 7Zip_Extract(sArcFile, hMyWnd)
; MsgBox % r
Sleep 100
While !7Zip_ProcessComplete
  Sleep 200
MsgBox, Archive extracted successfully!
ExitApp


Fn_ARCHIVERPROC(hWnd, Msg, nState, ExInfo) {
  global 7Zip_ProcessComplete = 0
  Critical
  iPercent := 0
  If !nState
  {
    iFileSize := NumGet(ExInfo+0, 0, "UInt")
    iWriteSize := NumGet(ExInfo+0, 4, "UInt")
    iSourceFileName := StrGet(ExInfo+8,513,"CP0")
    iDestFileName := StrGet(ExInfo+524,513,"CP0")

    iCompressedSize := NumGet(ExInfo+0, 1040, "UInt")
    iCRC := NumGet(ExInfo+0, 1044, "UInt")
    iRatio := NumGet(ExInfo+0, 1052, "UShort")
    iDate := NumGet(ExInfo+0, 1054, "UShort")
    iTime := NumGet(ExInfo+0, 1056, "UShort")
    iAttribute := StrGet(ExInfo+1058,8,"CP0")
    iMode := StrGet(ExInfo+1066,8,"CP0")
    
    iPercent := (iWriteSize/iFileSize) * 100
    FileAppend, % "" . iSourceFileName . " - " . iDestFileName . " " . iPercent . "% Compressed Size:" . iCompressedSize 
                     . " CRC:" . iCRC . " Ratio:" . iRatio . " Attribute:" . iAttribute . " Mode:" . iMode . "`n"
                     , *  ;output to console
    Critical, Off
    Return 1
  }
    
  If nState = 2
  {
    FileAppend, Process Complete`n`n, *
    7Zip_ProcessComplete := 1
    Critical, Off
  }
  Critical, Off
  Return 1
} ;End Function

Quit(Msg) {
  MsgBox % Msg
  ExitApp
}

#include 7Zip.ahk

Basic Info Example:
/* Function: Example archive info
   Requires: 7Zip.ahk (include or in Std Library) and AHK_L
   URL: http://www.autohotkey.com/forum/viewtopic.php?t=69249
*/

#NoEnv
SetWorkingDir %A_ScriptDir%
FileSelectFile,sArcFile, 3,,Open archive..,Archives (*.zip; *.7z; *.bzip2; *.tar; *.iso; *.udf; *.gzip)
If   !( o7z := 7Zip_Init() ) || !( hArc := 7Zip_OpenArchive(sArcFile) )
  ExitApp
  
; ------- METHOD 1 -----------------------
oFile := 7Zip_FindFirst(hArc,"*.*")  ;this will find all files with extensions, for all files use "*"
For k,v in oFile                     ;enumerate all fields of first file
  sDetails .= k . " = " v . "`n"
MsgBox % sDetails

While (oFile := 7Zip_FindNext(hArc)) ;enumerate next files
{
  sDetails := ""
  For k,v in oFile
    sDetails .= k . " = " v . "`n"
  MsgBox % sDetails
  if A_Index > 3   ;Just show 4 files for brevity
    Break
}
; ----------------------------------------

; ------- METHOD 2 -----------------------
files := ""
If 7Zip_FindFirst(hArc, "*.*", 0) ;Notice the last parameter is zero, so just true is returned (no details)
  Loop
    files .= 7Zip_GetFileName(hArc) "`n" ;Details can be extracted with individual functions
  Until !7Zip_FindNext(hArc)
Sort files
MsgBox % files
; ----------------------------------------

7Zip_CloseArchive(hArc)

#Include 7zip.ahk

If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

PS: Some functions in the library (related to SevenZipOpenArchive function) are not working, and I have marked them and not included in the documentation. It seems to be bug of hArc handle which is return.

If the script and dll are 64-bit, SevenZipOpenArchive's return value must be "Ptr". However, they are 32-bit, so the handle is fine.

As far as I can tell, the only real problem is your use of the tINDIVIDUALINFO variable. It is a local variable, so will be freed when the function returns. Thus, storing a pointer to it in 7Zip_$Info$._handle is not wise. You don't actually need to store it at all, since you're extracting all of the useful information from it.

FindNext accepts a parameter tINDIVIDUALINFO, but then uses VarSetCapacity, which clears it. What's the point? Remove that parameter. Next, you are passing the invalid stored pointer (7Zip_$Info$._handle) to SevenZipFindNext, but then extracting data from tINDIVIDUALINFO, which only contains zeros. Just pass &tINDIVIDUALINFO to SevenZipFindNext.

I suggest making 7Zip_$Info$ an optional parameter rather than a global variable. Since we pass the hArc variable each time, it is possible to examine multiple archives at once. However, since 7Zip_$Info$ is global, only the information for the most recent file is available. If it is made an optional parameter instead, we can reuse an existing object or let a new one be created.

[color=red]--- a/7zip_.ahk[/color]
[color=green]+++ b/7zip.ahk[/color]
[color=#107095]@@ -510,15 +510,12 @@[/color]
   Return DllCall("7-zip32\SevenZipCloseArchive", "Ptr", hArc)
 } ;End Function

[color=red]-7Zip_FindFirst(hArc, sSearch) {
-  global 7Zip_$Info$[/color]
[color=green]+7Zip_FindFirst(hArc, sSearch, 7Zip_$Info$="") {[/color]
   if !IsObject(7Zip_$Info$)
     7Zip_$Info$ := Object()
   VarSetCapacity(tINDIVIDUALINFO , 558, 0)
[color=red]-
-  If DllCall("7-zip32\SevenZipFindFirst", "Ptr", hArc, "AStr", sSearch, "ptr", &tINDIVIDUALINFO) = -1[/color]
[color=green]+  If DllCall("7-zip32\SevenZipFindFirst", "Ptr", hArc, "AStr", sSearch, "ptr", &tINDIVIDUALINFO)[/color]
     Return 0
[color=red]-  7Zip_$Info$._handle := &tINDIVIDUALINFO[/color]
   7Zip_$Info$.OriginalSize := NumGet(tINDIVIDUALINFO , 0, "UInt")
   7Zip_$Info$.CompressedSize := NumGet(tINDIVIDUALINFO , 4, "UInt")
   7Zip_$Info$.CRC := NumGet(tINDIVIDUALINFO , 8, "UInt")
[color=#107095]@@ -534,14 +531,12 @@[/color]
   return 7Zip_$Info$
 } ;End Function

[color=red]-7Zip_FindNext(hArc, tINDIVIDUALINFO) {
-  global 7Zip_$Info$[/color]
[color=green]+7Zip_FindNext(hArc, 7Zip_$Info$="") {[/color]
   if !IsObject(7Zip_$Info$)
     7Zip_$Info$ := Object()
   VarSetCapacity(tINDIVIDUALINFO , 558, 0)
[color=red]-  if DllCall("7-zip32\SevenZipFindNext","Ptr", hArc, "ptr", 7Zip_$Info$._handle)[/color]
[color=green]+  if DllCall("7-zip32\SevenZipFindNext","Ptr", hArc, "ptr", &tINDIVIDUALINFO)[/color]
     Return 0
[color=red]-  7Zip_$Info$._handle := &tINDIVIDUALINFO[/color]
   7Zip_$Info$.OriginalSize := NumGet(tINDIVIDUALINFO , 0, "UInt")
   7Zip_$Info$.CompressedSize := NumGet(tINDIVIDUALINFO , 4, "UInt")
   7Zip_$Info$.CRC := NumGet(tINDIVIDUALINFO , 8, "UInt")
Example (working on my end, using "src.7z" file from 7zip dll download):
If   !( o7z := 7Zip_Init() )
  || !( hArc := 7Zip_OpenArchive(0, "src.7z") )
  ExitApp

files := ""
If 7Zip_FindFirst(hArc, "")
  Loop
    files .= 7Zip_GetFileName(hArc) "`n"
  Until !7Zip_FindNext(hArc)
7Zip_CloseArchive(hArc)
Sort files
MsgBox % files
It looks like all of the functions below 7Zip_FindNext are redundant, since FindFirst and FindNext already return all of the information. They can be kept for users who prefer that style. If FindFirst or FindNext is not provided with an object, it could avoid the unnecessary work of initializing tINDIVIDUALINFO, passing it and extracting information from it; i.e. just assume the caller will use the other functions to get the appropriate information. You can pass NULL (0) in place of &tINDIVIDUALINFO.

Alternatively, you could provide a "flat" API and an object-oriented one. For instance, the following will work with the modifications outlined above:
7Zip_Files(sArc, sSearch="") {
  static base := Object(  "_NewEnum", "7Zip_Files_Self"
                        , "Next",     "7Zip_Files_Next"
                        , "__Delete", "7Zip_Files_Delete"  )
  if !( hArc := 7Zip_OpenArchive(0, sArc) )
    return 0
  return Object("hArc", hArc, "sSearch", sSearch, "base", base)
}
7Zip_Files_Self(oFind) {
  return oFind
}
7Zip_Files_Next(oFind, ByRef oInfo) {
  if !oFind.HasKey("CRC") ; First call.
    oInfo := 7Zip_FindFirst(oFind.hArc, oFind.sSearch, oFind)
  else
    oInfo := 7Zip_FindNext(oFind.hArc, oFind)
  return IsObject(oInfo)
}
7Zip_Files_Delete(oFind) {
  7Zip_CloseArchive(oFind.hArc)
}
; Example
7Zip_Init()
files := ""
for file in 7Zip_Files("src.7z")
  files .= file.FileName "`n"
Sort files
MsgBox % files
You could instead enumerate all of the files immediately in 7Zip_Files and return a single, simple array. Feel free to use any of this code as you see fit.

I suggest you add a check in 7Zip_Init to avoid doing anything if 7-zip has already been initialized (i.e. the 7Zip_ object already exists). Then you can have the other 7zip functions call Init automatically, avoiding the need for the user to do it (but still allowing them to if they need to specify the path of the dll).

shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006
Wonderful!!

THANK YOU SO MUCH FOR YOUR TIME AND DETAILED ANSWER.

I will clean up the script and post with documentation of the new functions.

Your second method is just superb, but after my FTP library, i have a feeling that i should just wrap available functionality and leave it up to the users on how they want to deal with the data. Hence i may end up using the first idea.

If FindFirst or FindNext is not provided with an object, it could avoid the unnecessary work of initializing tINDIVIDUALINFO, passing it and extracting information from it..


Here is my function incorporating all the changes proposed.
7Zip_FindFirst(hArc, sSearch, o7zip__info="") {
  if (o7zip__info = 0)
  {
    r := DllCall("7-zip32\SevenZipFindFirst", "Ptr", hArc, "AStr", sSearch, "ptr", 0)
    return ( r ? 0 : 1 ), ErrorLevel := (r ? r : ErrorLevel)
  }
  if !IsObject(o7zip__info)
    o7zip__info := Object()
  VarSetCapacity(tINDIVIDUALINFO , 558, 0)
  
  If DllCall("7-zip32\SevenZipFindFirst", "Ptr", hArc, "AStr", sSearch, "ptr", &tINDIVIDUALINFO)
    Return 0
  o7zip__info.OriginalSize   := NumGet(tINDIVIDUALINFO , 0, "UInt")
  o7zip__info.CompressedSize := NumGet(tINDIVIDUALINFO , 4, "UInt")
  o7zip__info.CRC            := NumGet(tINDIVIDUALINFO , 8, "UInt")
; uFlag                      := NumGet(tINDIVIDUALINFO , 12, "UInt") ;always 0
; uOSType                    := NumGet(tINDIVIDUALINFO , 16, "UInt") ;always 0  
  o7zip__info.Ratio          := NumGet(tINDIVIDUALINFO , 20, "UShort")
  o7zip__info.Date           := NumGet(tINDIVIDUALINFO , 22, "UShort")
  o7zip__info.Time           := NumGet(tINDIVIDUALINFO , 24, "UShort")
  o7zip__info.FileName       := StrGet(&tINDIVIDUALINFO+26 ,513,"CP0")
  o7zip__info.Attribute      := StrGet(&tINDIVIDUALINFO+542,8  ,"CP0")
  o7zip__info.Mode           := StrGet(&tINDIVIDUALINFO+550,8  ,"CP0")
  
  return o7zip__info
} ;End Function

7Zip_FindNext(hArc, o7zip__info="") {
  if (o7zip__info = 0)
  {
    r := DllCall("7-zip32\SevenZipFindFirst", "Ptr", hArc, "AStr", sSearch, "ptr", 0)
    return ( r ? 0 : 1 ), ErrorLevel := (r ? r : ErrorLevel)
  }
  if !IsObject(o7zip__info)
    o7zip__info := Object()
  VarSetCapacity(tINDIVIDUALINFO , 558, 0)
  if DllCall("7-zip32\SevenZipFindNext","Ptr", hArc, "ptr", &tINDIVIDUALINFO)
    Return 0 

  o7zip__info.OriginalSize   := NumGet(tINDIVIDUALINFO , 0, "UInt")
  o7zip__info.CompressedSize := NumGet(tINDIVIDUALINFO , 4, "UInt")
  o7zip__info.CRC            := NumGet(tINDIVIDUALINFO , 8, "UInt")
  o7zip__info.Ratio          := NumGet(tINDIVIDUALINFO , 20, "UShort")
  o7zip__info.Date           := NumGet(tINDIVIDUALINFO , 22, "UShort")
  o7zip__info.Time           := NumGet(tINDIVIDUALINFO , 24, "UShort")
  o7zip__info.FileName       := StrGet(&tINDIVIDUALINFO+26 ,513,"CP0")
  o7zip__info.Attribute      := StrGet(&tINDIVIDUALINFO+542,8  ,"CP0")
  o7zip__info.Mode           := StrGet(&tINDIVIDUALINFO+550,8  ,"CP0")
  
  return o7zip__info
} ;End Function
and example of usage
If   !( o7z := 7Zip_Init() ) || !( hArc := 7Zip_OpenArchive(0, "src.7z") )
  ExitApp
  
oFile := 7Zip_FindFirst(hArc,"*.txt")
For k,v in oFile
  sDetails .= k . " = " v . "`n"
MsgBox % sDetails

While (oFile := 7Zip_FindNext(hArc))
{
  sDetails := ""
  For k,v in oFile
    sDetails .= k . " = " v . "`n"
  MsgBox % sDetails
}

files := ""
If 7Zip_FindFirst(hArc, "*.txt", [color=red]0[/color])
  Loop
    files .= 7Zip_GetFileName(hArc) "`n"
  Until !7Zip_FindNext(hArc)
7Zip_CloseArchive(hArc)
Sort files
MsgBox % files

#Include 7zip.ahk

Please let me know if you have any improvements, or any fault with these functions.
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006
Update:
- Many bug-fixes.
- conversion of Dos Date and Time added.
- New examples added.
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

trueski
  • Members
  • 121 posts
  • Last active: Jun 25 2014 09:12 PM
  • Joined: 08 Apr 2008

Update:
- Many bug-fixes.
- conversion of Dos Date and Time added.
- New examples added.


Nice work! This is very useful. Is there a way to write the contents of a variable to a file within an archive without writing a temporary text file, and/or is there a way to read the contents of a file within an archive without writing a temporary file?
-trueski-

shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006

Is there a way to write the contents of a variable to a file within an archive without writing a temporary text file, and/or is there a way to read the contents of a file within an archive without writing a temporary file?

In short, No. These are file archiving functions. If you want to compress+store and retrieve random data, you may use zlib instead
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

trueski
  • Members
  • 121 posts
  • Last active: Jun 25 2014 09:12 PM
  • Joined: 08 Apr 2008

... you may use zlib instead


Oh ok. I may try to integrate ZipArchive (http://www.artpol-so...com/ZipArchive/, which actually uses zlib) for a 'hybrid' type approach. I would like to generate CSV files from arrays, and write multiple CSV files to a compressed archive without writing any temp files. I currently use ZipArchive in PHP to do this.
-trueski-

shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006
yes, that looks good. maybe you can wrap the important functions so that everybody is benefitted :wink:
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

Peixoto
  • Members
  • 16 posts
  • Last active: Oct 02 2015 01:11 AM
  • Joined: 16 Sep 2011
Thanks for the lib

I've found a small error in the documentation

The function 7zip_extract() is described with the arguments in inverse order

  • Guests
  • Last active:
  • Joined: --

Thanks for the lib

I've found a small error in the documentation

The function 7zip_extract() is described with thei arguments in inverse order

Thanks for reporting

Peixoto
  • Members
  • 16 posts
  • Last active: Oct 02 2015 01:11 AM
  • Joined: 16 Sep 2011
Is there a way a can pause or cancel a extraction with the 7zip window hidden?

garry
  • Spam Officer
  • 3219 posts
  • Last active: Sep 20 2018 02:47 PM
  • Joined: 19 Apr 2005
ahk_basic drag&drop
MODIFIED=20120204
/*
;-- drag & drop 7z files and extract
;-- see also  http://www.autohotkey.com/forum/viewtopic.php?t=69249
http://sourceforge.net/projects/sevenzip/files/7-Zip/
7z922.exe=http://sourceforge.net/projects/sevenzip/files/latest/download?source=files
( used: )
7za452.zip= http://sourceforge.net/projects/sevenzip/files/7-Zip/4.52%20beta/7za452.zip/download
help   = http://dotnetperls.com/7-zip-examples
*/

#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%

outxx=%a_desktop%\ZIPPED
 IfNotExist, %OUTXX%
   FileCreateDir, %OUTXX%

pr=%a_scriptdir%\7za.exe
Exx=zip,7z,gz,gzip,tgz,tar,rar,cab,arj,taz,bz2,bzip2,tbz2,tbz,cpio,rpm,deb,lzh,lha

GUI,2:+AlwaysOnTop
Gui,2:Add, Edit, x5 y10 w580 h45 vF1 readonly,Drag & drop 7z-file here
Gui,2:add,button,x5 y80 w120 h25 gStart1 ,7za RUN
GUI,2:show, NA W700 H110 X20 Y20, 7za dropWin
return
;----------------------------------------------------------

start1:
gui,2:submit,nohide
guicontrolget,F1
if F1<>
{
SplitPath, F1, name, dir, ext, name_no_ext, drive
If Ext Not In %exx%
  {
  msgbox, 262192, 7z MESSAGE,Only 7z files
  return
  }
RunWait,"%pr%" x "%f1%" -o"%outxx%\%name_no_ext%"
;run,%outxx%\%name_no_ext%
}
return


;----------------------------------------------------------
2GuiDropFiles:
Loop, parse, A_GuiEvent, `n
GuiControl,2:,F1,%A_LoopField%
return


;----------------------------------------------------------
2GuiClose:
ExitApp
;----------------------------------------------------------


ZeLen1y
  • Members
  • 44 posts
  • Last active: Oct 13 2014 09:43 PM
  • Joined: 11 Oct 2006
404

garry
  • Spam Officer
  • 3219 posts
  • Last active: Sep 20 2018 02:47 PM
  • Joined: 19 Apr 2005
autohotkey.net user files deleted

http://www.autohotke...php?f=6&t=89243

...
Unfortunately there are no backups of user files on autohotkey.net but members are welcome to re-upload their files.
Please ensure that you always save your own backups and take the relevant precautions to protect any sensitive work
(i.e. saving them inside encrypted zip files with strong passwords)
....


I can't upload to autohotkey.net ....

ZeLen1y
  • Members
  • 44 posts
  • Last active: Oct 13 2014 09:43 PM
  • Joined: 11 Oct 2006

... I can't upload to autohotkey.net ...

how about other mirrors such as free website hosting or file sharing ?