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.
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.
|