ATL封装IE内核启示:使用Win32/ATL建立窗口
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,删减示例代码
原因是我们不需要采用传统方法来新建窗口

剩下的代码如下:

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()
};
因此最简单的代码如下:

class CMainWindow : public CWindowImpl<CMainWindow> { // 主窗口,基于CWindowImpl模板
public:
BEGIN_MSG_MAP(CMainWindow) // 利用宏实现ProcessWindowMessage函数,用以分发消息
END_MSG_MAP()
};
在这里我们实现了如下的代码(当然你也可以使用上边的代码):

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

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共享等等问题,可以尝试解决定制浏览器的问题。
网上的参考:

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建立窗口的更多相关文章
- 使用Win32/ATL建立窗口的过程
有时候想写个几十kb的小程序,MFC实在是太大了,Win32有时又太麻烦,怎么办呢?用ATL写会更方便和轻量级一些 ATL和MFC不同的是,ATL并没有强制性封装WinMain函数,仅封装了WndPr ...
- [COM/ATL]组件、对象、MFC、ATL的区别
组件(Component)和对象(Object)之间的区别 先明确组件(Component)和对象(Object)之间的区别.组件是一个可重用的模块,它是由一 组处理过程.数据封装和用户接口组成的业务 ...
- ATL与COM之间的关系、ATL的特点与基本使用方法
http://blog.csdn.net/titilima/archive/2004/07/18/44273.aspx ATL,Active Template Library活动模板库 是一种微软程序 ...
- win32程序之窗口程序,以及消息机制
win32程序值窗口程序,以及消息机制 一丶简介 通过上一讲.我们了解了窗口其实是绘制出来的.而且是不断绘制的过程. 所以窗口的本质是绘制. 但是我们现在看到的窗口程序.都可以点击关闭按钮. 使用鼠标 ...
- Win32知识之窗口绘制.窗口第一讲
Win32知识之窗口本质 一丶摘要 在学习Win32的时候. 很多操作都是窗口进行操作的.那么今天就说一下窗口的本质是什么. 窗口的本质是不断绘制.是windows通过消息机制进行绘制的. 我们知道. ...
- 探索Win32系统之窗口类(转载)
Window Classes in Win32 摘要 本文主要介绍win32系统里窗口类的运做和使用机制,探索一些细节问题,使win32窗口类的信息更加明朗化. 在本文中,"类", ...
- win32允许前置窗口
win32允许前置窗口函数 AllowSetForegroundWindow(HWND hWnd) 该函数允许其他窗口调用SetForegroundWindow()(将窗口设为前置窗口),前提是调用A ...
- Linux内核静态映射表的建立过程
/* * 平台: s5pv210 * 内核版本号: 2.6.35.7 */ kernel/arch/arm/mach-s5pv210/mach-smdkc110.c 这个文件是由三星在 ...
- [Win32]创建模态窗口
http://www.cnblogs.com/zplutor/archive/2011/02/20/1958973.html 在Win32编程中,如果要显示一个模态窗口,一般是先创建对话框模板,然后使 ...
随机推荐
- 我的Hcharts的页面应用
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...
- Python3.4下安装pip和MySQLdb
想用pyhton3.4做数据分析,pip和MySQLdb是必要的,一个便于安装常用模块,一个用来操作数据库.当时安装这两个模块时,由于没有人指导,花了很多的时间才安装好. 安装pip时,按照网上的教程 ...
- DIV+CSS布局
宽度自适应两列布局 <!DOCTYPE html> <html> <head> <meta charset="gbk"> <t ...
- MySql卸载重新安装出现Start service没有响应的解决办法(64位)
昨天因为自己手欠,不小心把mysql卸载了,于是又得重新安装,但是每次到了最后一步就报没有响应,于是就去寻找解决办法,如下就是啦! 安装Mysql卸载后又重新安装,每次到最后Start service ...
- python 装饰器
#!/usr/bin/env python3 #-*-encoding:utf-8-*- def w3(*args, **kwargs): ') def w1(): def ww1(func): de ...
- Linux下的DOS攻击
Linux下的DOS攻击 DOS是Denial of service的简称,即拒绝服务,造成Dos攻击行为被称为Dos攻击,其目的是使计算机或网络无法提供正常的服务.最常见的Dos攻击有计算机带宽攻击 ...
- TFS API:二、TFS 代码查询工作项
TFS API:二.TFS 代码查询工作项 首先我们需要认识TFS的两大获取服务对象的类. 他们分别为TfsConfigurationServer和TfsTeamProjectCollection, ...
- ubuntu 报错: The system is running in low-graphics mode
出错原因不知为何,apt-get install --reinstall unity-greeter 不起作用. 试了一下,这样居然有效: cd /etc/X11 sudo cp xorg.conf. ...
- mysql命令行修改字符编码
1.修改数据库字符编码 mysql> alter database mydb character set utf8 ; 2.创建数据库时,指定数据库的字符编码 mysql> create ...
- Jenkins持续集成 & .NET
最近受累于测试环境每次发布都很麻烦,而且我们有多个测试环境,因此专门抽时间做了Jenkins的配置和研究. 折腾了两天终于绿灯以后,先来个截图,BlueOcean UI还是很nice的. 环境搭建 找 ...