您的位置:首页 > 其它

Learning WTL8.0 Part-1 Win32 vs. ATL Windows Programming(3)

2007-09-21 19:41 411 查看
4. ATL Windows编程模型

参照3.1.1 Win32基础构造块和主要流程,来初步的了解ATL Windows编程模型(有关ATL Windows编程的文档极为“罕见“, 甚至与WTL相比 : -)) ;ATL Windows编程是WTL的基石,当然有必要在此费一番力气。
4.1 RegisterClass在哪?
在 1.2.1 Register windows class 中,MyRegisterClass函数要完成的工作:1. 初始化WNDCLASSEX;2. RegisterClassEx 。 而在ATL中,由CWellcomeWindow之由宏定义的成员函数(member function by macro defined)DECLARE_WND_CLASS(NULL)完成,其由wnd.Create(NULL, 0, appTitle) 调用(例如,在win32.cpp中)。

4.1.1 DECLARE_WND_CLASS(NULL)宏定义

[align=left]/////////////////////////////////////////////////////////////////////////////[/align]
[align=left]// CWndClassInfo - Manages Windows class information[/align]
[align=left] [/align]
[align=left]#define DECLARE_WND_CLASS(WndClassName) /[/align]
[align=left]static ATL::CWndClassInfo& GetWndClassInfo() /[/align]
[align=left]{ /[/align]
[align=left] static ATL::CWndClassInfo wc = /[/align]
[align=left] { /[/align]
[align=left] { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc, /[/align]
[align=left] 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, /[/align]
[align=left] NULL, NULL, IDC_ARROW, TRUE, 0, _T("") /[/align]
[align=left] }; /[/align]
[align=left] return wc; /[/align]
[align=left]}[/align]

CWndClassInfo为ATL内使用WNDCLASSEX结构的结构(C++),看看代码就应该有所了解了,关键在于 4.1.2 CWndClassInfo结构(_ATL_WNDCLASSINFOW)定义 的黑体部分(Bold)。

4.1.2 CWndClassInfo结构(_ATL_WNDCLASSINFOW)定义

[align=left]struct _ATL_WNDCLASSINFOW[/align]
[align=left]{[/align]
[align=left] WNDCLASSEXW m_wc;[/align]
[align=left] LPCWSTR m_lpszOrigName;[/align]
[align=left] WNDPROC pWndProc;[/align]
[align=left] LPCWSTR m_lpszCursorID;[/align]
[align=left] BOOL m_bSystemCursor;[/align]
[align=left] ATOM m_atom;[/align]
[align=left] WCHAR m_szAutoName[5+sizeof(void*)*CHAR_BIT];[/align]
[align=left] ATOM Register(WNDPROC* p)[/align]
[align=left] {[/align]
[align=left] return AtlWinModuleRegisterWndClassInfoW(&_AtlWinModule, &_AtlBaseModule, this, p);[/align]
[align=left] }[/align]
[align=left]};[/align]

4.1.3 ATL::CWindowImpl::Create定义

[align=left]HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,[/align]
[align=left] DWORD dwStyle = 0, DWORD dwExStyle = 0,[/align]
[align=left] _U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)[/align]
[align=left] {[/align]
[align=left] if (T::GetWndClassInfo().m_lpszOrigName == NULL)[/align]
[align=left] T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();[/align]
[align=left] ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);[/align]
[align=left] [/align]
[align=left] dwStyle = T::GetWndStyle(dwStyle);[/align]
[align=left] dwExStyle = T::GetWndExStyle(dwExStyle);[/align]
[align=left] [/align]
[align=left] // set caption[/align]
[align=left] if (szWindowName == NULL)[/align]
[align=left] szWindowName = T::GetWndCaption();[/align]
[align=left] [/align]
[align=left] return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rect, szWindowName,[/align]
[align=left] dwStyle, dwExStyle, MenuOrID, atom, lpCreateParam);[/align]
[align=left] }[/align]

真正完成CreateWindow。
4.2 WndProc在哪?
Main message loop在ATL予以了保留(例如,在win32.cpp中)。

WndProc由宏定义成员函数完成,参看 2.2 添加CWellcomeWindow.h可以看到如下代码:

[align=left] BEGIN_MSG_MAP(CWellcomeWindow)[/align]
[align=left] MESSAGE_HANDLER(WM_CREATE, OnCreate)[/align]
[align=left] MESSAGE_HANDLER(WM_PAINT, OnPaint)[/align]
[align=left] MESSAGE_HANDLER(WM_DESTROY, OnDestroy)[/align]
[align=left] END_MSG_MAP()[/align]

4.2.1 Message-Map

[align=left]#define BEGIN_MSG_MAP(theClass) /[/align]
[align=left]public: /[/align]
[align=left] BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) /[/align]
[align=left] { /[/align]
[align=left] BOOL bHandled = TRUE; /[/align]
[align=left] (hWnd); /[/align]
[align=left] (uMsg); /[/align]
[align=left] (wParam); /[/align]
[align=left] (lParam); /[/align]
[align=left] (lResult); /[/align]
[align=left] (bHandled); /[/align]
[align=left] switch(dwMsgMapID) /[/align]
[align=left] { /[/align]
[align=left] case 0:[/align]
[align=left] [/align]
[align=left]#define END_MSG_MAP() /[/align]
[align=left] break; /[/align]
[align=left] default: /[/align]
[align=left] ATLTRACE(ATL::atlTraceWindowing, 0, _T("Invalid message map ID (%i)/n"), dwMsgMapID); /[/align]
[align=left] ATLASSERT(FALSE); /[/align]
[align=left] break; /[/align]
[align=left] } /[/align]
[align=left] return FALSE; /[/align]
[align=left] }[/align]

你所定义的特定的消息处理将会置于case 0defaul之间,例如 2.2 添加CWellcomeWindow.h将会产生如下代码:

[align=left]BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) [/align]
[align=left] { [/align]
[align=left] BOOL bHandled = TRUE; [/align]
[align=left] (hWnd); [/align]
[align=left] (uMsg); [/align]
[align=left] (wParam); [/align]
[align=left] (lParam); [/align]
[align=left] (lResult); [/align]
[align=left] (bHandled); [/align]
[align=left] switch(dwMsgMapID) [/align]
[align=left] { [/align]
[align=left] case 0:[/align]
[align=left] if(uMsg == msg) [/align]
[align=left] { [/align]
[align=left] bHandled = TRUE; [/align]
[align=left] lResult = OnCreate(uMsg, wParam, lParam, bHandled); [/align]
[align=left] if(bHandled) [/align]
[align=left] return TRUE; [/align]
[align=left] }[/align]
[align=left] ……[/align]
[align=left] break; [/align]
[align=left] default: [/align]
[align=left] break; [/align]
[align=left] } [/align]
[align=left] return FALSE; [/align]
[align=left] }[/align]

5. Tips

对于一些技术点和平台作一定的介绍,以便于后续的学习。
5.1 UNREFERENCED_PARAMETER Macro
主要为消除M$ C++编译器在Level 4 (/W4)产生的C4100 :unreferenced formal parameter警告,但在/TC编译器选项下不可用。

消除C4100警告的还有另外一种常见的Unamed object的写法,如在 2.2 添加CWellcomeWindow.h中OnPaint(UINT /*uMsg*/...) ;这两种为消除C4100警告的写法,并无明显的优劣之分,且都是平台可移植的;但,从标准C++的编码规范来说,笔者更倾向于后者。
在M$ C++ Specification下还有其它的写法,但因其是M$ C++所特有,不便于学习标准C++,故在此不予考虑。
5.2 CXxx : public CYyy<CXxx>
此种声明在C++中是合法的,主要为实现编译时多态(Compile-time Polymophism)。

可参看如下代码:

[align=left]//CXxxx declarations[/align]
[align=left]#pragma once[/align]
[align=left]#include "stdafx.h"[/align]
[align=left] [/align]
[align=left]template <typename T>[/align]
[align=left]class CYyy {[/align]
[align=left]public:[/align]
[align=left] [/align]
[align=left] void Wellcome(const char* s) [/align]
[align=left] {[/align]
[align=left] T* pT = static_cast<T*>(this);[/align]
[align=left] pT->sayHello(s);[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] void sayHello(const char* s)[/align]
[align=left] {[/align]
[align=left] std::cout<<"Hi, "<<s<<std::endl;[/align]
[align=left] }[/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]class CXxx1 : public CYyy<CXxx1> {[/align]
[align=left] [/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]class CXxx2 : public CYyy<CXxx2> {[/align]
[align=left]public:[/align]
[align=left] void sayHello(const char* s) [/align]
[align=left] {[/align]
[align=left] std::cout<<"Wellcome, "<<s<<std::endl;[/align]
[align=left] }[/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]// main entry point[/align]
[align=left]int _tmain(int argc, _TCHAR* argv[])[/align]
[align=left]{[/align]
[align=left] CXxx1 x1;[/align]
[align=left] CXxx2 x2;[/align]
[align=left] [/align]
[align=left] x1.Wellcome("Joe");[/align]
[align=left] x2.Wellcome("JoeM");[/align]
[align=left] [/align]
[align=left] return 0;[/align]
}

以上代码中Cyyy ::Wellcome相当于一个多态函数的一个包装器(wrapper),而所有的秘密就在T* pT = static_cast<T*>(this) 语句;编译时多态在空间开销上至少比运行时多态节省一个vtable指针的空间开销,且因其在编译时就已决定了函数入口点,故具有更高的执行效率。
5.3 throw()
C++ 异常规范(Exception Specifications),用于函数声明之后,通知编译器此函数不会抛出异常;但在ATL中主要目的是使M$ C 的SEH (Structured Exception Handling)在ATL中具有可移植性。

在ATL中经常可以看到这样的代码,如在atlwin.h中Cwindow的声明中:

[align=left]class CWindow[/align]
[align=left]{[/align]
[align=left]public:[/align]
[align=left] static RECT rcDefault;[/align]
[align=left] HWND m_hWnd;[/align]
[align=left] [/align]
[align=left] CWindow(HWND hWnd = NULL) throw() :[/align]
[align=left] m_hWnd(hWnd)[/align]
[align=left] {[/align]
[align=left] }[/align]
...
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: