zoukankan      html  css  js  c++  java
  • 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! "));
    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应该不是难事。

  • 相关阅读:
    Android 的 ramdisk.img、system.img、userdata.img 作用说明,以及UBoot 系统启动过程
    Android启动过程以及各个镜像的关系
    程序员如何利用空余时间挣零花钱?
    hcharts实现堆叠柱形图
    [慕课笔记] node+mongodb建站攻略
    【每周一图】蜂鸟
    [慕课笔记]Node入口文件分析和目录初始化
    [慕课笔记] node+mongodb建站攻略
    hcharts实现堆叠柱形图
    程序员常用的六大技术博客类
  • 原文地址:https://www.cnblogs.com/JczmDeveloper/p/3480366.html
Copyright © 2011-2022 走看看