使用Win32/ATL建立窗口的過程


有時候想寫個幾十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 項目


點擊確定,再點擊下一步,選上ATL支持(注意此時MFC是灰色的)點擊完成以新建工程


二、打開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;
}

六、運行


七、發布
將默認目標改為Release,右擊項目->屬性->C/C++->代碼生成,運行庫設置為『多線程 (/MT)』,以便可以免運行庫:


按F7生成,然后打開項目父目錄,找到Release文件夾(不是項目子目錄下的Release),可以找到我們可以發布的程序:


八、總結
通過ATL,我們使用很短的代碼就實現了一個標准的Windows窗口,比用傳統的Win32方法不知道高到哪里去了,然而程序的體積並沒有大幅度的增長,相對於MFC,還算是輕量級的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM