Author Topic: Color Buttons  (Read 881 times)

fearless

  • Member
  • ***
  • Posts: 469
    • LetTheLightIn
Re: Color Buttons
« Reply #15 on: October 29, 2019, 12:43:06 PM »
I was just viewing GDI Handles on Process Explorer. Right click on the process and properties brings up the info. The Handles section bottom right of the performance tab. Click and paint and watch the GDI handles increase.

fearless

CM690II Case, HX1000 PSU, Asus Z97, Intel i7-4790K, Seidon 120v Cooler, 16GB DDR3, MSI GTX 980TI

My Github  Twitter

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 6758
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Color Buttons
« Reply #16 on: October 29, 2019, 02:08:48 PM »
guga,

With GDI, ALWAYS test your return values and keep track of what you allocate and must delete after. It sounds old fashioned but that is how you get GDI leak free.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

guga

  • Member
  • *****
  • Posts: 1074
  • Assembly is a state of art.
    • RosAsm
Re: Color Buttons
« Reply #17 on: October 30, 2019, 08:30:42 AM »
Hi Steve

Quote
With GDI, ALWAYS test your return values and keep track of what you allocate and must delete after. It sounds old fashioned but that is how you get GDI leak free.
Tks. :thumbsup: :thumbsup:

I´ll give a test on the app tonight to try to get rid of the leaking once i finished one more small routine. I managed to update one of the functions using BITMAPV5HEADER and forcing the dib to create the pixels in RGBA format rather then the default RGBQUAD. Msdn is poorly documented on this, but i suceeded to make it works . I was trying to understand what a hell this BI_BITFIELDS equate is all about when used to create a bitmap (or icon) with createdib.

Under the BMIHEADERV5 things becomes a bit hard to follow, but, to make the output be in RGBA all is necessary to invert the pixel mask and make sure to use BI_BITFIELDS rather then the default BI_RGB.  I´m still giving a test on this to check for speed etc, but it seems fast when not use others Gdi apis to manipulate the pixels. I.e: when manipulating them directly it seems to be faster.

The updated function i created to paint a button is as:

Code: [Select]
______________________________________________

[BITMAPINFO_V5.bmiHeaderV5.bv5SizeDis 0
 BITMAPINFO_V5.bmiHeaderV5.bv5WidthDis 4
 BITMAPINFO_V5.bmiHeaderV5.bv5HeightDis 8
 BITMAPINFO_V5.bmiHeaderV5.bv5PlanesDis 12
 BITMAPINFO_V5.bmiHeaderV5.bv5BitCountDis 14
 BITMAPINFO_V5.bmiHeaderV5.bV5CompressionDis 16
 BITMAPINFO_V5.bmiHeaderV5.bv5SizeImageDis 20
 BITMAPINFO_V5.bmiHeaderV5.bv5XPelsPerMeterDis 24
 BITMAPINFO_V5.bmiHeaderV5.bv5YPelsPerMeterDis 28
 BITMAPINFO_V5.bmiHeaderV5.bv5ClrUsedDis 32
 BITMAPINFO_V5.bmiHeaderV5.bv5ClrImportantDis 36
 BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 40
 BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 44
 BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 48
 BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 52
 BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis 56
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzXDis 60
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzYDis 64
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzZDis 68
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzXDis 72
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzYDis 76
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzZDis 80
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzXDis 84
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzYDis 88
 BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzZDis 92
 BITMAPINFO_V5.bmiHeaderV5.bv5GammaRedDis 96
 BITMAPINFO_V5.bmiHeaderV5.bv5GammaGreenDis 100
 BITMAPINFO_V5.bmiHeaderV5.bv5GammaBlueDis 104
 BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis 108
 BITMAPINFO_V5.bmiHeaderV5.bV5ProfileDataDis 112
 BITMAPINFO_V5.bmiHeaderV5.bV5ProfileSizeDis 116
 BITMAPINFO_V5.bmiHeaderV5.bV5ReservedDis 120
 BITMAPINFO_V5.bmiColors.rgbBlueDis 124
 BITMAPINFO_V5.bmiColors.rgbGreenDis 125
 BITMAPINFO_V5.bmiColors.rgbRedDis 126
 BITMAPINFO_V5.bmiColors.rgbReservedDis 127]

[Size_of_BITMAPINFO_V5 128]

[Size_Of_BITMAPV5HEADER 124]

