开发大型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. 【ASP.NET】利用Nuget打包package——命令行方式

    通过命令行 官方说明,可以参考:creating-and-publishing-a-package 如果你希望可以使用图形界面的方式,请参考这篇文章   打包dll   使用如下的命令: nuget  ...

  2. ORA-01502: index 'INDEX_NAME' or partition of such index is in unusable state

    ORA-01502: index 'INDEX_NAME' or partition of such index is in unusable state 原因: 这个错误一般是因为索引状态为UNUS ...

  3. iOS self

    如果self在对象方法中 那么self就代表调用当前对象方法的那个对象 如果self在类方法中 那么self就代表调用当前类方法的那个类 总结:self的使用只需关注self在哪个方法中 如果在类方法 ...

  4. Session在类库中的使用

    转自:http://www.cnblogs.com/JiangXiaoTian/articles/3490904.html 网站开发中,为了保存用户的信息,有时候需要使用session.如果我们在as ...

  5. LeetCode 205 Isomorphic Strings

    Problem: Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if ...

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

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

  7. Windows HTTP Services

    原文:https://msdn.microsoft.com/zh-cn/library/windows/desktop/aa384273(v=vs.85).aspx Purpose (目的) Micr ...

  8. Android-RelativeLayout(相对布局)、LinearLayout(线性布局)

    RelativeLayout(相对布局):按照各子元素之间的位置关系完成布局. 定位:android:layout_above="@id/xxx" --将控件置于给定ID控件之上 ...

  9. mac显示任何来源

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px "Microsoft YaHei"; color: #333333; ba ...

  10. 可视化日历_Java实现

    //刚刚学Java,写的小程序 package cn.xiaocangtian.testDate; import java.text.DateFormat; import java.text.Pars ...