Hello Everyone,

I've been around here for a while now and I would just like to thank the lot of you for such a valuable resource, you guys solved much of my troubles.

Well I've been getting interested in drawing my own controls something to make my app look different from the now tired looks of standard windows. Knowing this I've hit up the forums and searched for posts that hit a common interest. We I came up with several hits but one particularly sparked some interest: http://www.asmcommunity.net/board/showthread.php?threadid=6573&highlight=set+dialog+colors . LuHa gave an example of an ownerdraw control in C. I was somewhat disappointed that it was in C but I took a look at it and it didn't seem all that complex. Thinking this would be a decent way to start I attempted to port over the example to ASM. Well needless to say I've ran into a few problems.

WM_CTLCOLORSTATIC,
For some reason when the message get processed nothing happens to my static control. It still retains the default look. I'm guessing the device context is no go. Perhaps something to do with the way I set up the window.

WM_DRAWITEM,
This is the one that has been driving me crazy. I've gotten it to draw all right but the message doesn't process correctly. From what I experienced my button never sends a ODS_SELECTED message. When I checked the value in ItemState it up in the hundreds while all the ODS constants appear to be 1 or 2 digit numbers.

I've attached my source. Hopefully one of you guys can see what I did wrong.


I also have a few other questions:

1) Is there any way to set the BS_OWNERDRAW flag in RADASM dialog editor? I took a look at visual C++ 6 resource editor and its able to set the flag.

2) Will windows delete the brushes, pens I created on its own or do I have to manually delete each one?

3) I wanted to learn more about the gdi api's. Anyone know of a good tut on the subject or good reference point?
Posted on 2003-12-14 03:11:48 by Lith
hi , this is my ASM example:

.ELSEIF uMsg == WM_ERASEBKGND
mov LogBrush.lbStyle, BS_SOLID
RGB 0, 0, 0
mov LogBrush.lbColor, eax
invoke CreateBrushIndirect, addr LogBrush
mov hBrush,eax
invoke GetClientRect, hWnd, addr rect
invoke FillRect, wParam, addr rect, hBrush
mov eax, TRUE
ret
.ELSEIF uMsg == WM_CTLCOLORSTATIC
invoke GetDlgCtrlID, lParam
.if eax == IDC_REGCODE
RGB 255, 255, 255
invoke SetTextColor,wParam, eax
RGB 0, 0, 0
INVOKE SetBkColor, wParam, eax
invoke GetStockObject, BLACK_BRUSH
.else
MOV eax,FALSE
ret
.endif
ret
.ELSEIF uMsg == WM_CTLCOLOREDIT
invoke GetDlgCtrlID,lParam
.if eax == IDC_REGNAME
RGB 255, 255, 255
invoke SetTextColor,wParam, eax
RGB 0, 0, 0
INVOKE SetBkColor, wParam, eax
invoke GetStockObject, BLACK_BRUSH
.else
MOV eax,FALSE
ret
.endif
ret
Posted on 2003-12-14 08:09:22 by benny
BTW, if you want to change the button color, you can use WM_CTLCOLORBTN message.

WM_CTLCOLORBTN
hdcButton = (HDC) wParam; // handle of button display context
hwndButton = (HWND) lParam; // handle of button
Posted on 2003-12-14 08:16:48 by benny
Thanks benny for you example. I'll probably recode a whole new window and just see if that one works. I really wanted to start drawing some of my own controls but I guess I should first work on changing colors then go from there.


Ahh.. finally got it to post. For some reason save cookies saved with the wrong password and I couldn't post.
Posted on 2003-12-15 01:12:42 by Lith
Can someone tell me why the code in WM_CTLCOLORBTN doesn't change the button's color?



.386
.model flat, stdcall
option casemap: none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

include ChangingColors.inc

WinMain PROTO :HINSTANCE,:HINSTANCE,:LPSTR,:DWORD
WndProc PROTO :HWND,:UINT,:WPARAM,:LPARAM

.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke GetCommandLine
mov CommandLine, eax
invoke WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
invoke ExitProcess, eax

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hDlg:HWND

invoke CreateSolidBrush, 00000000h
mov hBkBrush, eax

mov wc.cbSize, sizeof WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, offset WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, DLGWINDOWEXTRA
push hInst
pop wc.hInstance
push hBkBrush
pop wc.hbrBackground
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, offset ClassName
invoke LoadIcon, NULL, IDI_APPLICATION
mov wc.hIcon, eax
mov wc.hIconSm, eax
invoke LoadCursor, NULL, IDC_ARROW
mov wc.hCursor, eax

invoke RegisterClassEx, addr wc
xor eax, eax
mov ax, IDD_MAIN
invoke CreateDialogParam, hInstance, eax, NULL, offset WndProc, NULL
mov hDlg, eax
invoke ShowWindow, hDlg, SW_SHOWNORMAL
invoke UpdateWindow, hDlg

.while TRUE
invoke GetMessage, addr msg, NULL, 0, 0
.break .if (!eax)
invoke IsDialogMessage, hDlg, addr msg
.if eax == FALSE
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
.endif
.endw
mov eax, msg.wParam
ret

WinMain endp

