|
-
Feb 2nd, 2011, 08:39 PM
#1
[API] HICON/HCURSOR from Array
Actually needed to do this & couldn't find any help on the net. Much researching resulted in posts saying to extract the icon/cursor bits to 2 bitmaps and use CreateIconIndirect. Doable, but why? I mean if I already have everything in a proper icon/cursor image format, there must be an easier way and there is... But first some other alternatives.
a. Send array to OleLoadPicture API, but no support for 32bpp or PNG (not sure 16 bit is supported either)
b. Save array to file and use LoadImage API but don't use VB's LoadPicture for same reasons as OleLoadPicture API
Ensure you know the proper format if you create them yourself. Each icon/cursor resource contains a 6 byte directory structure, followed by a 16 byte entry structure per icon. Along with that comes your BitmapInfoHeader (40 bytes) then the palette (if any & 4 bytes per color), then the actual bitmap and last, followed by the mask, per icon. All icons/cursors have masks even if 32bpp ones don't use masks. PNGs are a bit different. There is no BitmapInfoHeader nor palette nor bitmap nor mask. The entire PNG file is used in their place. The structures would look something like the following.
Code:
Private Type ICONDIRENTRY ' ICONS CURSORS
bWidth As Byte ' width 256=0 width 256=0
bHeight As Byte ' height 256=0 height 256=0
bColorCount As Byte ' >= 8bpp = 0 >= 8bpp = 0
bReserved As Byte
wPlanes As Integer ' must be 1 X hot spot
wBitCount As Integer ' bit depth Y hot spot
dwBytesInRes As Long ' nr bytes in resource nr bytes in resource
dwImageOffset As Long ' offset to 1st byte offset to 1st byte
End Type
Private Type ICONDIR
idReserved As Integer
idType As Integer ' value is 1 value is 2
idCount As Integer ' nr idEntries nr idEntries
idEntries() As ICONDIRENTRY
End Type
The API to use is not well documented but works perfectly. On Vista, it can even be used to create an icon/cursor handle from PNGs embedded in icons. Or really any PNG (256x256 or less) if you create your own icon directory & entry structures.
Here is the API and there are only slight differences in usage if using it for a cursor vs. an icon. The differences in the two calls are highlighted in blue below.
Supply valid parameters & am assuming imgData() is a byte array, zero-bound, and imgData() has only 1 icon/cursor resource. If so, at byte 22 will be the BitmapInfoHeader which is what needs to be pointed to for icons & 4 bytes earlier for cursors. If the desired width & height are left at zero, then system default icon size will be used. If all goes well, and it should, the return value is a valid icon/cursor handle that must be destroyed sometime with DestroyIcon or DestroyCursor APIs, respectively. Exception to that rule would be using LR_Shared flag in the final parameter of the API. See MSDN documentation link provided below.
Icon:
Code:
Const ICRESVER As Long = &H30000
HICON = CreateIconFromResourceEx(imgData(22), UBound(imgData) - 21&, True, ICRESVER, _
DesiredWidth, DesiredHeight, 0&)
Note: If you don't need a real cursor, you can create an HICON from the cursor source simply by treating the cursor source as an icon source, i.e., process the cursor resource same as an icon resource.
Cursor. Requires a little extra. It is nearly identical but requires the cursor's hotspot as the first 4 bytes being referenced. Below I simply back them up, then move them in front of the BitmapInfoHeader, then restore them later
Code:
Dim lOldData As Long
Const ICRESVER As Long = &H30000
CopyMemory lOldData, imgData(18), 4& ' copy to restore
CopyMemory imgData(18), imgData(10), 4& ' move cursor hotspot to this position
HCURSOR = CreateIconFromResourceEx(imgData(18), UBound(imgData) - 17&, False, ICRESVER, _
DesiredWidth, DesiredHeight, 0&)
CopyMemory imgData(18), lOldData, 4& ' restore
And the API ... http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
Code:
Private Declare Function CreateIconFromResourceEx Lib "user32.dll" (presbits As Any, ByVal dwResSize As Long, ByVal fIcon As Long, ByVal dwVer As Long, ByVal cxDesired As Long, ByVal cyDesired As Long, ByVal Flags As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Function DestroyCursor Lib "user32.dll" (ByVal hCursor As Long) As Long
Private Declare Function DestroyIcon Lib "user32.dll" (ByVal hIcon As Long) As Long
Last edited by LaVolpe; Feb 11th, 2011 at 09:38 AM.
Reason: Added the final NOTE
-
Feb 2nd, 2011, 10:01 PM
#2
Re: [API] HICON/HCURSOR from Array
And I foresee a question being asked... "I have an icon file that has 10 icons in it and I want to extract the 7th one. How do I do that then?"
The offset into the array and size of the resource are the only 2 variables in that API call. To answer that question, simple math is involved. Using same code as 1st post above with slight modifications.
Code:
Dim lDirPos As Long, lSize As Long, lBMPpos As Long
lDirPos = 6 + (7-1) * 16
' ^^ (7-1) is 7th icon, but from zero-bound it is really the 6th
' ^^ 6 is the icon directory structure size
' ^^ 16 is the size of each directory entry structure
CopyMemory lSize, imgData(lDirPos + 8), 4&
' ^^ 8 is how many bytes into the directory where we can find the size of the resource
CopyMemory lBMPpos, imgData(lDirPos + 12), 4&
' ^^ 12 is how many bytes into the directory where we can find the offset to the BitmapInfoHeader (or PNG)
' Now call your function
HICON = CreateIconFromResourceEx(imgData(lBMPpos), lSize, True, ICRESVER, _
DesiredWidth, DesiredHeight, 0&)
' FOR CURSORS & SAME QUESTION, just one more offset will help
Dim lHotSpot As Long, lOldData As Long
CopyMemory lHotSpot, imgData(lDirPos + 4), 4&
' ^^ 4 is how many bytes into the directory where we can find the X hotspot
lBMPpos = lBMPpos - 4 ' move pointer back 4 bytes
lSize = lSize + 4 ' add 4 bytes to resource size
CopyMemory lOldData, imgData(lBMPpos), 4&
CopyMemory imgData(lBMPpos), imgData(lHotSpot), 4&
HCURSOR = CreateIconFromResourceEx(imgData(lBMPpos), lSize, False, ICRESVER, _
DesiredWidth, DesiredHeight, 0&)
CopyMemory imgData(lBMPpos), lOldData, 4&
-
Feb 10th, 2011, 10:08 PM
#3
Re: [API] HICON/HCURSOR from Array
FYI. Glad someone besides me found a real-world use for this code.
If interested, this is the thread I'm referring to.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|