Jump to content

Resources UDF


Zedna
 Share

Recommended Posts

Hello everybody

I want to use text files to store datas for a script I make.

So i created a first file, called FILE0.TXT containing the following lines :

File0 line1
File0 Line2

Then I created a second file called FILE1.TXT containing the following lines :

File1 line1
File1 Line2

Then I created a DLL (see attached file) containing 2 RCDATA named FILE0 and FILE1.

Then I created the following script :

#include "resources.au3"
$text=_ResourceGetAsString("FILE0", $RT_RCDATA, 1033, "AsciiFiles.dll")
ConsoleWrite(@crlf&$text&@CRLF&@CRLF)

My problem is that when I run this script I get a Windows error message saying Autoit crashed and must be closed.

I tryed to replace "1033" with zero or $ResLang, without success.

Can someone tell me what I did wrong ?

AsciiFiles.dll

Link to comment
Share on other sites

#include "resources.au3"
$text=_ResourceGetAsString("FILE0", $RT_RCDATA, 1033, "AsciiFiles.dll")
ConsoleWrite(@crlf&$text&@CRLF&@CRLF)

My problem is that when I run this script I get a Windows error message saying Autoit crashed and must be closed.

I tryed to replace "1033" with zero or $ResLang, without success.

With your DLL it crashed on my WIN XP too. I don't know why.

You can include TXT files directly to EXE without any problems.

This works OK:

#AutoIt3Wrapper_Res_File_Add=FILE0.TXT, rt_rcdata, FILE0
#AutoIt3Wrapper_Res_File_Add=FILE1.TXT, rt_rcdata, FILE1

#include "resources.au3"

$text=_ResourceGetAsString("FILE0")
MsgBox(0,'',$text)

EDIT: How exactly did you compile your DLL?

EDIT2: 

I tried it also with modified UDF using _WinAPI_LoadLibraryEx($DLL, $LOAD_LIBRARY_AS_DATAFILE) instead of _WinAPI_LoadLibrary($DLL) with the same result

Edited by Zedna
Link to comment
Share on other sites

Hi Zedna,

Thank you for investigating on this problem.

So Yes, I know I can include files in the EXE, and i will do it if I have no other solution.

ButI want to minimize memory occupation of my script, and the resource file will embed things like image & icon sets for themes, translations sets (FR/EN/DE/IT & SP)... etc witch are not all required together at the same time. The idea is to have them stored in one resource file instead of several files, and to pick the set chosen by user (theme & language).

To your EDIT :

I tryed 2 solutions to build my DLL. I first tryed with Visual Basic 2010 Express, then I tryed a utility called RDG issued by Tlem (Admin of Autoit French forum) (I think I joined this last one, but the result was the same with both)

To your EDIT2 :

It's a bit weird, isn't it ? This UDF works perfectly with icons, bitmap, sound...etc and not with something as basic as text.

Do you expect a positive issue or sould i start thinking about including files in my script, or keep them around the EXE in a (sub) folder ?

Link to comment
Share on other sites

I identified where is problem, but I don't know why is it and how to overcome this.

In _ResourceGetAsString() it crashes on DllStructGetData($struct, 1)

My UDF loads resource and gets pointer to that reource memory. Then it creates structure over that memory and get data from structure.

Maybe we need to apply the same princip as In GDI+ sections (_ResourceGetAsImage),  there is allocated/copied memory instead of direct access to resource memory.

I will try this if it helps.

EDIT: doesn't help

Func _ResourceGetAsString($ResName, $ResType = 10, $ResLang = 0, $DLL = -1) ; $RT_RCDATA = 10
 Local $ResPointer, $ResSize, $struct

 $ResPointer = _ResourceGet($ResName, $ResType, $ResLang, $DLL)
 If @error Then
    SetError(1, 0, 0)
    Return ''
 EndIf
 $ResSize = @extended
 
    $hData = _MemGlobalAlloc($ResSize,2)
    $pData = _MemGlobalLock($hData)
    _MemMoveMemory($ResPointer,$pData,$ResSize)
    _MemGlobalUnlock($hData)
 
 $struct = DllStructCreate("char[" & $ResSize & "]", $pData)
;~  $struct = DllStructCreate("char[" & $ResSize & "]", $ResPointer)
 Return DllStructGetData($struct, 1) ; returns string
EndFunc
Edited by Zedna
Link to comment
Share on other sites

It work with this old version of _ResourcesGet() :

