AHK_H v1.1.33.2 Compiled file doesn't handle the large script

Post AHK_H specific scripts & libraries and discuss the usage and development of HotKeyIt's fork/branch
teadrinker
Posts: 4325
Joined: 29 Mar 2015, 09:41
Contact:

AHK_H v1.1.33.2 Compiled file doesn't handle the large script

Post by teadrinker » 10 Feb 2021, 12:05

I need to load the dll from the resource, so I use Class _MemoryLibrary, Class _Struct and sizeof(), and the whole script is pretty large. The uncompiled script works (I read the dll using File.RawRead()), but the compiled script (dll is added to resource using @Ahk2Exe-AddResource) produces the error:
 
 Image
 
What may be the issue?
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: AHK_H v1.1.33.2 Compiled file doesn't handle the large script

Post by HotKeyIt » 10 Feb 2021, 18:14

Why don't you use AhkThread?
How do you read the dll from resource? The error must be here!
teadrinker
Posts: 4325
Joined: 29 Mar 2015, 09:41
Contact:

Re: AHK_H v1.1.33.2 Compiled file doesn't handle the large script

Post by teadrinker » 11 Feb 2021, 06:15

HotKeyIt wrote: Why don't you use AhkThread?
The dll is not AutoHotkey.dll.
HotKeyIt wrote: How do you read the dll from resource?

Code: Select all

ExtractResource(filePath, resourceName, ByRef buff)
{
   static LOAD_LIBRARY_AS_DATAFILE := 0x00000002, RT_RCDATA := "#10"
   if (filePath = "")
      hMod := 0
   else if !hMod := DllCall("LoadLibraryEx", "Str", filePath, "Ptr", 0, "UInt", LOAD_LIBRARY_AS_DATAFILE, "Ptr")
      throw "Failed to load file"
   if !hRes := DllCall("FindResource", "Ptr", hMod, "Str", resourceName, "Str", RT_RCDATA, "Ptr")
      throw "FindResource failed, error: " . A_LastError
   hData  := DllCall("LoadResource", "Ptr", hMod, "Ptr", hRes, "Ptr")
   szData := DllCall("SizeofResource", "Ptr", hMod, "Ptr", hRes)
   pData  := DllCall("LockResource", "Ptr", hData, "Ptr")
   VarSetCapacity(buff, szData, 0)
   DllCall("RtlMoveMemory", "Ptr", &buff, "Ptr", pData, "Ptr", szData)
   DllCall("FreeLibrary", "Ptr", hMod)
   Return szData
}
Also I tested with ResGet.ahk.
My script:

Code: Select all

;@Ahk2Exe-AddResource zlib1.dll

#NoEnv
SetBatchLines, -1
#Include <_MemoryLibrary>
; #Include D:\Downloads\ahkdll-v1-release-master\Compiler\Lib\ResGet.ahk

size := CreateScreenshot(50, buff)

len := GetZlibBuff(zlib)

; ensure the extraction is correct
File := FileOpen(A_ScriptDir . "\zlib_from_resource.dll", "w")
File.RawWrite(zlib, len)
File.Close()

size := CompressData(&buff, size, compressed, &zlib)
VarSetCapacity(buff, 0), buff := ""

File := FileOpen(A_ScriptDir . "\compressed.jpg", "w", "cp0")
File.RawWrite(compressed, size)
File.Close()
VarSetCapacity(compressed, 0), compressed := ""
ExitApp

GetZlibBuff(ByRef zlib) {
   if A_IsCompiled
      len := ExtractResource("", "ZLIB1.DLL", zlib)
      ; len := ResGet(zlib, A_AhkPath, "ZLIB1.DLL")
   else {
      File := FileOpen("zlib1.dll", "r")
      len := File.RawRead(zlib, File.Length)
      File.Close()
      if !len
         throw "Failed to read dll"
   }
   Return len
}

CompressData(pData, dataSize, ByRef outData, pZLib, compress := true) {
   ZL := new ZlibCompression(pZLib)
   size := ZL.Compression(pData, dataSize, outData, "deflate")
   Return size
}

ExtractResource(filePath, resourceName, ByRef buff)
{
   static LOAD_LIBRARY_AS_DATAFILE := 0x00000002, RT_RCDATA := "#10"
   if (filePath = "")
      hMod := 0
   else if !hMod := DllCall("LoadLibraryEx", "Str", filePath, "Ptr", 0, "UInt", LOAD_LIBRARY_AS_DATAFILE, "Ptr")
      throw "Failed to load file"
   if !hRes := DllCall("FindResource", "Ptr", hMod, "Str", resourceName, "Str", RT_RCDATA, "Ptr")
      throw "FindResource failed, error: " . A_LastError
   hData  := DllCall("LoadResource", "Ptr", hMod, "Ptr", hRes, "Ptr")
   szData := DllCall("SizeofResource", "Ptr", hMod, "Ptr", hRes)
   pData  := DllCall("LockResource", "Ptr", hData, "Ptr")
   VarSetCapacity(buff, szData, 0)
   DllCall("RtlMoveMemory", "Ptr", &buff, "Ptr", pData, "Ptr", szData)
   DllCall("FreeLibrary", "Ptr", hMod)
   Return szData
}

