孙鑫VC++第四章 1.简单绘图-MFC消息映射机制

news2024/11/29 20:43:37

1. MFC消息映射机制

接下来将剖析MFC消息映射机制,探讨发送给窗口的消息是如何被MFC框架通过窗口句柄映射表和消息映射表来用窗口类的处理函数进行响应的。另外,还将讲述“类向导”这一工具的运用,讨论设备描述表及其封装类CDC的使用,以及CDC是如何与具体的设备发生关联的,并结合具体的画图程序进行分析。

2.绘图

首先介绍一些绘图方面的知识,从最简单的画线开始。在程序中画线和在纸上画线不太一样,在纸上画线时,我们只需用笔在纸上拖动一下就可以绘制出一条线,但在程序中画线时需要知道两个点,即线条的起点和终点。程序中如何捕获到这两个点呢?Windows程序是基于消息编程的。在程序运行过程中,当单击鼠标左键时,就可以获得一个点,即线条的起点。接着按住鼠标左键并拖动一段距离后松开鼠标,此时也可以获得一个点,即线条的终点。也就是说,我们需要捕获两个消息,一个是鼠标左键按下消息(WM_LBUTTONDOWN),在该消息响应函数中可以获得将要绘制的线条的起点;另一个是鼠标左键弹起来的消息(WM_LBUTTONUP),在该消息响应函数中可以获得将要绘制的线条的终点。有了这两个点就可以绘制出一条线。下面就来实际编写一个绘制线条的程序。

1. 鼠标点击消息

新建一个单文档类型的MFC应用程序,项目名为Draw,解决方案名为ch05,步骤:VC++MFC应用程序向导。既可以在视类中进行鼠标左键操作消息的捕获,也可以在框架类中进行此项工作。

先在框架类中进行这项工作。我们为 CMainFrame 类添加 WM_LBUTTONDOWN这个消息的响应函数。在此函数内部,添加一条显示消息框的代码(利用MessageBox函数实现),用来表明在程序运行时鼠标左键确实被按下去了。

连接:VC++在窗口中显示按钮 CButton::Create Button Styles Window Styles

代码如下:

void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
 
    CFrameWnd::OnLButtonDown(nFlags, point);
}

在添加MessageBox函数这行代码时,根据VC++提供的智能提示(代码如下所示),可以发现此处的 MessageBox 函数与我们利用 SDK 编程时使用的MessageBox 函数有所区别,此处的 MessageBox 调用少了一个参数:窗口句柄(HWND类型的变量hWnd)。我们已经介绍过CWnd类定义了一个HWND类型的成员变量m_hWnd,用于保存当前窗口的句柄,并且该成员变量具有public类型的访问权限。这样,窗口的所有操作就不再需要传递这个句柄了,因为它已经是成员变量,可以直接使用。根据类继承性原理,所有派生于CWnd类的子类都拥有这一成员变量,用来保存当前子类窗口的句柄,因此在调用与子类窗口有关的操作时,也不再需要传递这个窗口句柄了。我们知道CMainFrame是CWnd类的一个子类,因此也就应该明白为什么此处MessageBox函数会没有窗口句柄这一参数了。

MessageBox函数:


提示:提示的 MessageBox 函数后面多了一个大写的字母W,因为Visual Studio 2017默认使用Unicode字符集(即宽字符,用两个字节表示一个字符),而此处我们使用的MessageBox只是一个宏,它会根据项目使用的字符集在编译时自动转换为宽字符函数版本,或者ANSI字符串函数版本。 

同时,可以发现 MessageBox 函数的后两个参数都具有默认值,因此,添加的MessageBox函数调用如下所示。

void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    MessageBox(L"MainFrame Clicked!");
    CFrameWnd::OnLButtonDown(nFlags, point);
}

Build并运行Draw程序,然后在程序窗口上单击鼠标左键,发现程序并未如我们所愿,弹出消息框。这是为什么呢?我们暂时先把这一问题搁置一下,再看一下,如果在视类中捕获鼠标左键操作消息并处理,结果会如何?

2.类向导

介绍过如何使用类向导给某个类添加消息响应的处理函数,类向导是Visual C++开发中一个很重要的组成部分。它可以帮助我们创建一个新类,为已有类添加成员变量,添加消息和命令的响应函数,以及虚函数的重写。这里,我们再详细介绍一下类向导所具有的功能。类向导对话框如图所示。

 

 类向导的功能主要由五个选项卡提供,分别是:命令、消息、虚函数、成员变量和方法。下面就分别介绍这五个选项卡。

1.命令选项卡主要用于添加对菜单、工具栏按钮、控件等所产生的命令消息进行响应的处理函数。

2.通过消息选项卡添加或删除消息处理函数。消息列表框列出了所有针对该类可以处理的消息,下方的“添加自定义消息”按钮可以添加自定义的消息,后面会介绍如何添加自定义消息,以及如何对其进行响应。

3.通过虚函数选项卡对基类的虚函数进行重写,或者删除已重写的虚函数。虚函数列表框列出了所有针对该类可以重写的虚函数。

4.通过成员变量选项卡我们可以加入与对话框上的控件相关联的成员变量,以便程序利用这些成员变量与对话框上的控件进行信息交换。至于如何将变量与控件相关联,后面介绍。

控件ID项显示对话框中所具有的控件的ID号;类型项显示添加的成员变量的类型;成员项显示添加的成员变量的名字。右侧的“添加变量”按钮用于给选定的控件添加成员变量;“添加自定义”按钮用于给类添加不与控件相关联的普通的成员变量。

5.通过方法选项卡可以给指定的类添加各种类型的函数(如静态函数、虚函数等),或者删除函数。

选中某个方法,单击“转到定义”按钮将定位到函数的实现处(即源文件中的相应位置),单击“转到声明”按钮将定位到函数的声明处(即头文件中的相应位置)。现在我们利用了类向导首先给项目Draw的视类CDrawView添加WM_LBUTTONDOWN消息的响应函数,切换到消息选项卡,确保类名选中的是CDrawView,然后在消息列表框中找到WM_LBUTTONDOWN并选中,单击“添加处理程序”按钮,“单击编辑代码”按钮,定位到OnLButtonDown函数的定义处。与前面CMainFrame类的处理一样,在此函数中添加一个显示消息框的函数,代码如下所示。

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	MessageBox(L"view clicked");
	CView::OnLButtonDown(nFlags, point);
}

为什么在框架类中捕获这一消息就没有生效呢?前面讲述文档/视类结构时,曾说过视类窗口始终覆盖在框架类窗口之上。我们可以打个比方,框架窗口就像一面墙,而视类窗口就像墙纸,它始终挡在这面墙的前面。那么此时对这面墙的所有操作,其实都是在墙纸上进行的。同样的道理也适用于框架窗口和视窗口。也就是说,所有操作,包括鼠标单击、鼠标移动等操作都只能由视类窗口捕获。这就是为什么在框架类窗口中收不到鼠标左键单击这一消息的原因。

这时,我们可以删除框架类中已经添加的 WM_LBUTTONDOWN 这一消息的响应函数。不过要注意的是,通过 MFC 提供的类向导添加消息响应函数后,类向导会在所选类的头文件和源文件中添加几处相关的信息,后面将介绍通过类向导添加的内容及其所在的位置。因此删除某个消息响应函数时要小心,一定要确保这几处相关代码均被删除。最好不要直接手工删除源代码中的函数定义。可以通过类向导来进行删除,这样就可以把头文件和源文件中所有与此函数相关的信息全部删除了。可以在类视图中右击该函数,点击delete进行删除。

3.消息映射机制

可以浏览一下Draw项目CDrawView的头文件和源文件,可以发现在为视类增加一个鼠标左键按下这一消息响应函数之后,在文件中增加了三处代码。

(1)消息响应函数原型在CDrawView类的头文件(DrawView.h)中,有如下所示代码。

// 生成的消息映射函数
protected:
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

如上所示这段代码中,在OnLButtonDown函数声明的前面有一个afx_msg限定符,这是一个宏。该宏表明这个函数是一个消息响应函数的声明。

(2)ON_WM_LBUTTONDOWN消息映射宏在CDrawView类的源文件(DrawView.cpp)中,有下所示代码。

BEGIN_MESSAGE_MAP(CDrawView, CView)
    // 标准打印命令
    ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
    ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

