previous page
next page

CWindow

An HWND Wrapper

The most basic of the windowing classes in ATL is CWindow. Its chief job is to hold an HWND, which it can obtain via several member functions:

class CWindow {                                              
public:                                                      
    CWindow(HWND hWnd = NULL) :                              
        m_hWnd(hWnd)                                         
    { }                                                      
                                                              
    CWindow& operator=(HWND hWnd)                            
    { m_hWnd = hWnd; return *this; }                         
                                                              
    void Attach(HWND hWndNew) {                              
        ATLASSERT(m_hWnd == NULL);                           
        ATLASSERT((hWndNew == NULL) || ::IsWindow(hWndNew)); 
        m_hWnd = hWndNew;                                    
    }                                                        
    HWND Create(LPCTSTR lpstrWndClass, HWND hWndParent,      
        _U_RECT rect = NULL,                                 
        LPCTSTR szWindowName = NULL,                         
        DWORD dwStyle = 0, DWORD dwExStyle = 0,              
        _U_MENUorID MenuOrID = 0U,                           
        LPVOID lpCreateParam = NULL) {                       
        // Calls ::CreateWindowEx and caches result in m_hWnd
        ...                                                  
        return m_hWnd;                                       
    }                                                        
    ...                                                      
};                                                           

The HWND itself is available either as a public data member or via the HWND typecast operator:

class CWindow {                           
public:                                   
  HWND m_hWnd;                            
  operator HWND() const { return m_hWnd; }
  ...                                     
};                                        

If you want to clear the HWND, you can set m_hWnd manually or use the Detach member function:

inline HWND CWindow::Detach() {
    HWND hWnd = m_hWnd;        
    m_hWnd = NULL;             
    return hWnd;               
}                              

A CWindow object represents a wrapper around the HWND, not the window itself. The CWindow destructor does not destroy the underlying window. Hence, there's really no need to ever call Detach.

HWND Wrapper Functions

When the CWindow object has an HWND, you can make use of the rest of the CWindow class member functions. The purpose of CWindow is to act as a wrapper for all the functions of the User32 API. For every function that takes an HWND as the first argument, the CWindow class has a corresponding member function that uses the cached m_hWnd. For example, instead of the calling SetWindowText:

void SayHello(HWND hwnd) {
  SetWindowText(hwnd, __T("Hello"));
}

you use the SetWindowText member function:

void SayHello(HWND hwnd) {
  CWindow wnd = hwnd;
  wnd.SetWindowText(__T("Hello"));
}

And when I said that all the User32 functions take an HWND as a first parameter, I meant all. As near as I can tell, with the exception of one function (SetForegroundWindow), the entire Windowing API is represented as a member function of CWindow. The CWindow class declaration comments break the wrapped functions into several categories:

Alert functions

Attributes

Caret functions

Clipboard functions

Coordinate-mapping functions

Dialog box item functions

Font functions

Help functions

Hot key functions

Icon functions

Menu functions

Message functions

Miscellaneous operations

Scrolling functions

Timer functions

Update and painting functions

Window-access functions

Window size and position functions

Window state functions

Window text functions

Window tree access

HWND Helper Functions

The vast majority of the CWindow member functions are merely inline wrappers on the raw functions. This means that you get the syntactic convenience of member functions without any additional runtime overhead. In addition, several helper functions above and beyond straight wrappers encapsulate common functionality that we often end up writing repeatedly:

class CWindow {                                   
...                                               
  DWORD GetStyle() const;                         
  DWORD GetExStyle() const;                       
  BOOL  ModifyStyle(DWORD dwRemove, DWORD dwAdd,  
    UINT nFlags = 0);                             
  BOOL  ModifyStyleEx(DWORD dwRemove, DWORD dwAdd,
    UINT nFlags = 0);                             
  BOOL ResizeClient(int nWidth, int nHeight,      
    BOOL bRedraw = TRUE);                         
  HWND  GetDescendantWindow(int nID) const;       
  BOOL  CenterWindow(HWND hWndCenter = NULL);     
  BOOL  GetWindowText(BSTR* pbstrText);           
  BOOL  GetWindowText(BSTR& bstrText);            
  HWND  GetTopLevelParent() const;                
  HWND  GetTopLevelWindow() const;                
...                                               
};                                                

