有時候想寫個幾十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,還算是輕量級的。