Jump to content

Calling 7z.dll


Starg
 Share

Recommended Posts

This is very useful, but im having issues trying to use CreateStreamOnHGlobal.

Under IArchiveExtractCallback_GetStream, i replaced _WinAPI_SHCreateStreamOnFile with CreateStreamOnHGlobal, and tried using CreateStreamOnHGlobal both before and after $oIStreamOut is released. The binary always returns 0x0000...
Any ideas? Please and thank you.

Edit:

I solved the problem.

Heres the modified source:

#include <WinApi.au3>
Global Const $sCLSID_Format7z="{23170f69-40c1-278a-1000-000110070000}"
#interface "IInArchive"
Global Const $sIID_IInArchive="{23170F69-40C1-278A-0000-000600600000}"
Global Const $tagIInArchive= _
        "Open hresult(ptr;uint64*;ptr);"& _
        "Close hresult();"& _
        "GetNumberOfItems hresult(uint*);"& _
        "GetProperty hresult(uint;uint;variant*);"& _
        "Extract hresult(struct*;uint;int;ptr);"& _
        "GetArchiveProperty hresult(int;variant*);"& _
        "GetNumberOfProperties hresult(uint*);"& _
        "GetPropertyInfo hresult(uint;bstr*;int*;int*);"& _
        "GetNumberOfArchiveProperties hresult(uint*);"& _
        "GetArchivePropertyInfo hresult(uint;bstr*;int*;int*);"
#interface "ISequentialInStream"
Global Const $sIID_ISequentialInStream="{23170F69-40C1-278A-0000-000300010000}"
Global Const $tagISequentialInStream="Read hresult(ptr;uint;uint*);"
#interface "IInStream"
Global Const $sIID_IInStream="{23170F69-40C1-278A-0000-000300030000}"
Global Const $tagIInStream= _
        $tagISequentialInStream& _
        "Seek hresult(int64;uint;uint64*);"
#interface "ISequentialStream"
Global Const $sIID_ISequentialStream="{0c733a30-2a1c-11ce-ade5-00aa0044773d}"
Global Const $tagISequentialStream= _
        "Read hresult(struct*;dword;ptr);"& _
        "Write hresult(struct*;dword;dword*);"
#interface "IStream"
Global Const $sIID_IStream="{0000000c-0000-0000-C000-000000000046}"
Global Const $tagIStream= _
        $tagISequentialStream& _
        "Seek hresult(int64;dword;ptr);"& _
        "SetSize hresult(uint64);"& _
        "CopyTo hresult(ptr;uint64;uint64*;uint64*);"& _
        "Commit hresult(dword);"& _
        "Revert hresult();"& _
        "LockRegion hresult(uint64;uint64;dword);"& _
        "UnlockRegion hresult(uint64;uint64;dword);"& _
        "Stat hresult(struct*;dword);"& _
        "Clone hresult(ptr*);"
#interface "IArchiveExtractCallback"
Global Const $sIID_IArchiveExtractCallback="{23170F69-40C1-278A-0000-000600200000}"
Global Const $tagIArchiveExtractCallback= _
        "SetTotal hresult(int);"& _
        "SetCompleted hresult(int*);"& _
        "GetStream hresult(int;ptr*;int*);"& _
        "PrepareOperation hresult(int);"& _
        "SetOperationResult hresult(int);"
#interface "ISequentialOutStream"
Global Const $sIID_ISequentialOutStream="{23170F69-40C1-278A-0000-000300020000}"
Global Const $tagISequentialOutStream="Write hresult(ptr;uint;uint*);"
#interface "IOutStream"
Global Const $sIID_IOutStream="{23170F69-40C1-278A-0000-000300040000}"
Global Const $tagIOutStream= _
        $tagISequentialOutStream& _
        "Seek hresult(int64;dword;ptr);"& _
        "SetSize hresult(uint64*)"

Func _7zInit()
    Global $h7Z_DLL=DllOpen(@ScriptDir&"\7z.dll");Migrate!DLLPool
    If $h7Z_DLL=-1 Then
        MsgBox(0,"error","fehler beim laden der dll")
        Exit
    EndIf
    Global $_7z_oIInArchive=_7z_CreateObject($sCLSID_Format7z,$sIID_IInArchive,$tagIInArchive)
    Global $_7z_tIArchiveExtractCallback
    Global $_7z_oIArchiveExtractCallback=ObjectFromTag("IArchiveExtractCallback_",$tagIArchiveExtractCallback,$_7z_tIArchiveExtractCallback,Default,$sIID_IArchiveExtractCallback)
    Global $_7z_oIStreamOut=CreateStreamOnHGlobal()
    Global $_7z_tIOutStream
    GLobal $_7z_oIOutStream=ObjectFromTag("IOutStream_",$tagIOutStream,$_7z_tIOutStream,Default,$sIID_IOutStream)
    Global $_7z_tIInStream
    Global $_7z_oIInStream=ObjectFromTag("IInStream_",$tagIInStream,$_7z_tIInStream,Default,$sIID_IInStream)
EndFunc

Func _7zLoadArchive($sFilePath)
    Global $_7z_oIStream=_WinAPI_SHCreateStreamOnFile($sFilePath)
    $_7z_oIInArchive.Open($_7z_oIInStream, 1024, 0)
    Local $_7z_iFileCount
    $_7z_oIInArchive.GetNumberOfItems($_7z_iFileCount)
    Enum $kpidNoProperty=0,$kpidMainSubfile=1,$kpidHandlerItemIndex=2,$kpidPath,$kpidName,$kpidExtension,$kpidIsDir,$kpidSize,$kpidPackSize
    Global $_7z_aFiles[$_7z_iFileCount]
    Global $_7z_tIndices=DllStructCreate("int["&$_7z_iFileCount&"]")
    Global $_7z_iExtractCount=$_7z_iFileCount
    For $_7z_FileIndex=0 To $_7z_iFileCount-1
        Local $sName,$iSize,$iIsDir
        $_7z_oIInArchive.GetProperty($_7z_FileIndex,$kpidPath,$sName)
        $_7z_oIInArchive.GetProperty($_7z_FileIndex,$kpidSize,$iSize)
        $_7z_oIInArchive.GetProperty($_7z_FileIndex,$kpidIsDir,$iIsDir)
        $_7z_aFiles[$_7z_FileIndex]=$sName
        IF Not $iIsDir Then
            DllStructSetData($_7z_tIndices,1,$_7z_FileIndex,$_7z_FileIndex+1)
        Else
            $_7z_iExtractCount-=1
        Endif
    Next
    Return $_7z_aFiles
EndFunc

Func _7zExtract(ByRef $aBinaryArray,$sFileType=-1)
    Global $_7z_GetFileType=$sFileType
    Global $_7z_aBinaryArray=$aBinaryArray
    $hresult=$_7z_oIInArchive.Extract($_7z_tIndices,$_7z_iExtractCount,0,$_7z_oIArchiveExtractCallback)
    $aBinaryArray=$_7z_aBinaryArray
    $_7z_aBinaryArray=""
    Return Hex($hresult)
EndFunc

Func IInStream_QueryInterface($pSelf,$pRIID,$pObj)
    Local $tStruct = DllStructCreate("ptr",$pObj)
    Switch _WinAPI_StringFromGUID($pRIID)
        Case $sIID_IInStream
        Case Else
            Return $E_NOINTERFACE
    EndSwitch
    DllStructSetData($tStruct,1,$pSelf)
    Return $S_OK
EndFunc

Func IInStream_AddRef($pSelf)
    Return 1
EndFunc

Func IInStream_Release($pSelf)
    Return 0
EndFunc

Func IInStream_Read($pSelf,$pData,$iSize,$iProcessedSize)
    Return $_7z_oIStream.Read($pData,$iSize,$iProcessedSize)
EndFunc

Func IInStream_Seek($pSelf,$iOffset,$iSeekOrigin,$iNewPosition)
    Return $_7z_oIStream.Seek($iOffset,$iSeekOrigin,$iNewPosition)
EndFunc

Func IOutStream_QueryInterface($pSelf,$pRIID,$pObj)
    Local $tStruct=DllStructCreate("ptr", $pObj)
    Switch _WinAPI_StringFromGUID($pRIID)
        Case $sIID_IOutStream
        Case Else
            Return $E_NOINTERFACE
    EndSwitch
    DllStructSetData($tStruct,1,$pSelf)
    Return $S_OK
EndFunc

Func IOutStream_AddRef($pSelf)
    Return 1
EndFunc

Func IOutStream_Release($pSelf)
    Return 0
EndFunc

Func IOutStream_Write($pSelf,$pData,$iSize,$iProcessedSize)
    Return $_7z_oIStreamOut.Write($pData,$iSize,$iProcessedSize)
EndFunc

Func IOutStream_Seek($pSelf,$iOffset,$iSeekOrigin,$iNewPosition)
    Return $_7z_oIStreamOut.Seek($iOffset,$iSeekOrigin,$iNewPosition)
EndFunc

Func IOutStream_SetSize($pSelf,$iNewSize)
    Return $E_NOTIMPL
EndFunc

Func IArchiveExtractCallback_QueryInterface($pSelf, $pRIID, $pObj)
    Local $tStruct = DllStructCreate("ptr", $pObj)
    Switch _WinAPI_StringFromGUID($pRIID)
        Case $sIID_IArchiveExtractCallback
        Case Else
            Return $E_NOINTERFACE
    EndSwitch
    DllStructSetData($tStruct, 1, $pSelf)
    Return $S_OK
EndFunc

Func IArchiveExtractCallback_AddRef($pSelf)
    Return 1
EndFunc

Func IArchiveExtractCallback_Release($pSelf)
    Return 0
EndFunc

Func IArchiveExtractCallback_SetTotal($pSelf, $total)
    Return 0
EndFunc

Func IArchiveExtractCallback_SetCompleted($pSelf, $completeValue)
    Return $S_OK
EndFunc

Func IArchiveExtractCallback_GetStream($pSelf,$index,$outStream,$askExtractMode)
    ;Progress
    $_7z_iExtractProgress=Round($index/$_7z_iExtractCount*100,3)
    ConsoleWrite("Read7z: "&$_7z_iExtractProgress&@CRLF)
    If StringRight($_7z_aFiles[$index],4)=".inf" Then;$_7z_GetFileType Then
        $vData=ReadBinaryFromStream($_7z_oIStreamOut)
        If $vData<>"" Then
            If StringLeft($vData,4+2)="0xFFFE" Then
                $vData=Unicode2Asc($vData)
                If StringLeft($vData,1)="?" Then $vData=StringTrimLeft($vData,1)
            EndIf
            Local $_7z_iBinaryArraySizeX=UBound($_7z_aBinaryArray,1)+1
            Local $_7z_iBinaryArrayDimSize=UBound($_7z_aBinaryArray,2)
            If $_7z_iBinaryArrayDimSize=1 Then
                Local $_7z_iBinaryArraySizeY=2
            Else
                Local $_7z_iBinaryArraySizeY=UBound($_7z_aBinaryArray,2)
            EndIf
            ReDim $_7z_aBinaryArray[$_7z_iBinaryArraySizeX][$_7z_iBinaryArraySizeY]
            $_7z_aBinaryArray[$_7z_iBinaryArraySizeX-1][0]=$_7z_aFiles[$index-1]
            $_7z_aBinaryArray[$_7z_iBinaryArraySizeX-1][1]=BinaryToString($vData)
            Local $tStruct=DllStructCreate("ptr",$outStream)
        EndIf
        Local $tStruct=DllStructCreate('ptr',$outStream)
        Local $Stream=$_7z_oIOutStream()
        DllStructSetData($tStruct,1,$Stream)
        If $_7z_oIStreamOut Then
            $_7z_oIStreamOut.Release()
        Endif
        $_7z_oIStreamOut=CreateStreamOnHGlobal()
    EndIf
    Return $S_OK
EndFunc

Func IArchiveExtractCallback_PrepareOperation($pSelf,$askExtractMode)
;~  IF $bCancel
;~      Return $E_ABORT
;~  endif
    Return $S_OK
