Chapter 10: Examples of Programs That Use Resources

Examples are essential for mastering the art of programming. It is impossible to study programming only on the basis of theory. Programming is closer to art. It is a way of self-actualization.

The topic of resource usage in Windows programming is important; therefore, it deserves a separate chapter. Here, I provide three more sophisticated programs illustrating the use of resources and supply detailed explanations .

A Dynamic Menu

You probably have already noticed that in many programs, menus can dynamically change during program execution: Some items are added or removed, one menu appears as the built-in menu of another one, etc. An example illustrating the simplest manipulations with a menu is provided in Listing 10.1.

Listing 10.1: An example of manipulations with the menu
image from book
 // The MENU2.RC file // Virtual key - <F5> #define VK_F5 0x74 //********* MENUP *********** MENUP MENU {  POPUP "&First item"  {  MENUITEM "&First", 1  MENUITEM "S&econd", 2  }  POPUP "&Second item"  {  MENUITEM "Thir&d", 3  MENUITEM "Fou&rth\tF5", 4  MENUITEM SEPARATOR  POPUP "Another submen&u"  {  MENUITEM "Additional &item", 6  }  }  MENUITEM "E&xit", 5 } //********* MENUC *********** MENUC MENU {  POPUP "Set 1"  {  MENUITEM "White", 101  MENUITEM "Gray", 102  MENUITEM "Black", 103  }  POPUP "Set 2"  {  MENUITEM "Red", 104  MENUITEM "Blue", 105  MENUITEM "Green", 106  } } // Accelerator table // One accelerator is defined // for calling an item from the MENUP menu MENUP ACCELERATORS {  VK_F5, 4, VIRTKEY, NOINVERT } ; The MENU2.INC file ; Constants ; The message arrives when the window is closed WM_DESTROY          equ 2 ; The message arrives when the window is created WM_CREATE           equ 1 ; The message arrives when the user clicks the ; left mouse button in the window WM_COMMAND          equ 111h WM_MENUSELECT       equ 11 Fh WM_SETTEXT          equ 0Ch MIIM_TYPE           equ 10h MF_STRING           equ 0h MF_POPUP            equ 10h ; Window properties CS_VREDRAW          equ 1h CS_HREDRAW          equ 2h CS_GLOBALCLASS      equ 4000h WS_OVERLAPPEDWINDOW equ 000CF0000H STYLE               equ CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS BS_DEFPUSHBUTTON    equ 1h WS__VISIBLE         equ l0000000h WS_CHILD            equ 40000000h STYLBTN             equ WS_CHILD+BS_DEFPUSHBUTTON+WS_VISIBLE ; Standard icon identifier IDI_APPLICATION     equ 32512 ; Cursor identifier IDC_ARROW           equ 32512 ; Window display mode --- Normal SW_SHOWNORMAL       equ 1 SW_HIDE             equ 0 SW_SHOWMINIMIZED    equ 2 ; Prototypes of external procedures EXTERN wsprintfA:NEAR EXTERN GetMenuItemInfoA@16:NEAR EXTERN LoadMenuA@8:NEAR EXTERN SendMessageA@16:NEAR EXTERN MessageBoxA@16:NEAR EXTERN CreateWindowExA@48:NEAR EXTERN DefWindowProcA@16:NEAR EXTERN DispatchMessageA@4:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetMessageA@16:NEAR EXTERN GetModuleHandleA@4:NEAR EXTERN LoadCursorA@8:NEAR EXTERN LoadIconA@8:NEAR EXTERN PostQuitMessage@4:NEAR EXTERN RegisterClassA@4:NEAR EXTERN ShowWindow@8:NEAR EXTERN TranslateMessage@4:NEAR EXTERN UpdateWindow@4:NEAR EXTERN TranslateAcceleratorA@12:NEAR EXTERN LoadAcceleratorsA@8:NEAR EXTERN GetMenu@4:NEAR EXTERN DestroyMenu@4:NEAR EXTERN SetMenu@8:NEAR ; Structures ; Message structure MSGSTRUCT STRUC  MSHWND        DD ?  MSMESSAGE     DD ?  MSWPARAM      DD ?  MSLPARAM      DD ?  MSTIME        DD ?  MSPT          DD ? MSGSTRUCT ENDS ;---- Window class structure WNDCLASS STRUC  CLSSTYLE      DD ?  CLWNDPROC     DD ?  CLSCBCLSEX    DD ?  CLSCBWNDEX    DD ?  CLSHINST      DD ?  CLSHICON      DD ?  CLSHCURSOR    DD ?  CLBKGROUND    DD ?  CLMENNAME     DD ?  CLNAME        DD ? WNDCLASS ENDS MENINFO STRUCT  CbSize        DD ?  FMask         DD ?  FType         DD ?  FState        DD ?  WID           DD ?  HSubMenu      DD ?  HbmpChecked   DD ?  HbmpUnchecked DD ?  DwItemData    DD ?  DwTypeData    DD ?  Cch           DD ? MENINFO ENDS ; The MENU2.ASM file .586P ; Flat memory model .MODEL FLAT, stdcall include menu2.inc ; INCLUDELIB directives for the linker to link libraries includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ;-------------------- ; Data segment _DATA SEGMENT  SPACE     DB 30 dup(32), 0  MENI      MENINFO <0>  NEWHWND   DD 0  MSG       MSGSTRUCT <?>  WC        WNDCLASS <?>  HINST     DD 0 ; Application descriptor  CLASSNAME DB 'CLASS32', 0  CPBUT     DB 'BUTTON', 0 ; Exit  CLSBUTN   DB 'BUTTON', 0  HWNDBTN   DD 0  CAP       DB 'Message', 0  MES       DB 'Exit the program', 0  MEN       DB 'MENUP', 0  MENC      DB 'MENUC', 0  ACC       DD ?  HMENU     DD ?  PRIZN     DD ?  BUFER     DB 100 DUP(0) _DATA ENDS ; Code segment _TEXT SEGMENT START: ; Initialize the counter    MOV PRIZN, 2 ; Get the application descriptor    PUSH 0    CALL GetModuleHandleA@4    MOV  [HINST], EAX REG_CLASS: ; Fill the window structure ; Style    MOV  [WC.CLSSTYLE], STYLE ; Message-handling procedure    MOV  [WC.CLWNDPROC], OFFSET WNDPROC    MOV  [WC.CLSCBCLSEX], 0    MOV  [WC.CLSCBWNDEX], 0    MOV  EAX,  [HINST]    MOV  [WC.CLSHINST], EAX ;----------Window icon    PUSH  IDI_APPLICATION    PUSH  0    CALL  LoadIconA@8    MOV  [WC.CLSHICON], EAX ;---------- Window cursor    PUSH IDC_ARROW    PUSH 0    CALL LoadCursorA@8    MOV  [WC.CLSHCURSOR], EAX ;----------    MOV  [WC.CLBKGROUND], 17 ; Window color    MOV  DWORD PTR [WC.CLMENNAME], OFFSET MEN    MOV  DWORD PTR [WC.CLNAME], OFFSET CLASSNAME    PUSH OFFSET WC    CALL RegisterClassA@4 ; Create a window of the registered class    PUSH 0    PUSH [HINST]    PUSH 0    PUSH 0    PUSH 400  ; DY  Window height    PUSH 400  ; DX  Window width    PUSH 100  ; Y    PUSH 100  ; X    PUSH WS_OVERLAPPEDWINDOW    PUSH OFFSET SPACE ; Window name    PUSH OFFSET CLASSNAME ; Class name    PUSH 0    CALL CreateWindowExA@48 ; Check for errors    CMP  EAX, 0    JZ   _ERR    MOV  [NEWHWND], EAX ; Window descriptor ; Determine the menu identifier    PUSH EAX    CALL GetMenu@4    MOV  HMENU, EAX ; Load the accelerators    PUSH OFFSET MEN    PUSH [HINST]    CALL LoadAcceleratorsA@8    MOV  ACC, EAX ;------------------------------    PUSH SW_SHOWNORMAL    PUSH [NEWHWND]    CALL ShowWindow@8 ; Show the newly-created window ;------------------------------    PUSH [NEWHWND]    CALL UpdateWindow@4 ; Redraw the visible part of the                      ; window, the WM_PAINT message ; Message-processing loop MSG_LOOP:   PUSH  0   PUSH  0   PUSH  0    PUSH OFFSET MSG    CALL GetMessageA@16    CMP  EAX, 0    JE  END_LOOP    PUSH OFFSET MSG    PUSH [ACC]    PUSH [NEWHWND]    CALL TranslateAcceleratorA@12    CMP  EAX, 0    JNE  MSG_LOOP    PUSH OFFSET MSG    CALL TranslateMessage@4    PUSH OFFSET MSG    CALL DispatchMessageA@4    JMP  MSG__LOOP END_LOOP: ; Exit the program (close the process)    PUSH  [MSG.MSWPARAM]    CALL ExitProcess@4 _ERR:    JMP  END_LOOP ;---------------------- ; Window procedure ; Position of parameters in the stack ; [EBP+014H] ; LPARAM ; [EBP+10H]  ; WAPARAM ; [EBP+0CH]  ; MES ; [EBP+8]    ; HWND WNDPROC PROC   PUSH EBP   MOV  EBP, ESP   PUSH EBX   PUSH ESI   PUSH EDI ; The WM_DESTROY message  When closing the window   CMP   DWORD PTR [EBP+0CH], WM_DESTROY   JE    WMDESTROY ; The WM_CREATE message  When creating the window   CMP   DWORD PTR [EBP+0CH], WM_CREATE   JE    WMCREATE ; The WM_COMMAND message  In case events ; that happen to the window elements   CMP  DWORD PTR [EBP+0CH], WM_COMMAND   JE   WMCOMMND ; The WM_MENUSELECT message  Menu-related events   CMP  DWORD PTR [EBP+0CH], WM_MENUSELECT   JE   WMMENUSELECT ; Returning all other messages   JMP  DEFWNDPROC WMMENUSELECT: ; Skipping the first event when accessing the menu   CMP  WORD PTR [EBP+14H], 0   JE   FINISH ; Checking what has been activated --- menu item ; or popup menu header   MOV  EDX, 0   TEST WORD PTR [EBP+12H], MF_POPUP   SETNE DL ; Filling the structure for function call ; GetMenuItemInfo   MOVZX EAX, WORD PTR [EBP+10H] ; Identifier   MOV   MENI.cbSize, 48   MOV   MENI.fMask, MIIM_TYPE   MOV   MENI.fType, MF_STRING   MOV   EBX, DWORD PTR [EBP+14H]   MOV   MENI.hSubMenu, EBX   MOV   MENI.dwTypeData, OFFSET BUFER   MOV   MENI.cch, 100 ; Get information about the chosen menu item   PUSH  OFFSET MENI   PUSH  EDX   PUSH  EAX   PUSH  DWORD PTR [EBP+14H]   CALL  GetMenuItemInfoA@16 ; Check the result of function execution   CMP   EAX, 0   JE    FINISH ; Display the menu item name   PUSH  MENI.dwTypeData   PUSH  0   PUSH  WM_SETTEXT   PUSH  DWORD PTR [EBP+08H]   CALL  SendMessageA@16   MOV   EAX, 0   JMP   FINISH WMCOMMND:   MOV  EAX, HWNDBTN ; Check whether the button has been pressed   CMP  DWORD PTR [EBP+14H], EAX   JE  YES_BUT ; Check whether the Exit menu item of MENUC has been chosen   CMP  WORD PTR [EBP+10H], 5   JE  WMDESTROY ; Check whether the menu item with the identifier 5 has been chosen   CMP  WORD PTR [EBP+10H], 4   JNE  LOO JMP YES_BUT LOO:   MOV  EAX, 0   JMP  FINISH YES_BUT: ; Button-click handling ; First, erase the name in the header   PUSH  OFFSET SPACE   PUSH  0   PUSH  WM_SETTEXT   PUSH  DWORD PTR [EBP+08H]   CALL  SendMessageA@16 ; Check whether the menu has been loaded   CMP   PRIZN, 0   JE    L1   CMP   RIZN, 1   JE    L2 ; Load MENC   PUSH  OFFSET MENC   PUSH  [HINST]   CALL  LoadMenuA@8 ; Set the menu   MOV   HMENU, EAX   PUSH  EAX   PUSH  DWORD PTR [EBP+08H]   CALL  SetMenu@8 ; Set the identifier   MOV   PRIZN, 0   MOV   EAX, 0   JMP   FINISH L2: ; Load MENUP   PUSH OFFSET MEN   PUSH  [HINST]   CALL LoadMenuA@8 ; Set the menu   MOV   HMENU, EAX   PUSH  EAX   PUSH DWORD PTR [EBP+08H]   CALL SetMenu@8 ; Set the indicator   MOV   PRIZN, 2   MOV   EAX, 0   JMP   FINISH L1: ; Delete the menu   PUSH  HMENU   CALL  DestroyMenu@4 ; Refresh the window contents   PUSH  SW_SHOWMINIMIZED   PUSH  DWORD PTR [EBP+08H]   CALL  ShowWindow@8   PUSH  SW_SHOWNORMAL   PUSH  DWORD PTR [EBP+08H]   CALL  ShowWindow@8   MOV   PRIZN, 1   MOV   EAX, 0   JMP   FINISH WMCREATE: ; Create a window button   PUSH  0   PUSH  [HINST]   PUSH  0   PUSH  DWORD PTR [EBP+08H]   PUSH  20 ; DY   PUSH  60 ; DX   PUSH  10 ; Y   PUSH  10 ; X   PUSH  STYLBTN ; Window name (button label)   PUSH  OFFSET CPBUT   PUSH  OFFSET CLSBUTN ; Class name   PUSH  0   CALL  CreateWindowExA@48   MOV   HWNDBTN, EAX ; Store the button descriptor   MOV   EAX, 0   JMP   FINISH DEFWNDPROC:   PUSH  DWORD PTR [EBP+14H]   PUSH  DWORD PTR [EBP+10H]   PUSH  DWORD PTR [EBP+0CH]   PUSH  DWORD PTR [EBP+08H]   CALL  DefWindowProcA@16   JMP   FINISH WMDESTROY:   PUSH  0         ; MB_OK   PUSH  OFFSET CAP   PUSH  OFFSET MES   PUSH  DWORD PTR [EBP+08H] ; Window descriptor   CALL  MessageBoxA@16   PUSH  0   CALL  PostQuitMessage@4 ; The WM_QUIT message   MOV   EAX, 0 FINISH:   POP   EDI   POP   ESI   POP   EBX   POP   EBP   RET   16 WNDPROC ENDP _TEXT ENDS END START 
