Extract ZIP to RAM?

Get help with using AutoHotkey and its commands and hotkeys
tmplinshi
Posts: 1561
Joined: 01 Oct 2013, 14:57

Re: Extract ZIP to RAM?

21 Nov 2019, 23:10

@hasantr That shoudn't be happen, but I tested anyway. I created the folder D:\Folder\inFolder, and copied test.zip to both D:\Folder\ and D:\Folder\inFolder\, the code just works fine.

Code: Select all

MsgBox % SevenZip_ExtractMem2("D:\Folder\test.zip", "test2.txt")
MsgBox % SevenZip_ExtractMem2("D:\Folder\inFolder\test.zip", "test2.txt")
Did you get any error messages?
User avatar
hasantr
Posts: 497
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: Extract ZIP to RAM?

22 Nov 2019, 01:09

tmplinshi wrote:
21 Nov 2019, 23:10
@hasantr That shoudn't be happen, but I tested anyway. I created the folder D:\Folder\inFolder, and copied test.zip to both D:\Folder\ and D:\Folder\inFolder\, the code just works fine.

Code: Select all

MsgBox % SevenZip_ExtractMem2("D:\Folder\test.zip", "test2.txt")
MsgBox % SevenZip_ExtractMem2("D:\Folder\inFolder\test.zip", "test2.txt")
Did you get any error messages?
@tmplinshi
Actually, the problem is the xml file, the zip file becomes inaccessible because it uses autohotkey. Sometimes it opens.
This test has an xml file that doesn't work in zip. Autohotkey gets stuck trying to open but does not give error.
test.zip
(1.37 KiB) Downloaded 34 times
tmplinshi
Posts: 1561
Joined: 01 Oct 2013, 14:57

Re: Extract ZIP to RAM?

22 Nov 2019, 01:43

oh, I think that's the problem of my SevenZip_ExtractMem2. For now you can use SevenZipExtractMem (https://www.autohotkey.com/boards/viewtopic.php?p=298798#p298798), and make sure that the dlls you use have a SevenZipExtractMem function.
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

10 Jan 2020, 10:34

My try to implement extraction to the buffer without external libraries:

Code: Select all

size := UnzipToBuffer(buff, "C:\Users\User\Desktop\test.zip", "Folder\Subfolder\notes.txt")
; test
File := FileOpen(A_Desktop . "\notes.txt", "w", "cp0")
File.RawWrite(buff, size)
File.Close()

UnzipToBuffer(ByRef buff, zipFile, pathInsideZip) {
   static STREAM_SEEK_SET := 0, STREAM_SEEK_END := 2
   
   Parent_IShellFolder := IShellFolder.Create()
   pidl := Parent_IShellFolder.ParseDisplayName(zipFile)
   arPath := StrSplit(pathInsideZip, "\")
   for k, v in arPath {
      Isf := Parent_IShellFolder.BindToObject(pidl)
      DllCall("ole32\CoTaskMemFree", "Ptr", pidl)
      pidl := Isf.ParseDisplayName(v)
      if (k = arPath.MaxIndex()) {
         IStream := Isf.BindToStorage(pidl)
         DllCall("ole32\CoTaskMemFree", "Ptr", pidl)
         size := IStream.Seek(0, STREAM_SEEK_END)
         IStream.Seek(0, STREAM_SEEK_SET)
         VarSetCapacity(buff, size, 0)
         IStream.Read(buff, size)
         break
      }
      Parent_IShellFolder := Isf
   }
   Return size
}

CLSIDFromString(IID, ByRef CLSID) {
   VarSetCapacity(CLSID, 16, 0)
   if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
      throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res))
   Return &CLSID
}

class InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   
   __Delete() {
      ObjRelease(this.ptr)
   }
   
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      this.error := method . " failed. Result: " . (result = "" ? "No result" : Format("{:#x}", result & 0xFFFFFFFF))
      if !exc
         Return this.error
      throw Exception(this.error)
   }
}

class IShellFolder extends InterfaceBase {  ; shobjidl.h
   Create() {
      DllCall("shell32\SHGetDesktopFolder", "PtrP", pIShellFolder)
      Return new IShellFolder(pIShellFolder)
   }
   
   ParseDisplayName(pszDisplayName, pdwAttributes := 0, hwnd := 0, pbc := 0, pchEaten := 0) {
      hr := DllCall(this.VTable(3), "Ptr", this.ptr, "Ptr", hwnd, "Ptr", pbc, "WStr", pszDisplayName
                                                   , "Ptr", pchEaten, "PtrP", pidl, "UIntP", pdwAttributes)
      this.IsError("IShellFolder::ParseDisplayName", hr)
      Return pidl
   }
   
