ATL封装IE内核启示:使用Win32/ATL建立窗口

时间:2022-10-16 12:25:06
开发大型GUI界面程序MFC当仁不让,但如果是开发图形应用程序,并不需要大规模界面控件,没有必要链接庞大的MFC库,直接使用platform sdk会很麻烦,这时ATL中的关于Windows的封装就是最好的选择

ATL的窗口架构是这样的——

【两个底层封装类】
CWindow
窗口句柄和API封装类
只封装了hWnd窗口句柄和与之有关的WinAPI,CWindow和hWnd可以方便地进行转换。
CMessageMap
消息映射接口
该基类有一个待实现的函数ProcessWindowMessage,用以分发消息,可使用宏实现:
BEGIN_MSG_MAP(CMyClass)
END_MSG_MAP()

【两个窗口类实现模板】(最终多继承自CWindow和CMessageMap)
CWindowImpl<T>
自定义窗口模板(实现了WNDCLASS和WndProc)
可选参数:<T, TBase = CWindow, TWinTraits = CControlWinTraits>
通过继承CWindowImpl<CMyWindow>,并实现消息映射,可以实现一个自定义窗口CMyWindow。
CDialogImpl<T>
自定义对话框模板(实现了DlgProc)
可选参数:<T, TBase = CWindow>
通过继承CDialogImpl<CMyDialog>,并实现消息映射、资源绑定,可以实现一个自定义对话框CMyDialog。
资源绑定的实现:enum { IDD = IDD_DIALOG };

【两个即刻可用的窗口类】
CSimpleDialog<IDD_DIALOG>
简单对话框
可选参数:<IDD_DIALOG, bCenter = TRUE>
用来创建只有确定和取消的简单对话框,使用这个类就不需要每次都从CDialogImpl<T>派生了。
CContainedWindow
被容纳的窗口
可选参数:CContainedWindowT<TBase = CWindow, TWinTraits = CControlWinTraits>
可以用来创建子窗口(控件),也可以SubclassWindow来绑定它们,这样就不用每次从CWindowImpl<T>派生了。
这个类将消息路由到父窗口的ALT_MSG_MAP(n),方便接收子窗口消息,自己并不进行消息分发。

以及一些附加的类和模板,如CWinTraits<>、CWinTraitsOR<>、CWndClassInfo等。

一、新建一个支持ATL的Win32项目

新建一个项目,选择Visual C++ -> Win32 -> Win32 项目
ATL封装IE内核启示:使用Win32/ATL建立窗口

点击确定,再点击下一步,选上ATL支持(注意此时MFC是灰色的)点击完成以新建工程
ATL封装IE内核启示:使用Win32/ATL建立窗口

二、打开MyAtlWindowTest.cpp,删减示例代码

原因是我们不需要采用传统方法来新建窗口

ATL封装IE内核启示:使用Win32/ATL建立窗口

剩下的代码如下:

ATL封装IE内核启示:使用Win32/ATL建立窗口ATL封装IE内核启示:使用Win32/ATL建立窗口
 1 // MyAtlWindowTest.cpp : 定义应用程序的入口点。
 2 //
 3                                                                      
 4 #include "stdafx.h"
 5 #include "MyAtlWindowTest.h"
 6                                                                      
 7 // 全局变量:
 8 HINSTANCE hInst;                                // 当前实例
 9                                                                      
 // TODO: 实现窗口类CMainWindow
                                                                      
 int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        LPTSTR lpCmdLine, int nCmdShow)
 {
     MSG msg;
     hInst = hInstance; // 将实例句柄存储在全局变量中
                                                                      
     // TODO: 初始化窗口
                                                                      
     // 主消息循环:
     while (GetMessage(&msg, NULL, , )) // 消息循环 - 等待消息
     {
         TranslateMessage(&msg); // 消息循环 - 翻译键盘消息
         DispatchMessage(&msg); // 消息循环 - 分发消息
     }
                                                                      
     return (int) msg.wParam;

三、在stdafx.h添加头文件atlwin.h

ATL封装IE内核启示:使用Win32/ATL建立窗口

向导只给我们添加了基本的atlbase.h和atlstr.h支持,并没有给我们添加窗口支持,因此要手动添加:

复制代码

 #include <atlwin.h>

四、添加CMainWindow实现

ATL窗口最基本的形式如下:
class 自己的窗口类 : public CWindowImpl<自己的窗口类, 基类=CWindow, 特性类=CControlWinTraits> {
public:
    BEGIN_MSG_MAP(自己的窗口类) // 利用宏实现ProcessWindowMessage消息分发函数
    END_MSG_MAP()
};

因此最简单的代码如下:

ATL封装IE内核启示:使用Win32/ATL建立窗口ATL封装IE内核启示:使用Win32/ATL建立窗口
 // TODO: 实现窗口类CMainWindow
 class CMainWindow : public CWindowImpl<CMainWindow> { // 主窗口,基于CWindowImpl模板
 public:
     BEGIN_MSG_MAP(CMainWindow) // 利用宏实现ProcessWindowMessage函数,用以分发消息
     END_MSG_MAP()
 };

在这里我们实现了如下的代码(当然你也可以使用上边的代码):

ATL封装IE内核启示:使用Win32/ATL建立窗口ATL封装IE内核启示:使用Win32/ATL建立窗口
 1 // TODO: 实现窗口类CMainWindow
 2 class CMainWindow : public CWindowImpl<CMainWindow> { // 主窗口,基于CWindowImpl模板
 3 public:
 4     BEGIN_MSG_MAP(CMainWindow) // 利用宏实现ProcessWindowMessage函数,用以分发消息
 5         COMMAND_ID_HANDLER(IDM_ABOUT, OnAbout) // if命令分发分支
 6         COMMAND_ID_HANDLER(IDM_EXIT, OnExit) // if命令分发分支
 7         MESSAGE_HANDLER(WM_PAINT, OnPaint) // if消息分发分支
 8         MESSAGE_HANDLER(WM_DESTROY, OnDestroy) // if消息分发分支
 9     END_MSG_MAP()
     LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // ATL消息处理函数的标准形式
         PAINTSTRUCT ps;
         this->BeginPaint(&ps); // 开始绘图
         // 在这里进行绘图操作
         this->EndPaint(&ps); // 结束绘图
         // bHandled如果不手动赋值FALSE的话,默认为TRUE
         return ;
     }
     LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
         PostQuitMessage(); // 退出消息循环
         return ;
     }
     LRESULT OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { // ATL命令处理函数的标准形式
         CSimpleDialog<IDD_ABOUTBOX> dlg;
         dlg.DoModal(); // 显示『关于』对话框
         return ;
     }
     LRESULT OnExit(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) {
         this->DestroyWindow(); // 点击文件->关闭时,销毁窗口
         return ;
     }
 };

五、在WinMain中加载窗口

加载一个Win32窗口很麻烦,但是加载一个ATL窗口是很简单的事情
——根本不用操心窗口类的注册,因为Create函数会自动为我们注册一个。

在WinMain中加载CMainWindow窗口:

ATL封装IE内核启示:使用Win32/ATL建立窗口ATL封装IE内核启示:使用Win32/ATL建立窗口
 1 int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 2                        LPTSTR lpCmdLine, int nCmdShow)
 3 {
 4     MSG msg;
 5     hInst = hInstance; // 将实例句柄存储在全局变量中
 6                                                                      
 7     // TODO: 初始化窗口
 8     // 加载菜单资源
 9     HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDC_MYATLWINDOWTEST));
                     
     // 创建窗口
     CMainWindow wnd;
     wnd.Create(NULL, CWindow::rcDefault, _T("My Window"), WS_OVERLAPPEDWINDOW, WS_EX_CLIENTEDGE, hMenu);
                                                                      
     // 显示并更新窗口
     wnd.ShowWindow(nCmdShow);
     wnd.UpdateWindow();
                                                                      
     // 主消息循环:
     while (GetMessage(&msg, NULL, , )) // 消息循环 - 等待消息
     {
         TranslateMessage(&msg); // 消息循环 - 翻译键盘消息
         DispatchMessage(&msg); // 消息循环 - 分发消息
     }
                                                                      
     return (int) msg.wParam;
 }