image from book
 

The program opens a window with a menu and a command button. When the user clicks the button, another menu replaces the current one. If the button is clicked again, the menu disappears. Repeatedly clicking the button displays the first menu, the second menu, and so on, cyclically. Additionally, the first menu contains the item that, when chosen, produces the same result as clicking the button. Finally, for this menu item there is an accelerator key<F5>. When scrolling the menu, the titles of menu items and popup menus are displayed in the window header. This, briefly , is the way of the program's operation. The mechanisms according to which the program works are described in detail after Listing 10.1.

The program provided in Listing 10.1 implements several mechanisms that I need to describe. First, note that the program uses three resources: two menus and one accelerator table (see the resource file).

  • First, I'd like to draw your attention to the PRIZN variable. It stores the menu status: 2 means the MENUP menu has been loaded; 1 means no menu; and 0 means the initial menu, MENUC , has been loaded. The initial state is ensured by specifying the menu when registering the window class:

     MOV  DWORD PTR [WC.CLMENNAME], OFFSET MEN 
  • The second aspect that deserves attention is the button. The mechanism used for detecting button-clicking events has already been considered , so I won't concentrate on it any more. One of the events that can take place as a result of the button-clicking events is menu removal. The menu is removed using the DestroyMENU function. After removing the menu, it is necessary to refresh the window by calling the ShowWindow function twice.

  • Another event that takes place when the button is clicked is menu change. The menu will be changed automatically if you load and install a new menu.

  • Choosing one of the items of the MENUP menu also changes the menu. Here, everything should be clear to you, because the same section of the program is accessed like in case of the button click.

  • An interesting situation arises with the accelerator. The accelerator key is <F5>. When this key is pressed, the same message is generated as when choosing the "fourth" item of the MENUP menu. The important point is that the same message will be generated when MENUC is loaded and when no menu is displayed. Because the procedure processes the message in either case, the <F5> key will also work in either case.

  • Now, consider how the name of the chosen menu item is determined. The central role in this mechanism is delegated to the WM_MENUSELECT message. This message arrives any time a menu item is selected. It is important to note that when you activate the menu, the WM_MENUSELECT message will be the first to arrive . This message has the LPARAM value that defines the menu identifier as zero. This is achieved by the following lines of code:

     CMP  WORD PTR [EBP+14H], 0  JE   FINISH 
  • When receiving the WM_MENUSELECT message, the least significant word of the WPARAM parameter can contain either the identifier of the menu item or the number of the header of the popup menu. This is the key point. You must know this information, because the header string of the popup menu item and the string of the menu item are obtained differently. To define what has been chosen, it is possible to use the most significant word of WPARAM. For this purpose, use the MF_POPUP constant: TEST WORD PTR [EBP+12H], MF_POPUP . Note how convenient the SETNE command is here.

  • Furthermore, to get the name string, use the GetMenuItemInfo function. The third parameter of this function can be either 0 or 1. If 0 is chosen, then the second parameter is the menu item identifier. If 1 is chosen, then the second parameter is the identifier of the popup menu header. The fourth parameter is the pointer to the structure that will be filled as a result of function execution. However, some fields of this structure must be filled beforehand. I draw your attention to the dwTypeData field, which must contain the pointer to the buffer containing the required string. The cch field must contain the length of that buffer. However, for the function to interpret the dwTypeData and cch fields exactly as the pointer to the buffer and the buffer length, the fields fMask and fType must be filled properly (see Listing 10.1). Finally, the cbsize field must contain the length of the entire structure.

  • Having received the required information (e.g., the menu item name string), send the WM_SETTEXT message using the SendMessage function. This message gives the command to set the window header.



The Assembly Programming Master Book
The Assembly Programming Master Book
ISBN: 8170088178
EAN: 2147483647
Year: 2004
Pages: 140
Authors: Vlad Pirogov

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net