News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Load From Resource

Started by dedndave, November 27, 2012, 02:28:32 PM

Previous topic - Next topic

dedndave

a couple months ago, i wrote this routine for a project i am working on
as it turned out, i didn't need it for that project - did it a different way   :P
but, i came across the code today and thought it might save someone the time of writing their own...

;Load From Resource Include File - DednDave, 9-2012

;###################################################################################################

LoadFromRsrc PROTO :HINSTANCE,:LPSTR,:UINT

;###################################################################################################

        .CODE

;***************************************************************************************************

LoadFromRsrc PROC USES EBX ESI EDI hinstLfr:HINSTANCE,lpszLfr:LPSTR,uTypeLfr:UINT

;Load From Resource - DednDave, 9-2012
;
;Call With: hinstLfr:HINSTANCE = handle of module containing the resource (NULL = current process)
;           lpszLfr:LPSTR      = pointer to resource name string or integer resource ordinal
;           uTypeLfr:UINT      = integer type of resource
;
;  Returns: EAX = hgLfrData:HGLOBAL, global allocation handle or 0 if error
;           ECX = uLenLfrData:UINT , size of resource data or 0 if error
;           EDX = lpLfrData:LPVOID , pointer to resource data or 0 if error
;
;     Note: When done using the resource data, use GlobalUnlock and GlobalFree as follows:
;
;           INVOKE  GlobalUnlock,hgLfrData
;           INVOKE  GlobalFree,hgLfrData

;--------------------------------------------

    LOCAL   hrsrcLfr        :HRSRC
    LOCAL   hgLfr           :HGLOBAL
    LOCAL   uLenLfrData     :UINT
    LOCAL   lpLfrData       :LPVOID

;--------------------------------------------

    xor     ebx,ebx
    mov     uLenLfrData,ebx
    mov     lpLfrData,ebx
    INVOKE  FindResource,hinstLfr,lpszLfr,uTypeLfr
    .if eax
        mov     hrsrcLfr,eax
        INVOKE  LoadResource,hinstLfr,eax
        .if eax
            mov     hgLfr,eax
            INVOKE  LockResource,eax
            .if eax
                xchg    eax,esi
                INVOKE  SizeofResource,hinstLfr,hrsrcLfr
                .if eax
                    mov     uLenLfrData,eax
                    add     eax,31
                    and     al,-32
                    INVOKE  GlobalAlloc,GMEM_MOVEABLE,eax
                    .if eax
                        xchg    eax,ebx
                        INVOKE  GlobalLock,ebx
                        .if eax
                            mov     ecx,uLenLfrData
                            xchg    eax,edi
                            mov     edx,ecx
                            mov     lpLfrData,edi
                            shr     ecx,2
                            rep     movsd
                            and     edx,3
                            .if !ZERO?
                                mov     ecx,edx
                                rep     movsb
                            .endif
                        .else
                            xchg    eax,ebx
                            INVOKE  GlobalFree,eax
                            mov     uLenLfrData,ebx
                        .endif
                    .else
                        mov     uLenLfrData,eax
                    .endif
                .endif
            .endif
            INVOKE  FreeResource,hgLfr
        .endif
    .endif
    mov     edx,lpLfrData
    xchg    eax,ebx
    mov     ecx,uLenLfrData
    ret

LoadFromRsrc ENDP

;***************************************************************************************************

frktons

Nice job Dave, in a few days we'll talk about it a little,
if you don't mind earning your $50 as usual.  :P
There are only two days a year when you can't do anything: one is called yesterday, the other is called tomorrow, so today is the right day to love, believe, do and, above all, live.

Dalai Lama

dedndave

it's similar to other code i have seen
i chose not to use RtlMemCopy, though

dedndave

finally got the group resource icon/cursor thing working   :P
i want to add support for color cursors, then i will post the code



it uses LoadFromRsrc, above, as a support routine

Vortex

Hi Dave,

You can also use binary resource templates.

dedndave

bare with me, Erol   :P

are you refering to raw data, a user-defined format, or something else ?
is there an advantage to using them for icons and/or cursors ?