六、运行

ATL封装IE内核启示:使用Win32/ATL建立窗口

七、发布

将默认目标改为Release,右击项目->属性->C/C++->代码生成,运行库设置为『多线程 (/MT)』,以便可以免运行库:
ATL封装IE内核启示:使用Win32/ATL建立窗口

按F7生成,然后打开项目父目录,找到Release文件夹(不是项目子目录下的Release),可以找到我们可以发布的程序:
ATL封装IE内核启示:使用Win32/ATL建立窗口

八、总结

通过ATL,我们使用很短的代码就实现了一个标准的Windows窗口,比用传统的Win32方法不知道高到哪里去了,然而程序的体积并没有大幅度的增长,相对于MFC,还算是轻量级的。

注:内部使用IWebBrowser2,实现多进程多线程通讯,cookies共享等等问题,可以尝试解决定制浏览器的问题。

网上的参考:

ATL封装IE内核启示:使用Win32/ATL建立窗口ATL封装IE内核启示:使用Win32/ATL建立窗口
 1 #include <atlbase.h>
 2 #include <atlwin.h>
 3 class CMyWindow
 4     : public CWindowImpl<CMyWindow, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW, > >
 5 {
 6 public:
 7     DECLARE_WND_CLASS(_T("CMyWindow")) 
 8     BEGIN_MSG_MAP(CMyWindow)
 9         MESSAGE_HANDLER(WM_PAINT, OnPaint)
     END_MSG_MAP()
     LRESULT OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
     {
         PAINTSTRUCT ps;
         ::BeginPaint(m_hWnd, &ps);
         ::EndPaint(m_hWnd, &ps);
         bHandled = TRUE;
         return ;
     }
     void OnFinalMessage(HWND hwnd)
     {
         ::PostQuitMessage();
     }
 };
 int APIENTRY _tWinMain(HINSTANCE hInstance,
                        HINSTANCE hPrevInstance,
                        LPTSTR lpCmdLine,
                        int nCmdShow)
 {
     CMyWindow myWnd;
     myWnd.Create(NULL, CMyWindow::rcDefault, _T("Hello, world"));
     myWnd.ShowWindow(nCmdShow);
     myWnd.UpdateWindow();
     MSG msg;
     msg.message = ~(UINT)WM_QUIT;
     while(msg.message != WM_QUIT)
     {
         if(::GetMessage(&msg, NULL, , ))
         {
             TranslateMessage(&msg);
             DispatchMessage(&msg);
         }
     }
     return (int)msg.wParam;
 }

