WTL 核心机制

空扰寡人 提交于 2020-02-05 15:08:03

最近闲了一段时间,学了学WIN32的界面编程,由于对API有那么一点基础,所以想挑个轻量级的界面库学习,以便在较短时间内学得深入些,so,就选择了WTL。并在此记录自己的学习成果。

WTL背景介绍

WTL是微软ATL开发组成员Nenad Stefanovic先生在ATL Windowing机制上发展起来的一整套GUI框架,运用template技术组织和创建GUI对象,构筑了精致的面向对象框架(在这里object oriented与template达成了精致的融合)。虽然没有获得微软的官方支持,虽然其使用者人数很少,但是确实是“用过的都说好”,有位微软MVP人士甚至说,这是微软有史以来推出的最优秀的一个framework。真是一个有趣的讽刺,最好的东西居然不被官方支持。有关于WTL的流言不少,比如这东西原本是微软内部专用,只是因为不小心才被泄漏出来等等,这更加剧它的神秘色彩

WTL安装

从WTL主页(http://wtl.sourceforge.net/)上可以下载到最新的WTL,解压缩之后运行根据你当前安装的VC版本选择不同的setup.js安装即可。注意,最新的WTL安装程序已经没有VC6的安装向导了,用VC6的童鞋们可以下载WTL7.1或者尝试使用这种方法(http://hi.baidu.com/yykbrother/blog/item/cb7079caeefc0d8ec91768c9.html)。

WTL使用

这个就不用细说了,按照向导创建项目,然后include头文件就行了。

WTL 核心机制

先来熟悉一下基于API的Win32应用程序的机制。

先来看下面一段例程:

 1 int APIENTRY WinMain(HINSTANCE hInstance, 2                      HINSTANCE hPrevInstance, 3                      LPSTR     lpCmdLine, 4                      int       nCmdShow) 5 { 6      //定义一个消息和一个加速键表 7      MSG msg; 8     HACCEL hAccelTable; 9 10     //加载存在Resource文件里的字符串11      LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);12     LoadString(hInstance, IDC_WIN32TEST, szWindowClass, MAX_LOADSTRING);13     14     //定义个窗体类15      WNDCLASSEX wcex;    16     wcex.cbSize = sizeof(WNDCLASSEX);     17     wcex.style            = CS_HREDRAW | CS_VREDRAW;18     wcex.lpfnWndProc    = (WNDPROC)WndProc;19     wcex.cbClsExtra        = 0;20     wcex.cbWndExtra        = 0;21     wcex.hInstance        = hInstance;22     wcex.hIcon            = LoadIcon(hInstance, (LPCTSTR)IDI_WIN32TEST);23     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);24     wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);25     wcex.lpszMenuName    = (LPCSTR)IDC_WIN32TEST;26     wcex.lpszClassName    = szWindowClass;27     wcex.hIconSm        = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);28     //注册窗体类29      RegisterClassEx(&wcex);30 31     //创建主窗体32      HWND hWnd;    33     hInst = hInstance; // Store instance handle in our global variable34      35     hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,36         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);37     38     if (!hWnd)39     {40         return FALSE;41     }42     //显示窗体43      ShowWindow(hWnd, nCmdShow);44     UpdateWindow(hWnd);    45     //加载加速键表46      hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WIN32TEST);47 48     //进入主消息循环49      while (GetMessage(&msg, NULL, 0, 0)) 50     {51         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 52         {53             TranslateMessage(&msg);54             DispatchMessage(&msg);55         }56     }57 58     return msg.wParam;59 }

首先要为要显示的窗体注册一个WNDCLASS,在WNDCLASS实例中可以设置classname、style、instance、WndProc、ICON等,然后就可以以这个窗口类名创建一个Window(调用CreateWindow)并显示,最后程序就进入主消息循环,分别调用GetMessage从消息队列中取出消息,TranslateMessage将消息转化为字符消息,DispatchMessage将消息分发到具体的窗体。

再来看WTL的典型例程:

 1 //全局Module对象 2  CAppModule _Module;     3  int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) 4 { 5    //初始化COM 6     HRESULT hRes = ::CoInitialize(NULL);   7     ATLASSERT(SUCCEEDED(hRes)); 8  9     // this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used10     ::DefWindowProc(NULL, 0, 0, 0L);11     // add flags to support other controls12     AtlInitCommonControls(ICC_BAR_CLASSES);    13     //初始化Module14     hRes = _Module.Init(NULL, hInstance);    15     ATLASSERT(SUCCEEDED(hRes));16     17     //定义一个消息循环18     CMessageLoop theLoop; 19   //将此线程的消息循环加入到Module中20     _Module.AddMessageLoop(&theLoop); 21 22     //定义主窗体23     CCusWindow wndMain; 24     //创建主窗体,CCusWindow类内部必须调用DECLARE_WND_CLASS或相关宏注册窗体类,并在Create时注册窗体类25     if(wndMain.Create(NULL,CWindow::rcDefault,_T("CCusWindow")) == NULL)26     {27         ATLTRACE(_T("Main window creation failed!\n"));28         return 0;29     }30     //显示窗体31     wndMain.ShowWindow(nCmdShow);32     //进入消息循环33     int nRet = theLoop.Run();34     //线程退出,一些清理工作35   _Module.RemoveMessageLoop();36 37     _Module.Term();38 39     ::CoUninitialize();40 41     return nRet;42 }

下面我们对WTL的做法做详细分解

WTL对这整个过程进行了抽象,其中涉及到的主要类有CAppModule、CMessageLoop、CWindowImpl等

CAppModule封装了初始化模块,并维持了一个消息循环的map,具体定义为ATL::CSimpleMap<DWORD, CMessageLoop*>* m_pMsgLoopMap;其中DWORD为线程ID,也就是说每个线程对应一个CMessageLoop也就对应一个消息循环。

CMessageLoop是对消息循环的封装。其中主要的方法为Run(),这个方法运行后,当前线程就进入了主消息循环,直到线程退出。当然这里边有很多重要的内容,避免复杂性,这里先不说了。

CWindowImpl是WTL对窗体的封装,大多数窗体都要继承他。该类内部有一个DECLARE_WND_CLASS 或者DECLARE_WND_CLASS_EX宏,这个宏会实现GetWndClassInfo 函数,此函数创建一个static 类型的CWndClassInfo(对WNDCLASS的封装)对象,并且将WNDPROC设置为StartWindowProc,在调用 CWindowImpl::Create 时,会注册此窗体类并创建一个新窗口。此窗体在接收到第一个消息后会自动调用StartWindowProc函数进行消息处理,在这个函数内部进行了thunk的初始化并通过调用SetWindowLong将WNDPROC设为了WindowProc,这个才是真正的消息处理函数。下面是DECLARE_WND_CLASS_EX的宏定义

 1 #define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \ 2 static CWndClassInfo& GetWndClassInfo() \ 3 { \ 4     static CWndClassInfo wc = \ 5     { \ 6         { style, StartWindowProc, \ 7           0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ 8         NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \ 9     }; \10     return wc; \11 }

CWindowImpl::Create的定义

 1 template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits> 2 class ATL_NO_VTABLE CWindowImpl : public CWindowImplBaseT< TBase, TWinTraits > 3 { 4 public: 5     DECLARE_WND_CLASS(NULL) 6  7     HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, 8             DWORD dwStyle = 0, DWORD dwExStyle = 0, 9             UINT nID = 0, LPVOID lpCreateParam = NULL)10     {11         if (T::GetWndClassInfo().m_lpszOrigName == NULL)12             T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();13         ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);14 15         dwStyle = T::GetWndStyle(dwStyle);16         dwExStyle = T::GetWndExStyle(dwExStyle);17 18         return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName,19             dwStyle, dwExStyle, nID, atom, lpCreateParam);20     }21 };

可以看出WTL只是对WIN32 API做了封装,具体的调用过程没有任何改变,因此如果有一些WIN32 API编程的底子,直接看源代码学习WTL应该不是难事。

--THE END

下一篇会详细介绍WTL的消息机制。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!