Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Crazy Scripting : Resource-Only DLL for Dummies - 36L / v0.7


  • Please log in to reply
71 replies to this topic
SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

how to get GDI+ to use the font without actually extracting it from the DLL


Load & Call ( RCDATA ) a TrueType Font for Private use:

#SingleInstance, Force
SetWorkingDir %A_ScriptDir%
Gui, Margin, 0, 0
Gui, Color, 202020

IfNotExist, Wicked.dll, URLDownloadToFile
                      , http://dl.dropbox.com/u/6428211/Sample/wicked.dll, Wicked.dll

; Step 1 : Load the data from DLL
[color=darkred]nSize[/color] := DllRead( [color=darkred]Buffer[/color], "Wicked.dll", "Fonts", "DS-DIGIB.TTF" )

; Step 2 : Load the font for private use. ( No other application can get an handle to it )
DllCall( "AddFontMemResourceEx", UInt,&[color=darkred]Buffer[/color], UInt,[color=darkred]nSize[/color], Int,0, UIntP,n )

; Step 3 : Obtain handle to the above loaded font. ( You need to know the [color=orange]Font name[/color] )
[color=Indigo]hFont[/color] := GDI_ModifyFont( 0, "FontFace=[color=Orange]DS-Digital Bold[/color], Height=72" )


; You may now use the above hFont with GDI+
; or use it with text controls like follows:

Gui, Add, Text, w520 h90 hwndhText cFEFEFE Center, AutoHotkey
SendMessage, 0x30, hFont, ,, ahk_id %hText% ; WM_SETFONT
Gui, Show
Return


DllRead( ByRef Var, Filename, Section, Key ) {          ; Functionality and Parameters are
 VarSetCapacity( Var,128,0 ), VarSetCapacity( Var,0 )   ; identical to IniRead command ;-)
 If hMod := DllCall( "LoadLibrary", Str,Filename )
  If hRes := DllCall( "FindResource", UInt,hMod, Str,Key, Str,Section )
   If hData := DllCall( "LoadResource", UInt,hMod, UInt,hRes )
    If pData := DllCall( "LockResource", UInt,hData )
 Return VarSetCapacity( Var,nSize := DllCall( "SizeofResource", UInt,hMod, UInt,hRes ) )
     , DllCall( "RtlMoveMemory", UInt,&Var, UInt,pData, UInt,nSize )
     , VarSetCapacity( Var, -1 )
     , DllCall( "FreeLibrary", UInt,hMod )
Return 0, DllCall( "FreeLibrary", UInt,hMod )
}

; Copy Paste [color=red]GDI_ModifyFont()[/color] below       ; www.autohotkey.com/forum/viewtopic.php?t=80322


kWo4Lk1.png

Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
Thank you, SKAN!

I'm going to try and merge your solution with tic's.

Currently the method posted on tic's thread requires a font file to draw. I'm going to see if I can get it to draw straight from the DLL with the help you've provided.

Thanks!

3nL8f.png


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

the method posted on tic's thread requires a font file
to draw. I'm going to see if I can get it to draw straight from the DLL with the help you've provided.


To load FontData from DLL use:
DllRead( [color=red]FontData[/color], "Wicked.dll", "FONTS", "DS-DIGIB.TTF" )

You may then pass the variable FontData to the following modified version of Gdip_TextToGraphics_Private()

Gdip_TextToGraphics_Private(pGraphics, Text, Options, [color=red]ByRef[/color] [color=darkred]FontData[/color], Font, Width="", Height="", Measure=0)
{
; Original by thanh00 ( Closed ) ; www.autohotkey.com/forum/viewtopic.php?p=471381#471381
   IWidth := Width, IHeight:= Height

   RegExMatch(Options, "i)X([\-\d\.]+)(p*)", xpos)
   RegExMatch(Options, "i)Y([\-\d\.]+)(p*)", ypos)
   RegExMatch(Options, "i)W([\-\d\.]+)(p*)", Width)
   RegExMatch(Options, "i)H([\-\d\.]+)(p*)", Height)
   RegExMatch(Options, "i)C(?!(entre|enter))([a-f\d]+)", Colour)
   RegExMatch(Options, "i)Top|Up|Bottom|Down|vCentre|vCenter", vPos)
   RegExMatch(Options, "i)NoWrap", NoWrap)
   RegExMatch(Options, "i)R(\d)", Rendering)
   RegExMatch(Options, "i)S(\d+)(p*)", Size)

   if !Gdip_DeleteBrush(Gdip_CloneBrush(Colour2))
      PassBrush := 1, pBrush := Colour2

   if !(IWidth && IHeight) && (xpos2 || ypos2 || Width2 || Height2 || Size2)
      return -1

   Style := 0, Styles := "Regular|Bold|Italic|BoldItalic|Underline|Strikeout"
   Loop, Parse, Styles, |
   {
      if RegExMatch(Options, "\b" A_loopField)
      Style |= (A_LoopField != "StrikeOut") ? (A_Index-1) : 8
   }

   Align := 0, Alignments := "Near|Left|Centre|Center|Far|Right"
   Loop, Parse, Alignments, |
   {
      if RegExMatch(Options, "\b" A_loopField)
         Align |= A_Index//2.1      ; 0|0|1|1|2|2
   }

   xpos := (xpos1 != "") ? xpos2 ? IWidth*(xpos1/100) : xpos1 : 0
   ypos := (ypos1 != "") ? ypos2 ? IHeight*(ypos1/100) : ypos1 : 0
   Width := Width1 ? Width2 ? IWidth*(Width1/100) : Width1 : IWidth
   Height := Height1 ? Height2 ? IHeight*(Height1/100) : Height1 : IHeight
   if !PassBrush
      Colour := "0x" (Colour2 ? Colour2 : "ff000000")
   Rendering := ((Rendering1 >= 0) && (Rendering1 <= 5)) ? Rendering1 : 4
   Size := (Size1 > 0) ? Size2 ? IHeight*(Size1/100) : Size1 : 12

   DllCall("gdiplus\GdipNewPrivateFontCollection", "uint*", hcollection)


/*
[color=#808080]  if !A_IsUnicode
      {
      nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &FontFile, "int", -1, "uint", 0, "int", 0)
      VarSetCapacity(wFontFile, nSize*2)
         DllCall("kernel32\MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &FontFile, "int", -1, "uint", &wFontFile, "int", nSize)
         DllCall("gdiplus\GdipPrivateAddFontFile", "uint", hcollection, "uint", &wFontFile)
      }
      else
         DllCall("gdiplus\GdipPrivateAddFontFile", "uint", hcollection, "uint", &FontFile)
[/color]
*/

  DllCall("gdiplus\[color=darkred]GdipPrivateAddMemoryFont[/color]", "uint", hcollection, "uint", &[color=darkred]FontData[/color]
          , "uint",VarSetCapacity([color=darkred]FontData[/color]) )

     if !A_IsUnicode
   {
      nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &Font, "int", -1, "uint", 0, "int", 0)

      VarSetCapacity(wFont, nSize*2)
      DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &Font, "int", -1, "uint", &wFont, "int", nSize)
    error:=DllCall("gdiplus\GdipCreateFontFamilyFromName", "uint", &wFont, "uint", hcollection, "uint*", hFamily)
   }
   else
    DllCall("gdiplus\GdipCreateFontFamilyFromName", "uint", &Font, "uint", hcollection, "uint*", hFamily)

    DllCall("gdiplus\GdipCreateFont", "uint", hFamily, "float", Size, "int", Style, "int", 0, "uint*", hFont)

   FormatStyle := NoWrap ? 0x4000 | 0x1000 : 0x4000
   hFormat := Gdip_StringFormatCreate(FormatStyle)
   pBrush := PassBrush ? pBrush : Gdip_BrushCreateSolid(Colour)
   if !(hFamily && hFont && hFormat && pBrush && pGraphics)
      return !pGraphics ? -2 : !hFamily ? -3 : !hFont ? -4 : !hFormat ? -5 : !pBrush ? -6 : 0

   CreateRectF(RC, xpos, ypos, Width, Height)
   Gdip_SetStringFormatAlign(hFormat, Align)
   Gdip_SetTextRenderingHint(pGraphics, Rendering)
   ReturnRC := Gdip_MeasureString(pGraphics, Text, hFont, hFormat, RC)

   if vPos
   {
      StringSplit, ReturnRC, ReturnRC, |

      if (vPos = "vCentre") || (vPos = "vCenter")
         ypos += (Height-ReturnRC4)//2
      else if (vPos = "Top") || (vPos = "Up")
         ypos := 0
      else if (vPos = "Bottom") || (vPos = "Down")
         ypos := Height-ReturnRC4

      CreateRectF(RC, xpos, ypos, Width, ReturnRC4)
      ReturnRC := Gdip_MeasureString(pGraphics, Text, hFont, hFormat, RC)
   }

   if !Measure
      E := Gdip_DrawString(pGraphics, Text, hFont, hFormat, pBrush, RC)

   if !PassBrush
    Gdip_DeleteBrush(pBrush)
    Gdip_DeleteStringFormat(hFormat)
    Gdip_DeleteFont(hFont)
    Gdip_DeleteFontFamily(hFamily)
    DllCall("gdiplus\GdipDeletePrivateFontCollection", "uint*", hcollection)
   return E ? E : ReturnRC
}


Please try and let me know.

Wicked - Guest
  • Guests
  • Last active:
  • Joined: --
I'm travelling at the moment and posting this from an OnRoute stop, but will let you know once I get to Toronto for my appointment.

I will say, without even trying it, that you sir are a god. I've no doubt that you've pulled through once again.

Thanks so much for your time and help!

Klark92
  • Members
  • 870 posts
  • Last active: Dec 29 2015 09:47 PM
  • Joined: 19 Feb 2012
Hi Skan .. how to extract resource files by this code ? .. var only take string .. not binary files .. so I couldnt make something...

I CAN PROTECT YOUR SCRIPT (ANTI-DECOMPILER by Klark92) (AHK_L*)(PM)
Klark92's Script2Exe Wizard
AHK_L / AHK COMPILED EXE / BIN ICON CHANGER


gwarble
  • Members
  • 624 posts
  • Last active: Aug 12 2016 07:49 PM
  • Joined: 23 May 2009
Thanks for this SKAN

Do you know if its possible to use DllRead on a WAV resource, and successfully save the data back to the byref variable?
I posted in support here:
http://www.autohotke...lread-possible/

basically, it works if i make my own mod of DllRead to use the data internally (and even save it to static var for later use) but i can't figure out how to get the byref variable to be of the size returned

Of note, this works reading wav resource from the compiled script too, after adding the wav to the SC.bin beforehand, no dll. Oddly it doesn't work the same when reading the same wav from the RCData section created using FileInstall, i don't know why

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

Of note, this works reading wav resource from the compiled script too, after adding the wav to the SC.bin beforehand, no dll. Oddly it doesn't work the same when reading the same wav from the RCData section created using FileInstall, i don't know why

 
The following line in DllRead() makes it incompatible to use it for FileInstall resources.
Instead of 'Str, Section', it should be the 'UInt,10' for it to work. ( note: RT_RCDATA = 10 )
 
  If hRes := DllCall( "FindResource", UInt,hMod, Str,Key, Str,Section ) 
Here follows an example of how 'FileInstall resources' can be handled with Compiled/Uncompiled scripts:
 
#NoEnv 
FileInstall, C:\Windows\Media\chimes.wav, chimes.wav
ResRead( Sound, "C:\Windows\Media\chimes.wav" )
PlaySound( Sound )
Return ; // end of auto-execute section //


ResRead( ByRef Var, Key ) { 
  VarSetCapacity( Var, 128 ), VarSetCapacity( Var, 0 )
  If ! ( A_IsCompiled ) {
    FileGetSize, nSize, %Key%
    FileRead, Var, *c %Key%
    Return nSize
  }
 
  If hMod := DllCall( "GetModuleHandle", UInt,0 )
    If hRes := DllCall( "FindResource", UInt,hMod, Str,Key, UInt,10 )
      If hData := DllCall( "LoadResource", UInt,hMod, UInt,hRes )
        If pData := DllCall( "LockResource", UInt,hData )
  Return VarSetCapacity( Var, nSize := DllCall( "SizeofResource", UInt,hMod, UInt,hRes ) )
      ,  DllCall( "RtlMoveMemory", Str,Var, UInt,pData, UInt,nSize )
Return 0    
}

PlaySound( ByRef Sound ) {
 Return DllCall( "winmm.dll\PlaySound" ( A_IsUnicode ? "W" : "A" ), UInt,&Sound, UInt,0
               , UInt, 0x6 ) ; SND_MEMORY := 0x4 | SND_NODEFAULT := 0x2
}

kWo4Lk1.png

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
I forgot! If you do not want FileInstall to "Install" you may request a "FileInclude" in "Suggestions" forum.

gwarble
  • Members
  • 624 posts
  • Last active: Aug 12 2016 07:49 PM
  • Joined: 23 May 2009
Thanks skan!
I dont know how i ever would have figured out rt_rcdata should be 10...

I can suggest "FileInclude" but isnt it the same as FileInstall in a subroutine that never runs? Or even outside of any subroutine (or autoexec)? Or do you mean more options like what section to add it to

Edit: you answered my second and third questions (rcdata vs "files" and GetModuleHandle instead of LoadLibrary), but do you know why, when reading the wav manually added to "Files" (like your ini example) i wasn't able to save back the entire wav contents? nevermind, i guess its the same reason (ie that call is only retrieving a null terminated string i guess... even though the size was correct the data wasn't... nevermind again, since i can use it in the function, dllreads method works (for files added to SC.bin under Files because the resource type is a string, not for rcdata from fileinstall like you explained)... So i'm still not sure why i couldnt byref the wav data back...

The GetModuleHandle also allows use of resource from upx/mpress compressed exes as hoped... so thats cool, and should be preventing an additional read from file (when using LoadLibrary for this, when the module is already loaded)


Edit: apparently fincs is already adding something like FileInclude as a compiler directive, so thats sweet:
http://www.autohotke...hk2exe-changes/

Zephyr
  • Members
  • 1 posts
  • Last active: Jan 03 2014 11:15 AM
  • Joined: 16 Dec 2013

Hi,

 

I've been using this to create a .dll containing a lot of .png images, that I want to associate with my AHK program.

Now, I'd like to use those images, especially in an ImageSearch, but I can't seem to do so : DllRead returns the file in a variable but I can't then recreate the file with FileAppend (because of binary zeroes in the .png format), and I can't seem to access the images otherwise.

 

Is there any way I am missing ?

 

Thanks in advance.



Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

Hi there, i'm an idiot and don't understand the interaction between DLL's and autohotkey and hence can't appreciate this script.  It seems like this script is mainly to package images into a DLL that an autohotkey script can then use?  This seems very odd to me, why would you use a DLL to simply store images?  Is there any tutorials out there for dummies explaining DLL's and how to use them "properly" with autohotkey? 



acewp
  • Members
  • 13 posts
  • Last active: Oct 17 2014 06:23 AM
  • Joined: 28 Aug 2012

Hi everyone,

 

Using DllPack_Files(), I had packed some files such as .exe, txt, pdf to the DLL.

So how do I run the files after I had read (DllPack_Read) it out from the dll?

E.g. I will like to run the exe packed in the dll.

#Include DllPack.ahk

; my.exe is in the AHKFiles.dll

DllPackRead( Var, "AHKFiles.dll", "Files", "my.exe")
Run, %Var%         ;Something like this?
Run, Var           ;Something like this?

Many thanks.



kapastratos
  • Members
  • 2 posts
  • Last active:
  • Joined: 30 Dec 2014

AHK_L compatible version (tested on XP32Sp3 and Win7 64-bit)
I have also renamed the functions to be stdlib compatible. SKAN, I hope you don't mind.

Enjoy ;)
 

/*
              +-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+ +-+-+-+ +-+-+-+-+-+-+-+-+
              |R|e|s|o|u|r|c|e|-|O|n|l|y| |D|L|L| |f|o|r| |D|u|m|m|i|e|s|!|
              +-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+ +-+-+-+ +-+-+-+-+-+-+-+-+

 - Humble 36L wrapper to create and use DLL resources in AutoHotkey Scripting Language -

                  By SKAN - Suresh Kumar A N  ( [email protected] )
            Created: 05-Sep-2009 / Last Modified: 28-Oct-2010 / Version: 0.6u

  For usage, please refer Forum Topic : www.autohotkey.com/forum/viewtopic.php?t=62180


*/

DllPack_Files( Folder, DLL, Section="Files" ) {
 IfNotExist,%DLL%, SetEnv,DLL,% DLLPack_CreateEmpty( DLL )
 VarSetCapacity(Bin,64,Ix:=0)
 If hUPD := DllCall( "BeginUpdateResource", Str,DLL, Int,0 )
  Loop, %Folder%\*.*  {
  VarSetCapacity( Bin,0 )
  FileRead, Bin, *c %A_LoopFileLongPath%
  If nSize := VarSetCapacity(Bin)
  DllCall( "UpdateResource", Ptr,hUpd, Str,DllCall( "CharUpper", Str,Section, Str ), Str
 ,DllCall( "CharUpper", Str,A_LoopFileName, Str ), Int,0, Ptr,&Bin, UInt,nSize ),Ix:=Ix+1
} Return Ix, DllCall( "EndUpdateResource", Ptr,hUpd, Int,0 )
}


DllPack_CreateEmpty( F="empty.dll" ) { ; www.autohotkey.com/forum/viewtopic.php?p=381161#381161       
;Creates Empty Resource-Only DLL (1536 bytes)  / CD:05-Sep-2010 | LM:25-Oct-2010 - by SKAN
 IfNotEqual,A_Tab, % TS:=A_NowUTC, EnvSub,TS,1970,S  ;
 Src := "0X5A4DY3CXB8YB8X4550YBCX2014CYCCX210E00E0YD0X7010BYD8X400YE4X1000YE8X1000YECX78A"
 . "E0000YF0X1000YF4X200YF8X10005YFCX10005Y100X4Y108X3000Y10CX200Y114X2Y118X40000Y11CX200"
 . "0Y120X100000Y124X1000Y12CX10Y140X1000Y144X10Y158X2000Y15CX8Y1B0X7273722EY1B4X63Y1B8X1"
 . "0Y1BCX1000Y1C0X200Y1C4X200Y1D4X40000040Y1D8X6C65722EY1DCX636FY1E0X8Y1E4X2000Y1E8X200Y"
 . "1ECX400Y1FCX42000040", VarSetCapacity(Trg,1536,0), Numput(TS,Trg,192),AC := 0x40000000
 Loop, Parse, Src, XY
   Mod( A_Index,2 ) ? O := "0x" A_LoopField : NumPut( "0x" A_LoopField, Trg, O )
 If ( hF := DllCall( "CreateFile", Str,F, UInt,AC,UInt,2,Ptr,0,UInt,2,Int,0,Int,0 ) ) > 0
   B := DllCall( "_lwrite", Ptr,hF,Ptr,&Trg,UInt,1536 ),  DllCall( "CloseHandle",Ptr,hF )
Return B ? F :
}

DllPack_Read( ByRef Var, Filename, Section, Key ) {          ; Functionality and Parameters are
 VarSetCapacity( Var,64 ), VarSetCapacity( Var,0 )      ; identical to IniRead command ;-)
 If hMod := DllCall( "LoadLibrary", Str,Filename )
  If hRes := DllCall( "FindResource", Ptr,hMod, Str,Key, Str,Section )
   If hData := DllCall( "LoadResource", Ptr,hMod, Ptr,hRes )
    If pData := DllCall( "LockResource", Ptr,hData )
 Return VarSetCapacity( Var,nSize := DllCall( "SizeofResource", Ptr,hMod, Ptr,hRes ),32)
     , DllCall( "RtlMoveMemory", Ptr,&Var, Ptr,pData, UInt,nSize )
     , DllCall( "FreeLibrary", Ptr,hMod )
Return DllCall( "FreeLibrary", Ptr,hMod ) >> 32
}

 

 

 

 

I am using this script to add 9 images (.png) to a dll but all that I get is an empty dll ( 0 size) ...m I missing something?

 

Thank you!

 

My ahk version 1.0.48.05

 

I use this:

DllPack_Files("C:\Program Files (x86)\AutoHotkey\Files\", "some.dll", "Files")


kapastratos
  • Members
  • 2 posts
  • Last active:
  • Joined: 30 Dec 2014

Problem solved, I used the script from first post!



Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

Anyone here know why the script Skan posted here http://www.autohotke...l-v07/?p=609282 doesn't seem to play any sounds in Win 8.1 ?

Also, i can't seem to get the PlaySound() function to do anything if called from within a hotkey's function def ?