Page 2 of 4

Re: Extract ZIP to RAM?

Posted: 21 Nov 2019, 23:10
by tmplinshi
@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?

Re: Extract ZIP to RAM?

Posted: 22 Nov 2019, 01:09
by hasantr
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

Re: Extract ZIP to RAM?

Posted: 22 Nov 2019, 01:43
by tmplinshi
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.

Re: Extract ZIP to RAM?

Posted: 10 Jan 2020, 10:34
by teadrinker
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
   }
}

Re: Extract ZIP to RAM?

Posted: 10 Jan 2020, 12:19
by teadrinker
For some reason currently works only for 64-bit AHK.

Re: Extract ZIP to RAM?

Posted: 10 Jan 2020, 13:06
by malcev

Re: Extract ZIP to RAM?

Posted: 10 Jan 2020, 13:32
by teadrinker
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.

Re: Extract ZIP to RAM?

Posted: 10 Jan 2020, 14:31
by TheDewd
@teadrinker,

Amazing work! It does a great job. Now just need a way to do the same with 7-Zip compressed archives.

Re: Extract ZIP to RAM?

Posted: 10 Jan 2020, 16:18
by teadrinker
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.

Re: Extract ZIP to RAM?

Posted: 10 Jan 2020, 16:24
by TheDewd
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.

Re: Extract ZIP to RAM?

Posted: 11 Jan 2020, 06:07
by hasantr
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)

Re: Extract ZIP to RAM?

Posted: 11 Jan 2020, 09:08
by teadrinker
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")

Re: Extract ZIP to RAM?

Posted: 11 Jan 2020, 14:00
by hasantr
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.

Re: Extract ZIP to RAM?

Posted: 11 Jan 2020, 15:14
by teadrinker
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.

Re: Extract ZIP to RAM?

Posted: 11 Jan 2020, 16:12
by hasantr
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. :)

Re: Extract ZIP to RAM?

Posted: 12 Jan 2020, 15:19
by teadrinker
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.

Re: Extract ZIP to RAM?

Posted: 13 Jan 2020, 01:43
by hasantr
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

Re: Extract ZIP to RAM?

Posted: 13 Jan 2020, 03:38
by teadrinker
No it's not a solution.

Re: Extract ZIP to RAM?

Posted: 13 Jan 2020, 05:40
by teadrinker
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")
   }
}

Re: Extract ZIP to RAM?

Posted: 13 Jan 2020, 06:06
by teadrinker
Ha-ha, also freezes on double click :lol: