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

The file mine has created is here:
<!-- m -->https://ahknet.autoh...ed/Resource.dll<!-- m -->
See if you can read anything from it.


I have no problem reading resource.dll.
You either use SetWorkingDir or make sure dll and the script resides in the same folder ( or use the fullpath to the dll ).

Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
<!-- m -->https://ahknet.autoh...ying Images.zip<!-- m -->

All 64 images are inside. :p.

Thank you for taking the time to try and fix this, SKAN. It's really appreciated.

3nL8f.png


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

https://ahknet.autohotkey.com/~Wicked/Keying%20Images.zip

All 64 images are inside. :p.


Recieved with thanks a sum of 64 files totalling 65,539 bytes :p

I am able to reproduce it.
Simply put, EndUpdateResource() does not like the above numbers. :O
Try a different combination. :p

Thank you for taking the time to try and fix this, SKAN.



I will definitely fix this, but will take a while.
DO NOT READ THIS

Thank you very much for helping me to identify the bug. :)

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

I will definitely fix this, but will take a while.


It was simpler than I thought. Fixed DllCreateEmpty().

Its the End[UpdateResource] of the world we know it.

EndUpdateResource fails if it cannot extend the .rsrc section of your DLL. I’ve seen this happen if the .rsrc section isn’t the last section in the image – and that’s frequently the case (a few experiments show that .reloc usually follows .rsrc using the Microsoft linker). Annoyingly, LINK.EXE always seems to insert a .reloc section, even if you have a resource-only DLL.


@Wicked:
I have stress tested the wrapper as follows:
I maintain all my AHK projects in E:\AHK which has 172 subfolders with data aggregating to 468MB.
I am able to create 172 individual DLLs as well as one massive DLL ( pretty slow.. not recommended! ).
Please test the updated wrapper and let me know if you have any further problems.

Thanks. :)

Note to self:
The PE structure created by DllCreateEmpty() is now modeled from xpsp4res.dll which has only a .rsrc section.
Previously, it was modeled from msxml3r.dll, in which, .rsrc section was followed by .reloc



Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
It works great for my images at the moment!

Thanks again for your time and effort, SKAN. Always looked up to you on this forum, and, once again you've gone beyond expectations! :).

3nL8f.png


Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
Omg, SKAN, I'm sorry to post yet another problem. It's actually very similar to the one I posted way up on page 2; My images are losing transparency.

I'm reading the Dll correctly, converting them to HBitmap and then PBitmap for display on a GDI+ window using tic's GDI+ library.
Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop
Gui, 1: Show, NA, DGS | Keying
HWND:=WinExist()

PTOKEN:=Gdip_Startup()
HBM:=CreateDIBSection(30, 30)
HDC:=CreateCompatibleDC()
OBM:=SelectObject(HDC, HBM)
G:=Gdip_GraphicsFromHDC(HDC)

NSIZE:=DllRead(PIMG, "Resource\Resource.dll", "FILES", "BLUE CORNER.GIF")
PIMG:=Gdip_hBitmapFromBuffer(PIMG, NSIZE) ;~ I renamed the function and placed it in the Gdip library on my machine.
PIMG:=Gdip_CreateBitmapFromHBITMAP(PIMG) 
Gdip_DrawImage(G, PIMG, 0, 0, 30, 30)
Gdip_DisposeImage(PIMG)

That's just copied/pasted and quickly edited from my larger script but at a quick glance seems like it should work. The transparency worked when I loaded the GIF files directly using...
PIMG:=Gdip_CreateBitmapFromFile("BLUE CORNER.GIF")
...for example.

I've not seen anyone post this problem yet, but could it be because it's being displayed on a GDI+ window and not SetImage()ed onto a GUI?

Posted Image

3nL8f.png


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

Omg, SKAN, I'm sorry to post yet another problem.



:p

NSIZE:=DllRead(PIMG, "Resource\Resource.dll", "FILES", "BLUE CORNER.GIF")
PIMG:=Gdip_hBitmapFromBuffer(PIMG, NSIZE) ;~ I renamed the function and placed it in the Gdip library on my machine.
PIMG:=Gdip_CreateBitmapFromHBITMAP(PIMG) 

The above is where you are losing the transparency.
Why convert the buffer into hBitmap and then convert it back to GDI+ bitmap?

Replace the code with following ( untested! )