Func _ResourceGet($ResName, $ResType = 10, $ResLang = 0, $DLL = -1) ; $RT_RCDATA = 10
    Local Const $IMAGE_BITMAP = 0
    Local $hInstance, $hBitmap, $InfoBlock, $GlobalMemoryBlock, $MemoryPointer, $ResSize

    If $DLL = -1 Then
      $hInstance = DllCall("kernel32.dll", "int", "GetModuleHandleA", "int", 0)
    Else
      $hInstance = DllCall("kernel32.dll", "int", "LoadLibrary", "str", $DLL)
    EndIf
    $hInstance = $hInstance[0]
    If $hInstance = 0 Then Return SetError(1, 0, 0)

    If $ResType = $RT_BITMAP Then
        $hBitmap = DllCall("user32.dll", "hwnd", "LoadImage", "hwnd", $hInstance, "str", $ResName, _
                "int", $IMAGE_BITMAP, "int", 0, "int", 0, "int", 0)
        If @error Then Return SetError(2, 0, 0)
        $hBitmap = $hBitmap[0]
        Return $hBitmap ; returns handle to Bitmap
    EndIf

    If $ResLang <> 0 Then
        $InfoBlock = DllCall("kernel32.dll", "int", "FindResourceExA", "int", $hInstance, "long", $ResType, "str", $ResName, "short", $ResLang)
    Else
        $InfoBlock = DllCall("kernel32.dll", "int", "FindResourceA", "int", $hInstance, "str", $ResName, "long", $ResType)
    EndIf

    If @error Then Return SetError(3, 0, 0)
    $InfoBlock = $InfoBlock[0]
    If $InfoBlock = 0 Then Return SetError(4, 0, 0)

    $ResSize = DllCall("kernel32.dll", "dword", "SizeofResource", "int", $hInstance, "int", $InfoBlock)
    If @error Then Return SetError(5, 0, 0)
    $ResSize = $ResSize[0]
    If $ResSize = 0 Then Return SetError(6, 0, 0)

    $GlobalMemoryBlock = DllCall("kernel32.dll", "int", "LoadResource", "int", $hInstance, "int", $InfoBlock)
    If @error Then Return SetError(7, 0, 0)
    $GlobalMemoryBlock = $GlobalMemoryBlock[0]
    If $GlobalMemoryBlock = 0 Then Return SetError(8, 0, 0)

    $MemoryPointer = DllCall("kernel32.dll", "int", "LockResource", "int", $GlobalMemoryBlock)
    If @error Then Return SetError(9, 0, 0)
    $MemoryPointer = $MemoryPointer[0]
    If $MemoryPointer = 0 Then Return SetError(10, 0, 0)

    If $DLL <> -1 Then DllCall("Kernel32.dll","int","FreeLibrary","str",$hInstance)
    If @error Then Return SetError(11, 0, 0)

    SetExtended($ResSize)
    Return $MemoryPointer
EndFunc

Best Regards.Thierry

Link to comment
Share on other sites

@Tlem, zeshrek

that older version works because it has an error in the call to FreeLibrary().

str is used instead of handle or ptr, so the FreeLibrary() call failed.

and without a working FreeLibrary() there is a growing memory leak with every call to _ResourceGet()

if you use that code...

@Zedna, All

the crashing is caused by calling FreeLibrary() before DllStructGetData() in _ResourceGetAsString()

I've modified _ResourceGet() for LoadLibraryEx with $LOAD_LIBRARY_AS_DATAFILE

LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE and LOAD_LIBRARY_AS_IMAGE_RESOURCE only work for Vista/7

I've added the three macros to _ResourceGet() that test the returned handle

Re: LOAD_LIBRARY_AS_DATAFILE/LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE

Article ID: 241856 - Last Review: December 11, 2003 - Revision: 3.0

PRB: Crash in DllMain After FreeLibrary is Called on a Resource DLL

http://support.microsoft.com/kb/241856

any update to the udf could check OS and use the two flags for Vista/7

and LOAD_LIBRARY_AS_DATAFILE for server 2003 on down.

if you are using Vista/7 then use LL_FLAG in

in _ResourceGet() _WinAPI_LoadLibraryEx()

this code fixes the memory leak or crash with a resource dll and _ResourceGetAsString()

the other functions in the udf need to be modified so FreeLibrary can be called,

or the module handle returned for user to close and free up resources.

#AutoIt3Wrapper_Res_File_Add=AsciiFiles.dll, rt_rcdata, FILE0
#include-once
#include <WinAPI.au3>
#include <Memory.au3>

Global Const $RT_RCDATA = 10
Global Const $RT_BITMAP = 2
Global $hInstance