Likewise, CWindow provides a number of type-safe wrappers for calling SendMessage for common messages, performing the error-prone casting chores for us:

class CWindow {                                                  
...                                                              
  void  SetFont(HFONT hFont, BOOL bRedraw = TRUE);               
  HFONT GetFont() const;                                         
  void  Print(HDC hDC, DWORD dwFlags) const;                     
  void  PrintClient(HDC hDC, DWORD dwFlags) const;               
  void  SetRedraw(BOOL bRedraw = TRUE);                          
  HICON SetIcon(HICON hIcon, BOOL bBigIcon = TRUE);              
  HICON GetIcon(BOOL bBigIcon = TRUE) const;                     
  int   SetHotKey(WORD wVirtualKeyCode, WORD wModifiers);        
  DWORD GetHotKey() const;                                       
  void  NextDlgCtrl() const;                                     
  void  PrevDlgCtrl() const;                                     
  void  GotoDlgCtrl(HWND hWndCtrl) const;                        
  void  SendMessageToDescendants(UINT message, WPARAM wParam = 0,
    LPARAM lParam = 0, BOOL bDeep = TRUE);                       
...                                                              
};                                                               

Using CWindow

Before we can put the CWindow class to use in our sample Windows application, we have to establish support for the ATL window classes in our Win32 application. If you run the Visual Studio 2005 Win32 Project Wizard, on the second page, you'll see a check box for Add Common Header Files for ATL, as shown in Figure 10.2.

Figure 10.2. Options for Win32 projects


This check box adds the following lines to the precompiled header file stdafx.h:

#include <atlbase.h>
#include <atlstr.h>

The ATL windowing classes are defined in atlwin.h. The project template creates a skeleton application that doesn't use the ATL windowing classes, so we'll also need to include atlwin.h in the stdafx.h generated by the ATL project template:

// stdafx.h
...
#include <atlwin.h>

After we've included atlwin.h, we can start using CWindow instead of raw Win32 calls.

The Win32 Project Wizard creates an InitInstance function that uses the Win32 API to register the window class and create the main window. We can update it to use CWindow instead like this:

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
  // Store instance handle in our global variable
  hInst = hInstance;
  CWindow wnd;
  wnd.Create(szWindowClass, 0, CWindow::rcDefault,
    __T("Windows Application"), WS_OVERLAPPEDWINDOW,
    WS_EX_CLIENTEDGE );

  if (!wnd) {
     return FALSE;
  }

  wnd.CenterWindow( );
  wnd.ShowWindow( nCmdShow );
  wnd.UpdateWindow( );
  return TRUE;
}

Notice that the structure of the program remains the same. The only difference is that we're calling member functions instead of global functions. WndProc can be similarly updated:

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam,
    LPARAM lParam) {
    CWindow wnd( hWnd );

    switch (nMsg) {
    // ...
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = wnd.BeginPaint(&ps);
        RECT rect; wnd.GetClientRect(&rect);

        DrawText(hdc, __T("Hello, Windows"), -1, &rect,
            DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        wnd.EndPaint(&ps);
        break;
    }
    // ... the rest is the same
    return 0;
}

CWindow is a step in the right direction. Instead of calling global functions and passing a handle, we're now able to call member functions on an object. However, we're still registering a Windows class instead of creating a C++ class, and we're still handing callbacks via a WndProc instead of via member functions. To completely fulfill our desires, we need the next most important class in the ATL windowing hierarchy, CWindowImpl.


previous page
next page
Converted from CHM to HTML with chm2web Pro 2.75 (unicode)