;;
        CreateDibButtonEx function
       
        Arguments:
       
            hCtrl (in)  - Handle of the button control to be painted
           
            hDC (in)    - Handle of the DC of the control. The Dc is the destination one, where the control will be painted to.
           
            pCtrlRect (out)  - Pointer to a RECT structure that will be used to save the coordinates of the rectangle (button).
                               This argument is optional.
           
            pBtnWidth (out)  -  Pointer to a variable (Dword size) use to save the width of the control.
           
            pBtnHeight (out) -  Pointer to a variable (Dword size) use to save the height of the control
           
            pvbits (out)     - Pointer to a variable (Dword size) where it will be used to store the pointer to the pixels array
                               of the generated dib file.
           
            TopDown (in)    - A variable used as a flag to determine the order of the dib pixels. It is the same behaviour as in any of
                              the BITMAPINFOHEADER, BITMAPINFO_V5, BITMAPINFO_V4, BITMAPINFO_V3 structures.
                              When the height of the bitmap (in pixels) is positive, the bitmap is a bottom-up DIB and its origin is the lower-left corner.
                              If the height is negative, the bitmap is a top-down DIB and its origin is the upper-left corner.
                              This flag is used to automate the order process. Therefore.
                                If TopDown is settled to &TRUE, the dib image is a top-down DIB (i.e.: the height becomes negative)
                                If TopDown is settled to &FALSE, the dib image is a bottom-up DIB (i.e.: the height becomes positive).
                             
                              Setting to &FALSE is the default one for bitmaps, since the majority of the bitmaps are created in bottom-up order.
                              For icons, they are created using top-down DIBs so we must set this flag to &TRUE when working on icons.

            IsRGBA (in)     - A dib (bitmap) is generally created in gdi with RGBQUAD format as described in BITMAPINFO structure.
                              Afterall, a BITMAPINFO structure is formed by a BITMAPINFOHEADER (or BITMAPINFO_V5, BITMAPINFO_V4, BITMAPINFO_V3) followed
                              with a RGBQUAD array of structures, like this:
                              [RGBQUAD:
                                RGBQUAD.Blue: B$ 0
                                RGBQUAD.Green: B$ 0
                                RGBQUAD.Red: B$ 0
                                RGBQUAD.Alpha: B$ 0]
                             
                              However, we can change the order of the pixels, and make the dib contains the pixel array in RGBA format.
                              This is what this parameter is used for.
                             
                              If IsRGBA is settled to &TRUE, the pixels are in RGBA format (COLORREF). I.e:
                               
                                [RGBA:
                                    RGBA.Red: B$ 0
                                    RGBA.Green: B$ 0
                                    RGBA.Blue: B$ 0
                                    RGBA.Alpha: B$ 0]
                               
                                Note: Remembering that RGBA format is the same as COLORREF
                             
                                [COLORREF:
                                    COLORREF.Red: B$ 0
                                    COLORREF.Green: B$ 0
                                    COLORREF.Blue: B$ 0
                                    COLORREF.Alpha: B$ 0]
                             
                              Otherwise, if IsRGBA is settled to &FALSE, the pixels are in RGQUAD format.

        Remarks:

                If biHeight is negative, indicating a top-down DIB  (i.e: when TopDown is &TRUE), biCompression must be either BI_RGB or BI_BITFIELDS.
                Top-down DIBs cannot be compressed.
                Therefore, the CreateDibButtonEx checks either the Dib must use BI_BITFIELDS or RGB. The rule (although unddocumented in msdn) is simple:
               
                Whenever we set IsRGBA to TRUE, we invert the order of the pixels (channels red and blue are switched), forcing it to be displayed in RGBA format. Thus, the BI_BITFIELDS flag
                is applied internally to make sure the result will be in RGBA.
               
                When you want the DIB to be created in RGBQUAD simply set IsRGBA flag to &FALSE, and the BI_RGB will be applied internally using the default masks that
                creates the RGBQUAD pixel order.
           
    References:
        Example of using BITMAPV5HEADER at:
        https://chromium.googlesource.com/chromium/chromium/+/master/ui/gfx/icon_util.cc
        https://stackoverflow.com/questions/4455655/how-do-i-create-a-bitmap-using-the-bitmapv5header-header
        https://ios.develop-bugs.com/article/16690047/BITMAPV5HEADER+getting+RGBA+keep+A+at+255
        https://msdn.microsoft.com/en-us/ie/dd372216(v=vs.100)#_color_bitmap.exe_a_command_line_utility_for_converting_bitmap_headers

;;

