




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、WTL起步 - 玩转图形界面Microsoft2008WTL起步玩转图形界面吴助建目录序言3第一部分 基础篇5第一章 WTL的基础-ATL5第二章 WTL之路11第三章 命令条14第四章 带视图的框架窗口15第五章 使用MRU17第六章 创建多线程SDI应用程序19第七章 创建MDI应用程序23第八章 分隔窗口26第九章 GDI的封装31第十章 CString及其它34第十一章 动态数据交换(DDX)的WTL支持35第十二章 WTL向导37第十三章 WTL例程39第二部分 提高篇40第一章 位图视图的例程40第二章 上下文菜单41第三章 滚动视图43第四章 通用对话框45第五章 控件封装47第
2、六章 打印与打印预览52第七章 属性页56第八章 消息过滤59第九章 空闲处理62第十章 UI更新63第十一章 消息分解65第十二章 WTL的未来67序言WTL是2000年1月随Windows的平台SDK始发的。起初是ATL项目组写的一个基于ATL的,封装了相关win32窗口API的例程。自ATL2.0开始,ATL就已经有一些简单的相关窗口函数的封装类,例如:CWindow,CWindowImpl和CDialogImpl。然而,当我们比较MFC的界面相关部分的功能时,ATL对界面编程的支持简直就是一个玩笑。甚至到了ATL3.0,ATL仍然没有对诸如MDI,命令条,DDX,打印,GDI等流行功能
3、的支持。最被人喜爱的MFC的CString也没被支持进来。没有对这些功能的支持,ATL很难满足拥有压倒性数量的使用MFC的编程人员的需求。WTL就是ATL项目组认为ATL风格的窗口编程模型应该有的样子。表1列出了WTL与MFC在界面编程相关功能方面的比较。特性MFCWTL依赖库支持不支持 (构建ATL之上)应用向导支持支持支持类向导支持支持不支持(第三方插件VisualFC支持)微软的公开支持支持不支持(微软内部的志愿者支持)支持OLE文档支持不支持支持视图支持支持支持文档支持不支持基本win32/通用控件封装支持支持高级通用控件封装(平坦滚动条、IP地址控件、页面控件等)不支持支持命令条支持
4、(包含bitmapped context menus)不支持 (MFC提供对话条)支持CString支持支持GDI封装支持支持辅助类(CRect, CPoint, 等)支持支持Wizards属性页/向导支持支持SDI, MDI支持支持支持多线程SDI支持不支持支持MRU支持支持支持可停靠窗口/条支持不支持分隔窗口支持支持DDX支持支持 (不是MFC的扩展)打印/打印预览支持支持滚动视图支持支持客户自画封装不支持支持消息/命令路由支持支持通用对话框支持支持HTML视图支持支持简单实例应用不支持不支持UI更新支持支持基于模板不支持支持带工具条,状态条和菜单的不做任何情事的SDI应用静态链接时大小超
5、过228KB(+MSVCRT.DLL (288KB)24k (带 /OPT:NOWIN98)(+ MSVCRT.DLL如果使用 CString)带工具条,状态条和菜单的不做任何情事的SDI应用动态链接时大小24KB +MFC42.DLL (972KB) +MSVCRT.DLL (288KB)N/A对运行时库的依赖 CRT (+ MFC42.DLL, 如果动态链接)None (如果使用需要CStringCRT)表1 WTL与MFC的比较当然,WTL不可能(也不愿意)做所有MFC都能做的事儿。MFC支持经典的OLE,文档/视图框架和可停靠窗口,而WTL没有。而且还缺乏微软的“官方”支持。然而,来自
6、于前ATL项目组成员,以及活跃在ATL开发社区的“非官方”支持,可以减轻您对支持方面的担心。为何ATL开发社区喜欢WTL?因为这四点:1> WTL是基于C+模板技术的;2> 应用程序的最小编译代码小于24K;3> 没有任何多如的动态链接库依赖(如果您用CString,会链接CRT);4> 拥有ATL一样的灵活和小巧。此外,WTL和MFC的界面编程模型非常接近,还包括了从它移植过来的CString。在我们这本分两部分的书里,我将揭开WTL神秘的面纱。在第一部分里,我们讨论WTL框架窗口的实现结构。我们将解释如何编写基于WTL的SDI,MDI和多线程SDI,以及IE浏览器样
7、式的应用程序。进而,我们讨论WTL的辅助类,包括对DDX的封装。最后,我们看一下WTL的AppWizard和本书附带的例程。在本书的第二部分,我们讨论WTL命令条的实现结构,以及对Windows通用控件的封装和一些自定义的用户界面小部件。我们还将进一步讨论WTL的Windows消息路由结构,包括消息分解,过滤和空闲处理。我们的WTL之旅没有结束,直到我们讨论完通用对话框,属性页/属性表,打印支持,以及滚动窗口。所有的这一切我们计划放在第二部分。在我们告诉你如何用WTL开发程序之前,让我们先复习一下怎样用纯ATL(即不包含WTL)来开发应用程序。第一部分 基础篇第一章 WTL的基础-ATLATL
8、提供了一套编写Windows用户界面的C+模板类。ATL本来的目的是用来支持COM组件和OLE属性页框架的。这套C+模板类当然成为WTL的基础。这套类提供了对所有基本的Windows窗口函数的封装,包括窗口/对话框的创建和管理,窗口函数,消息路由,窗口子类化,超类化和消息链。图1展示了ATL这套C+模板类的层次。图1:ATL界面相关类的层次如果想直接用ATL来创建一个窗口或者对话框,你需要从CWindowImpl或者CDialogImpl派生类。给你一个具体的例子。图2提供了一个简单的用前面讲到的这套C+类来开发SDI程序的示意图。图2 简单SDI应用程序这个例子的应用程序有一个SDI的框架窗
9、口,这个窗口有一个菜单条,状态条和客户区。它也提供了一个对话框用来演示在ATL里怎样使用对话框。我们就从vc6创建一个简单win32工程以及添加一些必要的启动ATL的代码来开始这个例子。图3展示了这个例子的主要源文件的源代码。stdafx.h :#if !defined(AFX_STDAFX_H_DE06DA2F_25B6_41BA_9B20_A17362C38C8C_INCLUDED_)#define AFX_STDAFX_H_DE06DA2F_25B6_41BA_9B20_A17362C38C8C_INCLUDED_#if _MSC_VER > 1000#pragma once#en
10、dif / _MSC_VER > 1000#define STRICT#ifndef _WIN32_WINNT#define _WIN32_WINNT 0x0400#endif#define _ATL_APARTMENT_THREADED#include <atlbase.h>/ 如果想重载某些方法,你可以从CComModule类派生一个类/ 但是不得改变_Module的名字extern CComModule _Module;#include <atlwin.h>/AFX_INSERT_LOCATION/ Microsoft Visual C+ 将即时从此行之前插
11、入附加声明。#endif / !defined(AFX_STDAFX_H_DE06DA2F_25B6_41BA_9B20_A17362C38C8C_INCLUDED)MainFrame.H#pragma once#ifndef _MAINFRAME_H_#define _MAINFRAME_H_#include "commctrl.H"class CMainFrame : public CWindowImpl<CMainFrame,CWindow, CWinTraits<WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN , WS_EX_AP
12、PWINDOW | WS_EX_WINDOWEDGE> >public:CMainFrame():m_hWndStatusBar(NULL),m_hBmp(NULL) m_hBmp =LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_ATLWINDOWING);CMainFrame() if(m_hBmp) :DeleteObject(m_hBmp); m_hBmp = NULL;BEGIN_MSG_MAP(CMainFrame)MESSAGE_HANDLER(WM_PAINT, OnPaint)MESSAG
13、E_HANDLER(WM_CREATE, OnCreate)MESSAGE_HANDLER(WM_SIZE, OnSize)MESSAGE_HANDLER(WM_CLOSE, OnClose)COMMAND_ID_HANDLER(ID_FILE_EXIT, OnFileExit)COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAbout)END_MSG_MAP()void OnFinalMessage(HWND /*hWnd*/) LRESULT OnCreate(UINT, WPARAM wParam, LPARAM lParam, BOOL& bHandled
14、) DefWindowProc();m_hWndStatusBar = :CreateStatusWindow(WS_CHILD | WS_VISIBLE |WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, _T("Ready"), m_hWnd, 1);return 0L;LRESULT OnSize(UINT, WPARAM wParam, LPARAM lParam, BOOL& bHandled) DefWindowProc();:SendMessage(m_hWndStatusBar, WM_SIZE,
15、 0, 0);return 0L;LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&) PAINTSTRUCT ps; HDC hdc = BeginPaint(&ps); RECT rect; GetClientRect(&rect); / 位图HDC hDCMem = :CreateCompatibleDC(hdc);HBITMAP hBmpOld = (HBITMAP):SelectObject(hDCMem,m_hBmp);BITMAP bmp;:GetObject(m_hBmp, sizeof(BITMAP), &b
16、mp);SIZE size = bmp.bmWidth,bmp.bmHeight ;:BitBlt(hdc, rect.left, rect.top, (size.cx), (size.cy), hDCMem, 0,0,SRCCOPY);/ 清除:SelectObject(hDCMem,hBmpOld);:DeleteDC(hDCMem);hDCMem = NULL; EndPaint(&ps); return 0;LRESULT OnClose(UINT,WPARAM,LPARAM, BOOL&) DestroyWindow();PostQuitMessage(0);retu
17、rn 0L;LRESULT OnFileExit(WORD,WORD wID, HWND,BOOL&) SendMessage(WM_CLOSE);return 0L;LRESULT OnAbout(WORD, WORD wID, HWND, BOOL&) CAboutDialog dlg;dlg.DoModal();return 0L;private:struct CAboutDialog : public CDialogImpl<CAboutDialog> enum IDD = IDD_ABOUT ;BEGIN_MSG_MAP(CAboutDialog)COMM
18、AND_ID_HANDLER(IDOK, OnClose)END_MSG_MAP()LRESULT OnClose(WORD, WORD wID, HWND, BOOL&) EndDialog(wID);return 0L;HWNDm_hWndStatusBar;HBITMAPm_hBmp;#endifAtlHelloWindowing.Cpp#include "stdafx.h"#include "resource.h"#include "MainFrame.H"CComModule _Module;extern "
19、;C" int WINAPI _tWinMain(HINSTANCE hInstance,HINSTANCE, LPTSTR lpCmdLine, int nShowCmd) lpCmdLine = GetCommandLine(); / 该行_ATL_MIN_CRT 所必要的_Module.Init(0, hInstance,NULL);/ 加载通用控件INITCOMMONCONTROLSEX iccx;iccx.dwSize = sizeof(iccx);iccx.dwICC = ICC_WIN95_CLASSES |ICC_BAR_CLASSES ;:InitCommonCon
20、trolsEx(&iccx);HMENU hMenu = LoadMenu(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDR_MAINFRAME);CMainFrame wndFrame;wndFrame.GetWndClassInfo().m_wc.hIcon = :LoadIcon(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDI_FORM);wndFrame.GetWndClassInfo().m_wc.style = 0;/CS_HREDRAW|CS_VREDRAW;wndFra
21、me.Create(GetDesktopWindow(), CWindow:rcDefault, _T("ATL Windowing is cool"), 0, 0, (UINT)hMenu);wndFrame.ShowWindow(nShowCmd);wndFrame.UpdateWindow();MSG msg;while (GetMessage(&msg, 0, 0, 0) TranslateMessage(&msg); DispatchMessage(&msg);_Module.Term();return 0;在MainFrame.h里,CM
22、ainFrame有两个数据成员:状态条的HWND和HBITMAP。CMainFrame通过通过调用 comctl32.dll的CreateStatusWindow()函数,在WM_CREATRE消息处理函数里把状态条创建成一个子窗口,而且通过发送WM_SIZE消息,调整状态条的大小。WM_PAINT消息的处理函数使用上述的HBITMAP演示了一点ATL里的 GDI编程。由于ATL对GDI没有提供包装类,所以这里的GDI编程是直接调用Win32的API来完成的。然而 MESSAGE_HANDLER宏需要你做你自己的消息分解,ATL通过一系列的宏为你分解了WM_ COMMAND和WM_NOTIFY
23、消息。MainFrame.h展示了如何使用COMMAND_ID_HANDLER宏,CMainFrame用这个宏来处理它的菜单命令。最后,CAboutDialog是一个对话框类,继承自CDialogImpl类。OnAbout命令处理函数调用了DoModal用来显示这个对话框。HelloAtlWindowing.cpp里有个_tWinMain,这是ATL程序的入口函数,它创建了一个CMainFrame的实例,而后调用该实例的Create()函数,以及ShowWindow()和UpdateWindow()这些成员函数,这些成员函数很明显是与他们名字相似的win32 API的封装。最后,因为这个程序从
24、根本上来说,是一个Win32窗口程序,我们必须从窗口的消息队列里通过GetMessage、DispatchMessage循环来抽出消息。如果你熟悉win32 API编程的话,你会注意到这个程序缺少RegisterClass()的调用和处理窗口消息的窗口过程,其他的部分你都能理解。如果你熟悉MFC,你可能奇怪ATL 没有提供那些最基本的支持,比如创建状态条和菜单。好吧,程序既然能运行,事实证明ATL肯定支持了。不过ATL并没有做足这方面的支持。我们不要忘记ATL的主要目的(ATL主要目的是支持COM编程)。ATL允许你,但是并没有直接支持MDI,多线程SDI,或IE浏览器样式的应用程序,也没有封
25、装通用控件,DDX,和GDI相关函数。如果你对这些感兴趣,那么我们就进入WTL的世界。第二章 WTL之路 WTL类使得我们更加容易地创建SDI框架窗口成为可能,这个类就是CFrameWindowImpl。图3 WTL的SDI窗口层次关系 类CFrameWindowImpl从类CFrameWindowImplBase派生,因此继承了标准应用程序框架窗口的所有功能。下面列出了一个WTL创建的框架窗口提供和支持的特性:1) 集合了工具条,菜单条,状态条和Rebar条;2) 基本视图处理,包括视图与框架同步大小,Rebar带维护(包括添加或调整带的大小);3) 命令条菜单;4) 键盘快捷键;5) 工具
26、条按钮的工具提示;6) 在状态条显示帮助字符串;7) 显示框架图标。为了创建一个SDI应用,步骤如下:1) 从类CFrameWindowImpl派生你的框架类;2) 添加WTL的宏DECLARE_FRAME_WND_CLASS,指定工具条和菜单的资源ID;3) 添加消息映射和消息响应处理,需要包含链入框架基类的链路。例子:class CMainFrame : public CFrameWindowImpl<CMainFrame> public: DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME) BEGIN_MSG_MAP(CMainFrame
27、) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_CREATE, OnCreate) COMMAND_ID_HANDLER(ID_FILE_EXIT, OnFileExit) COMMAND_ID_HANDLER(ID_HELP_ABOUT, OnAbout) CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>) END_MSG_MAP() LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&) CreateSimpleToolBar(); /
28、 创建工具条并设置为CFrameWindowImplBase:m_hWndToolBar成员 CreateSimpleStatusBar(); / 并创建状态条 return 0; LRESULT OnFileExit(WORD,WORD wID, HWND,BOOL&) SendMessage(WM_CLOSE); / 框架知道PostQuitMessage return 0L; ;宏DECLARE_FRAME_WND_CLASS为框架设置通用资源ID。相同资源ID可以用在字符串表中用来作为框架标题,菜单资源,快捷键表,图标和工具条资源等。如果WTL在创建框架窗口时,用通用资源ID找
29、到了资源,就自动加载。唯一的例外是工具条资源,你需要使用成员函数Create SimpleToolBar()来手工加载。状态条不需要通用资源。在消息映射中,使用宏CHAIN_MSG_MAP来路由消息给类CFrameWindowImpl,小心处理像WM_SIZE(重置工具条和状态条的大小)和WM_DESTROY(调用 PostQuitMessage)之类的消息。为了支持WTL的功能,你需要在stdafx.h中包含atlapp.h和atlframe.h:#define WIN32_LEAN_AND_MEAN#include <atlbase.h>#include <atlapp.
30、h>extern CAppModule _Module;#include <atlwin.h>#include <atlframe.h> 头文件atlapp.h定义了CAppModule结构,它是从标准ATL的CComModule类派生,并添加有消息循环的变量。头文件atlframe.h定义CFrameWindowImpl类。为了在我们WTL世界中创建SDI窗口,你需要实例化CMainFrame对象,并在winMain()调用基类的成员函数Create Ex()。CAppModule _Module;int APIENTRY WinMain() :InitComm
31、onControls(); _Module.Init(NULL, hInstance); CMainFrame wndMain; wndMain.CreateEx(); wndMain.ShowWindow(nCmdShow); wndMain.UpdateWindow(); CMessageLoop theLoop; _Module.AddMessageLoop(&theLoop); int nRet = theLoop.Run(); _Module.RemoveMessageLoop(); _Module.Term(); return nRet; CreateEx()成员函数调用基
32、类的CWindowImpl:Create()成员函数,并使用通用资源ID来加载资源。CMessageLoop对象代替我们需要的手工消息队列。ATL允许每个线程有一个消息队列,这就是多线程SDI的实现。当我们学习WTL的消息路由框架时,我们将第二部分分析CMessage Loop类和CAppModule类的细节。 就这样,我们的SDI应用看起来就如图4所示:图4 使用WTL创建的SDI应用我们设法简化了我们的代码,并添加了一个新的特性:工具条。当然,工具条和菜单条是老的风格。用户更喜欢命令条,就像他们在IE和MS Office中所看到的那样。第三章 命令条 命令条是一种看起来像Windows菜单
33、的工具条,并拥有位图的菜单项。从无到有写命令条是很痛苦的。如果你是一员MFC程序员,Paul DiLascia在1998年1月就已经那么做了,MSJ(给你应用程序添加看起来像酷菜单按钮的新的接口)。同样,如果你是一员WTL程序员,仅限于在你的WM_ CREAT处理函数中使用WTL的CCommandBarCtrl类。LRESULT CMainFrame:OnCreate(UINT, WPARAM, LPARAM, BOOL&) / m_CmdBar是CCommandBarCtrl类型,在AtlCtrlw.h中定义 HWND hWndCmdBar = m_CmdBar.Create(m_h
34、Wnd, rcDefault, 0, ATL_SIMPLE_CMDBAR_PANE_STYLE); m_CmdBar.AttachMenu(GetMenu(); / 当命令条代替当前的菜单 m_CmdBar.LoadImages(IDR_MAINFRAME); SetMenu(NULL); / 首先创建简单工具条,设置m_hWndToolBar成员变量 HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME,FALSE,ATL_SIMPLE_TOOLBAR_PANE_STYLE); CreateSimpleReBar(A
35、TL_SIMPLE_REBAR_NOBORDER_STYLE); AddSimpleReBarBand(hWndCmdBar); / 添加m_hWndCmdBar作为Rebar条的一条带 AddSimpleReBarBand(hWndToolBar, NULL, TRUE); / 添加m_hWndToolBar作为Rebar条的另一条带 CreateSimpleStatusBar(); / 创建状态条 return 0; 类CCommandBarCtrl是WTL封装命令条功能和特性的类,类CMainFrame中包含了该类的成员。在上述WM_CREATE处理函数的程序片段中,我们首先通过调用CC
36、ommandBarCtrl: Create()创建命令条,把主框架作为父窗口参数传递。然后,我们通过调用CCommandBarCtrl: AttachMenu()来attach我们的菜单资源,再调用CCommandBarCtrl:LoadImages()来传递工具条资源。命令条使用工具条位图,并把他们映射到菜单项的命令ID响应中。因为命令条管理酷菜单,我们需要通过调用SetMenu(NULL)来剔除原来缺省的应用程序菜单。然后,我们分别地通过调用CreateSimpleToolBarCtrl()和CreateSimpleRebar()来创建工具条控件和一个Rebar控件,传递工具条资源作为参数
37、。最后,我们通过调用CFrameWindowImplBase:Add SimpleRebarBand()添加命令条和工具条作为Rebar控件的2条带。图4显示带命令条的SDI的应用程序。同时也显示了程序片段中UI元素的映射关系。图4 带命令条的SDI应用程序第四章 带视图的框架窗口就MFC程序员的通常习惯而言,框架窗口的客户区是作为独立的子窗口而存在的,被称为视图。框架窗口负责窗口的修饰,比如菜单条和工具条;而视图仅仅被用来呈现信息,而这些信息是运行应用程序的重要地方。当包含分隔窗口或MDI时,这一点特别重要,这将在后面讲到。视图可以是包含任何窗口句柄HWND的窗口。在处理WM_CREATE消
38、息期间,把视图的HWND赋给框架窗口的成员变量m_hWndClient。例如,给我们SDI应用添加位图绘制功能,你可以如下所示那样定义一个视图类:class CBitmapView : public CWindowImpl<CBitmapView>public: CBitmapView(); CBitmapView(); BEGIN_MSG_MAP(CBitmapView) MESSAGE_HANDLER(WM_PAINT, OnPaint) END_MSG_MAP() LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&);private
39、: HBITMAP m_hBmp;为了使用该视图,如下所示操作:LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&) / 创建视图View (m_view是CBitmapView类型) m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE, WS_EX_CLIENTEDGE); return 0; 现在,框架窗口无论何时调整大小,这个视图都会被工具条,命令条和状态条所包围。ATL/WTL提供大量窗口类可以作为视图。你可以使用所有的窗口控件和通用控件封装
40、类作为视图。比如,通过把m_view类的类型从CBitmapView变为CEdit(在atlctrls.h中定义),你就有简单的文本编辑器(见图5)。图5 简单的文本编辑器 如果你想从ATL的窗口封装类中选一个类派生出来作为视图,你可以有2个方面的继承:C+方法与窗口方法。这就是超类化,这样你可以添加功能和处理消息。比如,通过从CAxWindow继承,我们可以有一个支持HTML的客户视图。/ 继承C+方法为来继承CAxWindow功能class CHtmlView : public CWindowImpl<CHtmlView, CAxWindow>public: / 继承Windo
41、ws方法来预处理Windows消息 DECLARE_WND_SUPERCLASS(NULL, CAxWindow:GetWndClassName() BEGIN_MSG_MAP(CHtmlView) END_MSG_MAP()CHtmlView() AtlAxWinInit(); / 初始化控件宿主(在atlhost.h定义) ; 我们可以使用新的视图来打开一个web页面(图6 显示这个结果)LRESULT CMainFrame:OnCreate(UINT, WPARAM, LPARAM, BOOL&) / 创建该视图(m_view 的类型是CHtmlView) m_hWndClien
42、t = m_view.Create(m_hWnd, rcDefault, "", WS_CHILD | WS_VISIBLE, WS_EX_CLIENTEDGE); return 0;图6 使用新的视图来打开网页第五章 使用MRU尽管WTL提供支持视图,但跟MFC不一样,它没有文档的概念。如果你想在WTL应用程序中支持文档/视图模型,你是很自由的。作为开始,我们已经写了一系列提供非常基本文档功能的类,你可以用在你应用程序中。这一章的WTLDocView例子就可见到这些类。如果你做过文档工作,你几乎可以肯定会在文件菜单中支持MRU(Most Recently Used)文件列
43、表。具有讽刺意味的是,尽管WTL不支持文档,它通过CRecentDocumentList类(在atlmisc.h中定义)提供全功能MRU支持。主框架窗口通常管理CRecentDocumentList类的一个实例。在主框架窗口的WM_CREATE消息处理中,主框架窗口用一个文件菜单句柄来初始化CRecent DocumentList对象,这样它就可以管理了。为了拥有MRU功能,框架窗口调用CRecentDocument List:ReadFromRegistry()成员函数来从指定的注册表键查找16个入口。缺省情况下,限制的MRU文档是4个,但你也可以通过调用CRecentDocumentLis
44、t:SetMaxEntries()来改变这个值。LRESULT CMainFrame:OnCreate(UINT, WPARAM, LPARAM, BOOL&) m_mru.SetMenuHandle(GetMenu().GetSubMenu(0); m_mru.ReadFromRegistry(_T("SoftwareMyCompanyMyCoolApp"); m_mru.SetMaxEntries(16); 为了首次添加一个文档到MRU列表,你可以调用CRecentDocumentList:AddToList():LRESULT CMainFrame:OnFil
45、eOpen(WORD, WORD, HWND, BOOL&)if (m_dlgOpen.DoModal(m_hWnd) = IDOK) / 试着打开文件if (bFileOpened) m_mru.AddToList(m_dlgOpen.m_bstrName);return 0; 你添加MRU的菜单项介于ID_FILE_MRU_FIRST和ID_FILE_MRU_LAST(在atlres.h定义)之间。你可以宏COMMAND_RANGE_HANDLER来处理这个范围。当用户点击MRU菜单项时,处理函数可以调用CRecentDocumentList:GetFromList()返回文档名。
46、在文档打开后,处理函数应该调用CRecentDocument List:MoveToTop()或CRecentDocumentList:Remove From List()来指示文档打开与否。LRESULT CMainFrame:OnOpenUsingMRU(WORD, WORD wID, HWND, BOOL&) TCHAR szDocumentMAX_PATH;m_mru.GetFromList(wID, szDocument);/ Try to open the file specified by the menu item if (bFileOpened)m_mru.MoveT
47、oTop(wID);else m_mru.RemoveFromList(wID);return 0; 最后,当你的应用程序关闭时,你需要调用CRecentDocumentList:WriteToRegistry()来把文件名列表写入注册表。void CMainFrame:OnFinalMessage(HWND /*hWnd*/)m_mru.WriteToRegistry(_T("SoftwareMyCompanyMyCoolApp");:PostQuitMessage(0);第六章 创建多线程SDI应用程序与多个SDI应用程序不同,IE浏览器使用一个应用程序来管理多个顶级S
48、DI窗口。如果你想在应用程序使用这个特性,你可以就使用WTL提供的多线程SDI支持。多线程SDI应用程序的设计原理是很简单的:1> 每个顶级窗口(包括它们的子窗口)运行在一个独立的线程;2> 每个线程都有一个独立的消息队列,都是UI线程,具有消息处理和分派窗口消息的能力。这意味着不仅所有的线程共享进程数据,而且当一个线程忙于处理某些事情的同时,其它线程仍可以作出及时的响应;3> 这样,每个顶级框架窗口对于用户来说,就像一个独立的应用。创建这样一个应用程序的技巧在于设计一个线程管理类,它拥有:1> 为每个线程创建一个新的框架窗口;2> 管理线程类保存活动线程的数量;
49、3> 保持命令行参数和初始化窗口大小。 WTL没有为多线程SDI应用提供任何基类。然而,它的应用程序向导可以创建这种类型的应用程序(本章节后面有充分的说明)。WTL向导产生如下的线程管理器类:class CThreadManager public:struct _RunData / 线程初始化参数LPTSTR lpstrCmdLine;int nCmdShow;DWORD m_dwCount;/ 线程数HANDLE m_arrThreadHandlesMAXIMUM_WAIT_OBJECTS - 1;CThreadManager() : m_dwCount(0) DWORD AddThr
50、ead(LPTSTR lpstrCmdLine, int nCmdShow);void RemoveThread(DWORD dwIndex);int Run(LPTSTR lpstrCmdLine, int nCmdShow);WinMain将实例化线程管理类。 int WINAPI WinMain()hRes = _Module.Init(NULL, hInstance);CThreadManager mgr;int nRet = mgr.Run(lpstrCmdLine, nCmdShow);_Module.Term();return nRet; CThreadManager:Run()
51、方法创建一个新的UI线程,并使用MsgWaitForMultipleObjects()等待所有UI线程。当MsgWaitForMultipleObjects()指出有一个线程已经终止,它减少线程数,并继续等待。一旦所有线程结束,Run()方法返回,我们应用程序也就结束。另一方面,如果MsgWaitForMultipleObjects()指出有一个窗口消息,而这个消息是WM_ USER,则线程管理类创建一个新的UI线程。int CThreadManager:Run(LPTSTR lpstrCmdLine, int nCmdShow) MSG msg;:PeekMessage(&msg,
52、NULL, WM_USER, WM_USER, PM_NOREMOVE); / 强迫创建消息队列AddThread(lpstrCmdLine, nCmdShow);int nRet = m_dwCount;DWORD dwRet;while(m_dwCount > 0)dwRet = :MsgWaitForMultipleObjects(m_dwCount, m_arrThreadHandles, FALSE, INFINITE, QS_ALLINPUT);if(dwRet = 0xFFFFFFFF) :MessageBox(NULL, _T("ERROR: Wait for
53、multiple objects failed!"), _T("MultiSDI_HTMLView"), MB_OK);else if(dwRet >= WAIT_OBJECT_0 && dwRet <= (WAIT_OBJECT_0 + m_dwCount - 1) RemoveThread(dwRet - WAIT_OBJECT_0);else if(dwRet = (WAIT_OBJECT_0 + m_dwCount):GetMessage(&msg, NULL, 0, 0);if(msg.message = WM_USER)AddThread("", SW_SHOWNORMAL);else:MessageBeep(UINT)-1);else:MessageBeep(UINT)-1);return nRet; 注意:WTL向导产生的代码使用WM_USER消息来
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 丰田用车无忧服务合同标准文本
- Al-CuO含能金属桥的制备及性能研究
- 二手房出售合同标准文本
- 优良物业合同范例
- 买卖食品合同标准文本
- 2024-2025学年高中历史 第三单元 资产阶级政治家 第8课 美国首任总统华盛顿教学教学实录 岳麓版选修4
- 西花蓟马胰岛素信号通路关键基因对3种食物的响应及其功能分析
- 兄弟间买车合同标准文本
- 入股私人合同范例
- 公路路基合同标准文本
- 2022-2023学年浙江省温州市文成县七年级(下)期中数学试卷-普通用卷
- AQ2012-2007 石油天然气安全规程
- 维克多高中英语3500词汇
- 除草机器人简介
- 2015-2022年苏州信息职业技术学院高职单招语文/数学/英语笔试参考题库含答案解析
- 高中音乐鉴赏 第一单元 学会聆听 第一节《音乐要素及音乐语言》
- 当代文学第一章1949-1966年的文学思潮
- GB/T 25254-2022工业用聚四亚甲基醚二醇(PTMEG)
- GB/T 24456-2009高密度聚乙烯硅芯管
- GB 6222-2005工业企业煤气安全规程
- 中国药典2015年版
评论
0/150
提交评论