Jump to content
kurtykurtyboy

WINAPI DRAWSTATE with HBITMAP and DSS_DISABLED

Recommended Posts

Hey all!

I am trying to draw a GDI bitmap as a 'disabled' state.
I believe this can be accomplished using DrawState with the DSS_DISABLED flag, but I seem to be missing something here. I found a DrawState example by funkey which works for icons but not bitmaps. 

The following code demonstrates that this works fine with an HICON, but only partially with HBITMAP. With DSS_NORMAL, the bitmap is drawn but there is a black border (background?). With DSS_DISABLED, it only shows a gray box.

Just as a test, I can draw the normal bitmap just fine using _WinAPI_AlphaBlend, but I don't know of a way to convert that to a disabled/grayed image.

Any help/tips/pointers is appreciated!

image.png.338ffe96c6435326b11344e298c7746e.png

The test code:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIEx.au3>
#include <GDIPlus.au3>

Global Const $DST_ICON = 0x03
Global Const $DST_BITMAP = 0x04

Global Const $DSS_NORMAL = 0x00
Global Const $DSS_UNION = 0x10
Global Const $DSS_DISABLED = 0x20
Global Const $DSS_MONO = 0x80

Example()

Func Example()

    _GDIPlus_Startup() ;initialize GDI+

    ;get images for demonstration
    Local $hIcon = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 258, 24, 24)   ;extract the 'Save' icon
    Local $hBitmap = _GDIPlus_BitmapCreateFromHICON($hIcon)                             ;Create Bitmap from Icon (for demonstration)
    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)                  ;Create HBitmap from Bitmap
    _GDIPlus_BitmapDispose($hBitmap) ;dispose the bitmap

    ;create GUI
    Local $hGUI = GUICreate("DrawState Bitmap Test", 350, 250)
    GUISetState(@SW_SHOW, $hGUI)

    $hDC = _WinAPI_GetDC($hGUI)

    GUICtrlCreateLabel("Bitmap AlphaBlend", 5, 5)
    ;draws bitmap fine with 'transparent' background
    Local $hSrcDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $srcObjectOld = _WinAPI_SelectObject($hSrcDC, $hHBitmap)
    _WinAPI_AlphaBlend($hDC, 5, 20, 24, 24, $hSrcDC, 0, 0, 24, 24, 255, True)
    _WinAPI_SelectObject($hSrcDC, $srcObjectOld)
    _WinAPI_DeleteDC($hSrcDC)

    ;*** draws bitmap OK but with black border
    GUICtrlCreateLabel("Bitmap DrawState Normal", 5, 50)
    _WinAPI_DrawState($hDC, 0, $hHBitmap, 5, 70, 24, 24, BitOR($DST_BITMAP, $DSS_NORMAL))

    ;*** draws bitmap as a gray box
    GUICtrlCreateLabel("Bitmap DrawState Disabled", 5, 100)
    _WinAPI_DrawState($hDC, 0, $hHBitmap, 5, 120, 24, 24, BitOR($DST_BITMAP, $DSS_DISABLED))


    ;draws icon OK
    GUICtrlCreateLabel("Icon DrawState Normal", 170, 50)
    _WinAPI_DrawState($hDC, 0, $hIcon, 170, 70, 24, 24, BitOR($DST_ICON, $DSS_NORMAL))

    ;draws disabled icon OK
    GUICtrlCreateLabel("Icon DrawState Disabled", 170, 100)
    _WinAPI_DrawState($hDC, 0, $hIcon, 170, 120, 24, 24, BitOR($DST_ICON, $DSS_DISABLED))


    ;clean up!
    _WinAPI_DestroyIcon($hIcon)
    _WinAPI_DeleteObject($hHBitmap)
    _WinAPI_ReleaseDC($hGUI, $hDC)
    _GDIPlus_Shutdown()

    Local $iMsg
    While 1
        $iMsg = GUIGetMsg()

        Switch $iMsg
            Case $GUI_EVENT_CLOSE
                ExitLoop

        EndSwitch

        Sleep(10)
    WEnd

    GUIDelete()
EndFunc   ;==>Example

;From funkey
Func _WinAPI_DrawState($hDC, $hBrush, $lData, $x, $y, $w, $h, $iFlags)
    Local $aRet = DllCall("User32.dll", "BOOL", "DrawState", "handle", $hDC, "handle", $hBrush, "ptr", 0, "long", $lData, "long", 0, _
            "int", $x, "int", $y, "int", $w, "int", $h, "UINT", $iFlags)

    If @error Then Return SetError(@error, @extended, False)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_DrawState

 