$text=_ResourceGetAsString("FILE0", $RT_RCDATA, 1033, "AsciiFiles.dll")
MsgBox(262144,'Debug line ~' & @ScriptLineNumber,'Selection:' & @lf & '$text' & @lf & @lf & 'Return:' & @lf & $text) ;### Debug MSGBOX

$text=_ResourceGetAsString("FILE1", $RT_RCDATA, 1033, "AsciiFiles.dll")
MsgBox(262144,'Debug line ~' & @ScriptLineNumber,'Selection:' & @lf & '$text' & @lf & @lf & 'Return:' & @lf & $text) ;### Debug MSGBOX


Func _ResourceGet($ResName, $ResType = 10, $ResLang = 0, $DLL = -1) ; $RT_RCDATA = 10
    Local Const $IMAGE_BITMAP = 0
    Local $hBitmap, $InfoBlock, $GlobalMemoryBlock, $MemoryPointer, $ResSize

    If $DLL = -1 Then
        $hInstance = _WinAPI_GetModuleHandle("")
    Else
        Local Const $LOAD_LIBRARY_AS_DATAFILE = 0x00000002
        Local Const $LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040
        Local Const $LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020
        Local Const $LL_FLAG = $LOAD_LIBRARY_AS_IMAGE_RESOURCE + $LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
        $hInstance = _WinAPI_LoadLibraryEx($DLL, $LOAD_LIBRARY_AS_DATAFILE) ;Vista/7/Server 2003-2008/XP/2000/98
        ;$hInstance = _WinAPI_LoadLibraryEx($DLL, $LL_FLAG) ;Vista/7 - Untested

        ;If this macro returns TRUE, the module was loaded with LOAD_LIBRARY_AS_DATAFILE or LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE.
        ;Local $LDR_IS_DATAFILE = BitAND($hInstance, 0x00000001) <> 0
        ;If this macro returns TRUE, the module was loaded with LOAD_LIBRARY_AS_IMAGE_RESOURCE.
        ;Local $LDR_IS_IMAGEMAPPING = BitAND($hInstance, 0x00000002) <> 0
        ;If this macro returns TRUE, the module was loaded with LOAD_LIBRARY_AS_IMAGE_RESOURCE and either LOAD_LIBRARY_AS_DATAFILE or LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE.
        ;Local $LDR_IS_RESOURCE = ($LDR_IS_DATAFILE And $LDR_IS_IMAGEMAPPING)
    EndIf

    If $hInstance = 0 Then Return SetError(1, 0, 0)

    If $ResType = $RT_BITMAP Then
        $hBitmap = _WinAPI_LoadImage($hInstance, $ResName, $IMAGE_BITMAP, 0, 0, 0)
        If @error Then Return SetError(2, 0, 0)
        Return $hBitmap ; returns handle to Bitmap
    EndIf

    If $ResLang <> 0 Then
        $InfoBlock = DllCall("kernel32.dll", "int", "FindResourceExA", "int", $hInstance, "long", $ResType, "str", $ResName, "short", $ResLang)
    Else
        $InfoBlock = DllCall("kernel32.dll", "int", "FindResourceA", "int", $hInstance, "str", $ResName, "long", $ResType)
    EndIf

    If @error Then Return SetError(3, 0, 0)
    $InfoBlock = $InfoBlock[0]
    If $InfoBlock = 0 Then Return SetError(4, 0, 0)

    $ResSize = DllCall("kernel32.dll", "dword", "SizeofResource", "int", $hInstance, "int", $InfoBlock)
    If @error Then Return SetError(5, 0, 0)
    $ResSize = $ResSize[0]
    If $ResSize = 0 Then Return SetError(6, 0, 0)

    $GlobalMemoryBlock = DllCall("kernel32.dll", "int", "LoadResource", "int", $hInstance, "int", $InfoBlock)
    If @error Then Return SetError(7, 0, 0)
    $GlobalMemoryBlock = $GlobalMemoryBlock[0]
    If $GlobalMemoryBlock = 0 Then Return SetError(8, 0, 0)

    $MemoryPointer = DllCall("kernel32.dll", "int", "LockResource", "int", $GlobalMemoryBlock)
    If @error Then Return SetError(9, 0, 0)
    $MemoryPointer = $MemoryPointer[0]
    If $MemoryPointer = 0 Then Return SetError(10, 0, 0)

    SetExtended($ResSize)
    Return $MemoryPointer
EndFunc   ;==>_ResourceGet