Proc CreateDibButtonEx:
    Arguments @hCtrl, @hDC, @pCtrlRect, @pBtnWidth, @pBtnHeight, @pvbits, @TopDown, @IsRGBA
    Structure @BtnBitMapInfoPlus 144, @BITMAPINFO_V5.bmiHeaderV5.bv5SizeDis 0, @BITMAPINFO_V5.bmiHeaderV5.bv5WidthDis 4, @BITMAPINFO_V5.bmiHeaderV5.bv5HeightDis 8,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5PlanesDis 12, @BITMAPINFO_V5.bmiHeaderV5.bv5BitCountDis 14, @BITMAPINFO_V5.bmiHeaderV5.bV5CompressionDis 16,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5SizeImageDis 20, @BITMAPINFO_V5.bmiHeaderV5.bv5XPelsPerMeterDis 24, @BITMAPINFO_V5.bmiHeaderV5.bv5YPelsPerMeterDis 28,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5ClrUsedDis 32, @BITMAPINFO_V5.bmiHeaderV5.bv5ClrImportantDis 36, @BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 40,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 44, @BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 48, @BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 52,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis 56, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzXDis 60,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzYDis 64, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzZDis 68,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzXDis 72, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzYDis 76,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzZDis 80, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzXDis 84,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzYDis 88, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzZDis 92,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5GammaRedDis 96, @BITMAPINFO_V5.bmiHeaderV5.bv5GammaGreenDis 100, @BITMAPINFO_V5.bmiHeaderV5.bv5GammaBlueDis 104,
                                      @BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis 108, @BITMAPINFO_V5.bmiHeaderV5.bV5ProfileDataDis 112, @BITMAPINFO_V5.bmiHeaderV5.bV5ProfileSizeDis 116,
                                      @BITMAPINFO_V5.bmiHeaderV5.bV5ReservedDis 120, @BITMAPINFO_V5.bmiColors.rgbBlueDis 124, @BITMAPINFO_V5.bmiColors.rgbGreenDis 125,
                                      @BITMAPINFO_V5.bmiColors.rgbRedDis 126, @BITMAPINFO_V5.bmiColors.rgbReservedDis 127,
                                      @RECT.LeftDis 128, @RECT.TopDis 132, @RECT.RightDis 136, @RECT.BottomDis 140

    Uses ecx, edx

    ; The default RosAsm macro does not allows (yet) multiple structures inside a procedure/function such as:
    ; LOCAL wc   :WNDCLASSEX
    ; LOCAL msg  :MSG
    ; So, to overcome this, simply is needed to build the proper displacements of more then one structure in the same structure macro.
    ; Therefore, BtnBitMapInfoPlus is nothing more then the displacement of 2 structures BITMAPINFO and RECT one after the other
    ; and '144' is the total size of both. i.e: 128 for BITMAPINFO_V5 (Labeled here as: BMIHEADERV5, that is simply BITMAPINFO_V5 + one RGBQUAD) + 16 for RECT

    ; Important: In rosAsm, the structure macro ALWAYS comes after the Local macro. The macro 'uses' where created to preserves the registers (Push at beginning and pop before exiting the function)

    ; Clean the BtnBitMapInfoPlus structure before using it
    call 'Rosmem.ZeroMemory' D@BtnBitMapInfoPlus, 144

    ; 1st get the dimensions of the controls
    lea eax D@RECT.LeftDis
    call 'USER32.GetClientRect' D@hCtrl, eax

    ; Then we copy our Ctrl rect to the output
    If D@pCtrlRect <> 0
        mov ecx D@pCtrlRect
        mov eax D@RECT.LeftDis | mov D$ecx+RECT.LeftDis eax
        mov eax D@RECT.TopDis | mov D$ecx+RECT.TopDis eax
        mov eax D@RECT.RightDis | mov D$ecx+RECT.RightDis eax
        mov eax D@RECT.BottomDis | mov D$ecx+RECT.BottomDis eax
    End_If

    ; calculate the width and height for output and also to use those values on the BITMAPV5HEADER header structure
    mov ecx D@pBtnWidth | mov eax D@RECT.RightDis | sub eax D@RECT.LeftDis | mov D$ecx eax
    ; TopDown height = negative
    ; bottom-up , height = positive
    mov edx D@pBtnHeight | mov ecx D@RECT.BottomDis | sub ecx D@RECT.TopDis | mov D$edx ecx | On D@TopDown <> 0, neg ecx  ; Default for top-down bitmap is &FALSE.

    ; Fill BITMAPINFO structure with the dimensions of the control to the BITMAPINFOHEADER stucture used in CreateDIBSection and a minimum of information to generate the dib

    mov D@BITMAPINFO_V5.BMIHEADERV5.bv5SizeDis Size_Of_BITMAPV5HEADER ; set the size of BITMAPV5HEADER Info structure
    mov D@BITMAPINFO_V5.BMIHEADERV5.bv5WidthDis eax
    mov D@BITMAPINFO_V5.BMIHEADERV5.bv5HeightDis ecx

    mov W@BITMAPINFO_V5.BMIHEADERV5.bv5PlanesDis 1 ; at least one plane is necessary
    mov W@BITMAPINFO_V5.BMIHEADERV5.bv5BitCountDis 32 ; and make the image with 32 Bits. Enough for a good quality of a button

    ; Since we zeroed at start, it means our image compression is BI_RGB (value = 0 = uncompressed). Therefore, no need to set this member again
    ; Also, the bmicolors are set to zero too (NULL).
     ;mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_BITFIELDS
    ; mov B@BITMAPINFO_V5.bmiColors.rgbBlueDis 0
    ; mov D@BITMAPINFO_V5.bmiColors.rgbGreenDis 0
    ; mov D@BITMAPINFO_V5.bmiColors.rgbRedDis 0
    ; mov B@BITMAPINFO_V5.bmiColors.rgbReservedDis 0

    ; One last note. Since biCompression = BI_RGB, the biSizeImage member can also be settled to 0 (Already is, since we zeroed the whole structure at start)
    ; Therefore, we don´t have to calculate the size of the bitmap.
    ; All we need to understand is that for 32 bit images the pixels are in RGBA format, so 4 bytes, on a total array of width*height*4 bytes (Size of a dword = 4).
    ; Ref: https://docs.microsoft.com/pt-br/previous-versions/dd183376(v=vs.85)

    ; mov D@BITMAPINFO_V5.bmiHeader.biSizeImageDis 0

    ; Initializing the bitmap format to 32 bit ARGB. Ref: https://chromium.googlesource.com/chromium/chromium/+/master/ui/gfx/icon_util.cc
    If D@IsRGBA = &TRUE
        ; make it in RGBA order
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 0FF
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 0FF00
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 0FF0000
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 0FF000000
        mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_BITFIELDS
    Else
        ; Setting to know. Transform the pixel order to RGBQUAD (the default one)
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 0FF0000
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 0FF00
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 0FF
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 0FF000000
        mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_RGB
    End_If

    ; Use the system color space.  The default value is LCS_CALIBRATED_RGB, which
    ; causes us to crash if we don't specify the approprite gammas, etc.
    ; See: http://msdn.microsoft.com/en-us/library/ms536531(VS.85).aspx
    mov D@BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis &LCS_WINDOWS_COLOR_SPACE

    ; Use a valid value for bV5Intent as 0 is not a valid one.
    ; See http://msdn.microsoft.com/en-us/library/dd183381(VS.85).aspx
    mov D@BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis &LCS_GM_IMAGES


    ; Finally we can create our dib image and retrieve the pixel data that will be stored in pvbits
    call 'GDI32.CreateDIBSection' D@hDC, D@BtnBitMapInfoPlus, &DIB_RGB_COLORS, D@pvBits, &NULL, 0