WndProc proc hwnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

.if uMsg == WM_INITDIALOG


.elseif uMsg == WM_DESTROY
invoke DeleteObject, hBkBrush
invoke PostQuitMessage, NULL


[b][color=red].elseif uMsg == WM_CTLCOLORBTN
invoke SetBkMode, wParam, TRANSPARENT
invoke SetBkColor, wParam, 00FF0000h
invoke SetTextColor, wParam, 00FFFFFFh
[/color][/b]

.elseif uMsg == WM_COMMAND
mov eax, wParam
shl eax, 16
shr eax, 16
.if eax == IDC_BTN_EXIT
invoke SendMessage, hwnd, WM_DESTROY, NULL, NULL
.endif


.else
invoke DefWindowProc, hwnd, uMsg, wParam, lParam
ret


.endif
xor eax, eax
ret

WndProc endp

end start
Posted on 2003-12-15 03:45:45 by Lith
set your button's style as BS_OWNERDRAW
Posted on 2003-12-15 04:28:10 by benny
Ok. Set the button to OwnerDraw. This is what I get:



Here is the code:



WndProc proc hwnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

.if uMsg == WM_INITDIALOG
;Set Exit button to OwnerDraw.
invoke GetDlgItem, hwnd, IDC_BTN_EXIT
mov hExit, eax
invoke GetWindowLong, hExit, GWL_STYLE
or eax, BS_OWNERDRAW
invoke SetWindowLong, hExit, GWL_STYLE, eax

.elseif uMsg == WM_DESTROY
invoke DeleteObject, hBkBrush
invoke PostQuitMessage, NULL


.elseif uMsg == WM_CTLCOLORBTN
invoke SetBkMode, wParam, TRANSPARENT
invoke SetBkColor, wParam, 00FF0000h
invoke SetTextColor, wParam, 00FFFFFFh


.elseif uMsg == WM_COMMAND
mov eax, wParam
shl eax, 16
shr eax, 16
.if eax == IDC_BTN_EXIT
invoke SendMessage, hwnd, WM_DESTROY, NULL, NULL
.endif


.else
invoke DefWindowProc, hwnd, uMsg, wParam, lParam
ret


.endif
xor eax, eax
ret

WndProc endp
Posted on 2003-12-15 04:46:37 by Lith
Ok. I found out that I had to return a brush to windows so it can fill in the background. I decided to make a static control and test my ideas on that. I've gotten somewhere although the solution is a but confusing. Here is what I did:



WndProc proc hwnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL temp:DWORD


.if uMsg == WM_INITDIALOG
;Set Button: Exit to OwnerDraw.
invoke GetDlgItem, hwnd, IDC_BTN_EXIT
mov temp, eax
invoke GetWindowLong, temp, GWL_STYLE
or eax, BS_OWNERDRAW
invoke SetWindowLong, temp, GWL_STYLE, eax

;Set Static: Title to OwnerDraw.
invoke GetDlgItem, hwnd, IDC_STC_TITLE
mov temp, eax
invoke GetWindowLong, temp, GWL_STYLE
or eax, BS_OWNERDRAW
invoke SetWindowLong, temp, GWL_STYLE, eax


.elseif uMsg == WM_DESTROY
invoke PostQuitMessage, NULL


.elseif uMsg == WM_CTLCOLORBTN
invoke SetBkMode, wParam, TRANSPARENT
invoke SetTextColor, wParam, 00FF0000h

;Return brush handle for background drawing.
invoke GetStockObject, DKGRAY_BRUSH
mov hBrush, eax
ret

[b][color=red]
.elseif uMsg == WM_CTLCOLORSTATIC
invoke SetTextColor, wParam, 00CC9900h
invoke SetBkMode, wParam, TRANSPARENT

;Return brush handle for background drawing.
invoke GetStockObject, BLACK_BRUSH
mov hBrush, eax ;<--Doesn't do anything to the background???
ret
[/color][/b]

.elseif uMsg == WM_COMMAND
mov eax, wParam
shl eax, 16
shr eax, 16
.if eax == IDC_BTN_EXIT
invoke SendMessage, hwnd, WM_DESTROY, NULL, NULL
.endif


.else
invoke DefWindowProc, hwnd, uMsg, wParam, lParam
ret


.endif
xor eax, eax
ret

WndProc endp


For some reason returning a predefinded stock object gives the effect I was looking for however if I were to take out the invoke SetBkMode the background wouldn't be the color of the brush I returned to windows. Just white, always white.

The button coloring doesn't work. I'm starting to think SetBkMode, SetBkColor, SetTextColor has no effect on the button. Probably because coloring the background and setting the text isn't setting the colors of the button because the button is some kind of object itself outside the background colors and text colors?
Posted on 2003-12-15 08:57:01 by Lith
Nevermind. I've solved my problem. Here is the source. Its pretty much LuHa's C example in ASM.

I had to shift bits around on DRAWITEMSTRUCT.itemState to get it to work properly. I'm not sure if this is the correct way in doing so but it works on my XP machine. Anyone using 9x around here? I would like to know if it worked for you guys.
Posted on 2003-12-15 12:13:09 by Lith