; for ANSI strings
Func _ResourceGetAsString($ResName, $ResType = 10, $ResLang = 0, $DLL = -1) ; $RT_RCDATA = 10
    Local $ResPointer, $ResSize, $struct

    $ResPointer = _ResourceGet($ResName, $ResType, $ResLang, $DLL)
    If @error Then
        SetError(1, 0, 0)
        Return ''
    EndIf
    $ResSize = @extended
    $struct = DllStructCreate("char[" & $ResSize & "]", $ResPointer)

    Local $sTemp = DllStructGetData($struct, 1) ; returns string
    If $DLL <> -1 Then _WinAPI_FreeLibrary($hInstance)

    Return SetError(@error, 0, $sTemp)
EndFunc   ;==>_ResourceGetAsString

I see fascists...

Link to comment
Share on other sites

  • 2 weeks later...

Hi zenda play sound not working.

I use your example and your includes but the sound dont working, autoit not found error etc but not play sound why?

First:

#AutoIt3Wrapper_Res_File_Add=G:\WINDOWS\Media\tada.wav, SOUND, MYWAV
_ResourcePlaySound("MYWAV")
_ResourcePlaySound("MYWAV", $SND_ASYNC)

Second:

#AutoIt3Wrapper_Res_File_Add=G:\WINDOWS\Media\tada.wav, SOUND, MYWAV
Global Const $SND_RESOURCE = 0x00040004
Global Const $SND_ASYNC = 1
DllCall("winmm.dll", "int", "PlaySound", "str", "MYWAV", "hwnd", 0, "int", $SND_RESOURCE)
DllCall("winmm.dll", "int", "PlaySound", "str", "MYWAV", "hwnd", 0, "int", BitOR($SND_RESOURCE, $SND_ASYNC))

It add file but not play sound :)

Link to comment
Share on other sites

  • Developers

AutoIt3Wrapper gives an error during compilation when the file isn't found.

- Skipping #AutoIt3Wrapper_Res_File_Add because the file is not found:G:\WINDOWS\Media\tada.wav, SOUND, MYWAV

The #include "resources.au3" is missing in the posted code as well.... is it in?

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

Hello.

I'm trying to add *.DLL to my program.EXE

...
#include "resources.au3"

;Add MyLib.dll 
#AutoIt3Wrapper_Res_File_Add=MyLib.dll, rt_rcdata, LIB

;Get MyLib.dll as string
$LibAsString = _ResourceGetAsString("LIB")

;Try to open this DLL
DllOpen($LibAsString)

...
;Use DLL

I doesn't work. Can someone tell me how to do it, please? :)

Link to comment
Share on other sites

  • 2 weeks later...

Hello.

I'm trying to add *.DLL to my program.EXE

...
#include "resources.au3"

;Add MyLib.dll 
#AutoIt3Wrapper_Res_File_Add=MyLib.dll, rt_rcdata, LIB

;Get MyLib.dll as string
$LibAsString = _ResourceGetAsString("LIB")

;Try to open this DLL
DllOpen($LibAsString)

...
;Use DLL

I doesn't work. Can someone tell me how to do it, please? :)

Get your hands on Resource Hacker and add the following line to your WRAPPER:

#AutoIt3Wrapper_Run_After=<<<** PATH TO **>>>ResHacker.exe -add %out%, %out%, <<<** PATH TO **>>>.dll, rcdata, LIB, 0

Edited by Mallie99

Are you telling me something I need to know or something I want to know?

Link to comment
Share on other sites

  • 3 weeks later...

using the demo script from the 1st post I can't get _GetResourceAsString to retrieve the contents of an embedded txt file. to work with a x64 bit compile. it works fine with 32bit.

the problem seems to be in _ResourceGet()

any ideas?

Link to comment
Share on other sites

I have a problem with including resources into the exe file, I don't know what I'm doing wrong. Sample of code (very simple):

#AutoIt3Wrapper_Res_File_Add=imie.txt, rt_rcdata, FILE0

#include <resources.au3>

$text=_ResourceGetAsString("FILE0")

MsgBox(0,'',$text)

Why this don't work?! Why why why???post-64043-0-46015200-1301683102_thumb.p

resources.au3 file is in "include" directory and in the same directory as the file imie.txt is.

Thank you all for AutoIt :)

Edited by hevoxer
Link to comment
Share on other sites

taietel, thanks for trying to help but this don't solve my problem. I checked the exe file with hex editor and there is no string from txt file so the conclusion is that the converter au3 2 exe didn't include resource.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...