   BindToObject(pidl) {
      static IID_IShellFolder := "{000214E6-0000-0000-C000-000000000046}"
      riid := CLSIDFromString(IID_IShellFolder, pIID_IShellFolder)
      hr := DllCall(this.VTable(5), "Ptr", this.ptr, "Ptr", pidl, "Ptr", 0, "Ptr", riid, "PtrP", pIShellFolder)
      this.IsError("IShellFolder::BindToObject", hr)
      Return new IShellFolder(pIShellFolder)
   }
   
   BindToStorage(pidl, objType := "IStream", pbc := 0) {
      static IID_IStream = "{0000000c-0000-0000-C000-000000000046}"
      if (objType = "IStream")
         riid := CLSIDFromString(IID_IStream, pIID_IStream)
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pidl, "Ptr", pbc, "Ptr", riid, "PtrP", ppv)
      this.IsError("IShellFolder::BindToStorage", hr)
      if (objType = "IStream")
         Return new IStream(ppv)
   }
}

class IStream extends InterfaceBase {  ; ObjIdl.h
   Read(ByRef buff, cb) {
      hr := DllCall(this.VTable(3), "Ptr", this.ptr, "Ptr", &buff, "UInt", cb, "UIntP", read)
      this.IsError("IStream::Read", hr)
      Return read
   }

   Seek(dlibMove, dwOrigin) {
      if (A_PtrSize = 8)
         hr := DllCall(this.VTable(5), "Ptr", this.ptr, "Ptr", dlibMove, "UInt", dwOrigin, "PtrP", libNewPosition)
      else
         hr := DllCall(this.VTable(5), "Ptr", this.ptr, "UInt", dlibMove >> 32
                                                      , "UInt", dlibMove & 0xFFFFFFFF
                                                      , "UInt", dwOrigin, "PtrP", libNewPosition)
      this.IsError("IStream::Seek", hr)
      Return libNewPosition
   }
}
Last edited by teadrinker on 10 Jan 2020, 13:43, edited 2 times in total.
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

10 Jan 2020, 12:19

For some reason currently works only for 64-bit AHK.
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

10 Jan 2020, 13:32

Thanks! But I'd like the code to work on Windows 7 too. :)
teadrinker wrote: For some reason currently works only for 64-bit AHK.
Fixed.
User avatar
TheDewd
Posts: 1391
Joined: 19 Dec 2013, 11:16
Location: USA

Re: Extract ZIP to RAM?

10 Jan 2020, 14:31

@teadrinker,

Amazing work! It does a great job. Now just need a way to do the same with 7-Zip compressed archives.
Image Bulldozer - Sokoban inspired game from 1994 recreated in AutoHotkey.
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

10 Jan 2020, 16:18

TheDewd wrote: Now just need a way to do the same with 7-Zip compressed archives.
Doesn't the code @tmplinshi provided work well enough? I haven't tested it yet.
User avatar
TheDewd
Posts: 1391
Joined: 19 Dec 2013, 11:16
Location: USA

Re: Extract ZIP to RAM?

10 Jan 2020, 16:24

teadrinker wrote:Doesn't the code @tmplinshi provided work well enough? I haven't tested it yet.
It sometimes crashes, and refuses to run directly. You can read the previous thread replies to find out more. Very strange bugs.
Image Bulldozer - Sokoban inspired game from 1994 recreated in AutoHotkey.
User avatar
hasantr
Posts: 497
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: Extract ZIP to RAM?

11 Jan 2020, 06:07

teadrinker wrote:
10 Jan 2020, 10:34
My try to implement extraction to the buffer without external libraries:

Code: Select all

size := UnzipToBuffer(buff, "C:\Users\User\Desktop\test.zip", "Folder\Subfolder\notes.txt")
; test
File := FileOpen(A_Desktop . "\notes.txt", "w", "cp0")
File.RawWrite(buff, size)
File.Close()