EndFunc

Func IArchiveExtractCallback_SetOperationResult($pSelf,$resultEOperationResult)
    Return $S_OK
EndFunc

Func _7z_CreateObject($sCLSID, $sIID, $sTag)
    Local $tCLSID=_WinAPI_GUIDFromString($sCLSID)
    Local $tIID=_WinAPI_GUIDFromString($sIID)
    Local $aCall=DllCall($h7Z_DLL,"long","CreateObject","struct*",$tCLSID,"struct*",$tIID,"ptr*",0)
    If @error Or $aCall[0] Then Return SetError(1,0,0)
    Return ObjCreateInterface($aCall[3],$sIID,$sTag)
EndFunc

Func _WinAPI_SHCreateStreamOnFile($sFile)
    Local $iGrfMode=0x00000002
    Local $aCall=DllCall("shlwapi.dll","long","SHCreateStreamOnFileW","wstr",$sFile,"uint",$iGrfMode,"ptr*",0)
    If @error Or $aCall[0] Then Return SetError(1,0,0)
    Return ObjCreateInterface($aCall[3],$sIID_IStream,$tagIStream)
EndFunc

Func ObjectFromTag($sFunctionPrefix,$tagInterface, ByRef $tInterface,$bIsUnknown=Default,$sIID="{00000000-0000-0000-C000-000000000046}")
    If $bIsUnknown=Default Then $bIsUnknown=True
    Local $sInterface=$tagInterface
    Local $tagIUnknown="QueryInterface hresult(ptr;ptr*);"&"AddRef dword();"&"Release dword();"
    If $bIsUnknown Then $tagInterface=$tagIUnknown&$tagInterface
    Local $aMethods=StringSplit(StringTrimRight(StringReplace(StringRegExpReplace(StringRegExpReplace($tagInterface,"\w+\*","ptr"),"\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)","$1\|$2;$4"&@LF),";"&@LF,@LF),1),@LF,3)
    Local $iUbound=UBound($aMethods)
    Local $sMethod,$aSplit,$sNamePart,$aTagPart,$sTagPart,$sRet,$sParams,$hCallback
    $tInterface=DllStructCreate("int RefCount;int Size;ptr Object;ptr Methods["&$iUbound&"];int_ptr Callbacks["&$iUbound&"];ulong_ptr Slots[16]")
    If @error Then Return SetError(1,0,0)
    For $i=0 To $iUbound-1
        $aSplit=StringSplit($aMethods[$i],"|",2)
        If UBound($aSplit)<>2 Then ReDim $aSplit[2]
        $sNamePart=$aSplit[0]
        $sTagPart=StringReplace(StringReplace(StringReplace(StringReplace($aSplit[1],"object","idispatch"),"hresult","long"),"bstr","ptr"),"variant","ptr")
        $sMethod=$sFunctionPrefix&$sNamePart
        $aTagPart=StringSplit($sTagPart,";",2)
        $sRet=$aTagPart[0]
        $sParams=StringReplace($sTagPart,$sRet,"",1)
        $sParams="ptr"&$sParams
        $hCallback=DllCallbackRegister($sMethod,$sRet,$sParams)
        DllStructSetData($tInterface,"Methods",DllCallbackGetPtr($hCallback),$i+1)
        DllStructSetData($tInterface,"Callbacks",$hCallback,$i+1)
    Next
    DllStructSetData($tInterface,"RefCount",1)
    DllStructSetData($tInterface,"Size",$iUbound)
    DllStructSetData($tInterface,"Object",DllStructGetPtr($tInterface,"Methods"))
    Return ObjCreateInterface(DllStructGetPtr($tInterface,"Object"),$sIID,$sInterface,$bIsUnknown)
EndFunc

Func DeleteObjectFromTag(ByRef $tInterface)
    For $i = 1 To DllStructGetData($tInterface, "Size")
        DllCallbackFree(DllStructGetData($tInterface, "Callbacks", $i))
    Next
    $tInterface = 0
EndFunc

Func ReadBinaryFromStream($oStream,$iWantedSize=Default)
    Local Const $S_OK=0,$S_FALSE=1
    Local Enum $STREAM_SEEK_SET=0,$STREAM_SEEK_CUR,$STREAM_SEEK_END
    $oStream.Seek(0,$STREAM_SEEK_SET,0)
    Local $tSize=DllStructCreate("uint64")
    $oStream.Seek(0,$STREAM_SEEK_END,DllStructGetPtr($tSize))
    Local $iSize=DllStructGetData($tSize,1)
    If $iSize=0 Then
        Return SetError(2,0,0)
    EndIf
    $oStream.Seek(0,$STREAM_SEEK_SET,0)
    If $iSize=-1 Then $iSize=262144
    If ($iWantedSize<>Default) And ($iWantedSize<$iSize) Then $iSize=$iWantedSize
    Local $tBinary=DllStructCreate("byte["&$iSize&"]")
    Local $tRead=DllStructCreate("dword")
    Local $bBinary=Binary(""),$iOverallRead
    While 1
        Switch $oStream.Read($tBinary,$iSize,DllStructGetPtr($tRead))
            Case $S_OK
                $iOverallRead+=DllStructGetData($tRead,1)
                $bBinary&=DllStructGetData($tBinary,1)
            Case $S_FALSE
                $iOverallRead+=DllStructGetData($tRead,1)
                $bBinary&=BinaryMid(DllStructGetData($tBinary,1),1,DllStructGetData($tRead,1))
                ExitLoop
            Case Else
                ExitLoop
        EndSwitch
        If $iOverallRead<=$iSize Then ExitLoop
    WEnd
    Return SetExtended($iOverallRead,$bBinary)
EndFunc

Func CreateStreamOnHGlobal($hGlobal=0,$iFlag=1)
    Local $aCall=DllCall("ole32.dll","long","CreateStreamOnHGlobal","handle",$hGlobal,"int",$iFlag,"ptr*",0)
    If @error Or $aCall[0] Then Return SetError(1,0,0)
    Return ObjCreateInterface($aCall[3],$sIID_IStream,$tagIStream)
EndFunc