上述例5-4所示代码中,BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()这两个宏之间定义了CDrawView类的消息映射表,其中有一个ON_WM_LBUTTONDOWN消息映射宏,这个宏的作用就是把鼠标左键按下消息(WM_LBUTTONDOWN)与一个消息响应函数关联起来(在本例中是把WM_LBUTTONDOWN消息与OnLButtonDown函数关联起来)。通过这种机制,一旦有消息产生,程序就会调用相应的消息响应函数来进行处理。

(3)消息响应函数的定义在CDrawView类的源文件(DrawView.cpp)中,可以看到OnLButtonDown函数的定义。

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    MessageBox(L"view clicked");
    CView::OnLButtonDown(nFlags, point);
}

经过以上分析可以知道,一个 MFC 消息响应函数在程序中有三处相关信息:函数原型、函数实现,以及用来关联消息和消息响应函数的宏。在头文件中使用afx_msg宏来表明这是一个消息响应函数原型的声明,在源文件中有两处:一处是在BEGIN_MESSAGE_MAP(…)和 END_MESSAGE_MAP()这两个宏之间的消息映射宏 ON_WM_LBUTTOND OWN();另一处是源文件中的消息响应函数的实现代码。

在讲述消息循环时曾介绍过,当有消息产生时,操作系统会把这条消息放到应用程序的消息队列中,应用程序通过 GetMessage 函数从这个队列中取出一条具体的消息,并通过 DispatchMessage 函数把消息交给操作系统,后者调用应用程序的窗口过程,即窗口过程函数 WndProc 进行处理。该函数利用 switch-case 结构来对消息进行判别并分类处理。然而,我们看到在 MFC 程序中,并不是按照这种途径进行处理的,只要遵照上述步骤,定义了与消息有关的三处信息后,就可以实现消息的响应处理。MFC中采用的这种消息处理机制称为MFC消息映射机制。

1. 消息映射表

实际上,消息路由可以有多种实现方式。其中一种可能的实现方式是,在基类中针对每种消息定义一个虚函数。当子类需要对某个消息进行处理时,只需要重写基类相应的虚函数即可。当在程序中调用这个函数时,根据多态性原理,如果子类重写了该函数,就调用子类的这个函数,否则就调用父类的相应函数。通过这种方式也可以完成消息的路由。这样做从原理上讲是没有问题的,但是从编程角度讲,是不可取的。

为什么不可取?因为虚函数必须由一个虚函数表(vtable)来实现。在应用程序中使用的每个派生类,系统都要为它们分配一个 vtable,并且不管基类中虚函数是否在派生类中被重写,这个vtable表都要为基类的每一个虚函数提供一个4字节的输入项。而我们知道,MFC中类的派生层次有很多,这样做将使MFC类及其派生类背着一个很大的虚拟函数表的包袱,这对内存资源是一种浪费。而且,每次扫描虚拟函数表也非常消耗时间,这种定义虚拟函数的做法显然是不合适的。所以,MFC没有采用虚拟函数这种机制,而是采用一种称之为消息映射的机制来完成消息路由。

MFC 消息映射机制的具体实现方法是:在每个能接收和处理消息的类中,定义一个消息和消息函数静态对照表,即消息映射表。在消息映射表中,消息与对应的消息处理函数指针是成对出现的。某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中。当有消息需要处理时,程序只要搜索该消息静态表,查看表中是否含有该消息,就可知道该类能否处理此消息。如果能处理该消息,那么依照静态表同样能很容易找到并调用对应的消息处理函数。

2. 实际实现过程

下面让我们看看MFC消息映射机制的实际实现过程。MFC在后台维护了一个窗口句柄与对应的C++对象指针的对照表。以本例中的CDrawView类为例,与CDrawView对象相关的有一个窗口,窗口当然有它的窗口句柄,该句柄与CDrawView对象的一个指针(即CDrawView*)存在着一一对应关系,在窗口句柄与 C++对象对照表中就维护了这种对应关系。当收到某一消息时,消息的第一个参数就指明该消息与哪个窗口句柄相关,通过对照表,就可以找到与之相关的C++对象指针。把这个指针传递给应用程序框架窗口类的基类,后者会调用一个名为WindowProc的函数。该函数的定义位于wincore.cpp文件,代码如下所示。

LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	// OnWndMsg does most of the work, except for DefWindowProc call
	LRESULT lResult = 0;
	if (!OnWndMsg(message, wParam, lParam, &lResult))
		lResult = DefWindowProc(message, wParam, lParam);
	return lResult;
}

转到WindowProc函数的声明处,我们可以发现它是一个虚函数。在这个函数的内部调用了一个 OnWndMsg 函数,真正的消息路由,也就是消息映射就是由此函数完成的。OnWndMsg函数的定义也位于wincore.cpp文件中,部分代码如下所示。

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

OnWndMsg 函数(wincore.cpp

BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	LRESULT lResult = 0;
	union MessageMapFunctions mmf;
	mmf.pfn = 0;
	CInternalGlobalLock winMsgLock;
	// special case for commands
	if (message == WM_COMMAND)
	{
		if (OnCommand(wParam, lParam))
		{
			lResult = 1;
			goto LReturnTrue;
		}
		return FALSE;
	}
 
	if (message == WM_CREATE && m_pDynamicLayout != NULL)
	{
		ASSERT_VALID(m_pDynamicLayout);
 
		if (!m_pDynamicLayout->Create(this))
		{
			delete m_pDynamicLayout;
			m_pDynamicLayout = NULL;
		}
		else
		{
			InitDynamicLayout();
		}
	}
 
	// special case for notifies
	if (message == WM_NOTIFY)
	{
		NMHDR* pNMHDR = (NMHDR*)lParam;
		if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))
			goto LReturnTrue;
		return FALSE;
	}
 
	// special case for activation
	if (message == WM_ACTIVATE)
		_AfxHandleActivate(this, wParam, CWnd::FromHandle((HWND)lParam));
 
	// special case for set cursor HTERROR
	if (message == WM_SETCURSOR &&
		_AfxHandleSetCursor(this, (short)LOWORD(lParam), HIWORD(lParam)))
	{
		lResult = 1;
		goto LReturnTrue;
	}
 
   // special case for windows that contain windowless ActiveX controls
   BOOL bHandled;
 
   bHandled = FALSE;
   if ((m_pCtrlCont != NULL) && (m_pCtrlCont->m_nWindowlessControls > 0))
   {
	  if (((message >= WM_MOUSEFIRST) && (message <= AFX_WM_MOUSELAST)) ||
		 ((message >= WM_KEYFIRST) && (message <= WM_IME_KEYLAST)) ||
		 ((message >= WM_IME_SETCONTEXT) && (message <= WM_IME_KEYUP)))
	  {
		 bHandled = m_pCtrlCont->HandleWindowlessMessage(message, wParam, lParam, &lResult);
	  }
   }
   if (bHandled)
   {
	  goto LReturnTrue;
   }
 
	switch (message)
	{
	case WM_SIZE:
		{
			ResizeDynamicLayout();
 
			CHwndRenderTarget* pRenderTarget = GetRenderTarget();
			if (pRenderTarget != NULL && pRenderTarget->IsValid())
			{
				pRenderTarget->Resize(CD2DSizeU(UINT32(LOWORD(lParam)), UINT32(HIWORD(lParam))));
				RedrawWindow();
			}
		}
		break;
 
	case WM_PAINT:
		if (DoD2DPaint())
		{
			lResult = 1;
			goto LReturnTrue;
		}
		break;
 
	case WM_ERASEBKGND:
		if (m_pRenderTarget != NULL && m_pRenderTarget->IsValid())
		{
			lResult = 1;
			goto LReturnTrue;
		}
		break;
	}
 
	const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
	UINT iHash; iHash = (LOWORD((DWORD_PTR)pMessageMap) ^ message) & (iHashMax-1);
	winMsgLock.Lock(CRIT_WINMSGCACHE);
	AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash];
	const AFX_MSGMAP_ENTRY* lpEntry;
	if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)
	{
		// cache hit
		lpEntry = pMsgCache->lpEntry;
		winMsgLock.Unlock();
		if (lpEntry == NULL)
			return FALSE;
 
		// cache hit, and it needs to be handled
		if (message < 0xC000)
			goto LDispatch;
		else
			goto LDispatchRegistered;
	}
	else
	{
		// not in cache, look for it
		pMsgCache->nMsg = message;
		pMsgCache->pMessageMap = pMessageMap;
 
		for (/* pMessageMap already init'ed */; pMessageMap->pfnGetBaseMap != NULL;
			pMessageMap = (*pMessageMap->pfnGetBaseMap)())
		{
			// Note: catch not so common but fatal mistake!!
			//      BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd)
			ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
			if (message < 0xC000)
			{
				// constant window message
				if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
					message, 0, 0)) != NULL)
				{
					pMsgCache->lpEntry = lpEntry;
					winMsgLock.Unlock();
					goto LDispatch;
				}
			}
			else
			{
				// registered windows message
				lpEntry = pMessageMap->lpEntries;
				while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)
				{
					UINT* pnID = (UINT*)(lpEntry->nSig);
					ASSERT(*pnID >= 0xC000 || *pnID == 0);
						// must be successfully registered
					if (*pnID == message)
					{
						pMsgCache->lpEntry = lpEntry;
						winMsgLock.Unlock();
						goto LDispatchRegistered;
					}
					lpEntry++;      // keep looking past this one
				}
			}
		}
 
		pMsgCache->lpEntry = NULL;
		winMsgLock.Unlock();
		return FALSE;
	}
 