EndP


called it as:

Code: [Select]
    lea ecx D@pvBits | mov D$ecx 0
    lea eax D@BtnWidth
    lea ebx D@BtnHeight
    call CreateDibButtonEx D@hCtrl, D@NewDC, D@BtnRect, eax, ebx, ecx, &FALSE, &TRUE
    mov D@memBM eax

I also gave a test on a gradient fill outine (the one i posted earlier) and i will later try the ones from Mr. Fierless to check the speed. The result, so far is as:



Once i succeed to fix the gdi leaking, i´ll rewrite the functions to coloring a button again and try to make it easier to use and post it here (maybe i´ll create a tiny library for that).  Using BITMAPV5HEADER seems better then the default BITMAPINFO structure, because (in theory) it can be used to create transparent bitmaps without the needs of visual style or owerdrawn etc.


Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

  • Member
  • *****
  • Posts: 1074
  • Assembly is a state of art.
    • RosAsm
Re: Color Buttons
« Reply #18 on: November 01, 2019, 04:06:17 AM »
Hi Guys.

Can someone help me fix or understand what i´m doing wrong ? I´m trying to eliminate the gdi leaking, but got nothing yet. I believe it happens in one of the 2 main functions that uses gdi, but don´t know what i´m doing wrong.

One of them is this. Is it correct/preserving the gdi api ? This is the functions that creates the rainbow area (the color picker).

The color picker is created at WM_INITDIALOG. It creates the pvbits (the pixels) to be manipulated later on the app, and also exports the Gdi handle (rainbowDC) and the dib file to be used OldRainbowBitMap.

It works like this:

Code: [Select]
    ...If D@Message = &WM_INITDIALOG

        call 'GDI32.CreateSolidBrush' {RGB 50,50, 50} | mov D$hDialogBrush eax
        (...)
        call CreateRainbowImage D$IconEditorHandle, OldRainbowBitMap, RainbowDC, RainbowData, D$SlideGreenPos


Code: [Select]
; Build a 2 dimensions color table in memory (blue/red):

[RainbowDC: D$ 0]
[RainBowHandle: D$ 0]
[OldRainbowBitMaP: D$ 0]
[IsRainbowActive: D$ 0]

[RainbowData: D$ 0] ; Rainbow pixels are stored here
(...)

 - parameters - hIcon was the handle of the main windows (dispites it´s name), but it is not being used since i associated the dc with the whole screen rather then the dialog at  call 'USER32.GetDC' &NULL

Proc CreateRainbowImage:
    Arguments @hIcon, @pRainbowBitMap, @pRainBowDC, @pRainBowData, @SliderPos
    Local @pvBits, @hDCImage, @hImageHandle

    ; Get any DC
    call 'USER32.GetDC' &NULL | mov D@hDCImage eax

    mov edi D@pRainBowDC
    call 'GDI32.CreateCompatibleDC' D@hDCImage
    mov D$edi eax

    lea eax D@pvBits | mov D$eax 0
    call InitializeDib D$edi, 256, 256, eax, RAINBOW_ORDER, RAINBOW_FORMAT
    mov D@hImageHandle eax ; dibm

    ; copy our pvbit (the pixels) to our output and create the rainbow to it
    mov eax D@pvBits
    mov ecx D@pRainBowData | mov D$ecx eax

    ; filling colors data: The pixels ae in RGBA format (Same as COLORREF structure)
    call CreateRainbowData D@pvBits, RAINBOW_FORMAT

    ; Select our created rainboww bitmnap to our created compatible handle to do whatever operations we want
    ; and later use BitBlt to display the image on screen
    call 'GDI32.SelectObject' D$edi, D@hImageHandle

    ; Release DC
    call 'user32.ReleaseDC' &NULL, D@hDCImage

    mov edi D@pRainbowBitMap
    mov eax D@hImageHandle
    mov D$edi eax

EndP

RAINBOW_ORDER and RAINBOW_FORMAT are just equates to create the dib on a top-down or bottom-up order or in RGBA or RGBQUAD formats
[RAINBOW_ORDER_NORMAL &TRUE]
[RAINBOW_ORDER_INVERTED &FALSE]

[RAINBOW_ORDER RAINBOW_ORDER_NORMAL];NORMAL] ; &TRUE = Normal dib (TopDown. Height = negative). &FALSE = inverted dib (Bottom-Up. Height = positive)

[RAINBOW_IS_RGB 1]
[RAINBOW_IS_RGBQUAD 0]

[RAINBOW_FORMAT RAINBOW_IS_RGB] ; The format of the Rainbow in memory and also in physical format of the pixels. If the foprmat is RGB, we use &TRUE (RAINBOW_IS_RGB). Otherwise it is false (RAINBOW_IS_RGBQUAD)

