博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[转] 窗口封装类与Windows窗口实例的关系-3、CWnd如何处理窗口消息
阅读量:5254 次
发布时间:2019-06-14

本文共 3956 字,大约阅读时间需要 13 分钟。

在窗口消息处理方面,CWnd使用了窗口子类化和消息映射机制,关于消息映射的知识将在第9章详述,下面着重阐述CWnd是如何应用子类化处理窗口消息的。其实,在6.2节的示例中,CBaseWnd已经使用了与CWnd类似的子类化方法处理窗口消息。成员函数CBaseWnd::SubWindowClass()将窗口过程子类化为CBaseWnd::MyBaseWndProc(),在这个窗口过程中调用CBaseWnd::WindowProc()处理窗口消息。原始的窗口过程存入成员m_Super WndProc中,在默认处理中调用。

CWnd在窗口建立之初,使用AfxWndProc()子类化窗口,在AfxWndProc()中同样调用CWnd::WindowProc()处理窗口消息。不同的是,对于具体的消息处理,CWnd::WindowProc()使用消息映射机制,而不是调用固定的虚拟函数。原始的窗口过程存储在CWnd::m_pfnSuper中,在默认的处理过程CWnd::DefWindowProc()中调用。

下面是与消息处理相关的几个CWnd成员函数:

//用于子类化的窗口过程

LRESULT CALLBACK

AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)

{

         // special message which identifies the window as using AfxWndProc

         if (nMsg == WM_QUERYAFXWNDPROC)

                  return 1;

         // all other messages route through message map

         //通过句柄取得CWnd对象指针

         CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);

         ASSERT(pWnd != NULL);

         ASSERT(pWnd->m_hWnd == hWnd);

         return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);

}

LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,

         WPARAM wParam = 0, LPARAM lParam = 0)

{  ……

//调用CWnd的虚拟成员函数处理消息

         lResult = pWnd->WindowProc(nMsg, wParam, lParam);

         ……

return lResult;

}

//可在类向导中重载的虚拟函数

LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

{

         // OnWndMsg函数处理消息映射,如果在映射中没有发现当前消息的处理函数,则返回false

         LRESULT lResult = 0;

         if (!OnWndMsg(message, wParam, lParam, &lResult))

         //如果当前消息没被映射处理,调用默认处理函数

         lResult = DefWindowProc(message, wParam, lParam);

         return lResult;

}

//默认的消息处理函数,同Default()

LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)

{

         if (m_pfnSuper != NULL)

         //调用原始的窗口过程

                  return::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);

         WNDPROC pfnWndProc;

         if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)

                  //调用默认窗口处理过程

                  return::DefWindowProc(m_hWnd, nMsg, wParam, lParam);

         else

                  return::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);

}

除以上几个相关成员函数外,CWnd类还定义了两个公共成员,SubclassWindow()和UnsubclassWindow(),前者用于动态地关联并使用AfxWndProc()子类化Windows窗口,后者执行相反过程。这意味着,可以随时将一个使用WIN32 API创建的窗口,通过调用SubclassWindow()关联到CWnd实例上。因为同时执行了子类化操作,所以此时就如同使用CWnd的Create()函数创建了这个Windows窗口一样。函数的代码如下:

BOOL CWnd::SubclassWindow(HWND hWnd)

{

         //hWnd应该是一个没有与任何CWnd实例关联的Windows窗口

         if (!Attach(hWnd)) //先建立关联,再子类化

                  return FALSE;

         //在子类化前调用这个虚函数,给用户提供编程接口

         PreSubclassWindow();

WNDPROC* lplpfn = GetSuperWndProcAddr();/*取得原始窗口函数。如果当前类尚未子类化窗口,返回NULL*/

         //使用AfxWndProc()子类化该窗口

         WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,

                  (DWORD)AfxGetAfxWndProc());//取得AfxWndProc()子类窗口函数

         ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());

         if (*lplpfn == NULL)

                  *lplpfn = oldWndProc; //保存原始窗口函数,在默认处理时调用

         return TRUE;

}

HWND CWnd::UnsubclassWindow()

{

         ASSERT(::IsWindow(m_hWnd));

//得到原始窗口过程

         WNDPROC* lplpfn = GetSuperWndProcAddr();

         //恢复窗口过程

SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)*lplpfn);

         *lplpfn = NULL;

         //分离窗口对象和窗口句柄

         return Detach();

}

virtual void CWnd::PreSubclassWindow()

{//该虚拟函数在建立窗口时,子类化前被调用,在CWnd::SubclassWindow中也被调用

//它不执行任何操作,可以重载它,根据需要执行子类化。那样,子类化过程会成为原始的窗口过程,在消息默认处理时被调用

}

对窗口操作的封装是很好理解的,成员CWnd::m_hWnd存储映射的窗口句柄,不同的窗口操作成员函数一般封装同名的WIN32 API,函数通过m_hWnd调用同名API即可。下面列举几个相关的成员函数。

void CWnd::SetWindowText(LPCTSTR lpszString)

         { ASSERT(::IsWindow(m_hWnd)); ::SetWindowText(m_hWnd, lpszString); }

BOOL CWnd::IsIconic() const

         { ASSERT(::IsWindow(m_hWnd)); return ::IsIconic(m_hWnd); }

void CWnd::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint)

         { ASSERT(::IsWindow(m_hWnd)); ::MoveWindow(m_hWnd, x, y, nWidth, nHeight, bRepaint); }

BOOL CWnd::SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags)

         { ASSERT(::IsWindow(m_hWnd));

 return ::SetWindowPos(m_hWnd, pWndInsertAfter->GetSafeHwnd(),         x, y, cx, cy, nFlags); }

CDC* CWnd::GetWindowDC()

         { ASSERT(::IsWindow(m_hWnd)); return CDC::FromHandle(::GetWindowDC(m_hWnd)); }

int CWnd::ReleaseDC(CDC* pDC)

         { ASSERT(::IsWindow(m_hWnd)); return ::ReleaseDC(m_hWnd, pDC->m_hDC); }

void CWnd::UpdateWindow()

         { ASSERT(::IsWindow(m_hWnd)); ::UpdateWindow(m_hWnd); }

关于CWnd的子窗口管理部分,将在第7章阐述。

转载于:https://www.cnblogs.com/qixiamu/p/3412517.html

你可能感兴趣的文章
influxDb数据备份
查看>>
手动创建一张表
查看>>
算法与并行计算(世界著名计算机教材精选)
查看>>
centos7 网络不通
查看>>
[bzoj1662] [Usaco2006 Nov]Round Numbers 圆环数
查看>>
CSS3中DIV水平垂直居中-2(3)
查看>>
myeclipse快捷键记忆
查看>>
STL - 仿函数
查看>>
Rectangle Area - LeetCode
查看>>
工厂方法模式(Factory Method)
查看>>
Healthy Holsteins_usaco2.1.4_codevs2044_dfs
查看>>
发布一个.NET正则表达式测试站点
查看>>
malloc函数详解
查看>>
poj 2443 Set Operation 位运算
查看>>
java.lang.ExceptionInInitializerError
查看>>
Laravel使用Form(转载)
查看>>
easy UI
查看>>
Java static的使用 --Java笔记
查看>>
博客园自定义地址栏logo
查看>>
单例模式(Singleton)
查看>>