我知道,可能会有很多朋友对上一章的“Hello, World!”ATL版不以为然,不过不管怎样我还是要说,它几乎仍然拥有了一个ATL GUI程序的所有组成部分:入口、初始化、程序体、卸载……
ATL等同品
在写作这本书的时候,我总是希望我每次都能够能使用让你不太陌生的代码来循序渐进地引导你。考虑再三,对于“Hello, ATL!”的这个程序,我决定先把它的WinMain展现给你:
int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd ) { _Module.Init( NULL, hInstance );
// 创建窗口 CHelloATLWnd wnd; wnd.Create( NULL, CHelloATLWnd::rcDefault, _T("Hello ATL") ); wnd.ShowWindow( nShowCmd ); wnd.UpdateWindow();
// 消息循环 MSG msg; while ( GetMessage( &msg, NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); }
_Module.Term(); return msg.wParam; } |
OK,上一章介绍过的_Module又出现在你的眼前了——不过还是没有什么特别的变化,仍然是那熟悉的Init和Term。而且,正如“山哟还是那座山”一样,消息循环哟也仍然是那个消息循环。当然,你肯定也发现了那寥寥的变化:CHelloATLWnd是什么?在我将它的代码展现给你之前,你可能会做出这样的猜想:
- 这是一个C++类,它对Win32窗口类进行了封装。
- 这个类封装了大多数窗口操作的API函数,诸如CreateWindow、ShowWindow、UpdateWindow。
- 窗口类的注册可能也是在这个C++类中完成的。
好,打住,这就够了。让我们来撩开CHelloATLWnd那貌似神秘的面纱吧,赶紧着。
class CHelloATLWnd : public CWindowImpl< CHelloATLWnd, CWindow, CWinTraits< WS_OVERLAPPEDWINDOW > > { public: CHelloATLWnd() { CWndClassInfo& wci = GetWndClassInfo(); wci.m_bSystemCursor = TRUE; wci.m_lpszCursorID = IDC_ARROW; wci.m_wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH ); wci.m_wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); } public: DECLARE_WND_CLASS( _T("HelloATL") ) public: BEGIN_MSG_MAP( CHelloATLWnd ) MESSAGE_HANDLER( WM_DESTROY, OnDestroy ) MESSAGE_HANDLER( WM_PAINT, OnPaint ) END_MSG_MAP() public: LRESULT OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& hHandled ) { ::PostQuitMessage( 0 ); return 0; } LRESULT OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& hHandled ) { HDC hdc; PAINTSTRUCT ps;
hdc = BeginPaint( &ps ); DrawText( hdc, _T("Hello, ATL!"), -1, &ps.rcPaint, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); EndPaint( &ps ); return 0; } }; |
猜想,还是猜想!
请允许我在本章中不为你解释这个类的任何具体细节,取而代之的是继续的猜想。因为,这个类中需要解释的东西太多了,以至于我必须为它单独开辟一章。
- 窗口类的注册是由这个C++类的构造函数与DECLARE_WND_CLASS宏一起完成的。
- 对于BEGIN_MSG_MAP与END_MSG_MAP这一部分,想必使用过MFC的朋友们应该更容易理解。是的,这一对宏可以算作ATL的消息映射,在其中由MESSAGE_HANDLER作为消息分流器,将各种窗口消息分配给各个处理函数。
- 创建窗口时指定的样式貌似和模板参数CWinTraits有关。
当然,除了这些猜想之外,你可能还会同时存在以下疑问:
- CWindowImpl、CWindow、CWinTraits究竟是什么?
- 窗口类是在何时注册的?
- 消息分流器是如何实现的?
也许你还会有更多的疑问,那么就让我一并将它们留到下一章再解决吧。如果你实在等不及的话,atlwin.h的代码也会告诉你一切的。
补叙CComModule
由于这本书主要针对的是ATL 3.0/Visual C++ 6.0,所以我疏忽了对CComModule的研究。在此感谢老李老刀兄提出的一点,就是CComModule在ATL 7.0中已经不建议使用了。于是我将MSDN中的相关章节摘抄下来,权作借花献佛之用。
CComModule 替换类
ATL 的早期版本使用 CComModule。在 ATL 7.0 中,CComModule 功能被若干个类所取代:
- CAtlBaseModule 包含大多数使用 ATL 的应用程序所需的信息。包含模块和资源实例的 HINSTANCE。
- CAtlComModule 包含 ATL 中的 COM 类所需的信息。
- CAtlWinModule 包含 ATL 中的窗口化类所需的信息。
- CAtlDebugInterfacesModule 包含接口调试支持。
- CAtlModule 下列 CAtlModule 派生的类被自定义为包含特定应用程序类型中所需的信息。这些类中的大部分成员都可以被重写:
CAtlDllModuleT 在 DLL 应用程序中使用。为标准导出提供代码。
CAtlExeModuleT 在 EXE 应用程序中使用。提供 EXE 中所需的代码。
CAtlServiceModuleT 为创建 Windows NT 和 Windows 2000 服务提供支持。
CComModule 仍然可用以便向后兼容。
分布 CComModule 功能的原因
由于以下原因,CComModule 的功能分布到了几个新类中:
- 使 CComModule 中的功能呈粒状分割。
对 COM、窗口化、接口调试和应用程序特定的(DLL 或 EXE)功能的支持现在在不同的类中。
- 自动为这些模块的每一个声明全局实例。
所需模块类的全局实例链接到项目中。
- 消除了调用 Init 和 Term 方法的必要性。
Init 和 Term 方法已移动到模块类的构造函数和析构函数中;不再需要调用 Init 和 Term。
不过,出于代码的兼容性以及WTL的内容考虑,本系列后续文章仍然将使用ATL 3.0中的CComModule。
点这里下载本章配套代码
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1664812