InitializeDib is the function that creates the dib (similar to CreateDibButtonEx i used for the buttons)
Code: [Select]
Proc InitializeDib:
    Arguments @hDC, @pBtnWidth, @pBtnHeight, @pvbits, @TopDown, @IsRGBA
    Structure @BtnBitMapInfoPlus 144, @BITMAPINFO_V5.bmiHeaderV5.bv5SizeDis 0, @BITMAPINFO_V5.bmiHeaderV5.bv5WidthDis 4, @BITMAPINFO_V5.bmiHeaderV5.bv5HeightDis 8,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5PlanesDis 12, @BITMAPINFO_V5.bmiHeaderV5.bv5BitCountDis 14, @BITMAPINFO_V5.bmiHeaderV5.bV5CompressionDis 16,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5SizeImageDis 20, @BITMAPINFO_V5.bmiHeaderV5.bv5XPelsPerMeterDis 24, @BITMAPINFO_V5.bmiHeaderV5.bv5YPelsPerMeterDis 28,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5ClrUsedDis 32, @BITMAPINFO_V5.bmiHeaderV5.bv5ClrImportantDis 36, @BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 40,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 44, @BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 48, @BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 52,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis 56, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzXDis 60,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzYDis 64, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzRed.ciexyzZDis 68,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzXDis 72, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzYDis 76,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzGreen.ciexyzZDis 80, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzXDis 84,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzYDis 88, @BITMAPINFO_V5.bmiHeaderV5.bv5Endpoints.ciexyzBlue.ciexyzZDis 92,
                                      @BITMAPINFO_V5.bmiHeaderV5.bv5GammaRedDis 96, @BITMAPINFO_V5.bmiHeaderV5.bv5GammaGreenDis 100, @BITMAPINFO_V5.bmiHeaderV5.bv5GammaBlueDis 104,
                                      @BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis 108, @BITMAPINFO_V5.bmiHeaderV5.bV5ProfileDataDis 112, @BITMAPINFO_V5.bmiHeaderV5.bV5ProfileSizeDis 116,
                                      @BITMAPINFO_V5.bmiHeaderV5.bV5ReservedDis 120, @BITMAPINFO_V5.bmiColors.rgbBlueDis 124, @BITMAPINFO_V5.bmiColors.rgbGreenDis 125,
                                      @BITMAPINFO_V5.bmiColors.rgbRedDis 126, @BITMAPINFO_V5.bmiColors.rgbReservedDis 127,
                                      @RECT.LeftDis 128, @RECT.TopDis 132, @RECT.RightDis 136, @RECT.BottomDis 140

    Uses ecx, edx

    ; Clean the BtnBitMapInfoPlus structure before using it
    call 'Rosmem.ZeroMemory' D@BtnBitMapInfoPlus, 144

    mov eax D@pBtnWidth
    mov ecx D@pBtnHeight | On D@TopDown <> 0, neg ecx  ; Default for top-down bitmap is &FALSE.

    ; Fill BITMAPINFO structure with the dimensions of the control to the BITMAPINFOHEADER stucture used in CreateDIBSection and a minimum of information to generate the dib

    mov D@BITMAPINFO_V5.BMIHEADERV5.bv5SizeDis Size_Of_BITMAPV5HEADER ; set the size of BITMAPV5HEADER Info structure
    mov D@BITMAPINFO_V5.BMIHEADERV5.bv5WidthDis eax
    mov D@BITMAPINFO_V5.BMIHEADERV5.bv5HeightDis ecx

    mov W@BITMAPINFO_V5.BMIHEADERV5.bv5PlanesDis 1 ; at least one plane is necessary
    mov W@BITMAPINFO_V5.BMIHEADERV5.bv5BitCountDis 32 ; and make the image with 32 Bits. Enough for a good quality of a button

    ; Since we zeroed at start, it means our image compression is BI_RGB (value = 0 = uncompressed). Therefore, no need to set this member again
    ; Also, the bmicolors are set to zero too (NULL).
     ;mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_BITFIELDS
    ; mov B@BITMAPINFO_V5.bmiColors.rgbBlueDis 0
    ; mov D@BITMAPINFO_V5.bmiColors.rgbGreenDis 0
    ; mov D@BITMAPINFO_V5.bmiColors.rgbRedDis 0
    ; mov B@BITMAPINFO_V5.bmiColors.rgbReservedDis 0

    ; One last note. Since biCompression = BI_RGB, the biSizeImage member can also be settled to 0 (Already is, since we zeroed the whole structure at start)
    ; Therefore, we don´t have to calculate the size of the bitmap.
    ; All we need to understand is that for 32 bit images the pixels are in RGBA format, so 4 bytes, on a total array of width*height*4 bytes (Size of a dword = 4).
    ; Ref: https://docs.microsoft.com/pt-br/previous-versions/dd183376(v=vs.85)

    ; mov D@BITMAPINFO_V5.bmiHeader.biSizeImageDis 0

    ; Initializing the bitmap format to 32 bit ARGB. Ref: https://chromium.googlesource.com/chromium/chromium/+/master/ui/gfx/icon_util.cc
    If D@IsRGBA = &TRUE
        ; make it in RGBA order
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 0FF
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 0FF00
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 0FF0000
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 0FF000000
        mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_BITFIELDS
    Else
        ; Setting to know. Transform the pixel order to RGBQUAD (the default one)
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5RedMaskDis 0FF0000
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5GreenMaskDis 0FF00
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5BlueMaskDis 0FF
        mov D@BITMAPINFO_V5.bmiHeaderV5.bv5AlphaMaskDis 0FF000000
        mov D@BITMAPINFO_V5.BMIHEADERV5.bV5CompressionDis &BI_RGB
    End_If

    ; Use the system color space.  The default value is LCS_CALIBRATED_RGB, which
    ; causes us to crash if we don't specify the approprite gammas, etc.
    ; See: http://msdn.microsoft.com/en-us/library/ms536531(VS.85).aspx
    mov D@BITMAPINFO_V5.bmiHeaderV5.bv5CSTypeDis &LCS_WINDOWS_COLOR_SPACE

    ; Use a valid value for bV5Intent as 0 is not a valid one.
    ; See http://msdn.microsoft.com/en-us/library/dd183381(VS.85).aspx
    mov D@BITMAPINFO_V5.bmiHeaderV5.bV5IntentDis &LCS_GM_IMAGES


    ; Finally we can create our dib image and retrieve the pixel data that will be stored in pvbits
    call 'GDI32.CreateDIBSection' D@hDC, D@BtnBitMapInfoPlus, &DIB_RGB_COLORS, D@pvBits, &NULL, 0

 EndP

; CreateRainbowData is the function that manipulates the pixels in the rainbow directly.
Code: [Select]
; Showing Square Rainbow for color choice:

Proc CreateRainbowData:
    Arguments @pOutput, @IsRGB

    If D@IsRGB = &TRUE
        call CreateRainbowData_RGBA D@pOutput
    Else
        call CreateRainbowData_RGBQUAD D@pOutput
    End_If

EndP

Proc CreateRainbowData_RGBA:
    Arguments @pOutput
    Uses ebx, ecx, edi

    mov edi D@pOutput
    xor ebx ebx
    .Do
        xor ecx ecx
        Do
            mov B$edi+ecx*4+RGBA.RedDis cl
            mov B$edi+ecx*4+RGBA.GreenDis 0
            mov B$edi+ecx*4+RGBA.BlueDis bl
            mov B$edi+ecx*4+RGBA.AlphaDis 0
            inc ecx
        Loop_Until ecx >= 256
        add edi (256*4)
        inc ebx
    .Loop_Until ebx >= 256

EndP

Proc CreateRainbowData_RGBQUAD:
    Arguments @pOutput
    Uses ebx, ecx, edi

    mov edi D@pOutput
    xor ebx ebx
    .Do
        xor ecx ecx
        Do
            mov B$edi+ecx*4+RGBQUAD.rgbBlueDis cl
            mov B$edi+ecx*4+RGBQUAD.rgbGreenDis 0
            mov B$edi+ecx*4+RGBQUAD.rgbRedDis bl
            mov B$edi+ecx*4+RGBQUAD.rgbReservedDis 0
            inc ecx
        Loop_Until ecx >= 256
        add edi (256*4)
        inc ebx
    .Loop_Until ebx >= 256

EndP

To show the rainbow a function was made to be used under mouse action. So, it is located inside other functions after WM_LBUTTONUP and WM_MOUSEMOVE. The main function is called ShowRainbow. This function is activated when the user right click on the toolbox squares  and also  when the user click the trackbar.


Code: [Select]

; call ShowRainbow D$IconEditorHandle, D$RainbowDC, D$RainbowData, D$SlideGreenPos
Proc ShowRainbow:
    Arguments @hIcon, @hRainBowBC, @pRainbowPixels, @SliderPos
    Local @RainbowData
    Structure @PAINTSTRUCT 64, @PAINTSTRUCT.hdcDis 0, @PAINTSTRUCT.fEraseDis 4,
                               @PAINTSTRUCT.rcPaint.leftDis 8, @PAINTSTRUCT.rcPaint.topDis 12, @PAINTSTRUCT.rcPaint.rightDis 16, @PAINTSTRUCT.rcPaint.bottomDis 20,
                               @PAINTSTRUCT.fRestoreDis 24, @PAINTSTRUCT.fIncUpdateDis 28, @PAINTSTRUCT.rgbReservedDis 32
    Uses ecx, edx

    call FillRainBowNew D@pRainbowPixels, D@SliderPos

    call 'Rosmem.ZeroMemory' D@PAINTSTRUCT, Size_of_PAINTSTRUCT

    call 'USER32.BeginPaint' D@hIcon, D@PAINTSTRUCT

    call 'USER32.GetDC' D@hIcon | mov D@PAINTSTRUCT.hdcDis eax

    ; Synchronize before we manipulate the pixels
    call 'GDI32.GdiFlush'

    call 'GDI32.BitBlt' D@PAINTSTRUCT.hdcDis, RAINBOW_CX_PIXEL_POS, RAINBOW_CY_PIXEL_POS, RAINBOW_WIDTH, RAINBOW_HEIGHT, D@hRainBowBC, 0, 0, &SRCCOPY

    call 'USER32.ReleaseDC' D@hIcon, D@PAINTSTRUCT.hdcDis

    call 'USER32.EndPaint' D@hIcon, D@PAINTSTRUCT


EndP


; FillRainBowNew is the one responsiblee for direct manipulation of the pixels when the user clicck teh trackbar, for example
Code: [Select]
; Fill Rainbow data biased on green pos of tracker