UnzipToBuffer(ByRef buff, zipFile, pathInsideZip) {
   static STREAM_SEEK_SET := 0, STREAM_SEEK_END := 2
   
   Parent_IShellFolder := IShellFolder.Create()
   pidl := Parent_IShellFolder.ParseDisplayName(zipFile)
   arPath := StrSplit(pathInsideZip, "\")
   for k, v in arPath {
      Isf := Parent_IShellFolder.BindToObject(pidl)
      DllCall("ole32\CoTaskMemFree", "Ptr", pidl)
      pidl := Isf.ParseDisplayName(v)
      if (k = arPath.MaxIndex()) {
         IStream := Isf.BindToStorage(pidl)
         DllCall("ole32\CoTaskMemFree", "Ptr", pidl)
         size := IStream.Seek(0, STREAM_SEEK_END)
         IStream.Seek(0, STREAM_SEEK_SET)
         VarSetCapacity(buff, size, 0)
         IStream.Read(buff, size)
         break
      }
      Parent_IShellFolder := Isf
   }
   Return size
}

CLSIDFromString(IID, ByRef CLSID) {
   VarSetCapacity(CLSID, 16, 0)
   if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
      throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res))
   Return &CLSID
}

class InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   
   __Delete() {
      ObjRelease(this.ptr)
   }
   
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      this.error := method . " failed. Result: " . (result = "" ? "No result" : Format("{:#x}", result & 0xFFFFFFFF))
      if !exc
         Return this.error
      throw Exception(this.error)
   }
}

class IShellFolder extends InterfaceBase {  ; shobjidl.h
   Create() {
      DllCall("shell32\SHGetDesktopFolder", "PtrP", pIShellFolder)
      Return new IShellFolder(pIShellFolder)
   }
   
   ParseDisplayName(pszDisplayName, pdwAttributes := 0, hwnd := 0, pbc := 0, pchEaten := 0) {
      hr := DllCall(this.VTable(3), "Ptr", this.ptr, "Ptr", hwnd, "Ptr", pbc, "WStr", pszDisplayName
                                                   , "Ptr", pchEaten, "PtrP", pidl, "UIntP", pdwAttributes)
      this.IsError("IShellFolder::ParseDisplayName", hr)
      Return pidl
   }
   
   BindToObject(pidl) {
      static IID_IShellFolder := "{000214E6-0000-0000-C000-000000000046}"
      riid := CLSIDFromString(IID_IShellFolder, pIID_IShellFolder)
      hr := DllCall(this.VTable(5), "Ptr", this.ptr, "Ptr", pidl, "Ptr", 0, "Ptr", riid, "PtrP", pIShellFolder)
      this.IsError("IShellFolder::BindToObject", hr)
      Return new IShellFolder(pIShellFolder)
   }
   
   BindToStorage(pidl, objType := "IStream", pbc := 0) {
      static IID_IStream = "{0000000c-0000-0000-C000-000000000046}"
      if (objType = "IStream")
         riid := CLSIDFromString(IID_IStream, pIID_IStream)
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pidl, "Ptr", pbc, "Ptr", riid, "PtrP", ppv)
      this.IsError("IShellFolder::BindToStorage", hr)
      if (objType = "IStream")
         Return new IStream(ppv)
   }
}

class IStream extends InterfaceBase {  ; ObjIdl.h
   Read(ByRef buff, cb) {
      hr := DllCall(this.VTable(3), "Ptr", this.ptr, "Ptr", &buff, "UInt", cb, "UIntP", read)
      this.IsError("IStream::Read", hr)
      Return read
   }

   Seek(dlibMove, dwOrigin) {
      if (A_PtrSize = 8)
         hr := DllCall(this.VTable(5), "Ptr", this.ptr, "Ptr", dlibMove, "UInt", dwOrigin, "PtrP", libNewPosition)
      else
         hr := DllCall(this.VTable(5), "Ptr", this.ptr, "UInt", dlibMove >> 32
                                                      , "UInt", dlibMove & 0xFFFFFFFF
                                                      , "UInt", dwOrigin, "PtrP", libNewPosition)
      this.IsError("IStream::Seek", hr)
      Return libNewPosition
   }
}
This was awesome. Thank you very much.
I have a simple request. I have files in the "zip" format with the extension "udf". This is an error in the files. If I edit the extension to "zip," it works fine. But there are too many files. Is there any way to ignore the extension disparity?
size := UnzipToBuffer(buff, "C:\Users\User\Desktop\test.udf", "Folder\Subfolder\notes.txt")

Code: Select all

Error:  IShellFolder::BindToObject failed. Result: 0x80004005
And I couldn't transfer the result to a variable. :think:
variableSmp := RawWrite(buff, size)
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

11 Jan 2020, 09:08

hasantr wrote: Is there any way to ignore the extension disparity?
Windows considers the file with zip extension a comressed folder, without one not, so I'm not sure there is a way to ignore the extension.
hasantr wrote: And I couldn't transfer the result to a variable
After UnzipToBuffer(buff, "C:\Users\User\Desktop\test.zip", "Folder\Subfolder\notes.txt") content of notes.txt is in the buff variable as binary data. To get it as text you need to know the file encoding. Assuming that encoding is CP0

Code: Select all

size := UnzipToBuffer(buff, "C:\Users\User\Desktop\test.zip", "notes.txt")
MsgBox, % StrGet(&buff, "cp0")
User avatar
hasantr
Posts: 497
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: Extract ZIP to RAM?

11 Jan 2020, 14:00

teadrinker wrote:
11 Jan 2020, 09:08
hasantr wrote: Is there any way to ignore the extension disparity?
Windows considers the file with zip extension a comressed folder, without one not, so I'm not sure there is a way to ignore the extension.
hasantr wrote: And I couldn't transfer the result to a variable
After UnzipToBuffer(buff, "C:\Users\User\Desktop\test.zip", "Folder\Subfolder\notes.txt") content of notes.txt is in the buff variable as binary data. To get it as text you need to know the file encoding. Assuming that encoding is CP0

Code: Select all

size := UnzipToBuffer(buff, "C:\Users\User\Desktop\test.zip", "notes.txt")
MsgBox, % StrGet(&buff, "cp0")
Bad. It was again disappointing that Zip didn't work out of the extension. :(

I assigned it to variable UTF-8. I thank you.

If I don't mind, is there a way to put the file into memory and make the extension look like a zip? Renaming Zip files will be a big waste of time again.
I don't want to take your time. If not, I'll try different ways.

Thanks for everything.
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

11 Jan 2020, 15:14

hasantr wrote: is there a way to put the file into memory and make the extension look like a zip?
No. :) In memory files have no extensions at all.
User avatar
hasantr
Posts: 497
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: Extract ZIP to RAM?

11 Jan 2020, 16:12

teadrinker wrote:
11 Jan 2020, 15:14
hasantr wrote: is there a way to put the file into memory and make the extension look like a zip?
No. :) In memory files have no extensions at all.
It didn't make any sense to me either. :)
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

12 Jan 2020, 15:19

The code for 7-zip32.dll/7-zip64.dll:

Code: Select all

#MaxMem 4095
SetBatchLines, -1

zipFile := A_Desktop . "\test.7z"
pathInsideZip := "Folder\SubFolder\test.txt"
7ZipDLL := "7-zip" . A_PtrSize*8 . ".dll"

if !FileExist(7ZipDLL) {
   MsgBox, %7ZipDLL% not found
   ExitApp
}

size := GetFileSize(zipFile, pathInsideZip, 7ZipDLL)
script := CreateScript(zipFile, pathInsideZip, 7ZipDLL)
DynaRunReadStdOutToBuff(script, buff, size)
MsgBox, % StrGet(&buff, "cp0")

CreateScript(zipFile, pathInsideZip, 7ZipDLL) {
   script =
   (
   #NoTrayIcon
   7ZipDLL := "%7ZipDLL%"
   zipFile := "%zipFile%"
   pathInsideZip := "%pathInsideZip%"
   If !hModule := DllCall("LoadLibrary", "Str", 7ZipDLL, "Ptr")
      Throw, "LoadLibrary fail"

   ret := 7Zip_SevenZip(7ZipDLL, "e -hide """ . zipFile . """ """ . pathInsideZip . """ -so")
   DllCall("FreeLibrary", "Ptr", hModule)

   if (ret ~= "i)error|no files")
      MsgBox, `% ret
   ExitApp

   7Zip_SevenZip(7ZipDLL, sCommand) {
      nSize := 1024
      VarSetCapacity(tOutBuffer, nSize)
      res := DllCall(7ZipDLL . "\SevenZip", "Ptr", hWnd, "AStr", sCommand, "Ptr", &tOutBuffer, "Int", nSize)
      return StrGet(&tOutBuffer, nSize, "CP0") . (res != 0 ? "``n``nResult: " . res : "")
   }
   )
   Return script
}

GetFileSize(zipFile, pathInsideZip, 7ZipDLL) {
   if !hModule := DllCall("Kernel32.dll\LoadLibrary", "Str", 7ZipDLL, "Ptr")
      Throw, "LoadLibrary fail"
   hArc := DllCall(7ZipDLL . "\SevenZipOpenArchive", "Ptr", 0, "AStr", zipFile, "Int", 0)
   VarSetCapacity(INDIVIDUALINFO, 558, 0)
   DllCall(7ZipDLL . "\SevenZipFindFirst", "Ptr", hArc, "AStr", pathInsideZip, "Ptr", &INDIVIDUALINFO)
   DllCall(7ZipDLL . "\SevenZipCloseArchive", "Ptr", hArc)
   DllCall("FreeLibrary", "Ptr", hModule)
   Return NumGet(INDIVIDUALINFO, "UInt")
}

DynaRunReadStdOutToBuff(script, ByRef buff, buffSize := 0)
{
   static HANDLE_FLAG_INHERIT := 0x00000001, flags := HANDLE_FLAG_INHERIT
        , STARTF_USESTDHANDLES := 0x100, CREATE_NO_WINDOW := 0x08000000
        , params := [ "UInt", PIPE_ACCESS_OUTBOUND     := 0x2, "UInt", 0
                    , "UInt", PIPE_UNLIMITED_INSTANCES := 255, "UInt", 0
                    , "UInt", 0, "Ptr", 0, "Ptr", 0, "Ptr" ]
        , BOM := Chr(0xFEFF)
        , HEAP_ZERO_MEMORY := 0x8
        , hHeap := DllCall("GetProcessHeap", "Ptr")
  
   DllCall("CreatePipe", "PtrP", hPipeRead, "PtrP", hPipeWrite, "Ptr", 0, "UInt", buffSize)
   DllCall("SetHandleInformation", "Ptr", hPipeWrite, "UInt", flags, "UInt", HANDLE_FLAG_INHERIT)
   
   VarSetCapacity(STARTUPINFO , siSize :=    A_PtrSize*4 + 4*8 + A_PtrSize*5, 0)
   NumPut(siSize              , STARTUPINFO)
   NumPut(STARTF_USESTDHANDLES, STARTUPINFO, A_PtrSize*4 + 4*7)
   NumPut(hPipeWrite          , STARTUPINFO, A_PtrSize*4 + 4*8 + A_PtrSize*3)
   NumPut(hPipeWrite          , STARTUPINFO, A_PtrSize*4 + 4*8 + A_PtrSize*4)
   
   VarSetCapacity(PROCESS_INFORMATION, A_PtrSize*2 + 4*2, 0)
   
   pipeName := "AHK_" . A_TickCount
   for k, v in ["pipeGA", "pipe"]
      %v% := DllCall("CreateNamedPipe", "Str", "\\.\pipe\" . pipeName, params*)
   
   sCmd := A_AhkPath . " ""\\.\pipe\" . pipeName . """"
      
   if !DllCall("CreateProcess", "UInt", 0, "Str", sCmd, "UInt", 0, "UInt", 0, "Int", true, "UInt", CREATE_NO_WINDOW
                              , "UInt", 0, "UInt", 0, "Ptr", &STARTUPINFO, "Ptr", &PROCESS_INFORMATION)
   {
      DllCall("CloseHandle", "Ptr", hPipeRead)
      DllCall("CloseHandle", "Ptr", hPipeWrite)
      for k, v in ["pipeGA", "pipe"]
         DllCall("CloseHandle", "Ptr", %v%)
      throw Exception("CreateProcess is failed")
   }
   DllCall("CloseHandle", "Ptr", hPipeWrite)
   for k, v in ["pipeGA", "pipe"]
      DllCall("ConnectNamedPipe", "Ptr", %v%, "Ptr", 0)
   tempScript := BOM . script
   tempScriptSize := ( StrLen(tempScript) + 1 ) << !!A_IsUnicode
   DllCall("WriteFile", "Ptr", pipe, "Str", tempScript, "UInt", tempScriptSize, "UIntP", 0, "Ptr", 0)
   
   for k, v in ["pipeGA", "pipe"]
      DllCall("CloseHandle", "Ptr", %v%)
   
   nSize := fullSize := 0, heapSize := buffSize = 0 ? 4096 : buffSize
   pHeap := DllCall("HeapAlloc", "Ptr", hHeap, "UInt", HEAP_ZERO_MEMORY, "Ptr", heapSize, "Ptr")
   Loop {
      Sleep, 10
      DllCall("PeekNamedPipe", "Ptr", hPipeRead, "Ptr", 0, "UInt", 0, "Ptr", 0, "UIntP", avail, "Ptr", 0)
   } until (buffSize && avail = buffSize) || (!buffSize && avail) || A_Index = 100
   
   while DllCall("ReadFile", "Ptr", hPipeRead, "Ptr", pHeap + fullSize, "UInt", heapSize, "UIntP", nSize, "UInt", 0) {
      fullSize += nSize
      if (fullSize > heapSize - nSize) {
         heapSize *= 2
         pHeap := DllCall("HeapReAlloc", "Ptr", hHeap, "UInt", HEAP_ZERO_MEMORY, "Ptr", pHeap, "Ptr", heapSize, "Ptr")
      }
   }
   DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION))
   DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION, A_PtrSize))
   DllCall("CloseHandle", "Ptr", hPipeRead)
   VarSetCapacity(buff, fullSize)
   DllCall("RtlMoveMemory", "Ptr", &buff, "Ptr", pHeap, "Ptr", fullSize)
   DllCall("HeapFree", "Ptr", hHeap, "UInt", 0, "Ptr", pHeap)
   Return fullSize
}
To prevent crashes I launch the extraction as another process and read its StdOut to the buffer.
I used not modified 7-zip.dll.
User avatar
hasantr
Posts: 497
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: Extract ZIP to RAM?

