Jump to content
Sign in to follow this  
rexx

How to convert a hIcon to a 32-bit hBitmap

Recommended Posts

rexx

I have created a menu, with items links to some files.

And I want to add icons for these menu items.

I found _GUICtrlMenu_SetItemBmp() function to do this, and it needs hBitmap

But i use _WinAPI_PrivateExtractIcon() to get an icon, which returns an icon handle.

So I needs to convert hicon to hbitmap so that i can add it to my menu item.

And i got _GdipCreateBitmapFromHICON() in a previous thread, it did create a bitmap, but the alpha transparent information is disappeared.

I have found something on the web but not in autoit code.

http://www.eggheadcafe.com/forumarchives/p...ost23715240.asp

And this, I wrote a au3 version MI_GetBitmapFromIcon32Bit() but not works.

Func GetBitmapFromIcon32Bit($hIcon, $iWidth=0, $iHeight=0)
    Local $aIcon = _WinAPI_GetIconInfo($hIcon)
;       $aIcon[0] - True on success, otherwise False
;       $aIcon[1] - True specifies an icon, False specifies a cursor
;       $aIcon[2] - Specifies the X coordinate of a cursor's hot spot
;       $aIcon[3] - Specifies the Y coordinate of a cursor's hot spot
;       $aIcon[4] - Specifies the icon bitmask bitmap
;       $aIcon[5] - Handle to the icon color bitmap
    Local $hbmMask  = $aIcon[4] ; used to generate alpha data (if necessary)
    Local $hbmColor = $aIcon[5] ; used to measure the icon

    if $iWidth = 0 or $iHeight = 0 then ; get size from bitmap
        Local $tBitmap = DllStructCreate("int bmType;int bmWidth;int bmHeight;int bmWidthBytes;ushort bmPlanes;ushort bmBitsPixel;ptr bmBits")
        if not $hbmColor or not _WinAPI_GetObject($hbmColor, 24, DllStructGetPtr($tBitmap)) then return 0
        $iWidth  = DllStructGetData($tBitmap,"bmWidth")
        $iHeight = DllStructGetData($tBitmap,"bmHeight")
        $tBitmap = 0 ; free struct
    endif

    ; Create a device context compatible with the screen.
    Local $hdcDest = _WinAPI_CreateCompatibleDC(0)
    if $hdcDest then
;       Local $tBitmapInfo = DllStructCreate("dword Size;long Width;long Height;ushort Planes;ushort BitCount;dword Compression;dword SizeImage;long XPelsPerMeter;long YPelsPerMeter;dword ClrUsed;dword ClrImportant;dword RGBQuad")
        Local $tBitmapInfo = DllStructCreate($tagBITMAPINFO)
        ; Create a 32-bit bitmap to draw the icon onto.
        ; Set parameters for 32-bit bitmap. May also be used to retrieve bitmap data from the icon's mask bitmap.
        DllStructSetData($tBitmapInfo, "Size"    , DllStructGetSize($tBitmapInfo) - 4) ;40)
        DllStructSetData($tBitmapInfo, "Width"   , $iWidth)
        DllStructSetData($tBitmapInfo, "Height"  , $iHeight)
        DllStructSetData($tBitmapInfo, "Planes"  , 1)
        DllStructSetData($tBitmapInfo, "BitCount", 32) ; 32-bit bitmap

        Local $pBits

        Local $hBitmap = CreateDIBSection($hdcDest, DllStructGetPtr($tBitmapInfo), 0, $pBits, 0, 0)
        if $hBitmap then
            ; SelectObject -- use hdcDest to draw onto bm
            Local $hBitmapOld = _WinAPI_SelectObject($hdcDest, $hBitmap)
            if $hBitmapOld then
                ; Draw the icon onto the 32-bit bitmap.
                _WinAPI_DrawIconEx($hdcDest, 0, 0, $hIcon)
                _WinAPI_SelectObject($hdcDest, $hBitmapOld)
            endif

            Local $pBitsEnd = $pBits + $iWidth*$iHeight
            ; Check for alpha data.
            Local $fHasAlpha = false
            for $pThisPixel = $pBits to $pBitsEnd-1
                if BitAND(Ptr($pThisPixel), 0xFF000000) then
                    $fHasAlpha = true
                    ExitLoop
                endif
            next

            if not $fHasAlpha then
                ; Ensure the mask is the right size.
;               $hbmMask = DllCall("CopyImage", "uint", $hbmMask, "uint", 0, "int", $iWidth, "int", $iHeight, "uint", BitOR(4,8))
                Local $pMaskBits
                if _WinAPI_GetDIBits($hdcDest, $hbmMask, 0, $iHeight, $pMaskBits, DllStructGetPtr($tBitmapInfo), 0) then
                    ; Use icon mask to generate alpha data.
                    Local $pThisMaskPixel = $pMaskBits
                    for $pThisPixel = $pBits to $pBitsEnd-1
                        if Ptr($pThisMaskPixel) then
                            Ptr($pThisPixel) = 0
                        else
                            Ptr($pThisPixel) = BitOR(Ptr($pThisPixel), 0xFF000000)
                        endif
                    next
                else
                    ; Make the bitmap entirely opaque.
                    for $pThisPixel = $pBits to $pBitsEnd-1
                        Ptr($pThisPixel) = BitOR(Ptr($pThisPixel), 0xFF000000)
                    next
                endif
            endif
        endif

        ; Done using the device context.
        _WinAPI_DeleteDC($hdcDest)
    endif

    if $hbmColor then _WinAPI_DeleteObject($hbmColor)
    if $hbmMask  then _WinAPI_DeleteObject($hbmMask)
    return $hBitmap
