Understanding CWindowImpl

 < Free Open Study > 



Understanding CWindowImpl<>

Now that we have created a main window with ATL, we can begin to dig into some of the nasty details. CWindowImpl<> wraps up the grunge of creating a WNDCLASSEX structure using the DECLARE_WND_CLASS macro. CWindowImpl<>'s Create() method then registers the resulting WNDCLASSEX. Here is the formal definition of CWindowImpl<>:

// CWindowImpl<> wraps up the details of creating and registering your window. template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits> class ATL_NO_VTABLE CWindowImpl : public CWindowImplBaseT< TBase, TWinTraits > { public:      // Create a WNDCLASSEX structure.      DECLARE_WND_CLASS(NULL)      HWND Create(HWND hWndParent, RECT& rcPos,                 LPCTSTR szWindowName = NULL,                 DWORD dwStyle = 0, DWORD dwExStyle = 0,                 UINT nID = 0, LPVOID lpCreateParam = NULL)      {           // Register the WNDCLASSEX structure.           ...      } };

Now truth be told, ATL takes a couple of twists and turns to define your window's WNDCLASSEX structure (imagine that, huh?). In reality, this Win32 structure is hidden away as a field in another structure: _ATL_WNDCLASSINFO. So, to follow the winding path, the DECLARE_WND_CLASS macro first expands to define a variable of type CWndClassInfo, which can be retrieved using the GetWndClassInfo() method, also inserted as a result of the DECLARE_WND_CLASS macro:

// ATL provides a window class structure indirectly using the CWndClassInfo // helper structure. The fields of this structure are filled in the following... #define DECLARE_WND_CLASS(WndClassName) \ static CWndClassInfo& GetWndClassInfo() \ { \      static CWndClassInfo wc = \      { \           { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | \           CS_DBLCLKS, StartWindowProc, \           0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), \           NULL, WndClassName, NULL }, \           NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \      }; \      return wc; \ }

The definition of CWndClassInfo ends up defining _ATL_WNDCLASSINFO, where your WNDCLASSEX structure is hidden deep from view:

// The WNDCLASSEX we all know and love. struct _ATL_WNDCLASSINFOA {      WNDCLASSEXA m_wc;          // Your window class structure.      LPCSTR m_lpszOrigName;      WNDPROC pWndProc;      LPCSTR m_lpszCursorID;      BOOL m_bSystemCursor;      ATOM m_atom;      CHAR m_szAutoName[13];      ATOM Register(WNDPROC* p)      {           return AtlModuleRegisterWndClassInfoA(&_Module, this, p);      } };

Note 

Remember, the Windows API defines Unicode (W) and ANSI (A) versions for all windowing primitives. Based on preprocessor definitions, the correct version is obtained. Thus, _ATL_WNDCLASSINFO results in either _ATL_WNDCLASSINFOA or _ATL_WNDCLASSINFOW.

Modifying the Default WNDCLASSEX Settings

ATL does a fine job of creating and filling a WNDCLASSEX structure on your behalf; however, if you should ever wish to change the default settings, you can obtain a reference to the m_wc data member in your derived class using GetWndClassInfo(). From this member, you can tweak the WNDCLASSEX fields to your own liking. If we were to extend the constructor of CMainWindow with the following code, we would see a window much like Figure 13-5.


Figure 13-5: Tweaking WNDCLASSEX in ATL.

// Change the hbrBackground field of WNDCLASSEX to a black background. CWndClassInfo &winInfo = GetWndClassInfo(); winInfo.m_wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); 

Uncovering ATL's WndProc Implementation

As we have seen, the DECLARE_WND_CLASS macro is used to populate the CWndClassInfo structure, which ultimately sets up the fields of WNDCLASSEX. If you looked carefully, you may have noticed an entry named StartWindowProc. If you did not look carefully, here is the DECLARE_WND_CLASS macro expansion one more time:

// ATL provides a window class structure indirectly using the CWndClassInfo // helper class. #define DECLARE_WND_CLASS(WndClassName) \ static CWndClassInfo& GetWndClassInfo() \ { \      static CWndClassInfo wc = \      { \           { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | \           CS_DBLCLKS, StartWindowProc, \           0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), \           NULL, WndClassName, NULL }, \           NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \      }; \      return wc; \ }

This name is used to fill the lpfnWndProc field of the WNDCLASSEX structure. Given the requirements of a Win32 Windows application, you can assume that ATL has some method named StartWindowProc(). This method is defined in CWindowImplBaseT<>, the templatized base class to CWindowImpl<>:

// StartWindowProc() configures a WndProc for your ATL window. template <class TBase, class TWinTraits> LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits > ::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {      // Figure out who this window is.      CWindowImplBaseT< TBase, TWinTraits >* pThis =           (CWindowImplBaseT< TBase, TWinTraits >*)                _Module.ExtractCreateWndData(); ...      pThis->m_hWnd = hWnd;      // Configure the WNDPROC.      WNDPROC pProc = (WNDPROC)&(pThis->m_thunk.thunk); ... }

This method associates the ATL-defined WndProc (pProc) to your custom ATL window. Once this association has been made, the ATL MSG_MAP structure will be consulted to determine what to do with the incoming messages.

CMessageMap and ProcessWindowMessage()

Every ATL window (including dialog boxes) inherits a single pure virtual function named ProcessWindowMessage(), which is defined in CMessageMap as the following:

// All CWindowImpl<> derived classes inherit this pure virtual function. // Therefore, every ATL window (or dialog) must implement this method. class ATL_NO_VTABLE CMessageMap { public:      virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg,                WPARAM wParam, LPARAM lParam,                LRESULT& lResult, DWORD dwMsgMapID) = 0; }; 

When a window's MSG structure has been packaged up, it will be sent into your class's implementation of ProcessWindowMessage(). If the given message is not handled by your class, CWindowImplBaseT<>::WindowProc() will forward the message to DefWin- dowProc():

// In essence, CWindowImplBaseT<> forwards all messages to your class's // implementation of ProcessWindowMessage(). // If your class does not handle the current message, it is passed to the // DefWindowProc(). template <class TBase, class TWinTraits> LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits > ::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {      ...      MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };      ...      BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg,                                         wParam, lParam, lRes, 0);      ...      // Do the default processing if message was not handled.      if(!bRet)      {           if(uMsg != WM_NCDESTROY)                lRes = pThis->DefWindowProc(uMsg, wParam, lParam);           else           {                ...           }      }      return lRes; }

So, to make a long story short, ATL forwards all Windows messages to the ProcessWin- dowMessage() function defined by your CWindowImpl<> derived class. If your class does not handle the current message, it will be eaten by DefWindowProc(). Given that ProcessWindowMessage() is a pure virtual function, your custom window must implement this method or else be deemed an abstract base class. The next logical question is where is ProcessWindowMessage() hiding within your CWindowImpl<> derived class?



 < Free Open Study > 



Developer's Workshop to COM and ATL 3.0
Developers Workshop to COM and ATL 3.0
ISBN: 1556227043
EAN: 2147483647
Year: 2000
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net