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
;***************************************************************************************************
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
it's similar to other code i have seen
i chose not to use RtlMemCopy, though
finally got the group resource icon/cursor thing working :P
i want to add support for color cursors, then i will post the code
(http://img541.imageshack.us/img541/7223/jbp5.png)
it uses LoadFromRsrc, above, as a support routine
Hi Dave,
You can also use binary resource templates.
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 (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
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.
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
:P
(http://img855.imageshack.us/img855/7563/zjui.png)
very nice , Dave :t ...
but where's the attachment? I want to play with those pretty cars also ;)
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 (http://blogs.msdn.com/b/oldnewthing/archive/2013/10/03/10453905.aspx)
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 (http://blogs.msdn.com/b/oldnewthing/archive/2012/07/20/10331787.aspx)
Hi Dave,
Very nice work :t
thanks Erol
almost done :P
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
Well done, Dave. I'm curious to see the demo.
Gunther
thanks, Gunther
i modifed the code posted in reply #14
it was missing one line of code to set the wBitCount member in the output structure
Quote from: dedndave on October 12, 2013, 01:12:11 AM
i modifed the code posted in reply #14
it was missing one line of code to set the wBitCount member in the output structure
Yes, I've seen it. Will you provide an archive with documentation, building etc?
Gunther
i'm not sure what you mean by an archive, Gunther
but, here is the source of the demo program
i have not finished the text document that helps understand ICO and CUR group resources
i will probably finish and post it later today
due to size, i did not include the assembled EXE
assuming you have Masm32 installed, just run the BuildIt.bat file
Hi Dave,
Quote from: dedndave on October 12, 2013, 02:52:07 AM
but, here is the source of the demo program ...
That was my point. Thank you for providing the entire sources. :t
Gunther