ITPub博客

首页 > IT职业 > IT生活 > iczelion tut18 (转)

iczelion tut18 (转)

原创 IT生活 作者:gugu99 时间:2007-10-31 16:37:54 0 删除 编辑
iczelion tut18 (转)[@more@]

Tutorial 18: Common Controls


We will learn what common controls are and how to use them. This tutorial will be a quick introduction to them only.
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 are 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 hence larger than its brethren.
You can load comctl32.dll by including a call to InitCommonControls in your program. InitCommonControls is a function in comctl32.dll, so referring to it anywhere in your code will make PE loader load comctl32.dll when your program runs.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 FreeLibrary 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 are just wrappers around CreateWindowEx to make 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 names. They are listed below:
 
Class Name
Common Control
ToolbarWindow32 Toolbar tooltips_class32 Tooltip msctls_statusbar32 Status bar SysTreeView32 Tree view SysListView32 List view SysAnimate32 Animation SysHeader32 Header msctls_hotkey32 Hot-key msctls_progress32 Progress bar RICHEDIT Rich edit msctls_updown32 Up-down SysTabControl32 Tab
Property sheets and property pages and image list control have their own specific creation functions. Drag list control are souped-up listbox so it doesn't 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_xxxx for 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 don't communicate with the parent via WM_COMMAND. 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 masm32includewindows.inc
include masm32includeuser32.inc
include masm32includekernel32.inc
include masm32includecomctl32.inc
includelib masm32libcomctl32.lib
includelib masm32libuser32.lib
includelib masm32libkernel32.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
  invoke DispatchMessage, 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
  .endif
  .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 endp
end start

Analysis:

      invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
      invoke ExitProcess,eax
      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 doesn't 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 regular interval of 100 ms so we must create a timer control. Below is the function prototype of SetTimer.
    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 interval 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 the 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_ICONINFORMATION
      invoke SendMessage,hwndStatus,SB_SETTEXT,0,0
      invoke SendMessage,hwndProgress,PBM_SETPOS,0,0
      .endif
When the specified time interval expires, the timer sends a WM_TIMER message. You will put your code that will be executed here. In this example, we update the progress bar and then check if the maximum limit has been reached. If it has, we kill the timer and then set the text in the status window with SB_SETTEXT message. A message box is displayed and when the user clicks OK, we clear the text in the status bar and the progress bar.

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10748419/viewspace-980173/,如需转载,请注明出处,否则将追究法律责任。

上一篇: iczelion tut16 (转)
下一篇: iczelion tut17 (转)
请登录后发表评论 登录
全部评论
  • 博文量
    3122
  • 访问量
    2251960