Tutorial 18: Common Controls
.
Download the Example Source Code
Here.
Theory: Windows 95 comes with several user-interface enhancements over Windows 3.1x They make the GUI richer Several of them are in widely used before Windows 95 hit the shelf, such as status bar, toolbars etc. Programmers have to code them themselves.. NOW Microsoft Has Included Them with Windows 9x and NT. We Will Learn About Them Here.
THESE is the New Controls:
Toolbar Tooltip Status bar Property sheet Property page Tree view List view Animation Drag list Header Hot-key Image list Progress bar Right edit Tab Trackbar Up-down Since there are many of them, loading them all into memory and registering them would be a waste of resource. All of them, with the exception of rich edit control, are stored in comctl32.dll with applications can load when they want to use the controls. Rich edit control resides in its own dll, richedXX.dll, because it's very complicated and Henene Than ITS BRETHREN.
You can load comctl32.dll by incruding a call to
INITCOMMONTROLS IN Your Program In ComctL32.dll, So Referring to it, So Referring to it, you.
You don't have to execute it, just include it in your code somewhere. This function does
NOTHING! Its only instruction is "ret". Its sole purpose is to include reference to comctl32.dll in the import section so that PE loader will load it whenever the program is loaded. The real workhorse is the DLL entrypoint function which registers all common control classes when the dll is loaded. Common controls are created based on those classes just like other child window controls such as edit, listbox etc.Rich edit is another matter entirely. If you want to use it, you have to call LoadLibrary to load IT Explicitly and Call FreeElibrary to Unload It.
Now we learn how to create them. You can use a resource editor to incorporate them into dialog boxes or you can create them yourself. Nearly all common controls are created by calling CreateWindowEx or CreateWindow, passing it the name of the control class. Some common Controls Have Specific Creation Functions, HOWEVER, They Arej Just Wrappers Around CreateWindowex To make it it it easier to create those controls. EXISTING SPECIFIC CREATION FUNCTIONS ARE LISTED BELOW:
CreateToolbarex CreateStatusWindow CreatePropertySheetPage PropertySheet Imagelist_create in Order To Create Common Controls, you have to know their class name. They is known
Class name
Common Control
ToolbarWindow32Toolbartooltips_class32Tooltipmsctls_statusbar32Status barSysTreeView32Tree viewSysListView32List viewSysAnimate32AnimationSysHeader32Headermsctls_hotkey32Hot-keymsctls_progress32Progress barRICHEDITRich editmsctls_updown32Up-downSysTabControl32Tab
Property sheets and property pages and image list control have their own specific creation functions. Drag list control are souped-up listbox so it does not have its own class. The above class names are verified by checking resource script generated by Visual C resource editor . They differ from the class names listed by Borland's win32 api reference and Charles Petzold's Programming Windows 95. The above list is the accurate one.Those common controls can use general window styles such as WS_CHILD etc. They also have their own specific styles such as TVS_XXXXX for Tree View Control, LVS_XXXFOR LIST View Control, etc. Win32 API Reference IS your best Friend In this regard.
Now that we know how to create common controls, we can move on to communication method between common controls and their parent. Unlike child window controls, common controls do not communicate via WM_COMMAND the parent with. Instead they send WM_NOTIFY messages to the parent window when some interesting events occur with the common controls. The parent can control the children by sending messages to them. There are also many new messages for those new controls. You should consult your win32 api reference for more detail.
Let's Examine Progress Bar and Status Bar Controls in The Following Example.
Sample Code:
.386
.Model flat, stdcall
Option CaseMAP: NONE
INCLUDE /MASM32/INCLUDE/Windows.inc
INCLUDE /MASM32/INCLUDE/USER32.INC
INCLUDE /MASM32/INCLUDE / WANEL32.INC
INCLUDE /MASM32/INCLUDE/ComctL32.inc
INCLUDELIB /MASM32/LIB/ComctL32.lib
INCLUDELIB /MASM32/LIB/USER32.LIB
INCLUDELIB /MASM32/LIB/kernel32.lib
Winmain Proto: DWORD,: DWORD,: DWORD,: DWORD
.const IDC_PROGRESS equ 1; control IDs IDC_STATUS equ 2 IDC_TIMER equ 3.data ClassName db "CommonControlWinClass", 0 AppName db "Common Control Demo", 0 ProgressClass db "msctls_progress32", 0; the class name of the progress bar Message db " Finished! ", 0 Timerid DD 0
? .Data hInstance HINSTANCE hwndProgress dd hwndStatus dd CurrentStep dd .code start:???? Invoke GetModuleHandle, NULL mov hInstance, eax invoke WinMain, hInstance, NULL, NULL, SW_SHOWDEFAULT invoke ExitProcess, eax invoke InitCommonControls
Winmain Proc Hinst: Hinstance, Hprevinst: Hinstance, Cmdline: LPSTR, CMDSHOW: DWORD LOCAL WC: WNDCLASSEX LOCAL MSG: MSG local hwnd: hwnd
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, NULL push hInst pop wc.hInstance mov wc.hbrBackground, COLOR_APPWORKSPACE 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 invoke CreateWindowEx, WS_EX_CLIENTEDGE, aDDR ClassName, ADDR AppName, / WS_OVERLAPPED WS_CAPTION WS_SYSMENU WS_MINIMIZEBOX WS_MAXIMIZEBOX WS_VISIBLE, CW_USEDEFAULT, / CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, / hInst, NULL mov hwnd, eax .while TRUE invoke GetMessage, ADDR msg, NULL, 0,0 .break .if (! EAX) Invoke TranslateMessage, Addr Msg .Endw Mov Eax, Msg.wParam RET WinMain Endp
WndProc proc hWnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM .if uMsg == WM_CREATE invoke CreateWindowEx, NULL, ADDR ProgressClass, NULL, / WS_CHILD WS_VISIBLE, 100, / 200,300,20, hWnd, IDC_PROGRESS, / hInstance, NULL mov hwndProgress, eax mov eax, 1000; the lParam of PBM_SETRANGE message contains the range mov currentStep, eax shl eax, 16; the high range is in the high word invoke SendMessage, hwndProgress, PBM_SETRANGE, 0, eax invoke SendMessage, hwndProgress, PBM_SETSTEP, 10,0 invoke CreateStatusWindow, WS_CHILD WS_VISIBLE, NULL, hWnd, IDC_STATUS mov hwndStatus, eax invoke SetTimer, hWnd, IDC_TIMER, 100, NULL; create a timer mov timerID, eax .elseif uMsg == WM_DESTROY invoke PostQuitMessage, Null .IF Timerid! = 0 Invoke Killtimer, HWnd, Timerid .ndif .elseif UMSG == WM_TIMER; WHEN A TIMER EVENT OCCURS invoke SendMessage, hwndProgress, PBM_STEPIT, 0,0; step up the progress in the progress bar sub CurrentStep, 10 .if CurrentStep == 0 invoke KillTimer, hWnd, TimerID mov TimerID, 0 invoke SendMessage, hwndStatus, SB_SETTEXT, 0, addr Message invoke MessageBox, hWnd, addr Message, addr AppName, MB_OK MB_ICONINFORMATION invoke SendMessage, hwndStatus, SB_SETTEXT, 0,0 invoke SendMessage, hwndProgress, PBM_SETPOS, 0,0 .endif .else invoke DefWindowProc, hWnd, uMsg, wParam, lParam ret. Endif xor Eax, EAX RET WNDPROC ENDS:
Invoke Winmain, Hinstance, Null, Null, SW_SHOWDEFAULTINVOKE EXITPROCESS, EX
Invoke INITCOMMONCONTROLS
I deliberately put InitCommonControls after ExitProcess to demonstrate that InitCommonControls is just there for putting a reference to comctl32.dll in the import section. As you can see, the common controls work even if InitCommonControls does not execute.
.IF uMSG == WM_CREATE
Invoke CreateWindowex, Null, Addr ProgressClass, NULL, /
WS_CHILD WS_VISIBLE, 100, /
200, 300, 20, hwnd, IDC_Progress, /
Hinstance, NULL
Mov HWndProgress, EAX
Here is where we create the common control. Note that this CreateWindowEx call contains hWnd as the parent window handle. It also specifies a control ID for identifying this control. However, since we have the control's window handle, this ID is not used. All Child WinDow Controls Must Have WS_Child Style.
Mov Eax, 1000
Mov Currentstep, EAX
SHL EAX, 16
Invoke SendMessage, HWndProgress, PBM_SETRANGE, 0, EAX
Invoke SendMessage, HWndProgress, PBM_SETSTEP, 10, 0
After the progress bar is created, we can set its range. The default range is from 0 to 100. If you are not satisfied with it, you can specify your own range with PBM_SETRANGE message. LParam of this message contains the range, the maximum range is in the high word and the minimum one is in the low word. you can specify how much a step takes by using PBM_SETSTEP message. The example sets it to 10 which means that when you send a PBM_STEPIT message to the progress bar, the Progress Indicator Will Rise by 10. You Can Also Set Your Own Indicator Level by Sending PBM_SETPOS MESSAGES. This Message Gives You Tighter Control Over The Progress Bar.
Invoke CreateStatusWindow, WS_CHILD WS_VISible, NULL, HWND, IDC_STATUS
Mov hwndstatus, EAX
Invoke SetTimer, HWND, IDC_TIMER, 100, NULL; CREATE A TIMER
Mov Timerid, EAX
Next, we create a status bar by calling CreateStatusWindow. This call is easy to understand so I'll not comment on it. After the status window is created, we create a timer. In this example, we will update the progress bar at a .
SetTimer Proto Hwnd: DWORD, TIMERID: DWORD, TIMEINTERVAL: DWORD, LPTIMERPROC: DWORD
HWnd: Parent Window Handle
Timerid: a Nonzero Timer Identifier. You can create your OWN IDENTIFIER.
Timerinterval: The Timer In Milliseconds That Must Pass Before The Timer Calls The Timer Procedure Or Sends A WM_TIMER MESSAGE
LPTIMERPROC: The Address of the Timer Function That Will Be Called WHEN TIME Interval Expires. IF this parameter is null, The Timer Will Send WM_Timer Message To The Parent Window INSTEAD.
IF this Call Is Successful, IT Will Return The Timerid. IF IT Failed, It Returns 0. This is why the Timer Identifer Must Be a Nonzero Value.
.ELSEIF uMSG == WM_TIMER
Invoke SendMessage, HWndProgress, PBM_STEPIT, 0, 0
Sub Currentstep, 10
.IF currentstep == 0
Invoke Killtimer, Hwnd, Timerid
Mov Timerid, 0
Invoke SendMessage, HWndStatus, Sb_Settext, 0, Addr Message
Invoke Messagebox, Hwnd, Addr Message, Addr Appname, MB_OK MB_ICONITIONFORMATION
Invoke SendMessage, HWndStatus, Sb_Settext, 0, 0
Invoke SendMessage, HWndProgress, PBM_SETPOS, 0, 0
.endif