13 Jan 2020, 01:43

teadrinker wrote:
12 Jan 2020, 15:19
The code for 7-zip32.dll/7-zip64.dll:

Code: Select all

#MaxMem 4095
SetBatchLines, -1

zipFile := A_Desktop . "\test.7z"
pathInsideZip := "Folder\SubFolder\test.txt"
7ZipDLL := "7-zip" . A_PtrSize*8 . ".dll"

if !FileExist(7ZipDLL) {
   MsgBox, %7ZipDLL% not found
   ExitApp
}

size := GetFileSize(zipFile, pathInsideZip, 7ZipDLL)
script := CreateScript(zipFile, pathInsideZip, 7ZipDLL)
DynaRunReadStdOutToBuff(script, buff, size)
MsgBox, % StrGet(&buff, "cp0")

CreateScript(zipFile, pathInsideZip, 7ZipDLL) {
   script =
   (
   #NoTrayIcon
   7ZipDLL := "%7ZipDLL%"
   zipFile := "%zipFile%"
   pathInsideZip := "%pathInsideZip%"
   If !hModule := DllCall("LoadLibrary", "Str", 7ZipDLL, "Ptr")
      Throw, "LoadLibrary fail"

   ret := 7Zip_SevenZip(7ZipDLL, "e -hide """ . zipFile . """ """ . pathInsideZip . """ -so")
   DllCall("FreeLibrary", "Ptr", hModule)

   if (ret ~= "i)error|no files")
      MsgBox, `% ret
   ExitApp

   7Zip_SevenZip(7ZipDLL, sCommand) {
      nSize := 1024
      VarSetCapacity(tOutBuffer, nSize)
      res := DllCall(7ZipDLL . "\SevenZip", "Ptr", hWnd, "AStr", sCommand, "Ptr", &tOutBuffer, "Int", nSize)
      return StrGet(&tOutBuffer, nSize, "CP0") . (res != 0 ? "``n``nResult: " . res : "")
   }
   )
   Return script
}

GetFileSize(zipFile, pathInsideZip, 7ZipDLL) {
   if !hModule := DllCall("Kernel32.dll\LoadLibrary", "Str", 7ZipDLL, "Ptr")
      Throw, "LoadLibrary fail"
   hArc := DllCall(7ZipDLL . "\SevenZipOpenArchive", "Ptr", 0, "AStr", zipFile, "Int", 0)
   VarSetCapacity(INDIVIDUALINFO, 558, 0)
   DllCall(7ZipDLL . "\SevenZipFindFirst", "Ptr", hArc, "AStr", pathInsideZip, "Ptr", &INDIVIDUALINFO)
   DllCall(7ZipDLL . "\SevenZipCloseArchive", "Ptr", hArc)
   DllCall("FreeLibrary", "Ptr", hModule)
   Return NumGet(INDIVIDUALINFO, "UInt")
}

DynaRunReadStdOutToBuff(script, ByRef buff, buffSize := 0)
{
   static HANDLE_FLAG_INHERIT := 0x00000001, flags := HANDLE_FLAG_INHERIT
        , STARTF_USESTDHANDLES := 0x100, CREATE_NO_WINDOW := 0x08000000
        , params := [ "UInt", PIPE_ACCESS_OUTBOUND     := 0x2, "UInt", 0
                    , "UInt", PIPE_UNLIMITED_INSTANCES := 255, "UInt", 0
                    , "UInt", 0, "Ptr", 0, "Ptr", 0, "Ptr" ]
        , BOM := Chr(0xFEFF)
        , HEAP_ZERO_MEMORY := 0x8
        , hHeap := DllCall("GetProcessHeap", "Ptr")
  
   DllCall("CreatePipe", "PtrP", hPipeRead, "PtrP", hPipeWrite, "Ptr", 0, "UInt", buffSize)
   DllCall("SetHandleInformation", "Ptr", hPipeWrite, "UInt", flags, "UInt", HANDLE_FLAG_INHERIT)
   
   VarSetCapacity(STARTUPINFO , siSize :=    A_PtrSize*4 + 4*8 + A_PtrSize*5, 0)
   NumPut(siSize              , STARTUPINFO)
   NumPut(STARTF_USESTDHANDLES, STARTUPINFO, A_PtrSize*4 + 4*7)
   NumPut(hPipeWrite          , STARTUPINFO, A_PtrSize*4 + 4*8 + A_PtrSize*3)
   NumPut(hPipeWrite          , STARTUPINFO, A_PtrSize*4 + 4*8 + A_PtrSize*4)
   
   VarSetCapacity(PROCESS_INFORMATION, A_PtrSize*2 + 4*2, 0)
   
   pipeName := "AHK_" . A_TickCount
   for k, v in ["pipeGA", "pipe"]
      %v% := DllCall("CreateNamedPipe", "Str", "\\.\pipe\" . pipeName, params*)
   
   sCmd := A_AhkPath . " ""\\.\pipe\" . pipeName . """"
      
   if !DllCall("CreateProcess", "UInt", 0, "Str", sCmd, "UInt", 0, "UInt", 0, "Int", true, "UInt", CREATE_NO_WINDOW
                              , "UInt", 0, "UInt", 0, "Ptr", &STARTUPINFO, "Ptr", &PROCESS_INFORMATION)
   {
      DllCall("CloseHandle", "Ptr", hPipeRead)
      DllCall("CloseHandle", "Ptr", hPipeWrite)
      for k, v in ["pipeGA", "pipe"]
         DllCall("CloseHandle", "Ptr", %v%)
      throw Exception("CreateProcess is failed")
   }
   DllCall("CloseHandle", "Ptr", hPipeWrite)
   for k, v in ["pipeGA", "pipe"]
      DllCall("ConnectNamedPipe", "Ptr", %v%, "Ptr", 0)
   tempScript := BOM . script
   tempScriptSize := ( StrLen(tempScript) + 1 ) << !!A_IsUnicode
   DllCall("WriteFile", "Ptr", pipe, "Str", tempScript, "UInt", tempScriptSize, "UIntP", 0, "Ptr", 0)
   
   for k, v in ["pipeGA", "pipe"]
      DllCall("CloseHandle", "Ptr", %v%)
   
   nSize := fullSize := 0, heapSize := buffSize = 0 ? 4096 : buffSize
   pHeap := DllCall("HeapAlloc", "Ptr", hHeap, "UInt", HEAP_ZERO_MEMORY, "Ptr", heapSize, "Ptr")
   Loop {
      Sleep, 10
      DllCall("PeekNamedPipe", "Ptr", hPipeRead, "Ptr", 0, "UInt", 0, "Ptr", 0, "UIntP", avail, "Ptr", 0)
   } until (buffSize && avail = buffSize) || (!buffSize && avail) || A_Index = 100
   
   while DllCall("ReadFile", "Ptr", hPipeRead, "Ptr", pHeap + fullSize, "UInt", heapSize, "UIntP", nSize, "UInt", 0) {
      fullSize += nSize
      if (fullSize > heapSize - nSize) {
         heapSize *= 2
         pHeap := DllCall("HeapReAlloc", "Ptr", hHeap, "UInt", HEAP_ZERO_MEMORY, "Ptr", pHeap, "Ptr", heapSize, "Ptr")
      }
   }
   DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION))
   DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION, A_PtrSize))
   DllCall("CloseHandle", "Ptr", hPipeRead)
   VarSetCapacity(buff, fullSize)
   DllCall("RtlMoveMemory", "Ptr", &buff, "Ptr", pHeap, "Ptr", fullSize)
   DllCall("HeapFree", "Ptr", hHeap, "UInt", 0, "Ptr", pHeap)
   Return fullSize
}
To prevent crashes I launch the extraction as another process and read its StdOut to the buffer.
I used not modified 7-zip.dll.
Thanks. It's the solution for my application. But I want to use it in a single exe.