Share this post


Link to post
Share on other sites
Posted (edited)

i don't think it will work, was looking in to that my self a time ago, it grays the whole image out all details are gone
i ended up creating a bitmap gray scale for my disabled item and a color one for enabled item, then switch displaying between the 2, there may be smarter ways but didn't dive to deep in to it, here is your example modified to display autoit example folders images

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIEx.au3>
#include <GDIPlus.au3>

Global Const $DST_ICON = 0x03
Global Const $DST_BITMAP = 0x04
Global Const $DSS_NORMAL = 0x00
Global Const $DSS_UNION = 0x10
Global Const $DSS_DISABLED = 0x20
Global Const $DSS_MONO = 0x80

Example()

Func Example()
    _GDIPlus_Startup() ;initialize GDI+

;~  $hBitmap = _GDIPlus_BitmapCreateFromFile ( @ProgramFilesDir &'\AutoIt3\Examples\GUI\Advanced\Images\blue.bmp' )
;~  $hBitmap = _GDIPlus_BitmapCreateFromFile ( @ProgramFilesDir &'\AutoIt3\Examples\GUI\logo4.gif' )
    $hBitmap = _GDIPlus_BitmapCreateFromFile(@ProgramFilesDir & '\AutoIt3\Examples\GUI\torus.png')

    $hClone = _GDIPlus_BitmapCloneArea($hBitmap, 0, 0, 80, 80,   $GDIP_PXF04INDEXED ) ;unfortinately $GDIP_PXF16GRAYSCALE does not work, set the correct size of image or get it with  _GDIPlus_ImageGetHeight/width
    $hHBitmaphClone = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hClone)

    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)                  ;Create HBitmap from Bitmap
    _GDIPlus_BitmapDispose($hBitmap) ;dispose the bitmap

    ;create GUI
    Local $hGUI = GUICreate("DrawState Bitmap Test", 350, 250)
    GUISetState(@SW_SHOW, $hGUI)

    $hDC = _WinAPI_GetDC($hGUI)

    ;*** draws bitmap OK but with black border
    GUICtrlCreateLabel("Bitmap DrawState Normal", 5, 10)
    _WinAPI_DrawState($hDC, 0, $hHBitmap, 5, 30, 80, 80, BitOR($DST_BITMAP, $DSS_NORMAL))  ;set size correcly not 80 80 

    ;*** draws bitmap as a gray box
    GUICtrlCreateLabel("Bitmap DrawState Disabled", 150, 10)
    _WinAPI_DrawState($hDC, 0, $hHBitmap, 150, 30, 80, 80, BitOR($DST_BITMAP, $DSS_DISABLED))


    ;*** draws bitmap OK but with black border
    GUICtrlCreateLabel("Bitmap DrawState Normal", 5, 130)
    _WinAPI_DrawState($hDC, 0, $hHBitmaphClone, 5, 150, 80, 80, BitOR($DST_BITMAP, $DSS_NORMAL))  ;set intended size of images not 80 80 

    ;*** draws bitmap as a gray box
    GUICtrlCreateLabel("Bitmap DrawState Disabled", 150, 130)
    _WinAPI_DrawState($hDC, 0, $hHBitmaphClone, 150, 150, 80, 80, BitOR($DST_BITMAP, $DSS_DISABLED))

    ;Sorry didnt I dit not clean up! 
    _GDIPlus_Shutdown()

    Local $iMsg
    While 1
        $iMsg = GUIGetMsg()

        Switch $iMsg
            Case $GUI_EVENT_CLOSE
                ExitLoop

        EndSwitch

        Sleep(10)
    WEnd

    GUIDelete()
EndFunc   ;==>Example

;From funkey
Func _WinAPI_DrawState($hDC, $hBrush, $lData, $x, $y, $w, $h, $iFlags)
    Local $aRet = DllCall("User32.dll", "BOOL", "DrawState", "handle", $hDC, "handle", $hBrush, "ptr", 0, "long", $lData, "long", 0, _
            "int", $x, "int", $y, "int", $w, "int", $h, "UINT", $iFlags)

    If @error Then Return SetError(@error, @extended, False)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_DrawState

 

Edited by jvds

Share this post


Link to post
Share on other sites

I managed to get the disabled look using DrawState, but I think it was only coincidence because now the normal state is black & white.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIEx.au3>
#include <GDIPlus.au3>

Global Const $DST_ICON = 0x03
Global Const $DST_BITMAP = 0x04

Global Const $DSS_NORMAL = 0x00
Global Const $DSS_UNION = 0x10
Global Const $DSS_DISABLED = 0x20
Global Const $DSS_MONO = 0x80

Example()

Func Example()

    _GDIPlus_Startup() ;initialize GDI+

    ;get images for demonstration
    Local $hIcon = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 258, 24, 24)   ;extract the 'Save' icon
    Local $hBitmap = _GDIPlus_BitmapCreateFromHICON($hIcon)                             ;Create Bitmap from Icon (for demonstration)
    Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)                  ;Create HBitmap from Bitmap
    _GDIPlus_BitmapDispose($hBitmap) ;dispose the bitmap

    ;create GUI
    Local $hGUI = GUICreate("DrawState Bitmap Test", 350, 250)
    GUISetState(@SW_SHOW, $hGUI)

    $hDC = _WinAPI_GetDC($hGUI)

    ;draws bitmap fine with 'transparent' background
    GUICtrlCreateLabel("Bitmap AlphaBlend", 5, 5)
    Local $hSrcDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $srcObjectOld = _WinAPI_SelectObject($hSrcDC, $hHBitmap)
    _WinAPI_AlphaBlend($hDC, 5, 20, 24, 24, $hSrcDC, 0, 0, 24, 24, 255, True)
    _WinAPI_SelectObject($hSrcDC, $srcObjectOld)
    _WinAPI_DeleteDC($hSrcDC)

    ;*** draws bitmap OK but with black border
    Local $hDestDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $hDestBmp = _WinAPI_CreateCompatibleBitmapEx($hDestDC, 24, 24, 0xFFFFFF)
    Local $hDestSv = _WinAPI_SelectObject($hDestDC, $hDestBmp)
    Local $hSrcDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $hSrcSv  = _WinAPI_SelectObject($hSrcDC, $hHBitmap)
    _WinAPI_AlphaBlend($hDestDC, 0, 0, 24, 24, $hSrcDC, 0, 0, 24, 24, 255, True)
    _WinAPI_SelectObject($hDestDC, $hDestSv)
    _WinAPI_DeleteDC($hDestDC)
    _WinAPI_SelectObject($hSrcDC, $hSrcSv)
    _WinAPI_DeleteDC($hSrcDC)
    GUICtrlCreateLabel("Bitmap DrawState Normal", 5, 50)
    _WinAPI_DrawState($hDC, 0, $hDestBmp, 5, 70, 0, 0, BitOR($DST_BITMAP, $DSS_NORMAL))

    ;*** draws bitmap as a gray box
    GUICtrlCreateLabel("Bitmap DrawState Disabled", 5, 100)
    _WinAPI_DrawState($hDC, 0, $hDestBmp, 5, 120, 0, 0, BitOR($DST_BITMAP, $DSS_DISABLED))


    ;draws icon OK
    GUICtrlCreateLabel("Icon DrawState Normal", 170, 50)
    _WinAPI_DrawState($hDC, 0, $hIcon, 170, 70, 0, 0, BitOR($DST_ICON, $DSS_NORMAL))

    ;draws disabled icon OK
    GUICtrlCreateLabel("Icon DrawState Disabled", 170, 100)
    _WinAPI_DrawState($hDC, 0, $hIcon, 170, 120, 0, 0, BitOR($DST_ICON, $DSS_DISABLED))


    ;clean up!
    _WinAPI_DestroyIcon($hIcon)
    _WinAPI_DeleteObject($hHBitmap)
    _WinAPI_ReleaseDC($hGUI, $hDC)
    _GDIPlus_Shutdown()

    Local $iMsg
    While 1
        $iMsg = GUIGetMsg()

        Switch $iMsg
            Case $GUI_EVENT_CLOSE
                ExitLoop

        EndSwitch

        Sleep(10)
    WEnd

    GUIDelete()
EndFunc   ;==>Example

;From funkey
Func _WinAPI_DrawState($hDC, $hBrush, $lData, $x, $y, $w, $h, $iFlags)
    Local $aRet = DllCall("User32.dll", "BOOL", "DrawState", "handle", $hDC, "handle", $hBrush, "ptr", 0, "long", $lData, "long", 0, _
            "int", $x, "int", $y, "int", $w, "int", $h, "UINT", $iFlags)

    If @error Then Return SetError(@error, @extended, False)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_DrawState

 

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

×
×
  • Create New...