ATL封装IE内核启示:使用Win32/ATL建立窗口的更多相关文章

  1. 使用Win32&sol;ATL建立窗口的过程

    有时候想写个几十kb的小程序,MFC实在是太大了,Win32有时又太麻烦,怎么办呢?用ATL写会更方便和轻量级一些 ATL和MFC不同的是,ATL并没有强制性封装WinMain函数,仅封装了WndPr ...

  2. &lbrack;COM&sol;ATL&rsqb;组件、对象、MFC、ATL的区别

    组件(Component)和对象(Object)之间的区别 先明确组件(Component)和对象(Object)之间的区别.组件是一个可重用的模块,它是由一 组处理过程.数据封装和用户接口组成的业务 ...

  3. ATL与COM之间的关系、ATL的特点与基本使用方法

    http://blog.csdn.net/titilima/archive/2004/07/18/44273.aspx ATL,Active Template Library活动模板库 是一种微软程序 ...

  4. win32程序之窗口程序&comma;以及消息机制

    win32程序值窗口程序,以及消息机制 一丶简介 通过上一讲.我们了解了窗口其实是绘制出来的.而且是不断绘制的过程. 所以窗口的本质是绘制. 但是我们现在看到的窗口程序.都可以点击关闭按钮. 使用鼠标 ...

  5. Win32知识之窗口绘制&period;窗口第一讲

    Win32知识之窗口本质 一丶摘要 在学习Win32的时候. 很多操作都是窗口进行操作的.那么今天就说一下窗口的本质是什么. 窗口的本质是不断绘制.是windows通过消息机制进行绘制的. 我们知道. ...

  6. 探索Win32系统之窗口类&lpar;转载&rpar;

    Window Classes in Win32 摘要 本文主要介绍win32系统里窗口类的运做和使用机制,探索一些细节问题,使win32窗口类的信息更加明朗化. 在本文中,"类", ...

  7. win32允许前置窗口

    win32允许前置窗口函数 AllowSetForegroundWindow(HWND hWnd) 该函数允许其他窗口调用SetForegroundWindow()(将窗口设为前置窗口),前提是调用A ...

  8. Linux内核静态映射表的建立过程

    /* *    平台:   s5pv210 *    内核版本号: 2.6.35.7 */ kernel/arch/arm/mach-s5pv210/mach-smdkc110.c 这个文件是由三星在 ...

  9. &lbrack;Win32&rsqb;创建模态窗口

    http://www.cnblogs.com/zplutor/archive/2011/02/20/1958973.html 在Win32编程中,如果要显示一个模态窗口,一般是先创建对话框模板,然后使 ...

随机推荐

  1. Java CopyOnWriteArrayList

    1. 为什么需要 CopyOnWriteArrayList ArrayList 的内部实现是一个数组, 并且是动态扩容的, 当插入数据时, 先判断数组是否需要扩容, 如果需要扩容, 则先扩容, 再插入 ...

  2. &lpar;34&rpar;odoo反代理中客户IP处理

    * 前言    一般我们部署时会用nginx做为前端处理,有时负载时还会用到其它web服务反代理    这里只给出nginx处理方法,其它参考处理    * nginx上的客户IP传递        ...

  3. javascript正则表达式&lpar;一&rpar;——语法

    前言 js中类RegExp类表示正则表达式,具有强大的模式匹配.文本检索和替换功能.正则表达式的模式规则是由一个字符序列组成,包括所有字母和数字在内,大多数的字符都是按照直接量匹配字符,某些特殊字符并 ...

  4. SpriteBuilder中的CCB Node尺寸

    当你创建一个类型为Layer的CCB文件时,你将注意到它的默认尺寸大小为568x384. 568个点是4英寸iphone的宽度,同时iPad屏幕只有512个点宽,更准确的说--SpriteBuilde ...

  5. JqGrid分页按钮图标不显示的bug

    开发中遇到的一个小问题,记录一下,如果有朋友也遇到了相同的问题,可以少走些弯路少花点时间. 如图: 分页插件使用了JqGrid,但是分页栏里出现了问题,上一页.下一页这些按钮的图标都显示为空,记得以前 ...

  6. css3 的新属性

    1,动画,animate------>//动画-名称-动画的时间间隔-以什么方式播放-循环 .right{ animate:dropdown 4px 5px #000; // x的偏移值 y的偏 ...

  7. B - Tree Recovery

    Little Valentine liked playing with binary trees very much. Her favorite game was constructing rando ...

  8. js 原型链与继承

    var A = function(){ this.name="xiaoming"; } A.prototype.age=9; var a = new A(); console.lo ...

  9. web 攻击靶机解题过程

    sql注入靶机攻击过程请参考 https://pentesterlab.com/exercises/from_sqli_to_shell/course http://www.sohu.com/a/12 ...

  10. dxg&colon;TreeListView&period;RowDecorationTemplate

    <dxg:TreeListView.RowDecorationTemplate> <ControlTemplate TargetType="ContentControl&q ...