Jump to content

PMGuide - Window Procedures

From EDM2
Revision as of 17:59, 15 April 2025 by Martini (talk | contribs) (Structure of a Window Procedure)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

Presentation Manager Programming Guide and Reference
  1. How to Use this Book
  2. Device Functions
  3. Direct Manipulation Functions
  4. Dynamic Data Formatting Functions
  5. Hooks and Procedures
  6. Profile Functions
  7. Spooler Functions
  8. Window Functions
  9. Message Processing
  10. Data Types
  11. Errors
  12. Atom Tables
  13. Button Controls
  14. Clipboards
  15. Combination Box
  16. Container Controls
  17. Control Windows
  18. Cursors
  19. Dialog Windows
  20. Direct Manipulation
  21. Drawing in Windows
  22. Dynamic Data Exchange
  23. Entry-Field Controls
  24. File Dialog Controls
  25. Font Dialog Controls
  26. Frame Windows
  27. Hooks
  28. Initialization Files
  29. Keyboard Accelerators
  30. List-Box Controls
  31. Menus
  32. Messages and Message Queues
  33. Multiple-Line Entry Field Controls
  34. Mouse and Keyboard Input
  35. Mouse Pointers and Icons
  36. Notebook Controls
  37. Painting and Drawing
  38. Presentation Parameters
  39. Resource Files
  40. Scroll-Bar Controls
  41. Slider Controls
  42. Spin Button Controls
  43. Static Controls
  44. Title-Bar Controls
  45. Value Set Controls
  46. Windows
  47. Window Classes
  48. Window Procedures
  49. Window Timers
  50. Appendices
  51. Notices
  52. Glossary

Windows have an associated window procedure-a function that processes all messages sent or posted to a window. Every aspect of a window's appearance and behavior depends on the window procedure's response to the messages. This chapter explains how window procedures function, in general, and describes the default window procedure.

About Window Procedures

Every window belongs to a window class that determines which window procedure a particular window uses to process its messages. All windows of the same class use the same window procedure. For example, the operating system defines a window procedure for the frame window class (WC_FRAME), and all frame windows use that window procedure.

An application typically defines at least one new window class and an associated window procedure. Then, the application can create many windows of that class, all of which use the same window procedure. This means that the same piece of code can be called from several sources simultaneously; therefore, you must be careful when modifying shared resources from a window procedure.

Dialog procedures have the same structure and function as window procedures. The primary difference between a dialog procedure and a window procedure is the absence of a client window in the dialog procedure; that is, the controls in a dialog procedure are the immediate child windows of the frame, whereas the controls in a normal window are the grandchildren of the frame. This makes significant differences in the code between the two; for example, WinSendDlgItemMsg does not work from a client window if you pass the client window handle as the first parameter.

Structure of a Window Procedure

A window procedure is a function that takes 4 arguments and returns a 32-bit pointer. The arguments of a window procedure consist of a window handle, a ULONG message identifier, and two arguments, called message parameters, that are declared with the MPARAM data type. The system defines an MPARAM as a 32-bit pointer to a VOID data type (a generic pointer). The message parameters actually might contain any of the standard data types. The message parameters are interpreted differently,depending on the value of the message identifier. The operating system includes several macros that enable the application to cast the information from the MPARAM values into the actual data type. SHORT1FROMMP, for example, extracts a 16-bit value from a 32-bit MPARAM. The window-procedure arguments are described in the following table:

Arguments and Descriptions
Argument Description
hwnd Handle of the window receiving the message.
msg Message identifier. The message will correspond to one of the predefined constants (for example, WM_CREATE) defined in the system include files or be an application-defined message identifier. The value of an application-defined message identifier must be greater than the value of WM_USER, and less than or equal to 0xffff.
mp1,mp2 Message parameters. Their interpretation depends on the particular message.

The return value of a window procedure is defined as an MRESULT data type. The interpretation of the return value depends on the particular message. Consult the description of each message to determine the appropriate return value.

Default Window Procedure

All windows in the system share certain fundamental behavior, defined in the default window-procedure function, WinDefWindowProc. The default window procedure provides the minimal functionality for a window. An application-defined window procedure should pass any messages it does not process to WinDefWindowProc for default processing.

Window-Procedure Subclassing

Subclassing enables an application to intercept and process messages sent or posted to a window before that window has a chance to process them. Subclassing most often is used to add functionality to a particular window or to alter a window's default behavior.