LDispatch:
	ASSERT(message < 0xC000);
 
	mmf.pfn = lpEntry->pfn;
 
	switch (lpEntry->nSig)
	{
	default:
		ASSERT(FALSE);
		break;
	case AfxSig_l_p:
		{
			CPoint point(lParam);
			lResult = (this->*mmf.pfn_l_p)(point);
			break;
		}
	case AfxSig_b_D_v:
		lResult = (this->*mmf.pfn_b_D)(CDC::FromHandle(reinterpret_cast<HDC>(wParam)));
		break;
 
	case AfxSig_l_D_u:
		lResult = (this->*mmf.pfn_l_D_u)(CDC::FromHandle(reinterpret_cast<HDC>(wParam)), (UINT)lParam);
		break;
 
	case AfxSig_b_b_v:
		lResult = (this->*mmf.pfn_b_b)(static_cast<BOOL>(wParam));
		break;
 
	case AfxSig_b_u_v:
		lResult = (this->*mmf.pfn_b_u)(static_cast<UINT>(wParam));
		break;
 
	case AfxSig_b_h_v:
		lResult = (this->*mmf.pfn_b_h)(reinterpret_cast<HANDLE>(wParam));
		break;
 
	case AfxSig_i_u_v:
		lResult = (this->*mmf.pfn_i_u)(static_cast<UINT>(wParam));
		break;
 
	case AfxSig_C_v_v:
		lResult = reinterpret_cast<LRESULT>((this->*mmf.pfn_C_v)());
		break;
 
	case AfxSig_v_u_W:
		(this->*mmf.pfn_v_u_W)(static_cast<UINT>(wParam),
			CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
		break;
 
	case AfxSig_u_u_v:
		lResult = (this->*mmf.pfn_u_u)(static_cast<UINT>(wParam));
		break;
 
	case AfxSig_b_v_v:
		lResult = (this->*mmf.pfn_b_v)();
		break;
 
	case AfxSig_b_W_uu:
		lResult = (this->*mmf.pfn_b_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
			LOWORD(lParam), HIWORD(lParam));
		break;
 
	case AfxSig_b_W_COPYDATASTRUCT:
		lResult = (this->*mmf.pfn_b_W_COPYDATASTRUCT)(
			CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
			reinterpret_cast<COPYDATASTRUCT*>(lParam));
		break;
 
	case AfxSig_b_v_HELPINFO:
		lResult = (this->*mmf.pfn_b_HELPINFO)(reinterpret_cast<LPHELPINFO>(lParam));
		break;
 
	case AfxSig_CTLCOLOR:
		{
			// special case for OnCtlColor to avoid too many temporary objects
			ASSERT(message == WM_CTLCOLOR);
			AFX_CTLCOLOR* pCtl = reinterpret_cast<AFX_CTLCOLOR*>(lParam);
			CDC dcTemp;
			dcTemp.m_hDC = pCtl->hDC;
			CWnd wndTemp;
			wndTemp.m_hWnd = pCtl->hWnd;
			UINT nCtlType = pCtl->nCtlType;
			// if not coming from a permanent window, use stack temporary
			CWnd* pWnd = CWnd::FromHandlePermanent(wndTemp.m_hWnd);
			if (pWnd == NULL)
			{
				// determine the site of the OLE control if it is one
				COleControlSite* pSite;
				if (m_pCtrlCont != NULL && (pSite = (COleControlSite*)
					m_pCtrlCont->m_siteMap.GetValueAt(wndTemp.m_hWnd)) != NULL)
				{
					wndTemp.m_pCtrlSite = pSite;
				}
 
				pWnd = &wndTemp;
			}
			HBRUSH hbr = (this->*mmf.pfn_B_D_W_u)(&dcTemp, pWnd, nCtlType);
			// fast detach of temporary objects
			dcTemp.m_hDC = NULL;
			wndTemp.m_hWnd = NULL;
			lResult = reinterpret_cast<LRESULT>(hbr);
		}
		break;
 
	case AfxSig_CTLCOLOR_REFLECT:
		{
			// special case for CtlColor to avoid too many temporary objects
			ASSERT(message == WM_REFLECT_BASE+WM_CTLCOLOR);
			AFX_CTLCOLOR* pCtl = reinterpret_cast<AFX_CTLCOLOR*>(lParam);
			CDC dcTemp;
			dcTemp.m_hDC = pCtl->hDC;
			UINT nCtlType = pCtl->nCtlType;
			HBRUSH hbr = (this->*mmf.pfn_B_D_u)(&dcTemp, nCtlType);
			// fast detach of temporary objects
			dcTemp.m_hDC = NULL;
			lResult = reinterpret_cast<LRESULT>(hbr);
		}
		break;
 
	case AfxSig_i_u_W_u:
		lResult = (this->*mmf.pfn_i_u_W_u)(LOWORD(wParam),
			CWnd::FromHandle(reinterpret_cast<HWND>(lParam)), HIWORD(wParam));
		break;
 
	case AfxSig_i_uu_v:
		lResult = (this->*mmf.pfn_i_u_u)(LOWORD(wParam), HIWORD(wParam));
		break;
 
	case AfxSig_i_W_uu:
		lResult = (this->*mmf.pfn_i_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
			LOWORD(lParam), HIWORD(lParam));
		break;
 
	case AfxSig_i_v_s:
		lResult = (this->*mmf.pfn_i_s)(reinterpret_cast<LPTSTR>(lParam));
		break;
 
	case AfxSig_i_v_S:
		lResult = (this->*mmf.pfn_i_S)(reinterpret_cast<LPCTSTR>(lParam));
		break;
 
	case AfxSig_v_F_b:
		(this->*mmf.pfn_v_F_b)(CFont::FromHandle(reinterpret_cast<HFONT>(wParam)), (BOOL)LOWORD(lParam));
		break;
 
	case AfxSig_h_v_v:
		{
			HANDLE handle = (this->*mmf.pfn_h_v)();
			lResult = reinterpret_cast<LRESULT>(handle);
		}
		break;
 
	case AfxSig_h_b_h:
		{
			HANDLE handle = (this->*mmf.pfn_h_b_h)(static_cast<BOOL>(wParam), reinterpret_cast<HANDLE>(lParam));
			lResult = reinterpret_cast<LRESULT>(handle);
		}
		break;
 
	case AfxSig_h_h_h:
		{
			HANDLE handle = (this->*mmf.pfn_h_h_h)(reinterpret_cast<HANDLE>(wParam), reinterpret_cast<HANDLE>(lParam));
			lResult = reinterpret_cast<LRESULT>(handle);
		}
		break;
 
	case AfxSig_l_w_l:
		lResult = (this->*mmf.pfn_l_w_l)(wParam, lParam);
		break;
 
	case AfxSig_l_uu_M:
		lResult = (this->*mmf.pfn_l_u_u_M)(LOWORD(wParam), HIWORD(wParam),
			CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
		break;
 
	case AfxSig_v_b_h:
	    (this->*mmf.pfn_v_b_h)(static_cast<BOOL>(wParam),
			reinterpret_cast<HANDLE>(lParam));
		break;
 
	case AfxSig_v_h_v:
	    (this->*mmf.pfn_v_h)(reinterpret_cast<HANDLE>(wParam));
		break;
 
	case AfxSig_v_h_h:
	    (this->*mmf.pfn_v_h_h)(reinterpret_cast<HANDLE>(wParam),
			reinterpret_cast<HANDLE>(lParam));
		break;
 
	case AfxSig_v_v_v:
		(this->*mmf.pfn_v_v)();
		break;
 
	case AfxSig_v_u_v:
		(this->*mmf.pfn_v_u)(static_cast<UINT>(wParam));
		break;
 
	case AfxSig_v_up_v:
		(this->*mmf.pfn_v_up)(static_cast<UINT_PTR>(wParam));
		break;
 
	case AfxSig_v_u_u:
		(this->*mmf.pfn_v_u_u)(static_cast<UINT>(wParam), static_cast<UINT>(lParam));
		break;
 
	case AfxSig_v_uu_v:
		(this->*mmf.pfn_v_u_u)(LOWORD(wParam), HIWORD(wParam));
		break;
 
	case AfxSig_v_v_ii:
		(this->*mmf.pfn_v_i_i)(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		break;
 
	case AfxSig_v_u_uu:
		(this->*mmf.pfn_v_u_u_u)(static_cast<UINT>(wParam), LOWORD(lParam), HIWORD(lParam));
		break;
 
	case AfxSig_v_u_ii:
		(this->*mmf.pfn_v_u_i_i)(static_cast<UINT>(wParam), LOWORD(lParam), HIWORD(lParam));
		break;
 
	case AfxSig_v_w_l:
		(this->*mmf.pfn_v_w_l)(wParam, lParam);
		break;
 
	case AfxSig_MDIACTIVATE:
		(this->*mmf.pfn_v_b_W_W)(m_hWnd == reinterpret_cast<HWND>(lParam),
			CWnd::FromHandle(reinterpret_cast<HWND>(lParam)),
			CWnd::FromHandle(reinterpret_cast<HWND>(wParam)));
		break;
 
	case AfxSig_MDINext:
		(this->*mmf.pfn_v_W_b)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), static_cast<BOOL>(lParam));
		break;
 
	case AfxSig_v_D_v:
		(this->*mmf.pfn_v_D)(CDC::FromHandle(reinterpret_cast<HDC>(wParam)));
		break;
 
	case AfxSig_v_M_v:
		(this->*mmf.pfn_v_M)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)));
		break;
 
	case AfxSig_v_M_ub:
		(this->*mmf.pfn_v_M_u_b)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)),
			GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		break;
 
	case AfxSig_v_W_v:
		(this->*mmf.pfn_v_W)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)));
		break;
 
	case AfxSig_v_v_W:
		(this->*mmf.pfn_v_W)(CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
		break;
 
	case AfxSig_v_W_uu:
		(this->*mmf.pfn_v_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), LOWORD(lParam),
			HIWORD(lParam));
		break;
 
	case AfxSig_v_W_p:
		{
			CPoint point(lParam);
			(this->*mmf.pfn_v_W_p)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), point);
		}
		break;
 
	case AfxSig_v_W_h:
		(this->*mmf.pfn_v_W_h)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
				reinterpret_cast<HANDLE>(lParam));
		break;
 
	case AfxSig_ACTIVATE:
		(this->*mmf.pfn_v_u_W_b)(LOWORD(wParam),
			CWnd::FromHandle(reinterpret_cast<HWND>(lParam)), HIWORD(wParam));
		break;
 
	case AfxSig_SCROLL:
	case AfxSig_SCROLL_REFLECT:
		{
			// special case for WM_VSCROLL and WM_HSCROLL
			ASSERT(message == WM_VSCROLL || message == WM_HSCROLL ||
				message == WM_VSCROLL+WM_REFLECT_BASE || message == WM_HSCROLL+WM_REFLECT_BASE);
			int nScrollCode = (short)LOWORD(wParam);
			int nPos = (short)HIWORD(wParam);
			if (lpEntry->nSig == AfxSig_SCROLL)
				(this->*mmf.pfn_v_u_u_W)(nScrollCode, nPos,
					CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
			else
				(this->*mmf.pfn_v_u_u)(nScrollCode, nPos);
		}
		break;
 
	case AfxSig_v_v_s:
		(this->*mmf.pfn_v_s)(reinterpret_cast<LPTSTR>(lParam));
		break;
 
	case AfxSig_v_u_cs:
		(this->*mmf.pfn_v_u_cs)(static_cast<UINT>(wParam), reinterpret_cast<LPCTSTR>(lParam));
		break;
 
	case AfxSig_OWNERDRAW:
		(this->*mmf.pfn_v_i_s)(static_cast<int>(wParam), reinterpret_cast<LPTSTR>(lParam));
		lResult = TRUE;
		break;
 
	case AfxSig_i_i_s:
		lResult = (this->*mmf.pfn_i_i_s)(static_cast<int>(wParam), reinterpret_cast<LPTSTR>(lParam));
		break;
 
	case AfxSig_u_v_p:
		{
			CPoint point(lParam);
			lResult = (this->*mmf.pfn_u_p)(point);
		}
		break;
 
	case AfxSig_u_v_v:
		lResult = (this->*mmf.pfn_u_v)();
		break;
 
	case AfxSig_v_b_NCCALCSIZEPARAMS:
		(this->*mmf.pfn_v_b_NCCALCSIZEPARAMS)(static_cast<BOOL>(wParam),
			reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam));
		break;
 
	case AfxSig_v_v_WINDOWPOS:
		(this->*mmf.pfn_v_v_WINDOWPOS)(reinterpret_cast<WINDOWPOS*>(lParam));
		break;
 
	case AfxSig_v_uu_M:
		(this->*mmf.pfn_v_u_u_M)(LOWORD(wParam), HIWORD(wParam), reinterpret_cast<HMENU>(lParam));
		break;
 
	case AfxSig_v_u_p:
		{
			CPoint point(lParam);
			(this->*mmf.pfn_v_u_p)(static_cast<UINT>(wParam), point);
		}
		break;
 
	case AfxSig_SIZING:
		(this->*mmf.pfn_v_u_pr)(static_cast<UINT>(wParam), reinterpret_cast<LPRECT>(lParam));
		lResult = TRUE;
		break;
 
	case AfxSig_MOUSEWHEEL:
		lResult = (this->*mmf.pfn_b_u_s_p)(LOWORD(wParam), (short)HIWORD(wParam),
			CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
		if (!lResult)
			return FALSE;
		break;
	case AfxSig_MOUSEHWHEEL:
		(this->*mmf.pfn_MOUSEHWHEEL)(LOWORD(wParam), (short)HIWORD(wParam),
			CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
		break;
	case AfxSig_l:
		lResult = (this->*mmf.pfn_l_v)();
		if (lResult != 0)
			return FALSE;
		break;
	case AfxSig_u_W_u:
		lResult = (this->*mmf.pfn_u_W_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), static_cast<UINT>(lParam));
		break;
	case AfxSig_v_u_M:
		(this->*mmf.pfn_v_u_M)(static_cast<UINT>(wParam), CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
		break;
	case AfxSig_u_u_M:
		lResult = (this->*mmf.pfn_u_u_M)(static_cast<UINT>(wParam), CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
		break;
	case AfxSig_u_v_MENUGETOBJECTINFO:
		lResult = (this->*mmf.pfn_u_v_MENUGETOBJECTINFO)(reinterpret_cast<MENUGETOBJECTINFO*>(lParam));
		break;
	case AfxSig_v_M_u:
		(this->*mmf.pfn_v_M_u)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)), static_cast<UINT>(lParam));
		break;
	case AfxSig_v_u_LPMDINEXTMENU:
		(this->*mmf.pfn_v_u_LPMDINEXTMENU)(static_cast<UINT>(wParam), reinterpret_cast<LPMDINEXTMENU>(lParam));
		break;
	case AfxSig_APPCOMMAND:
		(this->*mmf.pfn_APPCOMMAND)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), static_cast<UINT>(GET_APPCOMMAND_LPARAM(lParam)), static_cast<UINT>(GET_DEVICE_LPARAM(lParam)), static_cast<UINT>(GET_KEYSTATE_LPARAM(lParam)));
		lResult = TRUE;
		break;
	case AfxSig_RAWINPUT:
		(this->*mmf.pfn_RAWINPUT)(static_cast<UINT>(GET_RAWINPUT_CODE_WPARAM(wParam)), reinterpret_cast<HRAWINPUT>(lParam));
		break;
	case AfxSig_u_u_u:
		lResult = (this->*mmf.pfn_u_u_u)(static_cast<UINT>(wParam), static_cast<UINT>(lParam));
		break;
	case AfxSig_u_u_l:
		lResult = (this->*mmf.pfn_u_u_l)(static_cast<UINT>(wParam), lParam);
		break;
	case AfxSig_MOUSE_XBUTTON:
		(this->*mmf.pfn_MOUSE_XBUTTON)(static_cast<UINT>(GET_KEYSTATE_WPARAM(wParam)), static_cast<UINT>(GET_XBUTTON_WPARAM(wParam)), CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
		lResult = TRUE;
		break;
	case AfxSig_MOUSE_NCXBUTTON:
		(this->*mmf.pfn_MOUSE_NCXBUTTON)(static_cast<short>(GET_NCHITTEST_WPARAM(wParam)), static_cast<UINT>(GET_XBUTTON_WPARAM(wParam)), CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
		lResult = TRUE;
		break;
	case AfxSig_INPUTLANGCHANGE:
		(this->*mmf.pfn_INPUTLANGCHANGE)(static_cast<UINT>(wParam), static_cast<UINT>(lParam));
		lResult = TRUE;
		break;
	case AfxSig_INPUTDEVICECHANGE:
		(this->*mmf.pfn_INPUTDEVICECHANGE)(LOWORD(wParam), reinterpret_cast<HANDLE>(lParam));
		break;
	case AfxSig_v_u_hkl:
		(this->*mmf.pfn_v_u_h)(static_cast<UINT>(wParam), reinterpret_cast<HKL>(lParam));
		break;
	case AfxSig_b_v_ii:
		lResult = (this->*mmf.pfn_b_v_ii)(GET_Y_LPARAM(lParam), GET_X_LPARAM(lParam));
		break;
	}
	goto LReturnTrue;
 
LDispatchRegistered:    // for registered windows messages
	ASSERT(message >= 0xC000);
	ASSERT(sizeof(mmf) == sizeof(mmf.pfn));
	mmf.pfn = lpEntry->pfn;
	lResult = (this->*mmf.pfn_l_w_l)(wParam, lParam);
 
LReturnTrue:
	if (pResult != NULL)
		*pResult = lResult;
	return TRUE;
}

