有时候想写个几十kb的小程序,MFC实在是太大了,Win32有时又太麻烦,怎么办呢?用ATL写会更方便和轻量级一些 ATL和MFC不同的是,ATL并没有强制性封装WinMain函数,仅封装了WndProc,所以使用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 项目

图片:捕获.PNG


点击确定,再点击下一步,选上ATL支持(注意此时MFC是灰色的)点击完成以新建工程

图片:捕获2.PNG


二、打开MyAtlWindowTest.cpp,删减示例代码
原因是我们不需要采用传统方法来新建窗口

图片:捕获3.PNG


剩下的代码如下:
复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// MyAtlWindowTest.cpp : 定义应用程序的入口点。
//
                                                                     
#include "stdafx.h"
#include "MyAtlWindowTest.h"
                                                                     
// 全局变量:
HINSTANCE hInst;                                // 当前实例
                                                                     
// TODO: 实现窗口类CMainWindow
                                                                     
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       LPTSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    hInst = hInstance; // 将实例句柄存储在全局变量中
                                                                     
    // TODO: 初始化窗口
                                                                     
    // 主消息循环:
    while (GetMessage(&msg, NULL, 0, 0)) // 消息循环 - 等待消息
    {
        TranslateMessage(&msg); // 消息循环 - 翻译键盘消息
        DispatchMessage(&msg); // 消息循环 - 分发消息
    }
                                                                     
    return (int) msg.wParam;
}

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

图片:捕获4.PNG


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

1
#include <atlwin.h>

四、添加CMainWindow实现
ATL窗口最基本的形式如下: class 自己的窗口类 : public CWindowImpl<自己的窗口类, 基类=CWindow, 特性类=CControlWinTraits> { public:     BEGIN_MSG_MAP(自己的窗口类) // 利用宏实现ProcessWindowMessage消息分发函数     END_MSG_MAP() };
因此最简单的代码如下:
复制代码

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// TODO: 实现窗口类CMainWindow
class CMainWindow : public CWindowImpl<CMainWindow> { // 主窗口,基于CWindowImpl模板
public:
    BEGIN_MSG_MAP(CMainWindow) // 利用宏实现ProcessWindowMessage函数,用以分发消息
        COMMAND_ID_HANDLER(IDM_ABOUT, OnAbout) // if命令分发分支
        COMMAND_ID_HANDLER(IDM_EXIT, OnExit) // if命令分发分支
        MESSAGE_HANDLER(WM_PAINT, OnPaint) // if消息分发分支
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy) // if消息分发分支
    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 0;
    }
    LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
        PostQuitMessage(0); // 退出消息循环
        return 0;
    }
    LRESULT OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { // ATL命令处理函数的标准形式
        CSimpleDialog<IDD_ABOUTBOX> dlg;
        dlg.DoModal(); // 显示『关于』对话框
        return 0;
    }
    LRESULT OnExit(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) {
        this->DestroyWindow(); // 点击文件->关闭时,销毁窗口
        return 0;
    }
};

五、在WinMain中加载窗口
加载一个Win32窗口很麻烦,但是加载一个ATL窗口是很简单的事情 ——根本不用操心窗口类的注册,因为Create函数会自动为我们注册一个。
在WinMain中加载CMainWindow窗口:
复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       LPTSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    hInst = hInstance; // 将实例句柄存储在全局变量中
                                                                     
    // TODO: 初始化窗口
    // 加载菜单资源
    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, 0, 0)) // 消息循环 - 等待消息
    {
        TranslateMessage(&msg); // 消息循环 - 翻译键盘消息
        DispatchMessage(&msg); // 消息循环 - 分发消息
    }
                                                                     
    return (int) msg.wParam;
}

六、运行

图片:捕获5.PNG


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

图片:捕获7.PNG


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

图片:捕获6.PNG


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

使用Win32/ATL建立窗口的过程的更多相关文章

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

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

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

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

  3. WinMain与WndProc以及窗口诞生过程总结

    一.int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nCmdShow) 四个 ...

  4. (转)C#在父窗口中调用子窗口的过程(无法访问已释放的对象)

    C#在父窗口中调用子窗口的过程: 1. 创建子窗口对象 2. 显示子窗口对象   笔者的程序中,主窗体MainFrm通过菜单调用子窗口ChildFrm.在窗体中定义了子窗口对象,然后在菜单项点击事件中 ...

  5. win32程序之窗口程序,以及消息机制

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

  6. wxWidgets源码分析(6) - 窗口关闭过程

    目录 窗口关闭过程 调用流程 关闭文档 删除视图 删除文档对象 关闭Frame App清理 多文档窗口的关闭 多文档父窗口关闭 多文档子窗口关闭 窗口的正式删除 窗口关闭过程总结 如何手工删除view ...

  7. uCGUI窗口初始化过程

    一.相关结构体和变量 重要的uCGUI系统全局变量 NextDrawWin                      下一个需要重绘的窗口句柄 WM__NumWindows       系统当前的总共 ...

  8. MFC应用程序创建窗口的过程 good

    MFC应用程序中处理消息的顺序 1.AfxWndProc()      该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc 2.AfxCallWndProc()  该 ...

  9. C#在父窗口中调用子窗口的过程(无法访问已释放的对象)异常,不存在从对象类型System.Windows.Forms.DateTimePicker到已知的托管提供程序本机类型的映射。

    一:C#在父窗口中调用子窗口的过程(无法访问已释放的对象)异常 其实,这个问题与C#的垃圾回收有关.垃圾回收器管 理所有的托管对象,所有需要托管数据的.NET语言(包括 C#)都受运行库的 垃圾回收器 ...

随机推荐

  1. 九度OJ 1504 把数组排成最小的数【算法】-- 2009年百度面试题

    题目地址:http://ac.jobdu.com/problem.php?pid=1504 题目描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如 ...

  2. OpenJudg / Poj 1363 Rails

    1.链接: http://poj.org/problem?id=1363 http://bailian.openjudge.cn/practice/1363 2.题目: Rails Time Limi ...

  3. PH获取当前url路径及服务器路径汇总 (url 获取当前路径 服务器路径)

    以下是整理的一些, php中获取路径的小知识, 希望对你有所帮助! 1,$_SERVER["QUERY_STRING"] 说明:查询(query)的字符串 2,$_SERVER[& ...

  4. leetcode解题—Longest Palindromic Substring

    题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum l ...

  5. STL的pair学习, map学习

    http://blog.csdn.net/calvin_zcx/article/details/6072286 http://www.linuxidc.com/Linux/2014-10/107621 ...

  6. php中一些安全性防止问题建议

    只要我们作好了各类操作就可在基本防止一些朋友利用网站本身的漏洞进行网站操作了,很多在php中都有的如XSS用 htmlentities()预防XSS攻击还有sql注入可以用mysql_real_esc ...

  7. oracle 行转列问题

    select id, name, ),),)) "imp_value", ),), )) "click_value" from (SELECT a.id, a. ...

  8. 转载:STM32之中断与事件---中断与事件的区别

    这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚 ...

  9. android正在运行进程和后台缓存进程的区别

    正在运行的进程:需要占用一定的cpu资源和RAM(内存)空间,多少的话看是什么应用,要消耗一定的电量,影响手机速度等性能. 后台缓存的进程:不需要占用cpu资源,会在RAM中写入一部分数据,当下次打开 ...

  10. ExtJS4加载FormPanel数据的几种方式

    我们做web应用最多的就是处理表单,extjs为我们提供了很多处理表单的功能,很多初学者疑惑怎么加载表单数据,到底能用什么方式加载?本文中,我将我自己实验过的进行一下总结,自己备忘,也希望能帮助到其他 ...