Could Masonjar have found a solution? Unfortunately, I don't understand these codes.
https://www.autohotkey.com/boards/viewtopic.php?f=76&t=5896&start=20
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

13 Jan 2020, 03:38

No it's not a solution.
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

13 Jan 2020, 05:40

This is the solution:

Code: Select all

#MaxMem 4095
SetBatchLines, -1

zipFile := A_ScriptDir . "\test.7z"
pathInsideZip := "Folder\SubFolder\test.txt"
7ZipDLL := "7-zip" . A_PtrSize*8 . ".dll"

7zip := new 7zipToBuff(7ZipDLL, zipFile, pathInsideZip)
7zip.UnzipToBuff(buff)
output := 7zip.output
7zip := ""
MsgBox, % output
MsgBox, % Clipboard := StrGet(&buff, "cp0")

class 7zipToBuff {
   __New(7ZipDLL, zipFile, pathInsideZip) {
      static STD_OUTPUT_HANDLE := -11, DUPLICATE_SAME_ACCESS := 0x2
      
      if !FileExist(7ZipDLL)
         throw 7ZipDLL . " not found"
      if !this.hModule := DllCall("LoadLibrary", "Str", 7ZipDLL, "Ptr")
         throw "LoadLibrary failed"
      
      this.7ZipDLL := 7ZipDLL
      this.zipFile := zipFile
      this.pathInsideZip := pathInsideZip
      
      this.savedStdOut := DllCall("GetStdHandle", "UInt", STD_OUTPUT_HANDLE, "Ptr")
      this.buffSize := this.GetBuffSize()
      
      DllCall("CreatePipe", "PtrP", hReadTemp, "PtrP", hPipeWrite, "Ptr", 0, "UInt", this.buffSize)
      hProc := DllCall("GetCurrentProcess")
      DllCall("DuplicateHandle", "Ptr", hProc, "Ptr", hReadTemp, "Ptr", hProc, "PtrP", hReadPipe, "UInt", 0, "UInt", false, "UInt", DUPLICATE_SAME_ACCESS)
      this.hReadPipe := hReadPipe
      DllCall("CloseHandle", "Ptr", hReadTemp)
      DllCall("SetStdHandle", "UInt", STD_OUTPUT_HANDLE, "Ptr", hPipeWrite)
      this.saved_stdout := DllCall("msvcrt\_dup", "Int", 1)
      this.fd := DllCall("msvcrt\_open_osfhandle", "Ptr", DllCall("GetStdHandle", "UInt", STD_OUTPUT_HANDLE, "Ptr"), "Int", 0)
      DllCall("msvcrt\_dup2", "Int", this.fd, "Int", 1)
   }
   