OnWndMsg函数的处理过程是:

  • 判断消息是否有消息响应函数。
  • 判断方法是在消息映射表中进行查找。
  • 如果找到了,则直接通过传递给WindowProc函数的窗口子类指针调用子类中的消息响应函数。
  • 如果在子类中没有找到消息响应函数,那么就交由基类进行处理。
  • 而消息映射表就是通过头文件中的DECLARE_MESSAGE_MAP()宏,以及源文件中的BEGIN_MESSAGE_MAP(…)和END_MESSAGE_MAP()宏构建的,在这两个宏之间的每个消息映射宏都将作为消息映射表的一个条目。

通过以上步骤,MFC就实现了具体的消息映射,从而完成对消息的响应。

OnWndMsg 函数(wincore.cpp)

BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	LRESULT lResult = 0;
	union MessageMapFunctions mmf;
	mmf.pfn = 0;
	CInternalGlobalLock winMsgLock;
	// special case for commands
	if (message == WM_COMMAND)
	{
		if (OnCommand(wParam, lParam))
		{
			lResult = 1;
			goto LReturnTrue;
		}
		return FALSE;
	}
 
	if (message == WM_CREATE && m_pDynamicLayout != NULL)
	{
		ASSERT_VALID(m_pDynamicLayout);
 
		if (!m_pDynamicLayout->Create(this))
		{
			delete m_pDynamicLayout;
			m_pDynamicLayout = NULL;
		}
		else
		{
			InitDynamicLayout();
		}
	}
 
	// special case for notifies
	if (message == WM_NOTIFY)
	{
		NMHDR* pNMHDR = (NMHDR*)lParam;
		if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))
			goto LReturnTrue;
		return FALSE;
	}
 
	// special case for activation
	if (message == WM_ACTIVATE)
		_AfxHandleActivate(this, wParam, CWnd::FromHandle((HWND)lParam));
 
	// special case for set cursor HTERROR
	if (message == WM_SETCURSOR &&
		_AfxHandleSetCursor(this, (short)LOWORD(lParam), HIWORD(lParam)))
	{
		lResult = 1;
		goto LReturnTrue;
	}
 
   // special case for windows that contain windowless ActiveX controls
   BOOL bHandled;
 
   bHandled = FALSE;
   if ((m_pCtrlCont != NULL) && (m_pCtrlCont->m_nWindowlessControls > 0))
   {
	  if (((message >= WM_MOUSEFIRST) && (message <= AFX_WM_MOUSELAST)) ||
		 ((message >= WM_KEYFIRST) && (message <= WM_IME_KEYLAST)) ||
		 ((message >= WM_IME_SETCONTEXT) && (message <= WM_IME_KEYUP)))
	  {
		 bHandled = m_pCtrlCont->HandleWindowlessMessage(message, wParam, lParam, &lResult);
	  }
   }
   if (bHandled)
   {
	  goto LReturnTrue;
   }
 
	switch (message)
	{
	case WM_SIZE:
		{
			ResizeDynamicLayout();
 
			CHwndRenderTarget* pRenderTarget = GetRenderTarget();
			if (pRenderTarget != NULL && pRenderTarget->IsValid())
			{
				pRenderTarget->Resize(CD2DSizeU(UINT32(LOWORD(lParam)), UINT32(HIWORD(lParam))));
				RedrawWindow();
			}
		}
		break;
 
	case WM_PAINT:
		if (DoD2DPaint())
		{
			lResult = 1;
			goto LReturnTrue;
		}
		break;
 
	case WM_ERASEBKGND:
		if (m_pRenderTarget != NULL && m_pRenderTarget->IsValid())
		{
			lResult = 1;
			goto LReturnTrue;
		}
		break;
	}
 
	const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
	UINT iHash; iHash = (LOWORD((DWORD_PTR)pMessageMap) ^ message) & (iHashMax-1);
	winMsgLock.Lock(CRIT_WINMSGCACHE);
	AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash];
	const AFX_MSGMAP_ENTRY* lpEntry;
	if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)
	{
		// cache hit
		lpEntry = pMsgCache->lpEntry;
		winMsgLock.Unlock();
		if (lpEntry == NULL)
			return FALSE;
 
		// cache hit, and it needs to be handled
		if (message < 0xC000)
			goto LDispatch;
		else
			goto LDispatchRegistered;
	}
	else
	{
		// not in cache, look for it
		pMsgCache->nMsg = message;
		pMsgCache->pMessageMap = pMessageMap;
 
		for (/* pMessageMap already init'ed */; pMessageMap->pfnGetBaseMap != NULL;
			pMessageMap = (*pMessageMap->pfnGetBaseMap)())
		{
			// Note: catch not so common but fatal mistake!!
			//      BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd)
			ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
			if (message < 0xC000)
			{
				// constant window message
				if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
					message, 0, 0)) != NULL)
				{
					pMsgCache->lpEntry = lpEntry;
					winMsgLock.Unlock();
					goto LDispatch;
				}
			}
			else
			{
				// registered windows message
				lpEntry = pMessageMap->lpEntries;
				while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)
				{
					UINT* pnID = (UINT*)(lpEntry->nSig);
					ASSERT(*pnID >= 0xC000 || *pnID == 0);
						// must be successfully registered
					if (*pnID == message)
					{
						pMsgCache->lpEntry = lpEntry;
						winMsgLock.Unlock();
						goto LDispatchRegistered;
					}
					lpEntry++;      // keep looking past this one
				}
			}
		}
 
		pMsgCache->lpEntry = NULL;
		winMsgLock.Unlock();
		return FALSE;
	}
 
