窗口过程中:

case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 加绘画代码
EndPaint(hWnd, &ps);
break;
// TODO: 标签下添加 TextOut(hdc, 0, 0, _T("Hello world!"), 12);

win32你好

主程序:

1.2.1 WinMain

//APIENTRY代表程序从此开始运行(入口)处.
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// TODO: 放代码
MSG msg;
MyRegisterClass(hInstance);

// 初化应用
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

// 主消息循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return (int) msg.wParam;
}

三块构成:​​注册/初化/主消息循环​​.

1.2.1 注册窗口类

ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

1.2.3 初化应用

主要为​​创建并显示窗口​​.

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 全局变量中存储实例
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
return TRUE;
}

1.2.4 窗口过程

在这里,主要处理​​WM_PAINT​​​和​​WM_DESTROY​​等消息.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 加绘画代码
TextOut(hdc,0,0,_T("你好!"),12);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

构建并输出,略.

ATL中你好

2.1 修改stdafx.h

在​​1.1​​​中创建的​​Win32​​​代码中​​移除或注释​​​掉​​stdafx.h​​中的:

// 窗口头文件
#include <windows.h>
// C 运行时头文件
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

并在​​stdafx.h​​​中添加如下的​​include​​语句:

#include <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>
#include <atlwin.h>
#include "CWellcomeWindow.h"

2.2 添加CWellcomeWindow.h

#pragma once
#include "stdafx.h"

class CWellcomeWindow : public CWindowImpl<CWellcomeWindow,CWindow, CFrameWinTraits> {
public :
DECLARE_WND_CLASS(NULL);
BEGIN_MSG_MAP(CWellcomeWindow)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
END_MSG_MAP()

LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
HICON appIcon = LoadIcon(_Module.GetResourceInstance(),
MAKEINTRESOURCE(IDI_LEARNINGWTLPART1_ATL));
this->SetIcon(appIcon);

return 0;
}


LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
PAINTSTRUCT ps;
CComBSTR wellcome(_T("你好!"));

HDC hdc; // = this->GetDC();
hdc = this->BeginPaint(&ps); // this->BeginPaint(&ps);
TextOut(hdc, 0, 0, wellcome, wellcome.Length());
this->EndPaint(&ps);
//this->ReleaseDC(hdc);

return 0;
}

LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
::PostQuitMessage(0);
return 0;
}
};

2.3 修改win32.cpp

保留​​WinMain​​​方法声明和​​#include"stdafx.h"​​​语句,​​删除或注释掉​​​其余代码.添加​​_Module​​​定义,修改​​WndMain​​方法体;完成后的代码如下:

#include "stdafx.h"
#include "LearningWTLPart1_ATL.h"

CComModule _Module;
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
_Module.Init(NULL, hInstance);
CComBSTR appTitle;
appTitle.LoadString(_Module.GetResourceInstance(), IDS_APP_TITLE);
CWellcomeWindow wnd;
wnd.Create(NULL, 0, appTitle);
// 主消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);

}

_Module.Term();

return (int) msg.wParam;
}

3对比

​atl​​​轻量封装了​​基础构造块​​​.​​atl​​​四块:​​注册/初化/主循环/窗口过程​​.

3.1.2 ATL基础构造块和主要流程

​CComModule​​​下面函数完成.​​Init/Term​​​是​​atl​​​中​​com​​服务器的部分.

​函数​

作用

​Init​

初化​​CComModule​​类数据

​Create​

上面四步都在此函数

​主消息循环​

一样

​Term​

结束,释放数据

4atl编程模型

​atl​​​是​​wtl​​的基础.

4.1 注册类在哪?

上面​​MyRegisterClass​​函数要完成的工作:​​1​​.初化​​WNDCLASSEX​​;​​2​​.​​RegisterClassEx​​.

而在​​ATL​​中,由​​CWellcomeWindow​​之由宏定义的成员函数​​(宏定义的成员函数)DECLARE_WND_CLASS(NULL)​​完成,其由​​wnd.Create(NULL,0,appTitle)​​调用(例如,在​​win32.cpp​​中).

4.1.1 DECLARE_WND_CLASS(NULL)宏定义?

// CWndClassInfo 窗口类信息
#define DECLARE_WND_CLASS(WndClassName) \
static ATL::CWndClassInfo& GetWndClassInfo() \
{ \
static ATL::CWndClassInfo wc = \
{ \
{ sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc, \
0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
}; \
return wc; \
}

​CWndClassInfo​​​为​​ATL​​​内使用​​WNDCLASSEX​​​结构的结构​​(C++)​​​,看看代码就应该有所了解了,关键在于​​4.1.2CWndClassInfo​​​结构​​(_ATL_WNDCLASSINFOW)​​​定义的黑体部分​​(Bold)​​.

4.1.2CWndClassInfo结构(_ATL_WNDCLASSINFOW)定义

struct _ATL_WNDCLASSINFOW
{//类信息.
WNDCLASSEXW m_wc;
LPCWSTR m_lpszOrigName;
WNDPROC pWndProc;
LPCWSTR m_lpszCursorID;
BOOL m_bSystemCursor;
ATOM m_atom;
WCHAR m_szAutoName[5+sizeof(void*)*CHAR_BIT];
ATOM Register(WNDPROC* p)
{
return AtlWinModuleRegisterWndClassInfoW(&_AtlWinModule, &_AtlBaseModule, this, p);
}
};

4.1.3 ATL::CWindowImpl::Create定义

HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
{
if (T::GetWndClassInfo().m_lpszOrigName == NULL)
T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();
ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);

dwStyle = T::GetWndStyle(dwStyle);
dwExStyle = T::GetWndExStyle(dwExStyle);

// 置标题
if (szWindowName == NULL)
szWindowName = T::GetWndCaption();

return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rect, szWindowName,
dwStyle, dwExStyle, MenuOrID, atom, lpCreateParam);
}

真正完成​​CreateWindow​​.

4.2 WndProc在哪?

在​​ATL​​​中保留了​​主消息循环​​​(例如,在​​win32.cpp​​​中).​​WndProc​​​由​​宏定义成员函数​​​完成,参看​​2.2​​​添加​​CWellcomeWindow.h​​可以看到如下代码:

BEGIN_MSG_MAP(CWellcomeWindow)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
END_MSG_MAP()

4.2.1 映射消息

#define BEGIN_MSG_MAP(theClass) \
public : \
BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \
{ \
BOOL bHandled = TRUE; \
(hWnd); \
(uMsg); \
(wParam); \
(lParam); \
(lResult); \
(bHandled); \
switch(dwMsgMapID) \
{ \
case 0:

#define END_MSG_MAP() \
break; \
default: \
ATLTRACE(ATL::atlTraceWindowing, 0, _T("Invalid message map ID (%i)/n"), dwMsgMapID); \
ATLASSERT(FALSE); \
break; \
} \
return FALSE; \
}

你所定义​​特定消息处理​​​将会置于​​case 0​​​和​​defaul​​​之间,例如​​2.2​​​添加​​CWellcomeWindow.h​​将会产生如下代码:

BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0)
{
BOOL bHandled = TRUE;
(hWnd);
(uMsg);
(wParam);
(lParam);
(lResult);
(bHandled);
switch(dwMsgMapID)
{
case 0:
if(uMsg == msg)
{
bHandled = TRUE;
lResult = OnCreate(uMsg, wParam, lParam, bHandled);
if(bHandled)
return TRUE;
}
...
break;
default:
break;
}
return FALSE;
}