Proc FillRainBowNew:
    Arguments @pOutput, @Slider
    Uses ebx, ecx, edi

    mov eax D@Slider
    mov edi D@pOutput
    xor ebx ebx
    .Do
        xor ecx ecx
        Do
            mov B$edi+ecx*4+RGBA.GreenDis al
            inc ecx
        Loop_Until ecx >= 256
        add edi (256*4)
        inc ebx
    .Loop_Until ebx >= 256

EndP


The cleanup of the rainbow iss done when the user exits the app, so at WM_CLOSE or WM_DESTROY messages, like this:

Code: [Select]
Proc DeleteRainbowDCEx:

    call 'GDI32.DeleteObject' D$OldRainbowBitMap ; dibm
    ; pvBits is no longer valid!!!
    call 'GDI32.DeleteDC' D$RainbowDC ; dc1 this will also delete the pixels RainbowData

EndP


So, at CreateRainbowImage, do i need to use selectobject api ? If so, why / how ?
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

HSE

  • Member
  • *****
  • Posts: 1148
  • <AMD>< 7-32>
Re: Color Buttons
« Reply #19 on: November 01, 2019, 04:25:38 AM »
Hi Guga!

First brush is never deleted ¿?. But upload the file to see more.

guga

  • Member
  • *****
  • Posts: 1074
  • Assembly is a state of art.
    • RosAsm
Re: Color Buttons
« Reply #20 on: November 01, 2019, 04:29:58 AM »
Hi HSE, thanks :)

Here is the file. Remembering that the source is embedded. You need to open the file in RosAsm to see/edit the source.

There´s no brush on the function CreateRainbowImage, but, yes, the dib created at InitializeDib and the DC handle at CreateCompatibleDC are only deleted when the apps exits.  The reason is to make the pixels (at pvBits) be available to direct manipulation on other parts of the app. I don´t know if i need to use selçect api on thiss part of the function etcc. I´m trying to understand how this leaking works and how to properly use the selectobject etc. The leaking is happenning in other parts of the app on functions that draws the icon on the screen, but those i´ll post later once i understand if this part of the code at CreateRainbowImage is correct or not.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

LiaoMi

  • Member
  • ****
  • Posts: 593
Re: Color Buttons
« Reply #21 on: November 01, 2019, 05:03:11 AM »
Hi guga,

CreateSolidBrush

0040a96c
0040817b Proc
0040815a

make sure that every brush created with CreateSolidBrush gets properly destroyed, no other memory leaks found  :tongue: I took an example program from the first page...





guga

  • Member
  • *****
  • Posts: 1074
  • Assembly is a state of art.
    • RosAsm
Re: Color Buttons
« Reply #22 on: November 01, 2019, 05:27:46 AM »
Thks LiaoMi

How you achieved the addresses of the leaking GDI ? Which program did you used to see the addresses ?
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

LiaoMi

  • Member
  • ****
  • Posts: 593
Re: Color Buttons
« Reply #23 on: November 01, 2019, 05:51:03 AM »
Thks LiaoMi

How you achieved the addresses of the leaking GDI ? Which program did you used to see the addresses ?

using Deleaker utility - deleaker.com, sometimes helps!

HSE

  • Member
  • *****
  • Posts: 1148
  • <AMD>< 7-32>
Re: Color Buttons
« Reply #24 on: November 01, 2019, 06:17:04 AM »
After CreateCompatibleDC must be DeleteDC, not ReleaseDC (ej line 1369)

fearless

  • Member
  • ***
  • Posts: 469
    • LetTheLightIn
Re: Color Buttons
« Reply #25 on: November 01, 2019, 08:51:34 AM »
I've also used this in the past: http://www.nirsoft.net/utils/gdi_handles.html

But quick checking with process explorer is my first step to see if there are any leaks first.
fearless

CM690II Case, HX1000 PSU, Asus Z97, Intel i7-4790K, Seidon 120v Cooler, 16GB DDR3, MSI GTX 980TI

My Github  Twitter

guga

  • Member
  • *****
  • Posts: 1074
  • Assembly is a state of art.
    • RosAsm
Re: Color Buttons
« Reply #26 on: November 01, 2019, 01:18:56 PM »
Hi fearless

yes, this is the one i´m currently using. I gave a test on the one LiaoMi told (deleaker), but, it accused no leak whatsoever Then i gave a try on GDIView and a few things i´m not understanding.

Here a shot, for example. Take a look at the fonts dc. When i force GDiVioew to refresh every second, the "detect counter' keeps ground. So i presume it is due to a gdi leaking right ?



But...on the routines i made for the font, i was unable to find where it is leaking. That routine is like this:

Code: [Select]
Proc DrawButtonEx:
    Arguments @hIcon, @hDCDest, @hCtrl
    Local @NewDC, @pvBits, @BtnWidth, @BtnHeight, @memBM, @hFont, @OldFont, @memBMOld, @BtnStatus, @IsGradientFill
    Structure @BtnRect 16, @BtnRect.leftDis 0,  @BtnRect.topDis 4,  @BtnRect.rightDis 8,  @BtnRect.bottomDis 12
    Uses ecx, edx, ebx


    mov D@IsGradientFill &FALSE ; later make it as a structure to be usd in the btn conrols
    mov D@BtnRect.leftDis 0
    mov D@BtnRect.topDis 0
    mov D@BtnRect.rightDis 0
    mov D@BtnRect.bottomDis 0

    call GetButtonStatus D@hCtrl
    mov D@BtnStatus eax

    ; 1st Create a compatible DC biased on the one from the control button. This Dc is the one we are going to paint in.
    call 'GDI32.CreateCompatibleDC' D@hDCDest | mov D@NewDC eax

    ; 2nd create a new font for the control and set it to our control....
    call CreateNewControlFont D@hCtrl | mov D@hFont eax
    ; ... and select it to save it on the new DC
    call 'GDI32.SelectObject' D@NewDC, D@hFont |  mov D@OldFont eax


    ; Get the control dimensions and create a Dib image of it. So, we will retrieve their pixels to manipulate them directly
    lea ecx D@pvBits | mov D$ecx 0
    lea eax D@BtnWidth
    lea ebx D@BtnHeight
    call CreateDibButtonEx D@hCtrl, D@NewDC, D@BtnRect, eax, ebx, ecx, &FALSE, &TRUE
    mov D@memBM eax

    ; 3rd select the generated Dib image onto the Source Dc and save it to be blitted
    call 'GDI32.SelectObject' D@NewDC, D@memBM | mov D@memBMOld eax

    .If D@IsGradientFill = &FALSE
        ; Now we can start filling our pixels on the created image with whatever colorschema we like. Here i made a simple paint of
        ; the whole image with Red = 177, G = 179, B = 182
        mov eax D@BtnWidth | imul eax D@BtnHeight | shl eax 2
        call FastBtnFill D@pvBits, eax, {RGB 80,80,80}
    .Else
        call CreateGradientFill D@pvBits, D@BtnWidth, D@BtnHeight, {RGB 255,180, 0}, {RGB 180, 0,0}
    .End_If

    Test_If D@BtnStatus &BST_FOCUS
        call DrawFocusBtn D@NewDC, D@BtnWidth, D@BtnHeight, {RGB 0,0,0} ; here it is in RGB format
    Test_End

    Test_If D@BtnStatus &BST_PUSHED
        add D@BtnRect.leftDis 2
        add D@BtnRect.topDis 2
    Test_End
    call SetTextColorEx D@hCtrl, D@BtnRect, D@NewDC, {RGB 80,80,0}, &TRANSPARENT, {RGB 255,255,255} ; here color are in RGB format


    call PaintButton D@hCtrl, D@hDCDest, D@NewDC, D@BtnWidth, D@BtnHeight

    ; and finally start cleaning all of this
    call SafeCleanGDIObject D@NewDC, D@OldFont
    call SafeCleanGDIObject D@NewDC, D@memBMOld ; this will also delete the pixels RainbowData

    call 'GDI32.DeleteObject' D@memBM

    ; the new dc is no longer needed, since we blitted/painted onto the old one
    call 'GDI32.DeleteDC' D@NewDC


EndP

The only function responsible for handling the font is at CreateNewControlFont
Code: [Select]
;;
    Create a new font for the control

    hCtrl = Handle of the control that contains a font. It can be a button, tatic control etc.

    Return value:
    The fucntion will return in eax a new handle for the font
;;


Proc CreateNewControlFont:
    Arguments @hCtrl
    Uses ecx, edx, ebx

    ; Retrieves the font with which the control is currently drawing its text.
    call 'USER32.SendMessageA' D@hCtrl, &WM_GETFONT, 0, 0
    If eax = &NULL
        ; if no font is found, get the system one
        call 'GDI32.GetStockObject' &SYSTEM_FONT
        mov ebx eax
        ; ... and apply it to our control
        call 'USER32.SendMessageA' D@hCtrl, &WM_SETFONT, eax, &TRUE
        mov eax ebx
    End_If

EndP

DrawButtonEx is thbee one called from WM_CTLCOLORBTN messages....but....the font dc is deleted before the function ends, with SafeCleanGDIObject

Code: [Select]
; this function cleans the gdi objectes previously selected onto a DC

Proc SafeCleanGDIObject:
    Arguments @hDC, @hObject
    Uses ecx, edx

    call 'GDI32.SelectObject' D@hDC, D@hObject
    call 'GDI32.DeleteObject' D@hObject

EndP


So, since i deleted the new font at " call SafeCleanGDIObject D@NewDC, D@OldFont", shouldn´t be no leak at all ?

The only way i was ablee to remove the font for being listed in gdiview is adding a "call 'GDI32.DeleteObject' D@hFont" imemdiatelly before the end of the DrawButtonEx function. But, if i do that, the font become weird (fat/large) .
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

HSE

  • Member
  • *****
  • Posts: 1148
  • <AMD>< 7-32>
Re: Color Buttons
« Reply #27 on: November 01, 2019, 02:17:20 PM »
in safeclean: DeleteObject,eax

guga

  • Member
  • *****
  • Posts: 1074
  • Assembly is a state of art.
    • RosAsm
Re: Color Buttons
« Reply #28 on: November 01, 2019, 02:56:52 PM »
Indeed...but..now the font becomes weird.



How to make the font be thin again and release gdi at the same time ?
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

HSE

  • Member
  • *****
  • Posts: 1148
  • <AMD>< 7-32>
Re: Color Buttons
« Reply #29 on: November 01, 2019, 11:58:05 PM »
Hi Guga!

You have to:
  • make font handle persistent (global in your application)
  • create font at initialization (in WM_CREATE usually)
  • delete the font at the end (in WM_DESTROY usually)