LDispatch:
	ASSERT(message < 0xC000);
 
	mmf.pfn = lpEntry->pfn;
 
	switch (lpEntry->nSig)
	{
	default:
		ASSERT(FALSE);
		break;
	case AfxSig_l_p:
		{
			CPoint point(lParam);
			lResult = (this->*mmf.pfn_l_p)(point);
			break;
		}
	case AfxSig_b_D_v:
		lResult = (this->*mmf.pfn_b_D)(CDC::FromHandle(reinterpret_cast<HDC>(wParam)));
		break;
 
	case AfxSig_l_D_u:
		lResult = (this->*mmf.pfn_l_D_u)(CDC::FromHandle(reinterpret_cast<HDC>(wParam)), (UINT)lParam);
		break;
 
	case AfxSig_b_b_v:
		lResult = (this->*mmf.pfn_b_b)(static_cast<BOOL>(wParam));
		break;
 
	case AfxSig_b_u_v:
		lResult = (this->*mmf.pfn_b_u)(static_cast<UINT>(wParam));
		break;
 
	case AfxSig_b_h_v:
		lResult = (this->*mmf.pfn_b_h)(reinterpret_cast<HANDLE>(wParam));
		break;
 
	case AfxSig_i_u_v:
		lResult = (this->*mmf.pfn_i_u)(static_cast<UINT>(wParam));
		break;
 
	case AfxSig_C_v_v:
		lResult = reinterpret_cast<LRESULT>((this->*mmf.pfn_C_v)());
		break;
 
	case AfxSig_v_u_W:
		(this->*mmf.pfn_v_u_W)(static_cast<UINT>(wParam),
			CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
		break;
 
	case AfxSig_u_u_v:
		lResult = (this->*mmf.pfn_u_u)(static_cast<UINT>(wParam));
		break;
 
	case AfxSig_b_v_v:
		lResult = (this->*mmf.pfn_b_v)();
		break;
 
	case AfxSig_b_W_uu:
		lResult = (this->*mmf.pfn_b_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
			LOWORD(lParam), HIWORD(lParam));
		break;
 
	case AfxSig_b_W_COPYDATASTRUCT:
		lResult = (this->*mmf.pfn_b_W_COPYDATASTRUCT)(
			CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
			reinterpret_cast<COPYDATASTRUCT*>(lParam));
		break;
 
	case AfxSig_b_v_HELPINFO:
		lResult = (this->*mmf.pfn_b_HELPINFO)(reinterpret_cast<LPHELPINFO>(lParam));
		break;
 
	case AfxSig_CTLCOLOR:
		{
			// special case for OnCtlColor to avoid too many temporary objects
			ASSERT(message == WM_CTLCOLOR);
			AFX_CTLCOLOR* pCtl = reinterpret_cast<AFX_CTLCOLOR*>(lParam);
			CDC dcTemp;
			dcTemp.m_hDC = pCtl->hDC;
			CWnd wndTemp;
			wndTemp.m_hWnd = pCtl->hWnd;
			UINT nCtlType = pCtl->nCtlType;
			// if not coming from a permanent window, use stack temporary
			CWnd* pWnd = CWnd::FromHandlePermanent(wndTemp.m_hWnd);
			if (pWnd == NULL)
			{
				// determine the site of the OLE control if it is one
				COleControlSite* pSite;
				if (m_pCtrlCont != NULL && (pSite = (COleControlSite*)
					m_pCtrlCont->m_siteMap.GetValueAt(wndTemp.m_hWnd)) != NULL)
				{
					wndTemp.m_pCtrlSite = pSite;
				}
 
				pWnd = &wndTemp;
			}
			HBRUSH hbr = (this->*mmf.pfn_B_D_W_u)(&dcTemp, pWnd, nCtlType);
			// fast detach of temporary objects
			dcTemp.m_hDC = NULL;
			wndTemp.m_hWnd = NULL;
			lResult = reinterpret_cast<LRESULT>(hbr);
		}
		break;
 
	case AfxSig_CTLCOLOR_REFLECT:
		{
			// special case for CtlColor to avoid too many temporary objects
			ASSERT(message == WM_REFLECT_BASE+WM_CTLCOLOR);
			AFX_CTLCOLOR* pCtl = reinterpret_cast<AFX_CTLCOLOR*>(lParam);
			CDC dcTemp;
			dcTemp.m_hDC = pCtl->hDC;
			UINT nCtlType = pCtl->nCtlType;
			HBRUSH hbr = (this->*mmf.pfn_B_D_u)(&dcTemp, nCtlType);
			// fast detach of temporary objects
			dcTemp.m_hDC = NULL;
			lResult = reinterpret_cast<LRESULT>(hbr);
		}
		break;
 
	case AfxSig_i_u_W_u:
		lResult = (this->*mmf.pfn_i_u_W_u)(LOWORD(wParam),
			CWnd::FromHandle(reinterpret_cast<HWND>(lParam)), HIWORD(wParam));
		break;
 
	case AfxSig_i_uu_v:
		lResult = (this->*mmf.pfn_i_u_u)(LOWORD(wParam), HIWORD(wParam));
		break;
 
	case AfxSig_i_W_uu:
		lResult = (this->*mmf.pfn_i_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
			LOWORD(lParam), HIWORD(lParam));
		break;
 
	case AfxSig_i_v_s:
		lResult = (this->*mmf.pfn_i_s)(reinterpret_cast<LPTSTR>(lParam));
		break;
 
	case AfxSig_i_v_S:
		lResult = (this->*mmf.pfn_i_S)(reinterpret_cast<LPCTSTR>(lParam));
		break;
 
	case AfxSig_v_F_b:
		(this->*mmf.pfn_v_F_b)(CFont::FromHandle(reinterpret_cast<HFONT>(wParam)), (BOOL)LOWORD(lParam));
		break;
 
	case AfxSig_h_v_v:
		{
			HANDLE handle = (this->*mmf.pfn_h_v)();
			lResult = reinterpret_cast<LRESULT>(handle);
		}
		break;
 
	case AfxSig_h_b_h:
		{
			HANDLE handle = (this->*mmf.pfn_h_b_h)(static_cast<BOOL>(wParam), reinterpret_cast<HANDLE>(lParam));
			lResult = reinterpret_cast<LRESULT>(handle);
		}
		break;
 
	case AfxSig_h_h_h:
		{
			HANDLE handle = (this->*mmf.pfn_h_h_h)(reinterpret_cast<HANDLE>(wParam), reinterpret_cast<HANDLE>(lParam));
			lResult = reinterpret_cast<LRESULT>(handle);
		}
		break;
 
	case AfxSig_l_w_l:
		lResult = (this->*mmf.pfn_l_w_l)(wParam, lParam);
		break;
 
	case AfxSig_l_uu_M:
		lResult = (this->*mmf.pfn_l_u_u_M)(LOWORD(wParam), HIWORD(wParam),
			CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
		break;
 
	case AfxSig_v_b_h:
	    (this->*mmf.pfn_v_b_h)(static_cast<BOOL>(wParam),
			reinterpret_cast<HANDLE>(lParam));
		break;
 
	case AfxSig_v_h_v:
	    (this->*mmf.pfn_v_h)(reinterpret_cast<HANDLE>(wParam));
		break;
 
	case AfxSig_v_h_h:
	    (this->*mmf.pfn_v_h_h)(reinterpret_cast<HANDLE>(wParam),
			reinterpret_cast<HANDLE>(lParam));
		break;
 
	case AfxSig_v_v_v:
		(this->*mmf.pfn_v_v)();
		break;
 
	case AfxSig_v_u_v:
		(this->*mmf.pfn_v_u)(static_cast<UINT>(wParam));
		break;
 
	case AfxSig_v_up_v:
		(this->*mmf.pfn_v_up)(static_cast<UINT_PTR>(wParam));
		break;
 
	case AfxSig_v_u_u:
		(this->*mmf.pfn_v_u_u)(static_cast<UINT>(wParam), static_cast<UINT>(lParam));
		break;
 
	case AfxSig_v_uu_v:
		(this->*mmf.pfn_v_u_u)(LOWORD(wParam), HIWORD(wParam));
		break;
 
	case AfxSig_v_v_ii:
		(this->*mmf.pfn_v_i_i)(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		break;
 
	case AfxSig_v_u_uu:
		(this->*mmf.pfn_v_u_u_u)(static_cast<UINT>(wParam), LOWORD(lParam), HIWORD(lParam));
		break;
 
	case AfxSig_v_u_ii:
		(this->*mmf.pfn_v_u_i_i)(static_cast<UINT>(wParam), LOWORD(lParam), HIWORD(lParam));
		break;
 
	case AfxSig_v_w_l:
		(this->*mmf.pfn_v_w_l)(wParam, lParam);
		break;
 
	case AfxSig_MDIACTIVATE:
		(this->*mmf.pfn_v_b_W_W)(m_hWnd == reinterpret_cast<HWND>(lParam),
			CWnd::FromHandle(reinterpret_cast<HWND>(lParam)),
			CWnd::FromHandle(reinterpret_cast<HWND>(wParam)));
		break;
 
	case AfxSig_MDINext:
		(this->*mmf.pfn_v_W_b)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), static_cast<BOOL>(lParam));
		break;
 
	case AfxSig_v_D_v:
		(this->*mmf.pfn_v_D)(CDC::FromHandle(reinterpret_cast<HDC>(wParam)));
		break;
 
	case AfxSig_v_M_v:
		(this->*mmf.pfn_v_M)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)));
		break;
 
	case AfxSig_v_M_ub:
		(this->*mmf.pfn_v_M_u_b)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)),
			GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		break;
 
	case AfxSig_v_W_v:
		(this->*mmf.pfn_v_W)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)));
		break;
 
	case AfxSig_v_v_W:
		(this->*mmf.pfn_v_W)(CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
		break;
 
	case AfxSig_v_W_uu:
		(this->*mmf.pfn_v_W_u_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), LOWORD(lParam),
			HIWORD(lParam));
		break;
 
	case AfxSig_v_W_p:
		{
			CPoint point(lParam);
			(this->*mmf.pfn_v_W_p)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), point);
		}
		break;
 
	case AfxSig_v_W_h:
		(this->*mmf.pfn_v_W_h)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)),
				reinterpret_cast<HANDLE>(lParam));
		break;
 
	case AfxSig_ACTIVATE:
		(this->*mmf.pfn_v_u_W_b)(LOWORD(wParam),
			CWnd::FromHandle(reinterpret_cast<HWND>(lParam)), HIWORD(wParam));
		break;
 
	case AfxSig_SCROLL:
	case AfxSig_SCROLL_REFLECT:
		{
			// special case for WM_VSCROLL and WM_HSCROLL
			ASSERT(message == WM_VSCROLL || message == WM_HSCROLL ||
				message == WM_VSCROLL+WM_REFLECT_BASE || message == WM_HSCROLL+WM_REFLECT_BASE);
			int nScrollCode = (short)LOWORD(wParam);
			int nPos = (short)HIWORD(wParam);
			if (lpEntry->nSig == AfxSig_SCROLL)
				(this->*mmf.pfn_v_u_u_W)(nScrollCode, nPos,
					CWnd::FromHandle(reinterpret_cast<HWND>(lParam)));
			else
				(this->*mmf.pfn_v_u_u)(nScrollCode, nPos);
		}
		break;
 
	case AfxSig_v_v_s:
		(this->*mmf.pfn_v_s)(reinterpret_cast<LPTSTR>(lParam));
		break;
 
	case AfxSig_v_u_cs:
		(this->*mmf.pfn_v_u_cs)(static_cast<UINT>(wParam), reinterpret_cast<LPCTSTR>(lParam));
		break;
 
	case AfxSig_OWNERDRAW:
		(this->*mmf.pfn_v_i_s)(static_cast<int>(wParam), reinterpret_cast<LPTSTR>(lParam));
		lResult = TRUE;
		break;
 
	case AfxSig_i_i_s:
		lResult = (this->*mmf.pfn_i_i_s)(static_cast<int>(wParam), reinterpret_cast<LPTSTR>(lParam));
		break;
 
	case AfxSig_u_v_p:
		{
			CPoint point(lParam);
			lResult = (this->*mmf.pfn_u_p)(point);
		}
		break;
 
	case AfxSig_u_v_v:
		lResult = (this->*mmf.pfn_u_v)();
		break;
 
	case AfxSig_v_b_NCCALCSIZEPARAMS:
		(this->*mmf.pfn_v_b_NCCALCSIZEPARAMS)(static_cast<BOOL>(wParam),
			reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam));
		break;
 
	case AfxSig_v_v_WINDOWPOS:
		(this->*mmf.pfn_v_v_WINDOWPOS)(reinterpret_cast<WINDOWPOS*>(lParam));
		break;
 
	case AfxSig_v_uu_M:
		(this->*mmf.pfn_v_u_u_M)(LOWORD(wParam), HIWORD(wParam), reinterpret_cast<HMENU>(lParam));
		break;
 
	case AfxSig_v_u_p:
		{
			CPoint point(lParam);
			(this->*mmf.pfn_v_u_p)(static_cast<UINT>(wParam), point);
		}
		break;
 
	case AfxSig_SIZING:
		(this->*mmf.pfn_v_u_pr)(static_cast<UINT>(wParam), reinterpret_cast<LPRECT>(lParam));
		lResult = TRUE;
		break;
 
	case AfxSig_MOUSEWHEEL:
		lResult = (this->*mmf.pfn_b_u_s_p)(LOWORD(wParam), (short)HIWORD(wParam),
			CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
		if (!lResult)
			return FALSE;
		break;
	case AfxSig_MOUSEHWHEEL:
		(this->*mmf.pfn_MOUSEHWHEEL)(LOWORD(wParam), (short)HIWORD(wParam),
			CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
		break;
	case AfxSig_l:
		lResult = (this->*mmf.pfn_l_v)();
		if (lResult != 0)
			return FALSE;
		break;
	case AfxSig_u_W_u:
		lResult = (this->*mmf.pfn_u_W_u)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), static_cast<UINT>(lParam));
		break;
	case AfxSig_v_u_M:
		(this->*mmf.pfn_v_u_M)(static_cast<UINT>(wParam), CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
		break;
	case AfxSig_u_u_M:
		lResult = (this->*mmf.pfn_u_u_M)(static_cast<UINT>(wParam), CMenu::FromHandle(reinterpret_cast<HMENU>(lParam)));
		break;
	case AfxSig_u_v_MENUGETOBJECTINFO:
		lResult = (this->*mmf.pfn_u_v_MENUGETOBJECTINFO)(reinterpret_cast<MENUGETOBJECTINFO*>(lParam));
		break;
	case AfxSig_v_M_u:
		(this->*mmf.pfn_v_M_u)(CMenu::FromHandle(reinterpret_cast<HMENU>(wParam)), static_cast<UINT>(lParam));
		break;
	case AfxSig_v_u_LPMDINEXTMENU:
		(this->*mmf.pfn_v_u_LPMDINEXTMENU)(static_cast<UINT>(wParam), reinterpret_cast<LPMDINEXTMENU>(lParam));
		break;
	case AfxSig_APPCOMMAND:
		(this->*mmf.pfn_APPCOMMAND)(CWnd::FromHandle(reinterpret_cast<HWND>(wParam)), static_cast<UINT>(GET_APPCOMMAND_LPARAM(lParam)), static_cast<UINT>(GET_DEVICE_LPARAM(lParam)), static_cast<UINT>(GET_KEYSTATE_LPARAM(lParam)));
		lResult = TRUE;
		break;
	case AfxSig_RAWINPUT:
		(this->*mmf.pfn_RAWINPUT)(static_cast<UINT>(GET_RAWINPUT_CODE_WPARAM(wParam)), reinterpret_cast<HRAWINPUT>(lParam));
		break;
	case AfxSig_u_u_u:
		lResult = (this->*mmf.pfn_u_u_u)(static_cast<UINT>(wParam), static_cast<UINT>(lParam));
		break;
	case AfxSig_u_u_l:
		lResult = (this->*mmf.pfn_u_u_l)(static_cast<UINT>(wParam), lParam);
		break;
	case AfxSig_MOUSE_XBUTTON:
		(this->*mmf.pfn_MOUSE_XBUTTON)(static_cast<UINT>(GET_KEYSTATE_WPARAM(wParam)), static_cast<UINT>(GET_XBUTTON_WPARAM(wParam)), CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
		lResult = TRUE;
		break;
	case AfxSig_MOUSE_NCXBUTTON:
		(this->*mmf.pfn_MOUSE_NCXBUTTON)(static_cast<short>(GET_NCHITTEST_WPARAM(wParam)), static_cast<UINT>(GET_XBUTTON_WPARAM(wParam)), CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
		lResult = TRUE;
		break;
	case AfxSig_INPUTLANGCHANGE:
		(this->*mmf.pfn_INPUTLANGCHANGE)(static_cast<UINT>(wParam), static_cast<UINT>(lParam));
		lResult = TRUE;
		break;
	case AfxSig_INPUTDEVICECHANGE:
		(this->*mmf.pfn_INPUTDEVICECHANGE)(LOWORD(wParam), reinterpret_cast<HANDLE>(lParam));
		break;
	case AfxSig_v_u_hkl:
		(this->*mmf.pfn_v_u_h)(static_cast<UINT>(wParam), reinterpret_cast<HKL>(lParam));
		break;
	case AfxSig_b_v_ii:
		lResult = (this->*mmf.pfn_b_v_ii)(GET_Y_LPARAM(lParam), GET_X_LPARAM(lParam));
		break;
	}
	goto LReturnTrue;
 
LDispatchRegistered:    // for registered windows messages
	ASSERT(message >= 0xC000);
	ASSERT(sizeof(mmf) == sizeof(mmf.pfn));
	mmf.pfn = lpEntry->pfn;
	lResult = (this->*mmf.pfn_l_w_l)(wParam, lParam);
 
LReturnTrue:
	if (pResult != NULL)
		*pResult = lResult;
	return TRUE;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/528113.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Javase06|类和对象

Javase06|类和对象 文章目录 Javase06|类和对象1.面向对象的初步认识2.类的定义3.类的实例化4.this引用5.对象的构造及初始化6.封装7.static成员8.代码块 1.面向对象的初步认识 1.1对象的概念 Java是一门面向对象的语言&#xff0c;面向对象主要依靠对象之间的交互完成一件事…

审稿意见相互矛盾的11种可能情况及修改建议

遇到相互矛盾的审稿意见&#xff0c;作者很难不纠结&#xff0c;毕竟哪个审稿人都不想得罪&#xff0c;到底该怎么办呢&#xff1f; 虽然有些审稿意见乍一看上去相互矛盾&#xff0c;但深思之后&#xff0c;也能发现其中的共性或者根本问题。明确了这一点&#xff0c;就比较清楚…

<六> objectARX开发:创建、插入、删除图块

1、介绍 所有的实体都保存在块表记录中,而块表记录则存储在块表中。实际上,用户在AutoCAD中定义块相当于增加了一个块表记录,块表记录的名称就是块定义的名称。打开任意dwg文件,然后创建两个从图中可以看出,当前图形的块表中包含了五个记录: *Model_Space、 Paper_Space、…

Qt--基于TCP客户端与服务器的聊天程序(半双工通信)

目录 任务&#xff1a;实现一个基于TCP的聊天程序&#xff0c;需要使用的类有&#xff1a; QTcpServer ​编辑 QTcpSocket ​编辑 QTextStream 服务端&#xff1a;server&#xff08;QTcpServer&#xff09; 步骤&#xff1a; 代码&#xff1a; dialog.h dialog.cpp 客户端&am…

论文笔记:基于手机位置信息的地图匹配算法

2015计算机应用 整体思路和论文笔记&#xff1a;Hidden Markov Map MatchingThrough Noise and Sparseness_UQI-LIUWJ的博客-CSDN博客 很像&#xff0c;也是应用HMM进行地图匹配 HMMM本文 状态转移矩阵 观测概率矩阵 正态分布均值都是0&#xff0c;唯一不同的是S…

统计学习方法第五章——决策树

x.1 决策树前言 decision tree决策树是一种分类和回归的方法&#xff0c;本章只考虑在分类领域的使用。决策树使用了归纳法划分特征空间&#xff0c;以此来达到分类的目的。决策树不同于KNN中的kd树&#xff0c;它是多叉树&#xff0c;不是二叉树。决策树是一种概率模型。 决…

毕业2年,月薪25k,有时候人与人的差距比人和狗还大···

想起两年前交流过的一个应届生&#xff0c;当时他刚毕业技术水平不高&#xff0c;进了一个小公司做测试实习工作。最近联系上了&#xff0c;不问不知道&#xff0c;一问吓一跳&#xff0c;他现在已经进了某一线大厂&#xff0c;月薪25K。这位朋友其实也没比别人强多少&#xff…

原神服务端架构搭建工具+环境配置资料

原神服务端架构搭建工具环境配置资料 我是艾西&#xff0c;今天给大家分享一份详细的原神服务端结构资料教程&#xff0c;从服务端的获取到端口的使用以及安卓和ios的DAIL签名等一文让你明白怎么架设原神服务端&#xff0c;哪些工具资料又代表着什么意思&#xff08;保姆级教学…

RFM模型

目录标题 定义指标分析模型分析如何衡量每个客户的RFM指标1. 确定时间范围2. 要定义指标的衡量标准3. 对客户指标进行打分4. 计算平均值5. 用户分类 不同客户不同解决方案 RFM的最大短板RFM的深层问题R&#xff1a;用户离得越久就越有流失风险F&#xff1a;用户频次越高越忠诚M…

SpringBoot 日志文件从入门到实战

文章目录 1. 日志的作用2. 日志怎么用3. 自定义日志打印3.1 程序中得到日志对象3.2 使用日志对象打印日志3.3 日志格式说明 4. 日志级别4.1 日志级别的作用4.2 日志级别的分类与使用4.3 日志级别的设置4.4 综合练习 5. 日志的持久化5.1 配置日志文件的保存路径:5.2 配置日志文件…

MVP发布后,下一步该怎么办

MVP发布后&#xff0c;下一步该怎么办 一、为什么要从发布MVP开始&#xff1f;二、发布MVP后该做什么&#xff1f;1、推广MVP2、收集用户反馈3、进行用户发展访谈4、确定功能的优先次序5、建立一个产品路线图 三、如何衡量一个MVP的成功&#xff1f;1、分析仪表板的重要性2、创…

图解LeetCode——160. 相交链表

一、题目 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。注意&#xff0c;函数返回…

怎么把jfif改成png格式?这四种方法值得一试

怎么把JFIFf改成PNG格式&#xff1f;众所周知&#xff0c;JFIF是一种JPEG图像格式的子集&#xff0c;可以提供高质量的压缩效果。但是&#xff0c;JFIF格式有一些限制&#xff0c;例如它不支持透明度和多图层等功能&#xff0c;而PNG格式则是一种无损压缩的图像文件格式&#x…

从零开始Vue3+Element Plus后台管理系统(九)——使用API协作平台Mock数据

截止目前&#xff0c;本项目用了2个接口&#xff0c;一个登录&#xff0c;一个获取列表数据。接下来想做的页面和功能&#xff0c;为了看起来更真实&#xff0c;就需要增加更多的模拟数据。 Mock语法写得有些随意&#xff0c;看起来还是很假 &#x1f601; Mock数据可以使用M…

认识IPv6---寻址模式与地址类型与格式

本文目录 1、IPv6寻址模式1.1、单播(unicast)1.1、组播(multicast)1.1、任播(Anycast) 2、IPv6地址的类型与格式2.1、IPv6地址的格式2.2、IPv6地址的类型2.2.1、单播地址简介2.2.2、组播地址简介2.2.3、任播地址简介 IPv6的出现&#xff0c;最重要的原因是为了解决IPv4地址不足…

我扛住字节面试了,太干了......

春招进展快 2 个月&#xff0c;今年相比往年我感觉比较卷&#xff0c;很少见到offer收割机的选手。 不管环境如何&#xff0c;持续学习这个是不能放弃的&#xff0c;心态也要稳一稳&#xff0c;坦然面对失败&#xff0c;失败才是常态&#xff0c;成功可能才是偶然的。 好了&a…

LitCTF-web-WP(部分)

前言 CSDN内容合伙人 2023年CSDN新星计划Web安全方向导师。 华为MindSpore截至目前最年轻的优秀开发者 阿里云专家博主、华为网络安全云享专家以及腾讯云自媒体分享计划博主。 吉林师范大学CTF校队——SuD0战队的队长 吉林师范大学网信网安学生负责人 核心粉丝群超过50人 带队…

网址域名查询-域名注册查询工具

域名查找软件 域名查找软件是一种能够帮助用户快速查询域名相关信息的工具。它通常提供了批量域名查询和实时域名查询服务&#xff0c;能够帮助用户查询域名的注册信息、到期时间、所有者信息、域名服务器等多种相关信息。以下是域名查找软件的主要特点&#xff1a; 批量域名查…

roadmap go语言

技术类的Roadmap&#xff08;路线图&#xff09;具有许多好处&#xff0c;下面是其中几个主要的好处&#xff1a; 明确目标&#xff1a;Roadmap可以帮助技术团队明确目标和愿景。它提供了一个清晰的计划&#xff0c;使团队成员知道他们正在朝着什么方向前进&#xff0c;并且可…

网络正常但是web、ftp、telnet应用新建连接偶尔卡顿处理方法

目录 问题现象 故障定位 TCP报头 options详解 Opions Kind有哪些 options中的Timestamp详解 TSval & TSecr Timestamp Value的单位是什么 TCP连接的建立与释放 普通三次握手 带时间戳的三次握手 抓包展示带时间戳的tcp会话 WireShark中的时间 VS tcpdump 直接…