开发大型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. ajax待总结项

    1.get与post请求的区别 get请求调用send方法发送数据时,会忽略传入的数据 2.post请求的三种方式区别 1.form表单 2.ajax 3.ajax + FormData 表格绘制,代 ...

  2. 获取本地的IP地址(内网)

    方法一 public static String getLocalIpAddress() { try { for (Enumeration<NetworkInterface> en = N ...

  3. JOptionPane用法--java

    JOptionPane用法--java JOptionPane的简单应用: 1.首先引入包: import javax.swing.JOptionPane; 2.添加如下代码: Object[] op ...

  4. windows下的mysql忘记root密码的解决方法

    1.首先,需要关闭MySQL Server服务.在"运行"窗口,输入"services.msc",进入"服务"窗口. 2. 在服务窗口,可以 ...

  5. 51nod 1459 迷宫游戏 (最短路径—Dijkstra算法)

    题目链接 中文题,迪杰斯特拉最短路径算法模板题. #include<stdio.h> #include<string.h> #define INF 0x3f3f3f3f ],v ...

  6. oracleDBA-D2

    1.超级管理员sys和system的区别: sys权限比system大,system无法查看到当前数据库是否运行在归档模式下,无法关闭数据库.sys是老大,system是老二. 2.OEM-oracl ...

  7. freemarker IllegalAccessError 错误

    java.lang.IllegalAccessError: tried to access method freemarker.ext.servlet.AllHttpScopesHashModel.& ...

  8. vue.js 接收url参数

    1) 路由配置传参方式 在配置路由时 例如 "/firewall/authorize/:uid/:uname/:token" 页面url为 http://XXX.com/firew ...

  9. Reason: image not found

    刚生的Xcode8,出现好多Error,有些Error真的太麻烦不想记录,现在这个挺简单的,就记下来,控制台输出的Error信息如下: fix: Target -> Build Phases - ...

  10. javascript面向切面

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...