Func _7zFree()
EndFunc

Func Unicode2Asc($UniString)
    Local $BufferLen=StringLen($UniString)
    Local $Input=DllStructCreate("byte["&$BufferLen&"]")
    Local $Output=DllStructCreate("char["&$BufferLen&"]")
    DllStructSetData($Input,1,$UniString)
    Local $Return = DllCall("kernel32.dll","int","WideCharToMultiByte","int",0,"int",0,"ptr",DllStructGetPtr($Input),"int",$BufferLen/2,"ptr",DllStructGetPtr($Output),"int",$BufferLen,"int",0,"int",0)
    Local $AscString=DllStructGetData($Output,1)
    $Output=0
    $Input=0
    Return $AscString
EndFunc
Edited by Biatu

What is what? What is what.

Link to comment
Share on other sites

  • 3 months later...

Hi,

I would like to extract some ogg files from a 7z archive into memory and play them with bass.

I have just got bass to play a file in memory, which is great.

But I don't know how to get 7z to extract to memory.

Can you give me an example of extracting a file from a 7z archive (with encryption) into memory?

Marc

Link to comment
Share on other sites

  • 3 weeks later...

Hi Marc,

Were is the problem? There is code posted for memory extraction.

But actually I would recommand using 7z.exe.
Even with writing and than again reading the decompressed data to memory
it's usually faster than using the dll in Autoit.

Link to comment
Share on other sites

I thought the best solution would be to call 7z.exe to first get a file list, and use regex to filter out results. Afterwards extract the files one by one and capture stdout.

It's by no means eefficient but it should work. 

What is what? What is what.

Link to comment
Share on other sites

Where is the code?

My bad!, I was sure that I had posted it somewhere.

Well, after playing over 2 month with that dll I can only say forget about it.

The object handling of AutoIt v3 isn't user friendly and the 7z interfaces are not documented.
Also it will be slower than using 7z.exe.
Don't care about stdout just extract to disk, keep it easy.

Link to comment
Share on other sites

  • 2 weeks later...

 

Hi,

I don't want to extract to disk.

Isn't there a way to get the contents of a specific file from the archive as a string?

Marc

Trancexx, was helping me with an example function using the dll to extract an archive using various streams. I was able to modify it to use RegEx file matches, but...it just caused more problems, like not extracting the data properly. However it did succeed in extracting the files to memory. 

What is what? What is what.

Link to comment
Share on other sites

  • 11 months later...

I know this may be a dead thread, but i'd like to see if we could get together and knock this out for a change.

I have attached the example script and related files as trancexx has provided, 7z_Extract_Example.7z

The script works flawlessly, and my previous tests on this script find that it will extract all files properly when unmodified.

However, when introducing a small change, such as:

If $isDir Then
        $iExtractCount -= 1
        DirCreate($7zExtractDir & $sName & "/")
    Else
        If StringRight($sName,4)=".inf" Then
            DllStructSetData($tIndices, 1, $j, $j+1)
        Else
            $iExtractCount -= 1
        EndIf
    EndIf

Nothing is Extracted.

However, with a slight modification:

If $isDir Then
        $iExtractCount -= 1
        DirCreate($7zExtractDir & $sName & "/")
    Else
        If StringRight($sName,4)=".inf" Then
            DllStructSetData($tIndices, 1, $j, $j+1)
        EndIf
    EndIf

The files beholder.cat, and beholder.inf are extracted. Even though there is only 1 Inf file. 

I tried modifying tIndicies to have just 1 entry, tried sizing it to account for all files ($i), nothing.
even tried:

local $iExtractCount = 0
Local $tIndices = DllStructCreate("int[" & $i & "]")

For $j = 0 To $i - 1
    Local $sName, $iSize, $isDir
    $oIInArchive.GetProperty($j, $kpidPath, $sName)
    $oIInArchive.GetProperty($j, $kpidSize, $iSize)
    $oIInArchive.GetProperty($j, $kpidIsDir, $isDir)
    If $isDir Then
        ;$iExtractCount -= 1
        DirCreate($7zExtractDir & $sName & "/")
    Else
        If StringRight($sName,4)=".inf" Then
            $iExtractCount += 1
            DllStructSetData($tIndices, 1, $j, $j+1)
        EndIf
    EndIf
    ConsoleWrite($j & ".    " & $sName & ", size = " & $iSize & " bytes, " & $isDir & @CRLF)
Next

Nothing seems to work. Can anyone give me some insight as to why this keeps failing? 

Update@2016.08.09, 1:03:


Uncommenting lines 40, 67, and 69 in IArchiveExtractCallback.au3 shows that IArchiveExtractCallback_GetStream is getting called twice for some off reason

Test Mod:

local $iExtractCount = 0
Local $tIndices = DllStructCreate("int[" & $i & "]")

For $j = 0 To $i - 1
    Local $sName, $iSize, $isDir
    $oIInArchive.GetProperty($j, $kpidPath, $sName)
    $oIInArchive.GetProperty($j, $kpidSize, $iSize)
    $oIInArchive.GetProperty($j, $kpidIsDir, $isDir)
    If $isDir Then
        DirCreate($7zExtractDir & $sName & "/")
    ElseIf StringRight($sName,4)=".inf" Then
        DllStructSetData($tIndices, 1, $j, $iExtractCount+1)
        $iExtractCount += 1
    EndIf
    ConsoleWrite($j & ".    " & $sName & ", size = " & $iSize & " bytes, " & $isDir & @CRLF)
Next

Output:

0.    WinAll, size = 0 bytes, True
1.    WinAll\amd64.cab, size = 418789 bytes, False
2.    WinAll\i386.cab, size = 358996 bytes, False
3.    WinAll\beholder.bin, size = 281569 bytes, False
4.    WinAll\Install.exe, size = 75072 bytes, False
5.    WinAll\install.x64, size = 84480 bytes, False
6.    WinAll\beholder.cat, size = 22413 bytes, False
7.    WinAll\beholder.inf, size = 20452 bytes, False
8.    Beholder.nfo, size = 738 bytes, False
9.    www.SamLab.ws.url, size = 94 bytes, False
IArchiveExtractCallback_AddRef ref count = 1
IArchiveExtractCallback_AddRef ref count = 2
IArchiveExtractCallback_AddRef ref count = 3
IArchiveExtractCallback_AddRef ref count = 4
!@IArchiveExtractCallback_GetStream $index = 6
>!$sName = C:\Users\Biatu.INFINITYCOMMS\Desktop\Dev\2016.08.08\AutoIt\7zUtils\7z_Extract_Example\Extracted\WinAll\beholder.cat
!@IArchiveExtractCallback_GetStream $index = 7
>!$sName = C:\Users\Biatu.INFINITYCOMMS\Desktop\Dev\2016.08.08\AutoIt\7zUtils\7z_Extract_Example\Extracted\WinAll\beholder.inf


Update@1:19: 

But also, get this...changing the extension filter from .inf to .cat give this output:
 

0.    WinAll, size = 0 bytes, True
1.    WinAll\amd64.cab, size = 418789 bytes, False
2.    WinAll\i386.cab, size = 358996 bytes, False
3.    WinAll\beholder.bin, size = 281569 bytes, False
4.    WinAll\Install.exe, size = 75072 bytes, False
5.    WinAll\install.x64, size = 84480 bytes, False
!@Debug:6,1
6.    WinAll\beholder.cat, size = 22413 bytes, False
7.    WinAll\beholder.inf, size = 20452 bytes, False
8.    Beholder.nfo, size = 738 bytes, False
9.    www.SamLab.ws.url, size = 94 bytes, False
IArchiveExtractCallback_AddRef ref count = 1
IArchiveExtractCallback_AddRef ref count = 2
IArchiveExtractCallback_AddRef ref count = 3
IArchiveExtractCallback_AddRef ref count = 4
!@IArchiveExtractCallback_GetStream $index = 6
>!$sName = C:\Users\Biatu.INFINITYCOMMS\Desktop\Dev\2016.08.08\AutoIt\7zUtils\7z_Extract_Example\Extracted\WinAll\beholder.cat

oIInArchive.Extract Return: 00000000

 

Edited by Biatu
Updates, remove garbage

What is what? What is what.

Link to comment
Share on other sites

  • 5 months later...

I've been playing with these interfaces today. Everything seems to be fine, but you need to add some error checking to the callback functions, and the integer structure which contains indices of files to extract must be used properly.

List all items:

; List all items
ConsoleWrite( "All items:" & @CRLF )
Local $sName, $iSize, $isDir
For $i = 0 To $iCount - 1
  $oIInArchive.GetProperty($i, $kpidPath, $sName)
  $oIInArchive.GetProperty($i, $kpidSize, $iSize)
  $oIInArchive.GetProperty($i, $kpidIsDir, $isDir)
  ConsoleWrite($i & ". " & $sName & ", size = " & $iSize & " bytes" & ", isDir = " & $isDir & @CRLF)
Next
ConsoleWrite( @CRLF )

Extract WinAll\beholder.inf:

; Extract WinAll\beholder.inf
DirRemove( $7zExtractDir, 1 )
DirCreate($7zExtractDir)
$bCreateSubfolders = True
$tIndices = DllStructCreate( "int[1]" )
DllStructSetData( $tIndices, 1, 7, 1 )
; Pass error check info and flags to IArchiveExtractCallback_GetStream
IArchiveExtractCallback_GetStream( 0, $tIndices, $bCreateSubfolders, 0 )
; Extract files and folders from archive through $oIArchiveExtractCallback
$hResult = $oIInArchive.Extract( $tIndices, 1, 0, $oIArchiveExtractCallback )
ConsoleWrite( "oIInArchive.Extract $hresult = 0x" &  Hex( $hResult ) & @CRLF )
ConsoleWrite( @CRLF )

Extract WinAll, WinAll\beholder.inf and www.SamLab.ws.url:

; Extract WinAll, WinAll\beholder.inf and www.SamLab.ws.url
DirRemove( $7zExtractDir, 1 )
DirCreate($7zExtractDir)
$bCreateSubfolders = False
$tIndices = DllStructCreate( "int[3]" )
DllStructSetData( $tIndices, 1, 0, 1 )
DllStructSetData( $tIndices, 1, 7, 2 )
DllStructSetData( $tIndices, 1, 9, 3 )
; Pass error check info and flags to IArchiveExtractCallback_GetStream
IArchiveExtractCallback_GetStream( 0, $tIndices, $bCreateSubfolders, 0 )
; Extract files and folders from archive through $oIArchiveExtractCallback
$hResult = $oIInArchive.Extract( $tIndices, 3, 0, $oIArchiveExtractCallback )
ConsoleWrite( "oIInArchive.Extract $hresult = 0x" &  Hex( $hResult ) & @CRLF )
ConsoleWrite( @CRLF )

IArchiveExtractCallback_GetStream in IArchiveExtractCallback.au3:

Func IArchiveExtractCallback_GetStream($pSelf, $index, $outStream, $askExtractMode)
  Static $tIndices, $iCount, $iIdx, $bSubfolders
  If $pSelf = 0 Then
    $tIndices = $index
    $iCount = DllStructGetSize( $tIndices ) / 4
    $iIdx = 1
    $bSubfolders = $outStream
    Return
  EndIf

  If $iIdx <= $iCount And $index = DllStructGetData( $tIndices, 1, $iIdx ) Then
    ConsoleWrite( "IArchiveExtractCallback_GetStream $index = " & $index & @CRLF)
    Local $sName
    $oIInArchive.GetProperty($index, $kpidPath, $sName)
    ConsoleWrite("IArchiveExtractCallback_GetStream $sName = "  & $sName & @CRLF)
    If $bSubfolders Then
      Local $sSubFolder = StringLeft( $sName, StringInStr( $sName, "\", 0, -1 ) - 1 )
      If Not FileExists( $7zExtractDir & "\" & $sSubFolder ) Then _
        DirCreate( $7zExtractDir & "\" & $sSubFolder )
    EndIf
    $oIOutStream = 0
    DeleteObjectFromTag($tIOutStream)
    $oIOutStream = ObjectFromTag("IOutStream_", $tagIOutStream, $tIOutStream, Default, $sIID_IOutStream)
    $oIOutStream.AddRef()
    $oIStreamOut = SHCreateStreamOnFile($7zExtractDir & $sName, 0x00001000 + 2)
    Local $tStruct = DllStructCreate("ptr", $outStream)
    Local $Stream = $oIOutStream()
    $oIOutStream.AddRef()
    DllStructSetData($tStruct, 1, $Stream)
    $iIdx += 1
  EndIf
  Return $S_OK
EndFunc

IOutStream_Write in IOutStream.au3:

Func IOutStream_Write($pSelf, $pData, $iSize, $iProcessedSize)
  If IsObj( $oIStreamOut ) Then Return $oIStreamOut.Write($pData, $iSize, $iProcessedSize)
EndFunc

Output in SciTE:

Number of Items: 10

All items:
0. WinAll, size = 0 bytes, isDir = True
1. WinAll\amd64.cab, size = 418789 bytes, isDir = False
2. WinAll\i386.cab, size = 358996 bytes, isDir = False
3. WinAll\beholder.bin, size = 281569 bytes, isDir = False
4. WinAll\Install.exe, size = 75072 bytes, isDir = False
5. WinAll\install.x64, size = 84480 bytes, isDir = False
6. WinAll\beholder.cat, size = 22413 bytes, isDir = False
7. WinAll\beholder.inf, size = 20452 bytes, isDir = False
8. Beholder.nfo, size = 738 bytes, isDir = False
9. www.SamLab.ws.url, size = 94 bytes, isDir = False

IArchiveExtractCallback_GetStream $index = 7
IArchiveExtractCallback_GetStream $sName = WinAll\beholder.inf
oIInArchive.Extract $hresult = 0x00000000

IArchiveExtractCallback_GetStream $index = 0
IArchiveExtractCallback_GetStream $sName = WinAll
IArchiveExtractCallback_GetStream $index = 7
IArchiveExtractCallback_GetStream $sName = WinAll\beholder.inf
IArchiveExtractCallback_GetStream $index = 9
IArchiveExtractCallback_GetStream $sName = www.SamLab.ws.url
oIInArchive.Extract $hresult = 0x00000000

All code is included in the zip. Run Example.au3. You need 7z.dll and 7z_Extract_Example.7z from the zip in the post above (end of line 2).

7-ZipCode.7z

Edited by LarsJ
Link to comment
Share on other sites

10 hours ago, LarsJ said:

I've been playing with these interfaces today. Everything seems to be fine, but you need to add some error checking to the callback functions, and the integer structure which contains indices of files to extract must be used properly.

List all items:

; List all items
ConsoleWrite( "All items:" & @CRLF )
Local $sName, $iSize, $isDir
For $i = 0 To $iCount - 1
  $oIInArchive.GetProperty($i, $kpidPath, $sName)
  $oIInArchive.GetProperty($i, $kpidSize, $iSize)
  $oIInArchive.GetProperty($i, $kpidIsDir, $isDir)
  ConsoleWrite($i & ". " & $sName & ", size = " & $iSize & " bytes" & ", isDir = " & $isDir & @CRLF)
Next
ConsoleWrite( @CRLF )

Extract WinAll\beholder.inf:

; Extract WinAll\beholder.inf
DirRemove( $7zExtractDir, 1 )
DirCreate($7zExtractDir)
$bCreateSubfolders = True
$tIndices = DllStructCreate( "int[1]" )
DllStructSetData( $tIndices, 1, 7, 1 )
; Pass error check info and flags to IArchiveExtractCallback_GetStream
IArchiveExtractCallback_GetStream( 0, $tIndices, $bCreateSubfolders, 0 )
; Extract files and folders from archive through $oIArchiveExtractCallback
$hResult = $oIInArchive.Extract( $tIndices, 1, 0, $oIArchiveExtractCallback )
ConsoleWrite( "oIInArchive.Extract $hresult = 0x" &  Hex( $hResult ) & @CRLF )
ConsoleWrite( @CRLF )

Extract WinAll, WinAll\beholder.inf and www.SamLab.ws.url:

; Extract WinAll, WinAll\beholder.inf and www.SamLab.ws.url
DirRemove( $7zExtractDir, 1 )
DirCreate($7zExtractDir)
$bCreateSubfolders = False
$tIndices = DllStructCreate( "int[3]" )
DllStructSetData( $tIndices, 1, 0, 1 )
DllStructSetData( $tIndices, 1, 7, 2 )
DllStructSetData( $tIndices, 1, 9, 3 )
; Pass error check info and flags to IArchiveExtractCallback_GetStream
IArchiveExtractCallback_GetStream( 0, $tIndices, $bCreateSubfolders, 0 )
; Extract files and folders from archive through $oIArchiveExtractCallback
$hResult = $oIInArchive.Extract( $tIndices, 3, 0, $oIArchiveExtractCallback )
ConsoleWrite( "oIInArchive.Extract $hresult = 0x" &  Hex( $hResult ) & @CRLF )
ConsoleWrite( @CRLF )

IArchiveExtractCallback_GetStream in IArchiveExtractCallback.au3:

Func IArchiveExtractCallback_GetStream($pSelf, $index, $outStream, $askExtractMode)
  Static $tIndices, $iCount, $iIdx, $bSubfolders
  If $pSelf = 0 Then
    $tIndices = $index
    $iCount = DllStructGetSize( $tIndices ) / 4
    $iIdx = 1
    $bSubfolders = $outStream
    Return
  EndIf

  If $iIdx <= $iCount And $index = DllStructGetData( $tIndices, 1, $iIdx ) Then
    ConsoleWrite( "IArchiveExtractCallback_GetStream $index = " & $index & @CRLF)
    Local $sName
    $oIInArchive.GetProperty($index, $kpidPath, $sName)
    ConsoleWrite("IArchiveExtractCallback_GetStream $sName = "  & $sName & @CRLF)
    If $bSubfolders Then
      Local $sSubFolder = StringLeft( $sName, StringInStr( $sName, "\", 0, -1 ) - 1 )
      If Not FileExists( $7zExtractDir & "\" & $sSubFolder ) Then _
        DirCreate( $7zExtractDir & "\" & $sSubFolder )
    EndIf
    $oIOutStream = 0
    DeleteObjectFromTag($tIOutStream)
    $oIOutStream = ObjectFromTag("IOutStream_", $tagIOutStream, $tIOutStream, Default, $sIID_IOutStream)
    $oIOutStream.AddRef()
    $oIStreamOut = SHCreateStreamOnFile($7zExtractDir & $sName, 0x00001000 + 2)
    Local $tStruct = DllStructCreate("ptr", $outStream)
    Local $Stream = $oIOutStream()
    $oIOutStream.AddRef()
    DllStructSetData($tStruct, 1, $Stream)
    $iIdx += 1
  EndIf
  Return $S_OK
EndFunc

IOutStream_Write in IOutStream.au3:

Func IOutStream_Write($pSelf, $pData, $iSize, $iProcessedSize)
  If IsObj( $oIStreamOut ) Then Return $oIStreamOut.Write($pData, $iSize, $iProcessedSize)
EndFunc

Output in SciTE:

Number of Items: 10

All items:
0. WinAll, size = 0 bytes, isDir = True
1. WinAll\amd64.cab, size = 418789 bytes, isDir = False
2. WinAll\i386.cab, size = 358996 bytes, isDir = False
3. WinAll\beholder.bin, size = 281569 bytes, isDir = False
4. WinAll\Install.exe, size = 75072 bytes, isDir = False
5. WinAll\install.x64, size = 84480 bytes, isDir = False
6. WinAll\beholder.cat, size = 22413 bytes, isDir = False
7. WinAll\beholder.inf, size = 20452 bytes, isDir = False
8. Beholder.nfo, size = 738 bytes, isDir = False
9. www.SamLab.ws.url, size = 94 bytes, isDir = False

IArchiveExtractCallback_GetStream $index = 7
IArchiveExtractCallback_GetStream $sName = WinAll\beholder.inf
oIInArchive.Extract $hresult = 0x00000000

IArchiveExtractCallback_GetStream $index = 0
IArchiveExtractCallback_GetStream $sName = WinAll
IArchiveExtractCallback_GetStream $index = 7
IArchiveExtractCallback_GetStream $sName = WinAll\beholder.inf
IArchiveExtractCallback_GetStream $index = 9
IArchiveExtractCallback_GetStream $sName = www.SamLab.ws.url
oIInArchive.Extract $hresult = 0x00000000

All code is included in the zip. Run Example.au3. You need 7z.dll and 7z_Extract_Example.7z from the zip in the post above (end of line 2).

7-ZipCode.7z

Great Job! Will test this later with all DriverPacks

What is what? What is what.

Link to comment
Share on other sites

Is there a possibility to make this Example.au3 unicode-friendly? All I get from file with unicode fileName is:

>Running AU3Check (3.3.14.0)  from:C:\Program Files (x86)\AutoIt3  input: ... \7-ZipCode\Example.au3
+>18:45:07 AU3Check ended.rc:0
>Running:(3.3.14.0):C:\Program Files (x86)\AutoIt3\autoit3.exe " ... \7-ZipCode\Example.au3"    
--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
Number of Items: 0

All items:

oIInArchive.Extract $hresult = 0x8007000E

oIInArchive.Extract $hresult = 0x8007000E

+>18:45:10 AutoIt3.exe ended.rc:0
+>18:45:10 AutoIt3Wrapper Finished.
>Exit code: 0    Time: 3.804

Also - what about 64bit-ness? Original v15.14 7z.dll seems not working...

Link to comment
Share on other sites

This example works for me:

7-Zip -file:

ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔.7z

Contains one txt-file:

ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔.txt

With this content (UTF8):

ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔
ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔
ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔
ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔
ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔
ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔
ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔
ÀÐØÞßƵɄʬЖЗДلنرشحჱჶẶỘ⅝⇈≽⋛⍓⍫♬✠⬔

Output in SciTE:

>Running:(3.3.14.2):E:\Program Files (x86)\AutoIt3\autoit3_x64.exe "...\Example.au3"    
--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
Number of Items: 1

All items:
0. ÀÐØÞß????????????????????????.txt, size = 587 bytes, isDir = False

IArchiveExtractCallback_GetStream $index = 0
IArchiveExtractCallback_GetStream $sName = ÀÐØÞß????????????????????????.txt
oIInArchive.Extract $hresult = 0x00000000

64 bit code works for me with a 64 bit version of 7z.dll as you can see in the SciTE output.

Link to comment
Share on other sites

hmm... it seems i used wrong 64bit dll (7-zip.dll instead 7z.dll) sorry,  it now works. But only for *.7z files. My test archives was *.zip and *.lzh and they still give same output as in my previous post. Actual 7z opens those files without problem... I wanted to use 7z for all arc.types...

 

i found list of GUIDs, but still cannot read file list from *.zip

Handler GUIDs:

{23170F69-40C1-278A-1000-000110xx0000}

  01 Zip
  02 BZip2
  03 Rar
  04 Arj
  05 Z
  06 Lzh
  07 7z
  08 Cab
  09 Nsis
  0A lzma
  0B lzma86
  0C xz
  0D ppmd

 

Edited by Iczer
Link to comment
Share on other sites

@LarsJ, What about Extracting to memory? I intend to extract to an Array...

[0][0] iCount
[i][1] File Name
[i][2] Path in 7z
[i][3] Data
[i][4] 7z Index (Optional, Not Really Needed)

 

Thank you

Here is what I got so far, but im not sure how to Get the data from the stream.

Func IArchiveExtractCallback_GetStream($pSelf, $index, $outStream, $askExtractMode)
  Static $tIndices, $iCount, $iIdx, $bSubfolders
  If $pSelf = 0 Then
    $tIndices = $index
    $iCount = DllStructGetSize( $tIndices ) / 4
    $iIdx = 1
    $bSubfolders = $outStream
    Return
  EndIf

  If $iIdx <= $iCount And $index = DllStructGetData( $tIndices, 1, $iIdx ) Then
    ConsoleWrite( "IArchiveExtractCallback_GetStream $index = " & $index & @CRLF)
    Local $sName
    $oIInArchive.GetProperty($index, $kpidPath, $sName)
    ConsoleWrite("IArchiveExtractCallback_GetStream $sName = "  & $sName & @CRLF)
    $oIOutStream = 0
    DeleteObjectFromTag($tIOutStream)
    $oIOutStream = ObjectFromTag("IOutStream_", $tagIOutStream, $tIOutStream, Default, $sIID_IOutStream)
    $oIOutStream.AddRef()
    $oIStreamOut = CreateStreamOnHGlobal();SHCreateStreamOnFile($7zExtractDir & $sName, 0x00001000 + 2)
    Local $tStruct = DllStructCreate("ptr", $outStream)
    Local $Stream = $oIOutStream()
    $oIOutStream.AddRef()
    DllStructSetData($tStruct, 1, $Stream)
    $iIdx += 1
  EndIf
  Return $S_OK
EndFunc

 

Edited by Biatu

What is what? What is what.

Link to comment
Share on other sites

Iczer, The code in post 50 is definitely a minimum implementation which only supports the native 7z-format. A lot of the interface methods eg. $oIInArchive.Open() must be provided with a number of parameters. Some of these parameters are different for different archive types. Therefore, it's necessary to test more or less every single interface method for each archive format. It's far from enough to simply apply the proper archive GUID.

Biatu, Interesting.

Link to comment
Share on other sites

8 minutes ago, LarsJ said:

Iczer, The code in post 50 is definitely a minimum implementation which only supports the native 7z-format. A lot of the interface methods eg. $oIInArchive.Open() must be provided with a number of parameters. Some of these parameters are different for different archive types. Therefore, it's necessary to test more or less every single interface method for each archive format. It's far from enough to simply apply the proper archive GUID.

Biatu, Interesting.

Here is another snippet I have for initialization... (I realized that in my previous attempts I was incrementing the struct incorrectly, but this should do it.

;Get InfCount
For $i = 0 To $iCount - 1
  $oIInArchive.GetProperty($i, $kpidIsDir, $isDir)
  If $isDir Then ContinueLoop
  $oIInArchive.GetProperty($i, $kpidPath, $sName)
  $sExt=StringTrimLeft($sName,StringInStr($sName,".",0,-1))
  If $sExt<>"inf" Then ContinueLoop
  $iMax=UBound($a7z,1)
  ReDim $a7z[$iMax+1][10]
  $a7z[$iMax][0]=$sName
  $a7z[$iMax][1]=$i
  $iExtract+=1
Next
;_ArrayDisplay($a7z)
$tIndices = DllStructCreate( "int["&$iExtract&"]" )
For $i = 0 To $iExtract-1
  DllStructSetData($tIndices,1,$a7z[$i][1],$i+1)
Next
IArchiveExtractCallback_GetStream(0,$tIndices,0,0)

$hResult = $oIInArchive.Extract( $tIndices, $iExtract, 0, $oIArchiveExtractCallback )
ConsoleWrite( "oIInArchive.Extract $hresult = "&  _WinAPI_GetErrorMessage("0x"&Hex($hResult)) & @CRLF )

 

What is what? What is what.

Link to comment
Share on other sites

4 minutes ago, LarsJ said:

Do you have some code for IArchiveOpenCallback?

Unfortunately no. What i posted recently is all I have. But you may be able to pull from the first post, which was the only way I was able to get *some* data extracted to memory. What I think I did was read the memory stream on on the next call, then wipe it out before data was written back to the stream, and it seems the this old method will not work for only 1 file, and even so, the first file would always be left out.

 

Edit: everything im using is from that archive, that you were working on as well.

Edited by Biatu

What is what? What is what.

Link to comment
Share on other sites

Bingo!

 

At the top of IArchiveExtractCallback.au3:

Global $i7zIdx=0, $oIStreamOut, $i7zCapture=0

Here:

Func IArchiveExtractCallback_GetStream($pSelf, $index, $outStream, $askExtractMode)
  Static $tIndices, $iCount, $iIdx, $bSubfolders
  If $pSelf = 0 Then
    $tIndices = $index
    $iCount = DllStructGetSize( $tIndices ) / 4
    $iIdx = 1
    $bSubfolders = $outStream
    Return
  EndIf

  If $iIdx <= $iCount And $index = DllStructGetData( $tIndices, 1, $iIdx ) Then
    ConsoleWrite( "IArchiveExtractCallback_GetStream $index = " & $index & @CRLF)
    Local $sName
    $oIInArchive.GetProperty($index, $kpidPath, $sName)
    ConsoleWrite("IArchiveExtractCallback_GetStream $sName = "  & $sName & @CRLF)
    $oIOutStream = 0
    DeleteObjectFromTag($tIOutStream)
    $oIOutStream = ObjectFromTag("IOutStream_", $tagIOutStream, $tIOutStream, Default, $sIID_IOutStream)
    $oIOutStream.AddRef()
    $oIStreamOut = CreateStreamOnHGlobal();SHCreateStreamOnFile($7zExtractDir & $sName, 0x00001000 + 2)
    Local $tStruct = DllStructCreate("ptr", $outStream)
    Local $Stream = $oIOutStream()
    $oIOutStream.AddRef()
    DllStructSetData($tStruct, 1, $Stream)
    $i7zIdx=$iIdx-1
    $i7zCapture=1
    $iIdx += 1
  EndIf
  Return $S_OK
EndFunc

and Here:

Func IArchiveExtractCallback_SetOperationResult($pSelf, $resultEOperationResult)
    If $i7zCapture Then
        $i7zCapture=0
        $vData=ReadBinaryFromStream($oIStreamOut)
        If $vData<>"" Then
            $a7z[$i7zIdx][2]=$vData
        Else
            $a7z[$i7zIdx][2]="NaN"
        EndIf
    EndIf
    ConsoleWrite("@IArchiveExtractCallback_SetOperationResult" & @CRLF)
    Return $S_OK
EndFunc

 

What is what? What is what.

Link to comment
Share on other sites

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