最近学习使用WTL作Windows编程,网上找资料----->少,仅仅有个叫www.imyaker.com的网站上有个牛X老外的一本书,而且是针对MFC编程人员的,像我这种初学者简直----->难。
对于一个标准的windows应用,虽然╮(╯_╰)╭但是我们必需牢记在心,因为所有的什么messge map等等最终还是在switch case或者在if else。她包括一下几个部分:
1:-TWinMain,函数入口点
2:注册窗口类
3:创建主窗口
4:showWindow,UpdateWindow
5:消息循环,消息处理。
6:退出
然后WTL,ATL,MFC都是对这一过程的封装。
WTL继承自ATL,ATL是为COM而作的,她对windows组件进行了一定的包装。如:Cwindow,CDilog==,后来微软的一帮技术牛X人,觉得用模板库来做窗体的封装不错,然后就对ATL的这些东西做了扩展就是WTL。
以下我们就来看看他的CWindowImpl。
首先,CWindowImpl最终是从Cwindow派生的。
- template <class T, class TBase /* = CWindow */, class TWinTraits /* = CControlWinTraits */>
- class ATL_NO_VTABLE CWindowImpl : public CWindowImplBaseT< TBase, TWinTraits >
- {
- public:
- DECLARE_WND_CLASS(NULL)
- static LPCTSTR GetWndCaption()
- {
- return NULL;
- }
- 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);
- // set caption
- if (szWindowName == NULL)
- szWindowName = T::GetWndCaption();
- return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rect, szWindowName,
- dwStyle, dwExStyle, MenuOrID, atom, lpCreateParam);
- }
- };
Cwindow仅仅是做了一个类来存放一个HWND,几乎所有API中第一个参数是HWND的方法这个类都有。看它的源代码就可以得出,它仅仅是调用了API。此时它并没有消息循环,与窗口处理函数。
然后,再看看WTL给的.h文件就可以知道,它貌似是有一个叫:Cmessage的类里面拥有消息循环。如下:
- class ATL_NO_VTABLE CMessageMap
- {
- public:
- virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,LRESULT& lResult, DWORD dwMsgMapID) = 0;
- };
当然了,CWindowImpl 多半是继承了这个类。如下:
- template <class TBase /* = CWindow */>
- class ATL_NO_VTABLE CWindowImplRoot : public TBase, public CMessageMap
从此,CWindowImpl 就有了消息循环。
那么,注册窗口,与创建窗口在哪里喃?
看到源码中第一句就是一宏,展开看一下:
- #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; /
- }
....这个就是窗口的注册了,其中StartWindowProc很诡异,如下:
- static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg,
- WPARAM wParam, LPARAM lParam)
- {
- CContainedWindowT< TBase >* pThis = (CContainedWindowT< TBase >*)_AtlWinModule.ExtractCreateWndData();
- ATLASSERT(pThis != NULL);
- if(!pThis)
- {
- return 0;
- }
- pThis->m_hWnd = hWnd;
- // Initialize the thunk. This was allocated in CContainedWindowT::Create,
- // so failure is unexpected here.
- pThis->m_thunk.Init(WindowProc, pThis);
- WNDPROC pProc = pThis->m_thunk.GetWNDPROC();
- WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);
- #ifdef _DEBUG
- // check if somebody has subclassed us already since we discard it
- if(pOldProc != StartWindowProc)
- ATLTRACE(atlTraceWindowing, 0, _T("Subclassing through a hook discarded./n"));
- #else
- pOldProc; // avoid unused warning
- #endif
- return pProc(hWnd, uMsg, wParam, lParam);
- }
最终,以上的东西实现一个功能:将与窗口相联系的窗口过程变成了一个类与其方法的联系。
注:m_thunk 是一个ASM结构。作用:在调用CWindowImpl的静态成员方法WindowProc更进一步地进行消息处理 之前将HWND替换成为CWindowImpl 对象的this指针。
后面就是像这样的东西了:
- BEGIN_MSG_MAP(CWtl_SDIView)
- MESSAGE_HANDLER(WM_PAINT, OnPaint)
- MSG_WM_SETCURSOR(OnSetCursor)
- MESSAGE_HANDLER(WM_CREATE,OnCreate)
- MESSAGE_HANDLER(WM_LBUTTONDOWN,OnLbdown)
- MESSAGE_HANDLER(WM_DESTROY,OnDestroy)
- END_MSG_MAP()
什么也不说,这个就是一系列case,if等等的语句,展开就OK。
- 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:
然后就没有了。下面是一个列子:
- #pragma once
- #include "stdafx.h"
- class CWtl_SDIView : public CWindowImpl<CWtl_SDIView>
- {
- public:
- DECLARE_WND_CLASS(NULL)
- //BOOL PreTranslateMessage(MSG* pMsg);
- BEGIN_MSG_MAP(CWtl_SDIView)
- MESSAGE_HANDLER(WM_PAINT, OnPaint)
- MSG_WM_SETCURSOR(OnSetCursor)
- MESSAGE_HANDLER(WM_LBUTTONDOWN,OnLbdown)
- END_MSG_MAP()
- // Handler prototypes (uncomment arguments if needed):
- // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
- // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
- // void OnNcLButtonDown(UINT nHitTest, CPoint point)
- LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
- LRESULT OnLbdown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
- LRESULT OnSetCursor(HWND hwndCtrl, UINT uHitTest, UINT uMouseMsg)
- {
- static HCURSOR hcur = LoadCursor ( NULL, IDC_SIZEALL );
- if ( NULL != hcur )
- {
- SetCursor ( hcur );
- return TRUE;
- }
- else
- {
- SetMsgHandled(false);
- return FALSE;
- }
- }
- };
- LRESULT CWtl_SDIView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- CPaintDC dc(m_hWnd);
- //TODO: Add your drawing code here
- dc.TextOut(0,0,_T("hello world"));
- return 0;
- }
- LRESULT CWtl_SDIView::OnLbdown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) //向父窗口发送消息
- {
- if (wParam == (MK_CONTROL|MK_LBUTTON))
- {
- ::MessageBox(this->m_hWnd,_T("you press key"),_T("test0"),0);
- WPARAM wParam=MAKEWPARAM(ID_APP_ABOUT,0);
- ::SendMessage(this->GetParent(),WM_COMMAND,wParam,0);
- ::MessageBox(this->m_hWnd,_T("after SendMessage ID_APP_ABOUT"),_T("test1"),0);
- return 1;
- }
- else if (wParam == MK_LBUTTON)
- {
- ::MessageBox(this->m_hWnd,_T("you just press left button "),_T("test2"),0);
- WPARAM wParam=MAKEWPARAM(IDOK,0);
- ::SendMessage(this->GetParent(),WM_COMMAND,wParam,0);
- ::MessageBox(this->m_hWnd,_T("after SendMessage IDOK"),_T("test1"),0);
- return 1;
- }
- return 0;
- }