   __Delete() {
      DllCall("FreeLibrary", "Ptr", this.hModule)
      DllCall("msvcrt\_dup2", "Int", this.saved_stdout, "Int", 1)
      DllCall("msvcrt\_close", "Int", this.fd)
      DllCall("SetStdHandle", "UInt", STD_OUTPUT_HANDLE := -11, "Ptr", this.savedStdOut)
   }
   
   UnzipToBuff(ByRef buff) {
      VarSetCapacity(buff, this.buffSize)
      this.output := this.SevenZip("e -hide """ . this.zipFile . """ """ . this.pathInsideZip . """ -so")
      Loop {
         Sleep, 10
         DllCall("PeekNamedPipe", "Ptr", this.hReadPipe, "Ptr", 0, "UInt", 0, "Ptr", 0, "UIntP", avail, "Ptr", 0)
      } until avail = this.buffSize || A_Index = 100

      fullSize := 0
      Loop {
         res := DllCall("ReadFile", "Ptr", this.hReadPipe, "Ptr", &buff + fullSize, "UInt", this.buffSize, "UIntP", nSize, "UInt", 0)
         fullSize += nSize
      } until !res || fullSize = this.buffSize
   }
   
   GetBuffSize() {
      hArc := DllCall(this.7ZipDLL . "\SevenZipOpenArchive", "Ptr", 0, "AStr", this.zipFile, "Int", 0)
      VarSetCapacity(INDIVIDUALINFO, 558, 0)
      DllCall(this.7ZipDLL . "\SevenZipFindFirst", "Ptr", hArc, "AStr", this.pathInsideZip, "Ptr", &INDIVIDUALINFO)
      DllCall(this.7ZipDLL . "\SevenZipCloseArchive", "Ptr", hArc)
      Return NumGet(INDIVIDUALINFO, "UInt")
   }
   
   SevenZip(sCommand) {
      VarSetCapacity(output, size := 1024)
      res := DllCall(this.7ZipDLL . "\SevenZip", "Ptr", 0, "AStr", sCommand, "Ptr", &output, "Int", size)
      return StrGet(&output, nSize, "CP0")
   }
}
teadrinker
Posts: 1643
Joined: 29 Mar 2015, 09:41
Contact:

Re: Extract ZIP to RAM?

13 Jan 2020, 06:06

Ha-ha, also freezes on double click :lol:

Return to “Ask For Help”

Who is online

Users browsing this forum: artur1884, boiler, Google [Bot], marqqer, pirron, RubbeH and 65 guests