CreateScreenshot(jpgQuality, ByRef buff) {
   hBitmap := HBitmapFromScreen(0, 0, A_ScreenWidth, A_ScreenHeight)
   Gdip := new GDIplus
   pBitmap := Gdip.CreateBitmapFromHBITMAP(hBitmap)
   size := Gdip.SaveBitmap(pBitmap, buff := "jpg", jpgQuality, true)
   DllCall("DeleteObject", "Ptr", hBitmap)
   Gdip.DisposeImage(pBitmap)
   Return size
}

HBitmapFromScreen(X, Y, W, H) {
   static SRCCOPY := 0x00CC0020
   HDC := DllCall("GetDC", "Ptr", 0, "UPtr")
   HBM := DllCall("CreateCompatibleBitmap", "Ptr", HDC, "Int", W, "Int", H, "UPtr")
   PDC := DllCall("CreateCompatibleDC", "Ptr", HDC, "UPtr")
   DllCall("SelectObject", "Ptr", PDC, "Ptr", HBM)
   DllCall("BitBlt", "Ptr", PDC, "Int", 0, "Int", 0, "Int", W, "Int", H
                   , "Ptr", HDC, "Int", X, "Int", Y, "UInt", SRCCOPY)
   DllCall("DeleteDC", "Ptr", PDC)
   DllCall("ReleaseDC", "Ptr", 0, "Ptr", HDC)
   Return HBM
}

class ZlibCompression
{
/*                                                         
https://www.zlib.net/manual.html
http://refspecs.linuxbase.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/zlib-deflateinit2.html
http://refspecs.linuxbase.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/zlib-inflateinit2.html
*/
   __New(pZlib) {
      this.zlib := new _MemoryLibrary(pZlib)
   }
   
   __Delete() {
      if (this.zlib.MM.init = 1)
         this.zlib.Free()
   }

   Compression(pData, length, ByRef out, action)  ; actions: compress   — "deflate" or true
   {                                              ;          decompress — "inflate" or false
      static MAX_MEM_LEVEL := 9, Z_DEFLATED := 8, Z_DEFAULT_STRATEGY := 0
           , MAX_WBITS := 15, Z_OK := 0, Z_FINISH := 4, Z_STREAM_END := 1
           , errors := [ "Z_ERRNO"    , "Z_STREAM_ERROR", "Z_DATA_ERROR"
                       , "Z_MEM_ERROR", "Z_BUF_ERROR"   , "Z_VERSION_ERROR" ]
           , level := 9
      
      b := action ~= "i)1|de"
      VarSetCapacity(out, outMaxLen := length*(b ? 2 : 20), 0)
      VarSetCapacity(z_stream_s, szStream := 24 + 8*A_PtrSize, 0)
      NumPut(pData    , z_stream_s)
      NumPut(length   , z_stream_s, A_PtrSize, "UInt")
      NumPut(&out     , z_stream_s, A_PtrSize + 8)
      NumPut(outMaxLen, z_stream_s, A_PtrSize + 8 + A_PtrSize, "UInt")
      
      params := ["Int", 16 + MAX_WBITS, "AStr", "1", "Int", szStream]
      if b {
         params.InsertAt(3, "Int", MAX_MEM_LEVEL, "Int", Z_DEFAULT_STRATEGY)
         params.InsertAt(1, "Int", level, "Int", Z_DEFLATED)
      }
      Loop 1 {
         res := DllCall(this.zlib.GetProcAddress( (b ? "de" : "in") . "flateInit2_" ), Ptr, &z_stream_s, params*)
         if ( res != Z_OK && error := (b ? "de" : "in") . "flateInit2_: " . errors[-res] )
            break
         
         res := DllCall(this.zlib.GetProcAddress( (b ? "de" : "in") . "flate" ), Ptr, &z_stream_s, Int, Z_FINISH)
         if ( res != Z_STREAM_END && error := (b ? "de" : "in") . "flate: " . errors[-res] )
            break
         
         res := DllCall(this.zlib.GetProcAddress( (b ? "de" : "in") . "flateEnd" ), Ptr, &z_stream_s)
         ( res != Z_OK    && error := (b ? "de" : "in") . "flateEnd: " . errors[-res] )
      }
      if error
         throw Exception(error)
      Return outLen := NumGet(z_stream_s, A_PtrSize + 8 + A_PtrSize + 4, "UInt")
   }
}

class GDIplus  {
   __New() {
      if !DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
         DllCall("LoadLibrary", "Str", "gdiplus")
      VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
      DllCall("gdiplus\GdiplusStartup", "UPtrP", pToken, "Ptr", &si, "Ptr", 0)
      this.token := pToken
   }
   
   __Delete()  {
      DllCall("gdiplus\GdiplusShutdown", "Ptr", this.token)
      if hModule := DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
         DllCall("FreeLibrary", "Ptr", hModule)
   }

   CreateBitmapFromHBITMAP(hBitmap, Palette=0)  {
      DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "Ptr", hBitmap, "Ptr", Palette, "PtrP", pBitmap)
      return pBitmap
   }

   SaveBitmap(pBitmap, ByRef info, Quality := 75, tobuff := "")
   {
      ; info — если копируем в буфер, тогда расширение файла, если в файл, тогда путь к файлу
      if tobuff
         Extension := info
      else
         SplitPath, info,,, Extension
      if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
         return -1

      DllCall("gdiplus\GdipGetImageEncodersSize", "UIntP", nCount, "UIntP", nSize)
      VarSetCapacity(ci, nSize)
      DllCall("gdiplus\GdipGetImageEncoders", "UInt", nCount, "UInt", nSize, "Ptr", &ci)
      if !(nCount && nSize)
         return -2
      
      Loop, % nCount  {
         sString := StrGet(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
         if !InStr(sString, "*." Extension)
            continue
         
         pCodec := &ci+idx
         break
      }
      
      if !pCodec
         return -3
      
      if RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75  {
         DllCall("gdiplus\GdipGetEncoderParameterListSize", "Ptr", pBitmap, "Ptr", pCodec, "UIntP", nSize)
         VarSetCapacity(EncoderParameters, nSize, 0)
         DllCall("gdiplus\GdipGetEncoderParameterList", "Ptr", pBitmap, "Ptr", pCodec, "UInt", nSize, "Ptr", &EncoderParameters)
         Loop, % NumGet(EncoderParameters, "UInt")
         {
            elem := (24+A_PtrSize)*(A_Index-1) + 4 + (pad := A_PtrSize = 8 ? 4 : 0)
            if (NumGet(EncoderParameters, elem+16, "UInt") = 1) && (NumGet(EncoderParameters, elem+20, "UInt") = 6)
            {
               p := elem+&EncoderParameters-pad-4
               NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20, "UInt")), "UInt")
               break
            }
         }      
      }
      if !tobuff
         E := DllCall("gdiplus\GdipSaveImageToFile", "Ptr", pBitmap, "WStr", info, "Ptr", pCodec, "UInt", p ? p : 0)
      else  {
         DllCall( "ole32\CreateStreamOnHGlobal", "UInt", 0, "Int", 1, "PtrP", pStream )
         if !E := DllCall( "gdiplus\GdipSaveImageToStream", "Ptr", pBitmap, "Ptr", pStream, "Ptr", pCodec, "UInt", p ? p : 0 )  {
            DllCall( "ole32\GetHGlobalFromStream", "Ptr", pStream, "PtrP", hData )
            pData := DllCall( "GlobalLock", "Ptr", hData, "Ptr" )
            nSize := DllCall( "GlobalSize", "Ptr", hData, "Ptr" )
            VarSetCapacity( info, 0), VarSetCapacity( info, nSize, 0 )
            DllCall( "RtlMoveMemory", "Ptr", &info, "Ptr", pData, "Ptr", nSize )
            DllCall( "GlobalUnlock", "Ptr", hData )
            DllCall( "GlobalFree", "Ptr", hData )
         }
         ObjRelease(pStream)
      }
      return E ? -4 : tobuff ? nSize : 0
   }
   
   DisposeImage(pBitmap)  {
      return DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
   }
}
This script creates a screenshot, then compresses it using zlib1.dll and writes in the script directory.
I know that there is another way to do the same (ZipRawMemory), but in this case I'd like to ensure, that the issue is related/not related to the script size.
I tried to compile with the AHK_L interpreter, the script worked correctly.
zlib1.dll (64 bit) is in the attachment.
Attachments
zlib1.zip
(46.66 KiB) Downloaded 91 times
teadrinker
Posts: 4325
Joined: 29 Mar 2015, 09:41
Contact:

Re: AHK_H v1.1.33.2 Compiled file doesn't handle the large script

Post by teadrinker » 14 Feb 2021, 10:12

@HotKeyIt
Another observation. My script works, when it's compiled with AHK_H v1.1.30.00. There is a difference: the resource is encrypted in it, while it is not encrypted in AHK_H v1.1.33.2, in both cases the resource was added using ;@Ahk2Exe-AddResource directive.
Post Reply

Return to “AutoHotkey_H”