nSize := DllRead( Buffer, "Resource\Resource.dll", "FILES", "BLUE CORNER.GIF")
pImg := Gdip_CreateBitmapFromBuffer( Buffer, nSize ) 
VarSetCapacity( Buffer,0 )
Gdip_CreateBitmapFromBuffer( ByRef Buffer, nSize ) {
; Original code by Sean www.autohotkey.com/forum/viewtopic.php?p=147029#147029
  hData := DllCall("GlobalAlloc", UInt,2, UInt, nSize )
  pData := DllCall("GlobalLock",  UInt,hData )
  DllCall( "RtlMoveMemory", UInt,pData, UInt,&Buffer, UInt,nSize )
  DllCall( "GlobalUnlock", UInt,hData )
  DllCall( "ole32\CreateStreamOnHGlobal", UInt,hData, Int,True, UIntP,pStream )
  DllCall( "gdiplus\GdipCreateBitmapFromStream", UInt,pStream, UIntP,pBitmap )
  DllCall( NumGet( NumGet(1*pStream)+8 ), UInt,pStream ) 
Return pBitmap
}



Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
I take a quick nap and wake up and you've slam dunked it. Works great, SKAN!

Sorry for not being so great in this area... I've always struggled with the use of DLLs. :(.

3nL8f.png


  • Guests
  • Last active:
  • Joined: --
hey, SKAN, one question.

I'm new to AHK and I was wondering if it would be a good idea to save functions in a .dll file, and if so, how?

What I did was make a test folder, put a short .ahk file inside with one or two functions and I packed it in a dll, then I proceeded to DllRead it, by using Var := StrGet( &Var, "" ), and it seems to work.

But can't you load this file into memory somehow? Or am I saying something completely stupid?

I basically wanted to have a .dll file with my script that includes all the functions and other files I want with my script.

  • Guests
  • Last active:
  • Joined: --
I can't do this
DllRead(Var, "Function.dll", "Files", "Functions.ahk")
Var := StrGet( &Var, "" )
FileAppend, %Var%, %A_Desktop%\Funcs.ahk
#Include, Funcs.ahk
TestFunc()

because #Include doesn't work if the script can't find it when it starts ...
Workaround? Better way to do this?

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

because #Include doesn't work if the script can't find it when it starts ... Workaround? Better way to do this?


I do not understand your goal, but
If you build a script directly in memory, you can run it without writing it to disk:
How to: Run Dynamic Script... Through a Pipe!

MiamiGuy
  • Members
  • 61 posts
  • Last active: Nov 25 2011 07:44 AM
  • Joined: 03 Nov 2006
I just ran across this post and thought it was exellent. Recently I've been coding a program with ahk similar to "Windows Help and Support", where you have a series of html help pages that use CSS, Javascript and the like, and I was looking for a way of storing them all in one place (originally thought I would include them in the finished .exe file) but this solution would be equally beneficial. I'm using COM obviously to display them in the GUI, however I was wondering how difficult it would be to read them from a dll file. Additionally, the help pages have links to other help pages, which, if stored in either an .exe or .dll file,well... I'm not really quite sure they would work out. I read an article on that somewhere, which explained how it could be done with COM and CLS, by turning the .exe into a "server" of sorts, to serve the pages to itself, but that went flying over my head.
Anyway, my question is, would it be difficult to read html documents stored in a dll file into a variable and then display them on a COM object embedded in my GUI?

Any advise, or tutorials you could point me to would be great.

Thank you. :D

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

my question is, would it be difficult to read html documents stored in a dll file into a variable and then display them on a COM object embedded in my GUI?


You can find useful info from Lexikos, in the following topic ( Please read fully ):
<!-- m -->http://www.autohotke...pic.php?t=30122<!-- m -->

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
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 ;)

DllPack_CreateEmpty(...) former DllCreateEmpty(...)
DllPack_Files(...) former DllPackFiles(...)
DllPack_Read(...) former DllRead(...)

/*
              +-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+ +-+-+-+ +-+-+-+-+-+-+-+-+
              |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
}


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

I've been using these great functions along side GDI+ with some great results!

However, I've font the need to pack a font file inside the DLL. How do I go about doing two things: Getting the hFont of the file inside and possibly installing the font from the DLL.

The reason for the and is because I'm unsure as to which approach I'll take. I'd prefer to somehow figure out how to get GDI+ to use the font without actually extracting it from the DLL. But, if it comes down to where I have to install it, I'd like to be able to know how to install it using your DLLRead.

Thanks heaps, SKAN. I'm sure you'll have this in no time, as you always do. :).

3nL8f.png