Window Management Functions
Given the windows-centric nature of Windows, it's not surprising that you can choose from a number of functions that enable a window to interrogate its environment so that it might determine its location in the window family tree. To find its parent, a window can callHWND GetParent (HWND hWnd);
This function is passed a window handle and returns the handle of the calling window's parent window. If the window has no parent, the function returns NULL.
Enumerating Windows
GetWindow, prototyped as
HWND GetWindow (HWND hWnd, UINT uCmd);
is an omnibus function that allows a window to query its children, owner, and siblings. The first parameter is the window's handle, while the second is a constant that indicates the requested relationship. The GW_CHILD constant returns a handle to the first child window of a window. GetWindow returns windows in Z-order, so the first window in this case is the child window highest in the Zorder. If the window has no child windows, this function returns NULL. The two constants, GW_HWNDFIRST and GW_HWNDLAST, return the first and last windows in the Z-order. If the window handle passed is a top-level window, these constants return the first and last topmost windows in the Z-order. If the window passed is a child window, the GetWindow function returns the first and last sibling window. The GW_HWNDNEXT and GW_HWNDPREV constants return the next lower and next higher windows in the Z-order. These constants allow a window to iterate through all the sibling windows by getting the next window, then using that window handle with another call to GetWindow to get the next, and so on. Finally, the GW_OWNER constant returns the handle of the owner of a window.Another way to iterate through a series of windows is
BOOL EnumWindows (WNDENUMPROC lpEnumFunc, LPARAM lParam);
This function calls the callback function pointed to by lpEnumFunc once for each top-level window on the desktop, passing the handle of each window in turn. The lParam value is an application-defined value, which is also passed to the enumeration function. This function is better than iterating through a GetWindow loop to find the top-level windows because it always returns valid window handles; it's possible that a GetWindow iteration loop will get a window handle whose window is destroyed before the next call to GetWindow can occur. However, since EnumWindows works only with top-level windows, GetWindow still has a place when a program is iterating through a series of child windows.
Finding a Window
To get the handle of a specific window, use the function
HWND FindWindow (LPCTSTR lpClassName, LPCTSTR lpWindowName);
This function can find a window either by means of its window class name or by means of a window's title text. This function is handy when an application is just starting up; it can determine whether another copy of the application is already running. All an application has to do is call FindWindow with the name of the window class for the main window of the application. Because an application almost always has a main window while it's running, a NULL returned by FindWindow indicates that the function can't locate another window with the specified window class—therefore, it's almost certain that another copy of the application isn't running.You can find the handle to the desktop window by using the function
HWND GetDesktopWindow (void);
Editing the Window Structure Values
The pair of functions
LONG GetWindowLong (HWND hWnd, int nIndex);
and
LONG SetWindowLong (HWND hWnd, int nIndex, LONG dwNewLong);
allow an application to edit data in the window structure for a window. Remember that the WNDCLASS structure passed to the RegisterClass function has a field, cbWndExtra, that controls the number of extra bytes that are to be allocated after the structure. If you allocated extra space in the window structure when the window class was registered, you can access those bytes using the GetWindowLong and SetWindowLong functions. Under Windows CE, the data must be allocated and referenced in 4-byte (integer sized and aligned) blocks. So if a window class was registered with 12 in the cbWndExtra field, an application can access those bytes by calling GetWindowLong or SetWindowLong with the window handle and by setting the values 0, 4, and 8 in the nIndex parameter.GetWindowLong and SetWindowLong support a set of predefined index values that allow an application access to some of the basic parameters of a window. Here is a list of the supported values for Windows CE.
GWL_STYLE The style flags for the window
GWL_EXSTYLEThe extended style flags for the window
GWL_WNDPROCThe pointer to the window procedure for the window
GWL_IDThe ID value for the window
GWL_USERDATAAn application-usable 32-bit value
Dialog box windows support the following additional values:
DWL_DLGPROC The pointer to the dialog procedure for the window
DWL_MSGRESULTThe value returned when the dialog box function returns
DWL_USER An application-usable 32-bit value
Windows CE doesn't support the GWL_HINSTANCE and GWL_HWNDPARENT values supported by Windows 2000 and Windows XP.
Changing the Style Flags
Editing the window structure can be useful in a number of ways. The style bits of a window can be changed after the window has been created to change its default actions and look. For example, the title bar of a window can be shown or hidden by toggling the WS_CAPTION style bit. After changing any style flag that modifies the look of the window, it's customary to force the system to redraw the nonclient area of the window with a call to SetWindowPos.SetWindowPos is one of those functions used all the time in Windows. It allows the application to move, size, change the Z-order of, and as in this case, redraw the nonclient area of the window. Its prototype is
BOOL SetWindowPos (HWND hWnd, HWND hWndInsertAfter, int X, int Y,
int cx, int cy, UINT uFlags);
The first parameter is the handle of the window that will be changed. The hWndInsertAfter parameter optionally allows the function to set the Z-order of the window. This parameter can be either a window handle or one of four flags that position the window either at the top or the bottom of the Z-order. The flags are shown here:
HWND_BOTTOMThe window underneath all windows on the desktop
HWND_TOPThe window on top of all windows
HWND_TOPMOSTThe window to always be placed on top of other windows, even when the window is deactivated
HWND_NOTTOPMOSTThe window on top of all other nontopmost windows but not marked as a topmost window so that it will be covered when another window is activated
The X, Y, cx, and cy parameters optionally specify the position and size of the window. The flags parameter contains one or more flags that describe the task to accomplish. The flags are as follows:
SWP_NOMOVEDon't move the window.
SWP_NOSIZEDon't resize the window.
SWP_NOZORDERDon't set the window's Z-order.
SWP_NOACTIVATEIf the Z-order is set, don't activate the window.
SWP_DRAWFRAMERedraw the nonclient area.
SWP_FRAMECHANGEDRecalculate the nonclient area, and then redraw.
Two other flags, SWP_SHOWWINDOW and SWP_HIDEWINDOW, show and hide the window, but it's easier to call the ShowWindow function to show or hide a window. To use SetWindowPos to force the frame to be redrawn after the style bits are changed, the call would be
SetWindowPos (hWnd, 0, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
Subclassing a Window
Another use of SetWindowLong is to subclass a window. Subclassing a window allows an application to essentially derive an instance of a new window class from a preexisting window class. The classic use for subclassing is to modify the behavior of a window control, such as an edit control.The process of subclassing is actually quite simple. A window procedure is created that provides only the new functionality required of the subclassed window. A window is then creating using the base window class. GetWindowLong is called to get and save the pointer to the original window procedure for the window. SetWindowLong is then called to set the window procedure for this instance of the window to the new window procedure. The new window procedure then receives the message sent to the window. Any messages not acted upon by the new window procedure are passed on to the old window procedure with the function CallWindowProc. The following code shows a window being created and then subclassed. The subclass procedure then intercepts the WM_LBUTTONDOWN message and beeps the speaker when the window receives that message.
// Prototype of subclass procedure
LRESULT CALLBACK SCWndProc(HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam);
// Variable that holds the pointer to the original WndProc
WNDPROC lpfnOldProc = 0;
//
// Routine that subclasses the requested window.
//
BOOL SubClassThisWnd (HWND hwndSC) {
if (lpfnOldProc == 0) {
// Get and save the pointer to the original window procedure
lpfnOldProc = (WNDPROC)GetWindowLong (hwndSC, GWL_WNDPROC);
// Point to new window procedure
return SetWindowLong (hwndSC, GWL_WNDPROC, (DWORD)SCWndProc);
}
return FALSE;
}
//
// Subclass procedure
//
LRESULT CALLBACK SCWndProc(HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
switch (wMsg) {
case WM_LBUTTONDOWN:
MessageBeep(0);
break;
}
return CallWindowProc (lpfnOldProc, hWnd, wMsg, wParam, lParam);
}
To un-subclass the window, the program simply calls SetWindowLong to set the WndProc pointer back to the original window procedure.