[ Next ] [ Previous ] | Chapter 9 |
|
A window can be sized larger or smaller, it can be opened or closed, it can be made visible or invisible. Suffice it to say that there are a lot of things to do with a window. |
Figure 9.2 Drawing of a window's components |
Figure 9.2 looks like one window but, in reality,
it is seven windows:
|
Each of the five windows has a window procedure associated with it. In most cases, the programmer will be able to use the system-defined window procedures for all but the client window. The window procedure is a function that tells the window how to behave. Windows that share the same window procedure belong to the same window class. This is a familiar concept for those readers acquainted with object-oriented programming.
Imagine a fast food restaurant. Each item on the menu could be considered one class - a hot dog class, a hamburger class, and a pizza class. Suppose mustard, mayo, relish, or cheese could be put on a hot dog, in any combination. Each of these condiments would he a hot dog style.
The same is true for window classes. There are many predefined window
classes, including some classes specific to pen computing and the multimedia
extensions. The classes specific to Presentation Manager are:
Symbolic constant | Meaning |
WC_FRAME | The Frame control class |
WC_COMBOBOX | Combo box control class |
WC_BUTTON | Button control class |
WC_MENU | Menu control class |
WC_STATIC | Static text control class |
WC_ENTRYFIELD | Entryfield control class |
WC_LISTBOX | Listbox control class |
WC_SCROLLBAR | Scroll bar control class |
WC_TITLEBAR | Titlebar control class |
WC_MLE | Multi-line edit control class |
WC_SPINBUTTON | Spinbutton control class |
WC_CONTAINER | Container control class |
WC_SLIDER | Slider control class |
WC_VALUESET | Valueset control class |
WC_NOTEBOOK | Notebook control class |
Each window class is very different from the others. Some of these predefined classes will be covered in later chapters. The client window, which is the area inside the window frame, belongs to a user-defined class. Each window class also contains a set of window styles specific to that class. There is a set of class styles available to all classes. The styles are:
WIN1.C
WIN1.MAK
WIN1.DEF
#define INCL_WINThis is an all-encompassing define that will include the necessary headers for all the Win... functions. This is overkill in most cases, but for our first example we'll keep things simple.
#include <os2.h>
HWND hwndWnd,Window procedures are declared in a very special way, using the prefix MRESULT EXPENTRY. In OS2DEF.H, these expand to VOID * _System. The return type, MRESULT, gives the window procedure the freedom to return whatever it needs to by using the VOID * type. The _System tells the C-compiler that the operating system will be calling the function. It is a good idea to use the Presentation Manager-defined data types when dealing with window procedures and messages. There is a good probability that some definitions will change when moving to other machine architectures, and by using the defined data types, we save some headaches if we need to port the application to some other version of OS/2. A more detailed explanation of window procedure is in the section "The Window Procedure Revisited"
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2 );
The function's parameters are HWND hwndWnd, ULONG ulMsg, MPARAM mpParm1, and MPARAM mpParm2. This may look very familiar to Microsoft Windows programmers. The variable hwndWnd is a window handle. Each window has its own unique window handle, and most Win... functions will include this as a parameter. In this case, hwndWnd is the window to which the message is being sent. The parameter ulMsg is the specific message being sent so the window. We will cover messages in more detail in Chapter11.
The last two parameters are mpParm1 and mpParm2 which have the type MPARAM. These are "shape-shifter" parameters. MPARAM is really a PVOID in disguise. This gives the operating system two 32-bit spaces to insert whatever data corresponds to the message being sent. These values could be pointers or short or long integers. For example. the message WM_MOUSEMOVE is sent whenever the mouse is moved. The first message parameter, mpParm1, would contain two SHORTs. The second message parameter, mpParm2, also contains two SHORTs. Figure 9.3 provides a breakdown of a message-parameter variable.
|
||
|
||
|
Macro | Converts into MPARAM |
MPFROMVOID | 0 |
MPFROMP | PVOID |
MPFROMHWND | HWND |
MPFROMCHAR | CHAR |
MPFROMSHORT | SHORT |
MPFROM2SHORT | 2 SHORTs |
MPFROMSH2CH | 2 CHARs |
MPFROMLONG | ULONG |
Table 9.2 presents the macros used to convert a MPARAM data type into
a standard data type that can be used when receiving a window message.
Macro | Converts from MPARAM |
PVOIDFROMMP | PVOID |
HWNDFROMMP | HWND |
CHAR1FROMMP | CHAR |
CHAR2FROMMP | second CHAR |
CHAR3FROMMP | third CHAR |
CHAR4FROMMP | fourth CHAR |
SHORT1FROMMP | low SHORT |
SHORT2FROMMP | high SHORT |
LONGFROMMP | ULONG |
Table 9.3 presents the macros used to convert a MRESULT data type into
standard data type that can be used to examine a return value for the window
procedure.
Macro | Converts from MRESULT |
PVOIDFROMMR | PVOID |
SHORT1FROMMR | low SHORT |
SHORT2FROMMR | high SHORT |
LONGFROMMR | ULONG |
Table 9.4 presents the macros used to convert a standard data
typo into a MRESULT data type that can be used to construct a return value
from the window procedure.
Macro | Converts to MRESULT |
MRFROMP | PVOID |
MRFROMSHORT | SHORT |
MRFROM2SHORT | 2 SHORTs |
MRFROMLONG | ULONG |
habAncbor = WinInitialize ( 0 ) ;The beginning of a PM program will always start with a few things. First, WinInitialize is called to obtain an anchor block handle, or HAB. An anchor block is specific to each thread that contains a window procedure.
hmqQueue = WinCreateMsgQueue( habAncor,0) ;
HAB WinInitialize( ULONG. flOptions)The only parameter for WinInitialize is a ULONG that is used for initialization options. In a PM environment, this should be 0. An anchor block currently contains error information for each thread and also may be used for "future portability issues". Each Presentation Manager thread should obtain its own anchor block for two reasons: portability and also to obtain error information specific to that thread.
HMQ WinCreateMsgQueue( HAB habAnchor, Long lQueuesize )WinCreateMsgQueue will create a message queue for the thread that called the function. The message queue is how Presentation Manager communicates back and forth with the windows. The first parameter is the anchor block handle, habAnchor. The second parameter is the queue size. A parameter of 0 indicates the default queue size in OS/2, which holds 10 messages. A full queue will cause the user interface to respond rather slowly and sometimes to stop responding completely. The default queue size should be fine for most applications. If a queue is getting too full, the program should be checked to see where messages are getting backlogged. (One of the requirements for a PM interface is a crisp user response. Any response that consumes more than 100 milliseconds probably should be put in a separate thread. See Chapter 30 for more information on multithreading in a PM program.)
WinRegisterClassThe function WinRegisterClass is used to create a new class of windows, in this case CLS_CLIENT.
( habAnchor,
CLS_CLIENT,
ClientWndProc,
0,
0 ) ;
BOOL WinRegisterClassThe first parameter is the anchor, habAnchor. The next parameter is the class name. This parameter is a null-terminated string. The next parameter is the window procedure the class is assigned to, ClientWndProc. The fourth parameter is the class styles used for the new class. We're not going to use any class styles for now, so we put 0 here. The last parameter is the number of bytes of storage space that will be tacked on to each window belonging to this class. This piece of space is commonly referred to as "window words." This is covered in more detail later.
( HAB hab,
PSZ pszClassName,
PFNWP pfnWndProc,
ULONG flStyle,
ULONG cbWindowData)
By now readers are probably thinking "But I just wanted to create one lousy window". Well, this is it, the function call you've been waiting for: WinCreateStdWindow. This function actually creates five windows as stated earlier; but only two that are of any interest to us - the frame window and the client window. |
ulFlags = FCF_TITLEBAR |FCF_SYSMENU | FCF_SIZEBORDER | FCF_MINMAX | FCF_SHELLPOSITION | FCF_TASKLIST ;
hwndFrame = WinCreateStdWindow(The function returns the frame window handle.
HWND_DESKTOP,
WS_VISIBLE,
&ulFlags,
CLS_CLIENT,
"Titlebar",
0L,
NULLHANDLE,
0,
&hwndClient );
/* This function creates a standard window. */
#define INCL_WINFRAMEMGR /* Or use INCL_WIN,
INCL_PM, Also in COMMON section */
#include <os2.h>
HWND hwndParent;
/* Parent-window handle. */
ULONG flStyle;
/* Frame-window style. */
PULONG pflCreateFlags; /* Frame-creation
flags. */
PSZ pszClassClient;
/* Client-window class name. */
PSZ pszTitle;
/* Title-bar text. */
ULONG flStyleClient;
/* Client-window style. */
HMODULE Resource;
/* Resource identifier. */
ULONG ulId;
/* Frame-window identifier. */
PHWND phwndClient;
/* Client-window handle. */
HWND hwndFrame;
/* Frame-window handle. */
hwndFrame = WinCreateStdWindow(hwndParent,
flStyle, pflCreateFlags, pszClassClient,
pszTitle, flStyleClient, Resource,
ulId, phwndClient);
The. first parameter specified is the parent of the frame window. We'll
discuss parents and owners in a minute. The second parameter is the frame
style. A frame can draw from two sets of styles: frame styles, because
this is a frame window; and window styles, because the frame class is a
subset of the window class "window". The most common window style available
is WS_VISIBLE. Yep, you guessed it, this means the window is not only created
but will show up as well.
The third parameter is the frame flags. Frame flags describe how the
frame will look. The possible descriptors are OR'ed together. Figure 9.4
is a diagram of all the possible descriptors and the bits that correspond
to them.
Bit | Constant |
0 | FCF_TITLEBAR |
1 | FCF_SYSMENU |
2 | FCF_MENU |
3 | FCF_SIZEBORDER |
4 | FCF_MINBUTTON |
5 | FCF_MAXBUTTON |
6 | FCF_VERTSCROLL |
7 | FCF_HORZSCROLL |
8 | FCF_DLGBORDER |
9 | FCF_BORDER |
10 | FCF_SHELLPOSITION |
11 | FCF_TASKLIST |
12 | FCF_NOBYTEALIGN |
13 | FCF_NOMOVEWITHOWNER |
14 | FCF_ICON |
15 | FCF_ACCELTABLE |
16 | FCF_SYSMODAL |
17 | FCF_SCREENALIGN |
18 | FCF_MOUSEALIGN |
[...] |
|
24 | FCF_HIDEBUTTON |
25 |
|
26 | FCF_CLOSEBUTTON |
[...] | |
30 | FCF_AUTOICON |
Flag | Description |
FCF_TITLEBAR | Creates a title bar on the frame. |
FCF_SYSMENU | Creates a system menu on the frame. |
FCF_MENU | Creates an application menu on the frame. This is loaded from the resource file or .DLL. (See Chapter 12 for more information.) |
FCF_SIZEBORDER | Creates a sizing border on the frame. |
FCF_MINBUTTON | Creates a minimize button on the frame. |
FCF_MAXBUTTON | Creates a maximize button on the frame. |
FCF_MINMAX | Creates both a minimize and maximize button on the frame. |
FCF_VERTSCROLL | Creates a vertical scroll bar on the frame. |
FCF_HORZSCROLL | Creates a horizontal scroll bar on the frame. |
FCF_DLGBORDER | Creates the thick dialog box border on the frame. |
FCF_BORDER | Creates a thin border on the frame. |
FCF_SHELLPOSITION | The system determines the initial size and placement of the frame window. |
FCF_TASKLIST | Adds the program title to the task list and window title to the window list. |
FCF_NOBYTEALIGN | Do not optimize window movements in 8 pel multiples. |
FCF_NOMOVEWITHOWNER | The frame window will not move when the owner is moved. |
FCF_ICON | An icon is added to the frame. This is loaded from the resource file or .DLL. (See Chapter 12 for more information.) |
FCF_ACCELTABLE | An accelerator table is added to the frame. This is loaded from the resource file or DLL. (See Chapter 12 for more information) |
FCF_SYSMODAL | The frame window is system modal. |
FCF_SCREENALIGN | The frame window is positioned relative to the desktop rather than relative to the owner window. |
FCF_MOUSEALIGN | The frame window is positioned relative to the position of the mouse rather than relative to the owner window. |
FCF_HIDEBUTTON | Creates "hide" button on the frame |
FCF_HIDEMAX | Creates "hide" and maximize buttons on the frame. |
FCF_CLOSEBUTTON | use when no other min/max button is present |
FCF_AUTOICON | A WM_PAINT message will tot be sent to the application when the frame window is iconized |
FCF_STANDARD | FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON | FCF_MAXBUTTON | FCF_SIZEBORDER |FCF_ICON |FCF_MENU | FCF_ACCELTABLE | FCF_SHELLPOSITION |FCF_TASKLIST |
In this example, we'll use the following flags:
FCF_TITLEBAR, FCF_SYSMENU, FCF_SIZEBORDER, FCF_MINMAX,
FCF_SHELLPOSITION, FCF_TASKLIST
Gotcha!Be sure to pass a pointer to a ULONG as this parameter |
The fourth parameter is the name of the window class that the client
window will belong to; in this case we use the string defined by CLS_CLIENT.
The next parameter is the window text for the title bar. The sixth parameter
is the client window style. Since we defined the parent of the client window
hwndFrame to have the style WS_VISIBLE, the client, as a child of hwndFrame,
will inherit the WS_VISIBLE style. This means we don't have to specify
any window styles here; we'll just leave that a 0.
The next parameter is the resource ID location. The next parameter
contains the resource ID for the frame window. This one resource ID will
point to all the resources that are defined for the frame. This includes
the menu, icon, accelerator table, and any other items defined using the
frame creation fags. For more information on resources, see Chapter 12.
The last parameter is the address of a window handle. Presentation
Manager will place the client window handle into this variable upon the
function's return.
If WinCreateStdWindow fails, NULLHANDLE is returned.
Before we attempt to do anything else, it is a good idea to check the return
handle to make sure it is valid; if not, the application should quit, preferably
with some sort of error message.
The two functions WinGetMsg and WinDispatchMsg, are the keys to getting the message queue up and running. Without some form of message retrieval and dispatch the system will respond with a "Program not responding..." error message. The secret to a well thought out Presentation Manager application is a message queue that is quick and responsive. WinGetMsg will retrieve the message from the message queue and place it into the variable qmMsg. The QMSG structure looks very similar to the variables that are passed to the window procedure. Eventually the QMSG structure will be passed on to ClientWndProc or the window procedure for the window receiving the message. WinGetMsg and WinDispatchMsg form a post office for messages. They pick up the messages and then make sure that the messages are delivered to the correct window.
BOOL WinGetMsg(The first parameter of WinGetMsg is the anchor block handle. The next one is the address of the QMSG structure that will handle the retrieved message information. The next three parameters are not used in this example. They provide a way for WinGetMsg to choose selectively which messages to pick out of the queue. By specifying zeroes here, WinGetMsg will retrieve all messages from the message queue in the order they were placed there. After the message is retrieved from the queue, it is then passed on to WinDispatchMsg.
HAB hab,
PQMSG pqmsgmsg,
HWND hwnfFilter,
ULONG ulFirst,
ULONG ulLast )
MRESULT WinDispatchMsg ( HAB hab, PQMSG pgmsgMsg ) ;It is WinDispatchMsg's job to take the message from the qmMsg variable and send it on to the window procedure associated with the window it is addressed to. For instance, if qmMsg.hwnd were equal to hwndWnd, WinDispatchMsg would take qmMsg and send it on to ClientWndProc.
/* QMSG structure */
typedef struct _QMSG /* qmsg */
{
HWND hwnd; /*
window handle that msg is being sent to */
ULONG msg; /*
the message itself */
MPARAM mp1; /* Message Parameter
1 */
MPARAM mp2; /* Message Parameter
2 */
ULONG time; /*
Time msg was sent */
POINTL ptl; /* mouse position
when msg was sent */
ULONG reserved;
} QMSG;
typedef QMSG *PQMSG;
The QMSG structure contains a lot of very interesting information about the message. The first field in the structure, hwnd, is the window handle the message is for. The field msg is the constant identifying the message. Some common messages are WM_CREATE, WM_PAINT, WM_QUIT and WM_SIZE. The next two parameters, mp1 and mp2, are the message parameters. Each message has a set use for these parameters. Usually they are used to convey more information about the message. The time field contains the time the message was sent, and the ptl field is a structure that contains the mouse position when the message was sent.
You may have noticed that WinGetMsg and WinDispatchMsg were running in a while loop. While WinGetMsg returns a TRUE value, this loop continues to process messages. When WinGetMsg receives a WM_QUIT, WinGetMsg returns FALSE and will fall out of the loop. At this point, the user has elected to close the application, and it's time for the final cleanup. We have created three things that need to be destroyed - the frame window hwndFrame, hmqQueue, and habAnchor. Each of these items has its own destroy function. |
BOOL WinDestroyMsgQueue( HMQ hmq ) ;By destroying hwndFrame, we also are destroying the client window, the title bar, and all the other windows that are children of the frame.
BOOL WinDestroyWindow(HWND hwnd );
BOOL WinTerminate (HAB hab);
WinDestroyWindow (hwndFrame );
} /* endif */
WinDestroyMsgQueue( hmqQueue ) ;
WinTerminate (habAnchor);
return 0;
Gotcha!
Be very careful about accidentally reversing WinDefWindowProc and WinDefDlgProc. Strange things can occur when calling WinDefWindowProc for a dialog box or using WinDefDlgProc for a non-dialog box window. |
MRESULT EXPENTRY ClientWndProc ( HWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2 )
{
switch ( ulMsg ) {
case WM_ERASEBACKGROUND:
return MRFROMSHORT ( TRUE ) ;
default:
return WinDefWindowProc ( hwndWnd,
ulMsg,
mpParm1,
mpParm2 ) ;
} /* endswitch */
return MRFROMSHORT ( FALSE ) ;
}
The only message that is utilized in ClientWndProc is WM_ERASEBACKGROUND. This message is used to fill the client window with the system-window background color. If we let this message pass on to WinDefWindowProc, the background of the window would be transparent and the desktop would show through. By returning TRUE, we tell the system to paint the client window with the background color. In some cases, this message doesn't need to be processed if the painting is handled in the WM_PAINT message. In a window procedure, most messages have a default handling of returning FALSE. Programmers can save a few extra function calls by returning FALSE themselves from the handled instead of calling WinDefWindowProc.
[ Next ] [ Previous ] | Chapter 9 |