shajul wrote:
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.
Code:
--- a/7zip_.ahk
+++ b/7zip.ahk
@@ -510,15 +510,12 @@
Return DllCall("7-zip32\SevenZipCloseArchive", "Ptr", hArc)
} ;End Function
-7Zip_FindFirst(hArc, sSearch) {
- global 7Zip_$Info$
+7Zip_FindFirst(hArc, sSearch, 7Zip_$Info$="") {
if !IsObject(7Zip_$Info$)
7Zip_$Info$ := Object()
VarSetCapacity(tINDIVIDUALINFO , 558, 0)
-
- If DllCall("7-zip32\SevenZipFindFirst", "Ptr", hArc, "AStr", sSearch, "ptr", &tINDIVIDUALINFO) = -1
+ If DllCall("7-zip32\SevenZipFindFirst", "Ptr", hArc, "AStr", sSearch, "ptr", &tINDIVIDUALINFO)
Return 0
- 7Zip_$Info$._handle := &tINDIVIDUALINFO
7Zip_$Info$.OriginalSize := NumGet(tINDIVIDUALINFO , 0, "UInt")
7Zip_$Info$.CompressedSize := NumGet(tINDIVIDUALINFO , 4, "UInt")
7Zip_$Info$.CRC := NumGet(tINDIVIDUALINFO , 8, "UInt")
@@ -534,14 +531,12 @@
return 7Zip_$Info$
} ;End Function
-7Zip_FindNext(hArc, tINDIVIDUALINFO) {
- global 7Zip_$Info$
+7Zip_FindNext(hArc, 7Zip_$Info$="") {
if !IsObject(7Zip_$Info$)
7Zip_$Info$ := Object()
VarSetCapacity(tINDIVIDUALINFO , 558, 0)
- if DllCall("7-zip32\SevenZipFindNext","Ptr", hArc, "ptr", 7Zip_$Info$._handle)
+ if DllCall("7-zip32\SevenZipFindNext","Ptr", hArc, "ptr", &tINDIVIDUALINFO)
Return 0
- 7Zip_$Info$._handle := &tINDIVIDUALINFO
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):
Code:
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:
Code:
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)
}
Code:
; 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).