here is some documentation on "custom resource templates"
http://msdn.microsoft.com/en-us/library/aa245970(v=vs.60).aspx

i am having great luck with the code i have been working on
it even creates 256x256 icons with opacity under XP   :biggrin:
(not PNG compressed, though - that's another layer of support)

by the way....
i have been doing a lot of reading on icon and cursor resources and handles, etc
i have seen the statement a half-dozen times, "cursors are almost identical to icons"
the fact is - they are handled quite differently, especially when it comes to loading from resource
hindsight: if MS had created the icon format with a hotspot - they would have saved themselves a lot of work

Vortex

Hi Dave,

No problem. You can avoid the resource section by moving all the resource specific information to the .data section. A tool like Resource Hacker can save the resources as a binary file. For icons and cursors, it's not a big advantage.

dedndave

oh - i gotcha   :t

i hadn't thought about that
i can tell you this....

we previously tried to use LoadIcon and LoadImage for an alpha icon (opacity)
we had no luck doing it that way under XP (there's a thread in the old forum)
i was pleasantly surprised when it showed the icon with opacity after using CreateIconFromResourceEx   8)

i am not sure how the OS handles resource memory
it could be that the resources are discarded if memory is low
not sure that happens with .DATA
that would be the only other advantage i can see

dedndave


GoneFishing

very nice , Dave  :t ...
but where's the attachment? I want to play with those pretty cars also  ;)

sinsi

Something interesting, maybe pertinent? Raymond Chen talking about special processing for resources.
The relationship between module resources and resource-derived objects in 32-bit Windows

dedndave

vertograd - i am cleaning it up, adding documentation, etc
i will post it in a day or two   :t

sinsi - thanks
i did use one of Ray's pages to help...
http://blogs.msdn.com/b/oldnewthing/archive/2012/07/20/10331787.aspx

Vortex


dedndave

thanks Erol
almost done   :P

dedndave

#14
for those who want to use the routine....
;***********************************************************************************************

LoadGrpRsrc PROC USES EBX EDI hinstLfr:HINSTANCE,lpszLfr:LPSTR,uTypeLfr:UINT,uStructSize:UINT,lpRsrcStruct:LPVOID

;Load Group Resource - DednDave, 10-2013
;
;--------------------------------------------
;
;This routine creates HCURSOR or HICON handles for each icon/cursor in a group resource.
;
;The structure buffer pointed to by lpRsrcStruct must allow 16 bytes for each individual resource:
;
;  INDIVIDUAL_RSRC_STRUCT STRUCT
;    hResource              HANDLE ?  ;HCURSOR or HICON
;    wWidth                 WORD   ?  ;width
;    wHeight                WORD   ?  ;height
;    wXHotspot              WORD   ?  ;8000h if icon, hotspot X if cursor
;    wYHotspot              WORD   ?  ;8000h if icon, hotspot Y if cursor
;    wBitCount              WORD   ?  ;bits per pixel (color depth)
;    nIconCursorId          WORD   ?  ;resource ID
;  INDIVIDUAL_RSRC_STRUCT ENDS
;
;If the size passed in uStructSize is too small or if lpRsrcStruct is NULL, the routine exits without creating
;any resource handles and reports the number of individual resources so that re-allocation may be performed.
;
;If successful, the routine will populate an INDIVIDUAL_RSRC_STRUCT structure for each indvidual resource.
;
;The routine may be used to load single resources, as long as they are
;defined in the resource file with type RT_GROUP_CURSOR or RT_GROUP_ICON.
;
;It is the responsibility of the caller to use DestroyIcon to delete each resource handle when done.
;This may be accomplished by calling the DestroyGrpRsrc function.
;
;This routine requires the LoadFromRsrc support routine.
;
;--------------------------------------------
;
;Call With: hinstLfr:HINSTANCE  = handle of module containing the resource (NULL = current process)
;           lpszLfr:LPSTR       = pointer to resource name string or integer resource ID
;           uTypeLfr:UINT       = resource type, RT_GROUP_CURSOR or RT_GROUP_ICON
;           uStructSize:UINT    = size, in bytes, of structure buffer pointed to by lpRsrcStruct
;           lpRsrcStruct:LPVOID = pointer to resource structure buffer
;
;  Returns: EAX = nQty:UINT, number of INDIVIDUAL_RSRC_STRUCT's returned in resource structure buffer
;            CX = _NEWHEADER.wResCount:WORD, number of resources reported in _NEWHEADER structure
;                 the high word of ECX is 0
;            DX = _NEWHEADER.wResType:WORD, type of resources reported in _NEWHEADER structure
;                 0 = error reading group resource
;                 1 = IMAGE_ICON
;                 2 = IMAGE_CURSOR
;                 the high word of EDX is 0
;           If successful, the structure is filled, and a
;           handle is created for each individual resource.

;--------------------------------------------

IFNDEF RT_CURSOR
  RT_CURSOR EQU 1
ENDIF

IFNDEF RT_ICON
  RT_ICON   EQU 3
ENDIF

IFNDEF _NEWHEADER
  _NEWHEADER STRUCT
    wReserved  WORD ?
    wResType   WORD ?
    wResCount  WORD ?
  _NEWHEADER ENDS
ENDIF

IFNDEF _ICONRESDIR
  _ICONRESDIR STRUCT
    bWidth      BYTE ?
    bHeight     BYTE ?
    bColorCount BYTE ?
    bReserved   BYTE ?
  _ICONRESDIR ENDS
ENDIF

IFNDEF _CURSORRESDIR
  _CURSORRESDIR STRUCT
    wWidth        WORD ?
    wHeight       WORD ?
  _CURSORRESDIR ENDS
ENDIF

IFNDEF _RESDIR
  _RESDIR       STRUCT
    UNION
      Icon          _ICONRESDIR   <>
      Cursor        _CURSORRESDIR <>
    ENDS
    wPlanes       WORD         ?
    wBitCount     WORD         ?
    dwBytesInRes  DWORD        ?
    nIconCursorId WORD         ?
  _RESDIR       ENDS
ENDIF

IFNDEF _LOCALHEADER
  _LOCALHEADER STRUCT
    wXHotspot    WORD  ?
    wYHotspot    WORD  ?
  _LOCALHEADER ENDS
ENDIF

;--------------------------------------------

    LOCAL   _nQty         :DWORD
    LOCAL   _dwResCount   :DWORD
    LOCAL   _dwResType    :DWORD
    LOCAL   _hgLfrData0   :HGLOBAL
    LOCAL   _nLoopCount   :DWORD
    LOCAL   _nLocalHdrOfs :DWORD

;--------------------------------------------

    xor     eax,eax
    mov     _nQty,eax
    mov     _dwResCount,eax
    mov     _dwResType,eax
    mov     _nLocalHdrOfs,eax
    INVOKE  LoadFromRsrc,hinstLfr,lpszLfr,uTypeLfr
    mov     _hgLfrData0,eax
    .if ecx
        mov     edi,lpRsrcStruct                         ;EDI = lpRsrcStruct
        movzx   ecx,word ptr [edx]._NEWHEADER.wResType   ;ECX = wResType
        movzx   eax,word ptr [edx]._NEWHEADER.wResCount  ;EAX = wResCount
        mov     _dwResType,ecx
        mov     _dwResCount,eax
        mov     ecx,eax                                  ;sizeof INDIVIDUAL_RSRC_STRUCT = 2^4
        shl     ecx,4                                    ;ECX = min struct size
        .if (eax) && (edi) && (ecx<=uStructSize)
            push    esi
            mov     ebx,RT_ICON
            mov     _nLoopCount,eax
            lea     esi,[edx+sizeof _NEWHEADER]          ;ESI = _RESDIR ptr
            .if (byte ptr _dwResType==IMAGE_CURSOR)
                sub     bl,RT_ICON-RT_CURSOR
                mov byte ptr _nLocalHdrOfs,sizeof _LOCALHEADER
            .endif
            .repeat
                movzx   edx,word ptr [esi]._RESDIR.nIconCursorId    ;EDX = _RESDIR.nIconCursorId
                mov     [edi].INDIVIDUAL_RSRC_STRUCT.nIconCursorId,dx
                INVOKE  LoadFromRsrc,hinstLfr,edx,ebx
                .if ecx
                    push    eax                                     ;save hgLfrDataX
                    .if bl==RT_CURSOR
                        mov     eax,dword ptr [edx]._LOCALHEADER.wXHotspot
                        add     edx,sizeof _LOCALHEADER             ;skip _LOCALHEADER structure
                    .else
                        mov     eax,80008000h
                    .endif
                    mov dword ptr [edi].INDIVIDUAL_RSRC_STRUCT.wXHotspot,eax
                    movzx   eax,word ptr [esi]._RESDIR.wBitCount    ;EAX = wBitCount
                    mov     [edi].INDIVIDUAL_RSRC_STRUCT.wBitCount,ax
                    dec     eax
                    .if ZERO?
                        inc     eax
                    .else
                        xor     eax,eax
                    .endif
                    push    eax                                     ;uFlags = 1 if monochrome, else 0
                    mov     eax,[edx].BITMAPINFOHEADER.biHeight
                    shr     eax,1
                    push    eax                                     ;cyDesired = height
                    mov     [edi].INDIVIDUAL_RSRC_STRUCT.wHeight,ax
                    mov     eax,[edx].BITMAPINFOHEADER.biWidth
                    push    eax                                     ;cxDesired = width
                    mov     [edi].INDIVIDUAL_RSRC_STRUCT.wWidth,ax
                    push    30000h                                  ;dwVersion
                    mov     eax,ebx
                    shr     eax,1
                    sub     edx,_nLocalHdrOfs                       ;point to _LOCALHEADER structure
                    push    eax                                     ;fIcon = 1 if icon, 0 if cursor
                    push    ecx                                     ;cbIconBits = size of resource data
                    push    edx                                     ;pbIconBits = pointer to resource data
                    CALL    CreateIconFromResourceEx
                    .if eax
                        mov     [edi].INDIVIDUAL_RSRC_STRUCT.hResource,eax
                        inc     _nQty
                        add     edi,sizeof INDIVIDUAL_RSRC_STRUCT
                    .endif
                    pop     eax                                     ;EAX = hgLfrDataX
                    push    eax
                    INVOKE  GlobalUnlock,eax
                    CALL    GlobalFree
                .endif
                dec     _nLoopCount
                lea     esi,[esi+sizeof _RESDIR]                    ;next _RESDIR structure
            .until ZERO?
            pop     esi
        .endif
    .endif
    mov     edi,_hgLfrData0
    .if edi
        INVOKE  GlobalUnlock,edi
        INVOKE  GlobalFree,edi
    .endif
    mov     eax,_nQty                       ;EAX = number of INDIVIDUAL_RSRC_STRUCT structures returned
    mov     ecx,_dwResCount                 ;ECX = number of individual resources reported in _NEWHEADER
    mov     edx,_dwResType                  ;EDX = IMAGE_ICON, IMAGE_CURSOR, or 0 if error
    ret

LoadGrpRsrc ENDP

;***********************************************************************************************

and another for destroying an array of resources created by the above routine...
;***********************************************************************************************

DestroyGrpRsrc PROC USES ESI EDI uQty:UINT,lpRsrcStruct:LPVOID

;Destroy Group Resource - DednDave, 10-2013
;
;Used to destroy resource handles in an array of INDIVIDUAL_RSRC_STRUCT structures.
;
;--------------------------------

    mov     esi,uQty
    mov     edi,lpRsrcStruct
    .if (esi) && (edi)
        .repeat
            mov     eax,[edi].INDIVIDUAL_RSRC_STRUCT.hResource
            .if eax
                and     [edi].INDIVIDUAL_RSRC_STRUCT.hResource,0
                INVOKE  DestroyIcon,eax
            .endif
            dec     esi
            lea     edi,[edi+sizeof INDIVIDUAL_RSRC_STRUCT]
        .until ZERO?
    .endif
    ret

DestroyGrpRsrc ENDP

;***********************************************************************************************


i should be able to finish the demo tomorrow
i am doing cleanup - and writing a document on CUR and ICO files and resources

EDIT: modified the routine - was missing one line of code to set BitCount in output struct