EndFunc

Func CreateDIBSection ($hdc, $pbmi, $iUsage, ByRef $ppvBits, $hSection, $dwOffset)
    Local $aRes = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', _
                                                'ptr',   $hdc,      _ ; // handle to DC
                                                'ptr',   $pbmi,     _ ; // bitmap data
                                                'uint',  $iUsage,   _ ; // data type indicator
                                                'ptr*',  $ppvBits,  _ ; // bit values
                                                'ptr',   $hSection, _ ; // handle to file mapping object
                                                'dword', $dwOffset )  ; // offset to bitmap bit values
    Local $cbSize = DllStructGetData (DllStructCreate ($tagBITMAPINFOHEADER, $pbmi), 'SizeImage')
    $ppvBits = DllStructCreate ('uint[' & $cbSize / 4 & ']', $aRes[4])
    Return $aRes[0]
EndFunc
Edited by rexx

Share this post


Link to post
Share on other sites
Yashied

Try this.

#Include <GUIConstantsEx.au3>
#Include <GUIMenu.au3>
#Include <Constants.au3>
#Include <WinAPI.au3>
#Include <WindowsConstants.au3>

Opt('MustDeclareVars', 1)

Global $hMenu, $hForm, $hFile = 1000, $idNew, $idExit

$hForm = GUICreate('Menu', 400, 300)

$hFile = _GUICtrlMenu_CreateMenu()
_GUICtrlMenu_InsertMenuItem ($hFile, 0, ' &Favorites', $idNew)
_GUICtrlMenu_InsertMenuItem ($hFile, 1, '', 0)
_GUICtrlMenu_InsertMenuItem($hFile, 2, ' E&xit', $idExit)
$hMenu = _GUICtrlMenu_CreateMenu()
_GUICtrlMenu_InsertMenuItem($hMenu, 0, '&File', 0, $hFile)
_GUICtrlMenu_SetMenu($hForm, $hMenu)
_GUICtrlMenu_SetItemBmp($hFile, 0, _CreateBitmapFromIcon(_WinAPI_GetSysColor($COLOR_MENU), @SystemDir & '\shell32.dll', 43, 16, 16))
_GUICtrlMenu_SetItemBmp($hFile, 2, _CreateBitmapFromIcon(_WinAPI_GetSysColor($COLOR_MENU), @SystemDir & '\shell32.dll', 27, 16, 16))

GUISetState()

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Func _CreateBitmapFromIcon($iBackground, $sIcon, $iIndex, $iWidth, $iHeight)

    Local $hDC, $hBackDC, $hBackSv, $hIcon, $hBitmap
    
    $hDC = _WinAPI_GetDC(0)
    $hBackDC = _WinAPI_CreateCompatibleDC($hDC)
    $hBitmap = _WinAPI_CreateSolidBitmap(0, $iBackground, $iWidth, $iHeight)
    $hBackSv = _WinAPI_SelectObject($hBackDC, $hBitmap)
    $hIcon = _WinAPI_PrivateExtractIcon($sIcon, $iIndex, $iWidth, $iHeight)
    If Not @error Then
        _WinAPI_DrawIconEx($hBackDC, 0, 0, $hIcon, 0, 0, 0, 0, $DI_NORMAL)
        _WinAPI_DestroyIcon($hIcon)
    EndIf
    _WinAPI_SelectObject($hBackDC, $hBackSv)
    _WinAPI_ReleaseDC(0, $hDC)
    _WinAPI_DeleteDC($hBackDC)
    Return $hBitmap
EndFunc   ;==>_CreateBitmapFromIcon

Func _WinAPI_PrivateExtractIcon($sIcon, $iIndex, $iWidth, $iHeight)

    Local $hIcon, $tIcon = DllStructCreate('hwnd'), $tID = DllStructCreate('hwnd')
    Local $Ret = DllCall('user32.dll', 'int', 'PrivateExtractIcons', 'str', $sIcon, 'int', $iIndex, 'int', $iWidth, 'int', $iHeight, 'ptr', DllStructGetPtr($tIcon), 'ptr', DllStructGetPtr($tID), 'int', 1, 'int', 0)

    If (@error) Or ($Ret[0] = 0) Then
        Return SetError(1, 0, 0)
    EndIf
    $hIcon = DllStructGetData($tIcon, 1)
    If ($hIcon = Ptr(0)) Or (Not IsPtr($hIcon)) Then
        Return SetError(1, 0, 0)
    EndIf
    Return $hIcon
EndFunc   ;==>_WinAPI_PrivateExtractIcon
Edited by Yashied

Share this post


Link to post
Share on other sites
rexx

It works!!

Thank you very much!! =D

Edited by rexx

Share this post


Link to post
Share on other sites
Yashied
wraithdu

Mmmm, I'm filing this one away :)

Share this post


Link to post
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
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.