What I will show is how to call ChooseColor, load and save the 16 "custom" colors from file, load and save the selected color to file, and get the Hue, Sat, Lum, Red, Blue and Green from selected color.
Code first then a breakdown:
include masm32rt.inc IDD_MAIN equ 1000 IDC_COLOR equ 1001 BTN_SELECT equ 1002 IDC_HUE equ 1004 IDC_SAT equ 1005 IDC_LUM equ 1007 IDC_RED equ 1009 IDC_GREEN equ 1011 IDC_BLUE equ 1013 ; ChooseColor Dialog equates ; From ColorDlg.h COLOR_HUE equ 703 COLOR_SAT equ 704 COLOR_LUM equ 705 COLOR_RED equ 706 COLOR_GREEN equ 707 COLOR_BLUE equ 708 DialogProc PROTO hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM .data szFile BYTE "settings.ini", 0 szCustomColors BYTE "Custom Colors", 0 szColors BYTE "Colors", 0 szStartColor BYTE "Start", 0 cc CHOOSECOLOR <sizeof cc, ?, ?, 0, ?, CC_FULLOPEN or CC_RGBINIT or CC_ENABLEHOOK, NULL, offset CCHookProc, NULL> DefColors DWORD 0ff0000h,0ff00h,0ffh,0ffff00h,0ffffh DWORD 0cc0000h,0cc00h,0cch,0cccc00h,0cccch DWORD 0800000h,08000h,080h,0808000h,08080h DWORD 0400000h ClrSize equ ($ - DefColors) .data? hInst DWORD ? MyColors DWORD ClrSize dup (?) lpszFile BYTE MAX_PATH + 1 dup (?) hColorCtl DWORD ? hBrush DWORD ? hMain DWORD ? .code start: invoke GetAppPath, offset lpszFile invoke szCatStr, offset lpszFile, offset szFile invoke GetModuleHandle, NULL mov hInst, eax invoke DialogBoxParam, eax, IDD_MAIN, NULL, offset DialogProc, NULL invoke ExitProcess, 0 DialogProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM mov eax,uMsg .if eax==WM_INITDIALOG push hWin pop hMain invoke GetDlgItem, hWin, IDC_COLOR mov hColorCtl, eax invoke exist, offset lpszFile .if eax !=0 invoke GetPrivateProfileStruct, offset szCustomColors, offset szColors, offset MyColors, lengthof MyColors, offset lpszFile invoke GetPrivateProfileStruct, offset szCustomColors, offset szStartColor, offset cc.rgbResult, sizeof CHOOSECOLOR.rgbResult, offset lpszFile .else invoke MemCopy, offset DefColors, offset MyColors, ClrSize mov cc.rgbResult, 00B68427H .endif .elseif eax==WM_COMMAND mov edx,wParam movzx eax,dx shr edx,16 .if edx==BN_CLICKED .if eax==BTN_SELECT push hInst pop cc.hInstance push hWin pop cc.hwndOwner mov cc.lpCustColors, offset MyColors invoke ChooseColor, offset cc test eax, eax jz @F invoke DeleteObject, hBrush invoke CreateSolidBrush, cc.rgbResult mov hBrush, eax invoke InvalidateRect, hColorCtl, NULL, TRUE @@: .endif .endif .elseif eax == WM_CTLCOLORSTATIC mov ecx, hColorCtl .if lParam == ecx mov eax, hBrush ret .endif .elseif eax==WM_CLOSE invoke WritePrivateProfileStruct, offset szCustomColors, offset szColors, offset MyColors, lengthof MyColors, offset lpszFile invoke WritePrivateProfileStruct, offset szCustomColors, offset szStartColor, offset cc.rgbResult, sizeof CHOOSECOLOR.rgbResult, offset lpszFile invoke DeleteObject, hBrush invoke EndDialog,hWin,NULL .else mov eax,FALSE ret .endif mov eax,TRUE ret DialogProc endp CCHookProc proc hDlg:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM mov eax,uMsg .if eax==WM_COMMAND mov edx,wParam movzx eax,dx shr edx,16 .if edx==BN_CLICKED .if eax==IDOK invoke GetDlgItemInt, hDlg, COLOR_HUE, NULL, FALSE invoke SetDlgItemInt, hMain, IDC_HUE, eax, FALSE invoke GetDlgItemInt, hDlg, COLOR_SAT, NULL, FALSE invoke SetDlgItemInt, hMain, IDC_SAT, eax, FALSE invoke GetDlgItemInt, hDlg, COLOR_LUM, NULL, FALSE invoke SetDlgItemInt, hMain, IDC_LUM, eax, FALSE invoke GetDlgItemInt, hDlg, COLOR_RED, NULL, FALSE invoke SetDlgItemInt, hMain, IDC_RED, eax, FALSE invoke GetDlgItemInt, hDlg, COLOR_GREEN, NULL, FALSE invoke SetDlgItemInt, hMain, IDC_GREEN, eax, FALSE invoke GetDlgItemInt, hDlg, COLOR_BLUE, NULL, FALSE invoke SetDlgItemInt, hMain, IDC_BLUE, eax, FALSE .endif .endif .endif xor eax, eax ret CCHookProc endp end start
Yeah, I am a bit "lazy" lately and am using dialogs...
; ChooseColor Dialog equates ; From ColorDlg.h COLOR_HUE equ 703 COLOR_SAT equ 704 COLOR_LUM equ 705 COLOR_RED equ 706 COLOR_GREEN equ 707 COLOR_BLUE equ 708
These are the control IDs for the 6 edit controls on the ChooseColor dialog. All of the control IDs can be found in ColorDlg.h (Part of the SDK)
szFile BYTE "settings.ini", 0 szCustomColors BYTE "Custom Colors", 0 szColors BYTE "Colors", 0 szStartColor BYTE "Start", 0 cc CHOOSECOLOR <sizeof cc, ?, ?, ?, ?, CC_FULLOPEN or CC_RGBINIT or CC_ENABLEHOOK, NULL, offset CCHookProc, NULL> DefColors DWORD 0ff0000h,0ff00h,0ffh,0ffff00h,0ffffh DWORD 0cc0000h,0cc00h,0cch,0cccc00h,0cccch DWORD 0800000h,08000h,080h,0808000h,08080h DWORD 0400000h ClrSize equ ($ - DefColors)
We will be using ini file APIs to save and load our colors, so our file will be called settings.ini
cc is a "pre-initialized" CHOOSECOLOR structure:
lStructSize We will let the Assembler fill in the structure size,
hwndOwner We don't know the handle of the dialogs owner, so we will leave that as uninitialized (fill it in later)
hInstance Same for the hInstance.
rgbResult, we will leave this uninitialized for now, and fill it in later. If the CC_RGBINIT flag is set (In our case it is) we set the initially set color here.
lpCustColors this is an array of 16 DWORDS that are the custom colors the dialog displays, we will fill this in later.
Flags We are using - CC_FULLOPEN or CC_RGBINIT or CC_ENABLEHOOK
There are a few other flags we can use:
- CC_ANYCOLOR
- CC_ENABLETEMPLATE
- CC_ENABLETEMPLATEHANDLE
- CC_PREVENTFULLOPEN
- CC_SHOWHELP
- CC_SOLIDCOLOR
- CC_FULLOPEN This causes the ChooseColor Dialog to fully open, without this, the user has to press the "Define Custom Color" button.
- CC_RGBINIT This tells the dialog to use the color we give it as the initial color
- CC_ENABLEHOOK This tells the dialog we want to hook into it and pass its messages on to our hook proc
CC_ENABLEHOOK
We will be hooking the BN_CLICKED message and will be looking for a message from the Ok button.
Here is how hooking the ChooseColor dialog works:
You call ChooseColor, and the dialog processes its own WM_INITDIALOG message to set up the dialog, then passes on the WM_INITDIALOG message to our hook proc. If we wanted to get messages from any of the controls, we would subclass the controls here in our WM_INITDIALOG handler.
lCustData this is an application defined value passed to our hook proc, lParam will contain a pointer to the CHOOSECOLOR structure we passed to ChooseColor. We don't need it so it is NULL
lpfnHook the address of our hook proc
lpTemplateName This would be the customized dialog in our resource section. We don't need, so NULL
DefColors is an array of 16 colors we will use to initialize the dialog with if it is the first time our sample app is starting and there is no settings.ini file.
MyColors is an array of DWORD we will pass to the ChooseColor dialog. The dialog will update this array each time a custom color is changed.
DialogProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM mov eax,uMsg .if eax==WM_INITDIALOG push hWin pop hMain invoke GetDlgItem, hWin, IDC_COLOR mov hColorCtl, eax invoke exist, offset lpszFile .if eax !=0 invoke GetPrivateProfileStruct, offset szCustomColors, offset szColors, offset MyColors, lengthof MyColors, offset lpszFile invoke GetPrivateProfileStruct, offset szCustomColors, offset szStartColor, offset cc.rgbResult, sizeof CHOOSECOLOR.rgbResult, offset lpszFile .else invoke MemCopy, offset DefColors, offset MyColors, ClrSize mov cc.rgbResult, 00B68427H .endif .elseif eax==WM_COMMAND mov edx,wParam movzx eax,dx shr edx,16 .if edx==BN_CLICKED .if eax==BTN_SELECT push hInst pop cc.hInstance push hWin pop cc.hwndOwner mov cc.lpCustColors, offset MyColors invoke ChooseColor, offset cc test eax, eax jz @F invoke DeleteObject, hBrush invoke CreateSolidBrush, cc.rgbResult mov hBrush, eax invoke InvalidateRect, hColorCtl, NULL, TRUE @@: .endif .endif .elseif eax == WM_CTLCOLORSTATIC mov ecx, hColorCtl .if lParam == ecx mov eax, hBrush ret .endif .elseif eax==WM_CLOSE invoke WritePrivateProfileStruct, offset szCustomColors, offset szColors, offset MyColors, lengthof MyColors, offset lpszFile invoke WritePrivateProfileStruct, offset szCustomColors, offset szStartColor, offset cc.rgbResult, sizeof CHOOSECOLOR.rgbResult, offset lpszFile invoke DeleteObject, hBrush invoke EndDialog,hWin,NULL .else mov eax,FALSE ret .endif mov eax,TRUE ret DialogProc endp
In WM_INITDIALOG, we check to see if our settings file exists and if it does we:
Use an underused (IMO) ini API - GetPrivateProfileStruct to load our 16 custom colors and the start color.
If the settings file does NOT exist, we copy our Default colors into MyColors array and set the initial color to a bluey color.
In WM_COMMAND/BN_CLICKED we fill in some missing fields of the cc struct:
We fill in hInstance, hwndOwner and lpCustColors and call ChooseColor and pass it our cc struct.
When the dialog is closed we check to see if the user clicked OK or cancel/X button; if the user selected a color we:
Delete our brush handle, create a new brush with the color from rgbResult, save the brush handle and then force a re paint of our static control on our window to display the selected color. That is done with InvalidateRect.
In WM_CTLCOLORSTATIC we check to see if the message is for our control and if it is we return the handle to our brush.
WM_CLOSE
We save our custom colors array and the selected color to our settings file with WritePrivateProfileStruct, and finally destroy our custom brush.
In our Dialog hook proc, we are only interested in the WM_COMMAND message and if the user clicked OK, this is where we get the text from the Hue, Sat, Lum, Red, Green, and Blue edit controls on the ChooseColor Dialog.
We return zero from our hook proc for ALL messages so the ChooseColor dialog will continue its processing of messages. If we return a non zero, ChooseColor will not process the message. So, if say the user selected red, and you don't want to allow red, return a non zero until the user selected anything but red.
Source and sample program attached.
Attached File(s)
-
ChooseColor.zip (4.04K)
Number of downloads: 1171
This post has been edited by GunnerInc: 20 January 2012 - 06:03 PM