An application subclasses a window by using the WinSubclassWindow function to replace the window's original window procedure with an application-defined window procedure. Thereafter, the new window procedure processes any messages that are sent or posted to the window. If the new window procedure does not process a particular message, it must pass the message to the original window procedure, not to WinDefWindowProc, for default processing.

Using Window Procedures

This section explains how to:

  • Design a window procedure
  • Associate a window procedure with a window class
  • Subclass a window

Designing a Window Procedure

The following code fragment shows the structure of a typical window procedure and how to use the message argument in a switch statement, with individual messages handled by separate case statements. Notice that each case returns a specific value for each message. For messages that it does not handle itself, the window procedure calls WinDefWindowProc.

    MRESULT ClientWndProc(
    HWND hwnd,
    ULONG msg,
    MPARAM mp1,
    MPARAM mp2)
    {
        /* Define local variables here, if required. */
        switch (msg) {
            case WM_CREATE:
 
        /* Initialize private window data.           */
            return (MRESULT) FALSE;

            case WM_PAINT:

        /* Paint the window.                         */
            return 0;

            case WM_DESTROY:

        /* Clean up private window data.             */
            return 0;

            default:
            break;
         }
         return WinDefWindowProc (hwnd, msg, mp1, mp2);
    }

A dialog window procedure does not receive the WM_CREATE message; however, it does receive a WM_INITDLG message when all of its control windows have been created. At the very least, a window procedure should handle the WM_PAINT message to draw itself. Typically, it should handle mouse and keyboard messages as well. Consult the descriptions of individual messages to determine whether your window procedure should handle them.

An application can call WinDefWindowProc as part of the processing of a message. In such a case, the application can modify the message parameters before passing the message to WinDefWindowProc or can continue with the default processing after performing its own operations.

Associating a Window Procedure with a Window Class

To associate a window procedure with a window class, an application must pass a pointer to that window procedure to the WinRegisterClass function. Once an application has registered the window procedure, the procedure automatically is associated with each new window created with that class.

The following code fragment shows how to associate the window procedure in the previous example with a window class:

    HAB hab;
    CHAR szClientClass[] = "My Window Class";

    WinRegisterClass(hab,      /* Anchor-block handle  */
        szClientClass,         /* Class name           */
        ClientWndProc,         /* Pointer to procedure */
        CS_SIZEREDRAW,         /* Class style          */
        0);                    /* Window data          */

Subclassing a Window

To subclass a window, an application calls the WinSubclassWindow function, specifying the handle of the window to subclass and a pointer to the new window procedure. The WinSubclassWindow function returns a pointer to the original window procedure; the application can use this pointer to pass unprocessed messages to the original procedure. The following code fragment subclasses a push button control window. The new window procedure generates a beep whenever the user clicks the push button.

    PFNWP pfnPushBtn;
    CHAR szCancel[] = "Cancel";
    HWND hwndClient;
    HWND hwndPushBtn;
        .
        .
        .

    /* Create a push button control.                  */
    hwndPushBtn = WinCreateWindow(
        hwndClient,     /* Parent-window handle       */
        WC_BUTTON,      /* Window class               */
        szCancel,       /* Window text                */
        WS_VISIBLE   |  /* Window style               */
        WS_SYNCPAINT |  /* Window style               */
        BS_PUSHBUTTON,  /* Button style               */
        50, 50,         /* Physical position          */
        70, 30,         /* Width and height           */
        hwndClient,     /* Owner-window handle        */
        HWND_TOP,       /* Z-order position           */
        1,              /* Window identifier          */
        NULL,           /* No control data            */
        NULL);          /* No presentation parameters */

    /* Subclass the push button control.              */
    pfnPushBtn = WinSubclassWindow(hwndPushBtn,
        SubclassPushBtnProc);
        .
        .
        .
}
    /* This procedure subclasses the push button.     */
    MRESULT EXPENTRY SubclassPushBtnProc(HWND hwnd,ULONG msg,MPARAM mp1, MPARAM mp2)
    {
        switch (msg) {

    /* Beep when the user clicks the push button.     */
            case WM_BUTTON1DOWN:
                DosBeep(1000, 250);
                break;

            default:
                break;
        }

    /* Pass all messages to the original window procedure. */
        return (MRESULT) pfnPushBtn(hwnd, msg, mp1, mp2);
    }