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 variable
34
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 used
10 ::DefWindowProc(NULL, 0, 0, 0L);
11 // add flags to support other controls
12 AtlInitCommonControls(ICC_BAR_CLASSES);
13 //初始化Module
14 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 return0;
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应该不是难事。
WTL的核心机制的更多相关文章
- JAVA基础之两种核心机制
突然之间需要学习Java,学校里学的东西早就忘记了,得用最短的时间把Java知识理顺,重点还是J2EE,毕竟所有的ava项目中95%都是J2EE,还是先从基础的J2SE学起吧....... 首先是了解 ...
- Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转
原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098 我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用 ...
- MFC六大核心机制之二:运行时类型识别(RTTI)
上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属 ...
- MFC六大核心机制之一:MFC程序的初始化
很多做软件开发的人都有一种对事情刨根问底的精神,例如我们一直在用的MFC,很方便,不用学太多原理性的知识就可以做出各种窗口程序,但喜欢钻研的朋友肯定想知道,到底微软帮我们做了些什么,让我们在它的框架下 ...
- 第七章 探秘Qt的核心机制-信号与槽
第七章 探秘Qt的核心机制-信号与槽 注:要想使用Qt的核心机制信号与槽,就必须在类的私有数据区声明Q_OBJECT宏,然后会有moc编译器负责读取这个宏进行代码转化,从而使Qt这个特有的机制得到使用 ...
- java核心机制
Java中有两种核心机制:Java虚拟机(Java Virtual Machine).垃圾收集机制(Garbage collection) 一.核心机制之Java虚拟机 ① Java虚拟机可以理解成一 ...
- Qt核心机制与原理
转: https://blog.csdn.net/light_in_dark/article/details/64125085 ★了解Qt和C++的关系 ★掌握Qt的信号/槽机制的原理和使用方法 ★ ...
- 前端工程化系列[06]-Yeoman脚手架核心机制
在前端工程化系列[05] Yeoman脚手架使用入门这边文章中,对Yeoman的使用做了简单的入门介绍,这篇文章我们将接着探讨Yeoman这个脚手架工具内部的核心机制,主要包括以下内容 ❏ Yeoma ...
- Flask核心机制--上下文源码剖析
一.前言 了解过flask的python开发者想必都知道flask中核心机制莫过于上下文管理,当然学习flask如果不了解其中的处理流程,可能在很多问题上不能得到解决,当然我在写本篇文章之前也看到了很 ...
随机推荐
- tornado异步请求非阻塞
前言也许有同学很迷惑:tornado不是标榜异步非阻塞解决10K问题的嘛?但是我却发现不是torando不好,而是你用错了 比如最近发现一个事情:某网 前言 也许有同学很迷惑:tornado不是标榜异 ...
- Java使用java命令运行程序出现:找不到主类错误
这是配置环境的问题. 在classpath里面添加 .; 即:点+分号 为什么呢,点代表当前目录.
- 使用HttpURLConnection向服务器发送post和get请求
一.使用HttpURLConnection向服务器发送get请求 1.向服务器发送get请求 @Test publicvoid sendSms() throws Exception{ String m ...
- 【Xamarin挖墙脚系列:对设备/模拟器的查看调试监听】
原文:[Xamarin挖墙脚系列:对设备/模拟器的查看调试监听] 有时候我们需要查看模拟器中的文件,比如进行了文件IO操作,sqlite数据库的操作等.我们想查看内容,这时候,如何将内容导出来?由于A ...
- 转:三十一、Java图形化界面设计——布局管理器之GridLayout(网格布局)
http://blog.csdn.net/liujun13579/article/details/7772491 网格布局特点: l 使容器中的各组件呈M行×N列的网格状分布. l 网格每列宽度相 ...
- bzoj1237
假如不存在相等的两个数不能配对,那很容易贪心得到,A中rank 1匹配B中rank 1 A中rank2 匹配B中rank 2…… 有了相等不能匹配这个条件,那么A中rank i可能和rank i,i- ...
- 【数据结构】之二叉树的java实现
转自:http://blog.csdn.net/wuwenxiang91322/article/details/12231657 二叉树的定义: 二叉树是树形结构的一个重要类型.许多实际问题抽象出来的 ...
- ARM学习笔记8——通用寄存器和存储器内容交换指令和软中断指令
交换指令将一个存储单元内容与制定的寄存器内容相交换,交换指令为进程间同步提供了一种方便的解决途径.该指令产生一堆原子Load/Store操作,该操作发生在一个连续的总线操作中,在操作期间阻止其他任何指 ...
- javascript 和jqurry详解
javascript写的图表库,收费 highcharts jqurry有两个图标函数不收费,好用 Flot.PlotKit与MochiKit 官网下载 http://www.flotcharts.o ...
- .net常見面試題(四)
1. .Net.C#.VisualStudio之间的关系是什么? .Net一般指的是.Net Framework,提供了基础的.Net类,这些类可以被任何一种.Net编程语言调用,.Net Frame ...