zoukankan      html  css  js  c++  java
  • ATL封装IE内核启示:使用Win32/ATL建立窗口

    开发大型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                                                                      
    10 // TODO: 实现窗口类CMainWindow
    11                                                                      
    12 int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    13                        LPTSTR lpCmdLine, int nCmdShow)
    14 {
    15     MSG msg;
    16     hInst = hInstance; // 将实例句柄存储在全局变量中
    17                                                                      
    18     // TODO: 初始化窗口
    19                                                                      
    20     // 主消息循环:
    21     while (GetMessage(&msg, NULL, 00)) // 消息循环 - 等待消息
    22     {
    23         TranslateMessage(&msg); // 消息循环 - 翻译键盘消息
    24         DispatchMessage(&msg); // 消息循环 - 分发消息
    25     }
    26                                                                      
    27     return (int) msg.wParam;
    View Code

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



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

    复制代码
    1 #include <atlwin.h>

    四、添加CMainWindow实现

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


    因此最简单的代码如下:
    1 // TODO: 实现窗口类CMainWindow
    2 class CMainWindow : public CWindowImpl<CMainWindow> { // 主窗口,基于CWindowImpl模板
    3 public:
    4     BEGIN_MSG_MAP(CMainWindow) // 利用宏实现ProcessWindowMessage函数,用以分发消息
    5     END_MSG_MAP()
    6 };
    View Code

    在这里我们实现了如下的代码(当然你也可以使用上边的代码):
     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()
    10     LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // ATL消息处理函数的标准形式
    11         PAINTSTRUCT ps;
    12         this->BeginPaint(&ps); // 开始绘图
    13         // 在这里进行绘图操作
    14         this->EndPaint(&ps); // 结束绘图
    15         // bHandled如果不手动赋值FALSE的话,默认为TRUE
    16         return 0;
    17     }
    18     LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
    19         PostQuitMessage(0); // 退出消息循环
    20         return 0;
    21     }
    22     LRESULT OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { // ATL命令处理函数的标准形式
    23         CSimpleDialog<IDD_ABOUTBOX> dlg;
    24         dlg.DoModal(); // 显示『关于』对话框
    25         return 0;
    26     }
    27     LRESULT OnExit(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) {
    28         this->DestroyWindow(); // 点击文件->关闭时,销毁窗口
    29         return 0;
    30     }
    31 };
    View Code

    五、在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));
    10                     
    11     // 创建窗口
    12     CMainWindow wnd;
    13     wnd.Create(NULL, CWindow::rcDefault, _T("My Window"), WS_OVERLAPPEDWINDOW, WS_EX_CLIENTEDGE, hMenu);
    14                                                                      
    15     // 显示并更新窗口
    16     wnd.ShowWindow(nCmdShow);
    17     wnd.UpdateWindow();
    18                                                                      
    19     // 主消息循环:
    20     while (GetMessage(&msg, NULL, 00)) // 消息循环 - 等待消息
    21     {
    22         TranslateMessage(&msg); // 消息循环 - 翻译键盘消息
    23         DispatchMessage(&msg); // 消息循环 - 分发消息
    24     }
    25                                                                      
    26     return (int) msg.wParam;
    27 }
    View Code

    六、运行



    七、发布

    将默认目标改为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, 0> >
     5 {
     6 public:
     7     DECLARE_WND_CLASS(_T("CMyWindow")) 
     8     BEGIN_MSG_MAP(CMyWindow)
     9         MESSAGE_HANDLER(WM_PAINT, OnPaint)
    10     END_MSG_MAP()
    11     LRESULT OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
    12     {
    13         PAINTSTRUCT ps;
    14         ::BeginPaint(m_hWnd, &ps);
    15         ::EndPaint(m_hWnd, &ps);
    16         bHandled = TRUE;
    17         return 0;
    18     }
    19     void OnFinalMessage(HWND hwnd)
    20     {
    21         ::PostQuitMessage(0);
    22     }
    23 };
    24 int APIENTRY _tWinMain(HINSTANCE hInstance,
    25                        HINSTANCE hPrevInstance,
    26                        LPTSTR lpCmdLine,
    27                        int nCmdShow)
    28 {
    29     CMyWindow myWnd;
    30     myWnd.Create(NULL, CMyWindow::rcDefault, _T("Hello, world"));
    31     myWnd.ShowWindow(nCmdShow);
    32     myWnd.UpdateWindow();
    33     MSG msg;
    34     msg.message = ~(UINT)WM_QUIT;
    35     while(msg.message != WM_QUIT)
    36     {
    37         if(::GetMessage(&msg, NULL, 00))
    38         {
    39             TranslateMessage(&msg);
    40             DispatchMessage(&msg);
    41         }
    42     }
    43     return (int)msg.wParam;
    44 }
    View Code
  • 相关阅读:
    windows 运行hadoop的WordCount报nativeio.NativeIO$Windows.createDirectoryWithMode0(Ljava/lang/String;I)
    java对象比较==和equals的区别
    java poi处理excel多sheet并实现排序
    hadoop-eclipse插件编译及windows下运行wordcount项目
    hadoop动态添加删除节点datanode及恢复
    hadoop的client搭建-即集群外主机访问hadoop
    appium+python,app自动化测试框架
    [adb]查看 App的appPackage和appActivity
    Django基础(二)
    JavaScript、Dom和jQuery
  • 原文地址:https://www.cnblogs.com/HANYI7399/p/5231162.html
Copyright © 2011-2022 走看看