News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

CTLCOLORSTATIC problem

Started by guga, August 13, 2016, 09:01:36 AM

Previous topic - Next topic

guga

Hi guys

i´m trying to make a static control changes color under user command, but i´m unable to get the brush to return the proper value.

I built a dialog containing a editbox and a updown controls and a static control from where the color needs to be changed.

The goal is whenever i increase or decrease the values on the edit control (or under the updown) the color of the static control changes automatically.

Someone have a working example of this ?
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

jj2007

#1
Quote from: guga on August 13, 2016, 09:01:36 AMSomeone have a working example of this ?

RichMasm static control (the one that shows line/col):

CASE WM_CTLCOLORSTATIC
mov eax, lParam
.if eax==hStatus
invoke SetTextColor, wParam, 0000A0h  ; BGR
invoke SetBkMode, wParam, TRANSPARENT
invoke GetSysColorBrush, COLOR_INFOBK   ; tooltip bg, instead of COLOR_BTNFACE
return eax ; return the brush
.endif


guga

Tks, JJ

but, it is not working...I don´t understand what i´m doing wrong.

The code organization is like:

a) Main dialog procedure

Proc ConfigDlgProc:
    Arguments @Adressee, @Message, @wParam, @lParam
    Local @mfd, @fa
    Uses ebx, esi, edi, ecx, edx

    call 'USER32.GetWindowLongA' D@Adressee, &DWL_USER
    mov D@mfd eax

    ...If D@Message = &WM_COMMAND ; User action

        If D@mfd <> 0
            call On_WmCommand D@Adressee, D@wParam, D@lParam, D@mfd
        Else
            xor eax eax
        End_If

    ...Else_If D@Message = &WM_INITDIALOG

(...)
        call SetupButtons D@fa, D@Adressee, D@lParam ; Here lparam returns mfd
        mov eax &TRUE
(...)
    ...Else_If D@Message = &WM_CTLCOLORSTATIC

        call PaintStaticFillControl D@Adressee, D@wParam, D@lParam, D@mfd

(...)
    ...End_If

EndP


b) On_WmCommand function controls the buttons and notification messages


Proc On_WmCommand:
    Arguments @Adressee, @wParam, @hBtn, @mfd
    Local @fa, @CtrlNotification, @CtrlId
(...)
    ..Else_If D@wParam = IDC_BTN_CHOOSE_COLOR

        call ChooseColor D@Adressee, D@mfd
        xor eax eax
(...)
    ..Else_If D@CtrlNotification = &EN_CHANGE

        call OnCommand_EditClasses D@Adressee, D@CtrlId, D@fa, D@mfd
        xor eax eax
(...)
EndP


c) ChooseColor function accessed when the user click the tiny button "..."

Proc ChooseColor::
    Arguments @hDlg, @mfd
    Local @RedColor, @GreenColor, @BlueColor
    Structure @CHOOSECOLORA 36, @CHOOSECOLORA.lStructSizeDis 0, @CHOOSECOLORA.hwndOwnerDis 4,
                                @CHOOSECOLORA.hInstanceDis 8,  @CHOOSECOLORA.rgbResultDis 12,
                                @CHOOSECOLORA.lpCustColorsDis 16,  @CHOOSECOLORA.FlagsDis 20,
                                @CHOOSECOLORA.lCustDataDis 24,  @CHOOSECOLORA.lpfnHookDis 28,
                                @CHOOSECOLORA.lpTemplateNameDis 32

    Uses esi, edi, ecx, edx, ebx

    call FastZeroMem D@CHOOSECOLORA, Size_Of_CHOOSECOLORA

    mov esi D@mfd
    mov eax D$esi+SolidFillColorDis | bswap eax | shr eax 8
    mov D@CHOOSECOLORA.lStructSizeDis Size_Of_CHOOSECOLORA
    move D@CHOOSECOLORA.hwndOwnerDis D@hDlg
    mov D@CHOOSECOLORA.hInstanceDis &NULL
    mov D@CHOOSECOLORA.rgbResultDis eax
    mov D@CHOOSECOLORA.lpCustColorsDis CustomColorSet
    mov D@CHOOSECOLORA.FlagsDis &CC_RGBINIT__&CC_FULLOPEN
    call 'COMDLG32.ChooseColorA' D@CHOOSECOLORA
    If eax <> 0
        mov eax D@CHOOSECOLORA.rgbResultDis
    End_If
;    mov esi D@mfd
    mov ebx eax | movzx ecx bl | mov D@RedColor ecx
    shr ebx 8 | movzx ecx bl | mov D@GreenColor ecx
    shr ebx 8 | movzx ecx bl | mov D@BlueColor ecx

    ;lea edi D$esi+Sz_SolidFillColorDis
    ;call utoa_exLingo eax, edi
    ;call 'USER32.SetDlgItemTextA' D@hDlg, IDC_EDIT_SOLID_FILL, edi

    call SetDlgItemInt D@hDlg, IDC_EDIT_SOLID_RED, D@RedColor, &FALSE
    call SetDlgItemInt D@hDlg, IDC_EDIT_SOLID_GREEN, D@GreenColor, &FALSE
    call SetDlgItemInt D@hDlg, IDC_EDIT_SOLID_BLUE, D@BlueColor, &FALSE

    mov D$esi+SolidFillColorDis 0
    mov eax D@RedColor | mov B$esi+SolidFillColorDis+RGBQUAD.rgbRedDis al
    mov eax D@GreenColor | mov B$esi+SolidFillColorDis+RGBQUAD.rgbGreenDis al
    mov eax D@BlueColor | mov B$esi+SolidFillColorDis+RGBQUAD.rgbBlueDis al

    ;call ResetStaticFillColor2 D@hDlg, hSolidFillBrush, StaticCtrlSolidFillColor

EndP


d) OnCommand_EditClasses is where the value is changed for Red, Green and Blue and the brush is created/deleted

Proc OnCommand_EditClasses::
    Arguments @hDlg, @wParam, @fa, @mfd
    Local @RangeXPos, @RangeWidth, @lpTranslated, @TextBuffer
    Uses esi, edi, ecx, edx, ebx
(...)
    ...Else_If D@wParam = IDC_EDIT_SOLID_RED
(...)
        call ResetStaticFillColor D$esi+SolidFillColorDis
        call IFilterPreviewRedoFrame D@fa

    ...Else_If D@wParam = IDC_EDIT_SOLID_GREEN
(...)
        call ResetStaticFillColor D$esi+SolidFillColorDis
        call IFilterPreviewRedoFrame D@fa

    ...Else_If D@wParam = IDC_EDIT_SOLID_BLUE
(...)
        call ResetStaticFillColor D$esi+SolidFillColorDis
        call IFilterPreviewRedoFrame D@fa
(...)
EndP





d) ResetStaticFillColor is the fucntion that creates and delete the brush whenever a edit control change the value



Proc ResetStaticFillColor::
    Arguments @BGRAColor

    On D$hSolidFillBrush <> 0, call 'GDI32.DeleteObject' D$hSolidFillBrush
    mov eax D@BGRAColor | bswap eax | shr eax 8 | mov D$StaticCtrlSolidFillColor eax
    call 'GDI32.CreateSolidBrush' eax
    mov D$hSolidFillBrush eax

EndP



e) on WM_CTLCOLORSTATIC message the color is changed as:

    ...Else_If D@Message = &WM_CTLCOLORSTATIC

        call PaintStaticFillControl D@Adressee, D@wParam, D@lParam, D@mfd
(...)

where PaintStaticFillControl is defined as below

[StaticCtrlSolidFillColor: D$ 0]

Proc PaintStaticFillControl:
    Arguments @hDlg, @hDC, @hCtrl, @mfd
    Uses esi, ecx, edx
   
    mov esi D@mfd
   
    call 'USER32.GetDlgItem' D@hDlg, IDC_STATIC_SOLID_COLORFILL
    .If eax = D@hCtrl
        call 'gdi32.SetBkColor' D@hDC, D$StaticCtrlSolidFillColor
        mov eax D$hSolidFillBrush
    .Else
        xor eax eax
    .End_If
EndP


Below are the screenshots of the result.

Image1 - The color is properly displayed on the static control, only after selecting it through the ChooseColor Api called from my function ChooseColor.


Image2 - here lies the problem. Whenever i change the values in the Red, or Green or Blue edit boxes, the color is not changed :(


I have no idea of what i[´m doing wrong. I tried before create the brush on WM_INITDIALOG. It worked but, still, only when the color is changed with ChooseCOlor Api and not from increasing/decreasing the values on the edit boxes.
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

jj2007

Build it as a console app, and see if the message gets treated, and if yes, what errors are signalled by Windows.

fearless

Are you using GetDlgItemInt in your OnCommand_EditClasses to read the value from each text box to reconstruct the red, green and blue bits before combining them? The choosecolor dialog code your using shows that its setting them correctly as it has each color then, so the variables are all there to place in desired mem location, but i dont see anything in the ResetStaticFillColor function that shows thats is reading the values and placing them in a mem location for use in creating a solid brush - again something like GetDlgItemInt might be what you need in this function or elsewhere perhaps.

guga

Hi Guys, many tks. I suceeded to fix. I took a look at a example from CppFrance http://codes-sources.commentcamarche.net/source/10501-choix-couleurs-win32#q=10501-832476-choix-couleurs-win32&cur=1&url=

The problem was that the brush wasn´t being deleted properly. I simply created a function called UpdateSolidBrush and make WM_CTLCOLORSTATIC only returns the new brush.

UpdateSolidBrush is called whenever the user increases or decreases the values (from the edit boxes) and also when he click on the choose color. The code is like this:


Proc ConfigDlgProc:
    Arguments @Adressee, @Message, @wParam, @lParam
    Local @mfd, @fa
    Uses ebx, esi, edi, ecx, edx

    call 'USER32.GetWindowLongA' D@Adressee, &DWL_USER
    mov D@mfd eax
(....)
    ...If D@Message = &WM_COMMAND ; User action

        If D@mfd <> 0
            call On_WmCommand D@Adressee, D@wParam, D@lParam, D@mfd
        Else
            xor eax eax
        End_If

    ...Else_If D@Message = &WM_INITDIALOG
        (...)
        call 'USER32.GetDlgItem' D@Adressee, IDC_STATIC_SOLID_COLORFILL | mov D$hStaticColorFill eax ; retrieve the handle of the static control whose color needs to be changed

    ...Else_If D@Message = &WM_CTLCOLORSTATIC

         mov eax D$hStaticColorFill
        .If eax = D@lParam ; The handle of the control
               mov eax D$hSolidFillBrush ; brush to return
        .Else
             xor eax eax
         .End_If



From inside On_WmCommand we have the same function as previously explained ChooseColor and OnCommand_EditClasses . They are updated as:


Proc ChooseColor::
    Arguments @hDlg, @mfd
    Local @RedColor, @GreenColor, @BlueColor
    Structure @CHOOSECOLORA 36, @CHOOSECOLORA.lStructSizeDis 0, @CHOOSECOLORA.hwndOwnerDis 4,
                                @CHOOSECOLORA.hInstanceDis 8,  @CHOOSECOLORA.rgbResultDis 12,
                                @CHOOSECOLORA.lpCustColorsDis 16,  @CHOOSECOLORA.FlagsDis 20,
                                @CHOOSECOLORA.lCustDataDis 24,  @CHOOSECOLORA.lpfnHookDis 28,
                                @CHOOSECOLORA.lpTemplateNameDis 32

    Uses esi, edi, ecx, edx, ebx

    call FastZeroMem D@CHOOSECOLORA, Size_Of_CHOOSECOLORA
    call FastZeroMem CustomColorSet, (Size_Of_COLORREF*4)

    mov esi D@mfd
    ; convert BGRA (RGBQUAD) to RGB (COLORREF)
    mov eax D$esi+SolidFillColorDis | bswap eax | shr eax 8
    mov D@CHOOSECOLORA.lStructSizeDis Size_Of_CHOOSECOLORA
    move D@CHOOSECOLORA.hwndOwnerDis D@hDlg
    mov D@CHOOSECOLORA.hInstanceDis &NULL
    mov D@CHOOSECOLORA.rgbResultDis eax
    mov D@CHOOSECOLORA.lpCustColorsDis CustomColorSet
    mov D@CHOOSECOLORA.FlagsDis &CC_RGBINIT__&CC_FULLOPEN
    call 'COMDLG32.ChooseColorA' D@CHOOSECOLORA
    On eax = 0, ExitP ; The user cancelled or an error occured
    mov eax D@CHOOSECOLORA.rgbResultDis
   
    ; retrieve values from the RGB (ColorRef) color
    mov ebx eax | movzx ecx bl | mov D@RedColor ecx
    shr ebx 8 | movzx ecx bl | mov D@GreenColor ecx
    shr ebx 8 | movzx ecx bl | mov D@BlueColor ecx

    call SetDlgItemInt D@hDlg, IDC_EDIT_SOLID_RED, D@RedColor, &FALSE
    call SetDlgItemInt D@hDlg, IDC_EDIT_SOLID_GREEN, D@GreenColor, &FALSE
    call SetDlgItemInt D@hDlg, IDC_EDIT_SOLID_BLUE, D@BlueColor, &FALSE

    mov D$esi+SolidFillColorDis 0
    mov eax D@RedColor | mov B$esi+SolidFillColorDis+RGBQUAD.rgbRedDis al
    mov eax D@GreenColor | mov B$esi+SolidFillColorDis+RGBQUAD.rgbGreenDis al
    mov eax D@BlueColor | mov B$esi+SolidFillColorDis+RGBQUAD.rgbBlueDis al

    call UpdateSolidBrush D$hStaticColorFill, hSolidFillBrush, D$esi+SolidFillColorDis, BGRA2RGB

EndP



; The value at D$esi+SolidFillColorDis is computed inside each @wParam related to the edit control to be changed
Proc OnCommand_EditClasses::
    Arguments @hDlg, @wParam, @fa, @mfd
(...)

    ...Else_If D@wParam = IDC_EDIT_SOLID_RED ; We compute D$esi+SolidFillColorDis here
(...)
        call UpdateSolidBrush D$hStaticColorFill, hSolidFillBrush, D$esi+SolidFillColorDis, BGRA2RGB
(...)
    ...Else_If D@wParam = IDC_EDIT_SOLID_GREEN ; We compute D$esi+SolidFillColorDis here
(...)
        call UpdateSolidBrush D$hStaticColorFill, hSolidFillBrush, D$esi+SolidFillColorDis, BGRA2RGB
(...)
    ...Else_If D@wParam = IDC_EDIT_SOLID_BLUE ; We compute D$esi+SolidFillColorDis here
        call UpdateSolidBrush D$hStaticColorFill, hSolidFillBrush, D$esi+SolidFillColorDis, BGRA2RGB
(...)
    ...End_If

EndP



And finally, UpdateSolidBrush is defined as:



; hCtrl = handle to the static control from where the background color need to be changed
; pOutBrush = Pointer to the brush to be updated
; crColor = A dword value containing the color data. It can be in RGBA (COLORREF) or BRGA (RGBQUAD).
; Flag = Convertion flag betwen the type of data in the crColor parameter. It can be one of the following equates
;    RGB_DEFAULT 0 : Simply RGBA triple. Same order as in COLORREF structure. THis is the default values used by windows brushes
;    BGRA2RGB 1 : Converts a BGRA (RGBQUAD) color form to RGBA (COLORREF) form.

Proc UpdateSolidBrush:
    Arguments @hCtrl, @pOutBrush, @crColor, @Flag
    Uses edi, edx, ecx

    mov edi D@pOutBrush
    If D$edi <> 0 ; Delete the previous brush if it was previously filled
        call 'GDI32.DeleteObject' D$edi
    End_If

    mov eax D@crColor
    ; convert BGRA (RGBQUAD) to RGB (COLORREF). BGRA is the default color form on VirtualDub
    If D@Flag = BGRA2RGB
        bswap eax | shr eax 8
    End_If

    call 'GDI32.CreateSolidBrush' eax
    mov D$edi eax

    call 'USER32.InvalidateRect' D@hCtrl, 0, 0

EndP



And, of course, inside WM_INITDIALOG, i created a function to create the brush when the dialog is loaded

    call CreateSolidBrushEx hSolidFillBrush, D$edi+SolidFillColorDis, BGRA2RGB



; pOutBrush = Pointer to the brush to be updated
; crColor = A dword value containing the color data. It can be in RGBA (COLORREF) or BRGA (RGBQUAD).
; Flag = Convertion flag betwen the type of data in the crColor parameter. It can be one of the following equates
;    RGB_DEFAULT 0 : Simply RGBA triple. Same order as in COLORREF structure. THis is the default values used by windows brushes
;    BGRA2RGB 1 : Converts a BGRA (RGBQUAD) color form to RGBA (COLORREF) form.

Proc CreateSolidBrushEx:
    Arguments @pOutBrush, @crColor, @Flag
    Uses edi, edx, ecx

    mov edi D@pOutBrush
    mov eax D@crColor
    ; convert BGRA (RGBQUAD) to RGB (COLORREF)
    If D@Flag = BGRA2RGB
        bswap eax | shr eax 8
    End_If
    call 'GDI32.CreateSolidBrush' eax
    mov D$edi eax

EndP
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

Fearless..btw...the SetDlgItemInt i used is my own version and not the windows Api. That´s because on Windows XP the Api SetDlgItemInt crashes if there is a endless loop on the control to be update. Internally it may have some stack flaw. I redesigned it as:


Proc SetDlgItemInt:
    Arguments @hDlg, @nIDDlgItem, @uValue, @bSigned
    Structure @StringBuff 36, @StringBuff.DataDis 0
    Uses ecx, edx, esi, edi

    mov edi D@StringBuff
    mov eax D@uValue
    If D@bSigned <> &FALSE
        neg eax
        mov B$edi '-'
        inc edi
    End_If
    call utoa_exLingo eax, edi
    call 'USER32.GetDlgItem' D@hDlg, D@nIDDlgItem
    If eax <> 0
        call 'USER32.SendMessageA' eax, &WM_SETTEXT, 0, D@StringBuff
    End_If

EndP




[chartabL:  W$ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
            W$ '10', '11', '12', '13', '14', '15', '16', '17', '18', '19',
            W$ '20', '21', '22', '23', '24', '25', '26', '27', '28', '29',
            W$ '30', '31', '32', '33', '34', '35', '36', '37', '38', '39',
            W$ '40', '41', '42', '43', '44', '45', '46', '47', '48', '49',
            W$ '50', '51', '52', '53', '54', '55', '56', '57', '58', '59',
            W$ '60', '61', '62', '63', '64', '65', '66', '67', '68', '69',
            W$ '70', '71', '72', '73', '74', '75', '76', '77', '78', '79',
            W$ '80', '81', '82', '83', '84', '85', '86', '87', '88', '89',
            W$ '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', 0]


Proc utoa_exLingo:
    Arguments @src, @lpdest
    Uses ecx, edx, esi, edi

    mov eax D@src
    mov edx 0D1B71759
    mov ecx D@lpdest
    mov edi eax
    mul edx
    shr edx 13
    mov esi 100 | je @lbl11
    imul eax edx 10000
    sub edi eax
    mov eax 068DB9
    mul edx | jae @lbl9
    cmp edx 9 | jbe @lbl8
    movzx edx W$edx+edx+chartabL
    add ecx 8
    mov D$ecx-8 edx

@lbl0:
    mul esi

@lbl1:
    movzx edx W$edx+edx+chartabL
    mov D$ecx-6 edx

@lbl2:
    mul esi

@lbl3:
    movzx edx W$edx+edx+chartabL
    mov D$ecx-4 edx

@lbl4:
    mov eax 028F5C29
    mul edi

@lbl5:
    movzx edx W$edx+edx+chartabL
    mov D$ecx-2 edx

@lbl6:
    mul esi

@lbl7:
    movzx eax W$edx+edx+chartabL
    mov D$ecx eax
    ; return to eax the lenght of the string
    ; sub ecx D@lpdest | lea eax D$ecx+2
    ExitP

@lbl8:
    add ecx 7
    add edx '0'
    mov D$ecx-7 edx | jne @lbl0

@lbl9:
    mul esi | jae @lbl10
    add ecx 6
    cmp edx 9 | ja @lbl1
    add edx '0' | sub ecx 1
    mov D$ecx-5 edx | jne @lbl2

@lbl10:
    mul esi | jae @lbl11
    add ecx 4
    cmp edx 9 | ja @lbl3
    add edx '0' | sub ecx 1
    mov D$ecx-3 edx | jne @lbl4

@lbl11:
    mov eax 028F5C29
    mul edi | jae @lbl12
    add ecx 2
    cmp edx 9 | ja @lbl5
    add edx '0' | sub ecx 01
    mov D$ecx-1 edx | jne @lbl6

@lbl12:
    mul esi
    cmp edx 9 | ja @lbl7
    lea eax D$edx+030 ; '0' Do not change this. RosAsm is not being able to compute '0' as a decimal char. Fix it later inside RoAsm for the next release
    mov D$ecx eax
    ; return to eax the lenght of the string
    ; sub ecx D@lpdest | lea eax D$ecx+1
EndP


The new function works exactly the same as the windows Api, except that it is for Ansi values not Unicode. While i was trying to make the color functions to work, the code i was using crashed badly whenever i used SetDlgItemInt Api. A stack pointer flaw was being generated internally. To check why it was happenning, i debugged the line that was crashing and ended rebuilding the whole Api, fixing the stack flaw.

if you disassemble SetDlgItemInt you will see that it is the same functionality as the function i made, except for the fixes and removing of runtime C libraries (exceptions data, few useless routines and so on).
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