开发大型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支持(注意此时MFC是灰色的)点击完成以新建工程

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

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

剩下的代码如下:

 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

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

复制代码

 #include <atlwin.h>

四、添加CMainWindow实现

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

因此最简单的代码如下:

 // TODO: 实现窗口类CMainWindow
 class CMainWindow : public CWindowImpl<CMainWindow> { // 主窗口,基于CWindowImpl模板
 public:
     BEGIN_MSG_MAP(CMainWindow) // 利用宏实现ProcessWindowMessage函数,用以分发消息
     END_MSG_MAP()
 };

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

 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窗口:

 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;
 }

六、运行

七、发布

将默认目标改为Release,右击项目->属性->C/C++->代码生成,运行库设置为『多线程 (/MT)』,以便可以免运行库:

按F7生成,然后打开项目父目录,找到Release文件夹(不是项目子目录下的Release),可以找到我们可以发布的程序:

八、总结

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

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

网上的参考:

 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/ATL建立窗口的过程

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

  2. [COM/ATL]组件、对象、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程序之窗口程序,以及消息机制

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

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

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

  6. 探索Win32系统之窗口类(转载)

    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. [Win32]创建模态窗口

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

随机推荐

  1. python string模块

    string.ascii_lowercase ='abcdefghijklmnopqrstuvwxyz' string.ascii_uppercase ='ABCDEFGHIJKLMNOPQRSTUV ...

  2. js_继承

    一,js中对象继承 js中有三种继承方式 1.js原型(prototype)实现继承 复制代码代码如下: <SPAN style="<SPAN style="FONT- ...

  3. 关于settimeout 和for循环

    for(var i=0;i<3;i++){ setTimeOut(function(){ console.log(i) },500) }; 执行结果:3,3,3 ---------------- ...

  4. 多功能弹窗控件layer

    开发网站的时候,如何合理运用好各种插件对开发的帮助是很大的. 免去了我们调试各种交互效果, 比如常用的弹窗.气泡.提示.加载.焦点.标签.导航.折叠等等 这里会推荐几个常用的js插件,丰富多样简单易移 ...

  5. 相机变换与Ray-Casting

    p { margin-bottom: 0.1in; direction: ltr; line-height: 120%; text-align: justify; orphans: 0; widows ...

  6. KAOS模型

    问题描述: 我们开发了一种针对时序数据的文件格式TSFile,本身不支持sql查询.为了让公司分析人员能够用SQL进行分析,并且应用一些机器学习算法进行预测,需要设计并实现一个TSFile与Spark ...

  7. java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  8. c++中4个与类型转换相关的关键字分析

    static_cast reinterpret_cast dynamic_cast const_cast 1.**static_cast------运算符完成相关类型之间的转换** 使用场景:如在同一 ...

  9. python map()

    map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回. 举例说明,比如我们有一个函数f(x)=x%2,要把这个函数作用在一个li ...

  10. Web Service 的创建简单编码、发布和部署

    最近,老大准备将已有的C/S架构项目中的通信部分做成通用,需要将其支持WebService为以后项目向着B/S架构升级做好铺垫,为此身为屌丝的我去各种百度WebService是个什么卵玩意,然后逐渐搭 ...