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 ?
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
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.
(http://i68.tinypic.com/ogz51z.jpg)
Image2 - here lies the problem. Whenever i change the values in the Red, or Green or Blue edit boxes, the color is not changed :(
(http://i64.tinypic.com/1415me1.jpg)
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.
Build it as a console app, and see if the message gets treated, and if yes, what errors are signalled by Windows.
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.
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= (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
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).