MFC消息映射源码 解析


void RunMessageLoop() throw()
{
	MSG msg;
	while (GetMessage(&msg, 0, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}
/*virtual int CWinApp::Run();可能是虚继承了模板类CAtlExeModuleT<T> 在该模板类中
  有 T* pT=>PreMessageLoop(); pT->RunMessageLoop(); pt->PostMessageLoop();*/
HRESULT Run(_In_ int nShowCmd = SW_HIDE) throw()
{
	HRESULT hr = S_OK;

	T* pT = static_cast<T*>(this);
	hr = pT->PreMessageLoop(nShowCmd);

	// Call RunMessageLoop only if PreMessageLoop returns S_OK.
	if (hr == S_OK)
	{
		pT->RunMessageLoop();
	}

	// Call PostMessageLoop if PreMessageLoop returns success.
	if (SUCCEEDED(hr))
	{
		hr = pT->PostMessageLoop();
	}

	ATLASSERT(SUCCEEDED(hr));
	return hr;
}
/////////////////////////////////////////////////////////////////////////////
// Official way to send message to a CWnd

LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
	WPARAM wParam = 0, LPARAM lParam = 0)
{
	_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
	MSG oldState = pThreadState->m_lastSentMsg;   // save for nesting
	pThreadState->m_lastSentMsg.hwnd = hWnd;
	pThreadState->m_lastSentMsg.message = nMsg;
	pThreadState->m_lastSentMsg.wParam = wParam;
	pThreadState->m_lastSentMsg.lParam = lParam;

#ifdef _DEBUG
	_AfxTraceMsg(_T("WndProc"), &pThreadState->m_lastSentMsg);
#endif

	// Catch exceptions thrown outside the scope of a callback
	// in debug builds and warn the user.
	LRESULT lResult;
	TRY
	{
#ifndef _AFX_NO_OCC_SUPPORT
		// special case for WM_DESTROY
		if ((nMsg == WM_DESTROY) && (pWnd->m_pCtrlCont != NULL))
			pWnd->m_pCtrlCont->OnUIActivate(NULL);
#endif

		// special case for WM_INITDIALOG
		CRect rectOld;
		DWORD dwStyle = 0;
		if (nMsg == WM_INITDIALOG)
			_AfxPreInitDialog(pWnd, &rectOld, &dwStyle);

		// delegate to object's WindowProc
		lResult = pWnd->WindowProc(nMsg, wParam, lParam); //将返回传入窗口对象指针pWnd的窗口过程函数WindowProc()

		// more special case for WM_INITDIALOG
		if (nMsg == WM_INITDIALOG)
			_AfxPostInitDialog(pWnd, rectOld, dwStyle);
	}
	CATCH_ALL(e)
	{
		lResult = AfxProcessWndProcException(e, &pThreadState->m_lastSentMsg);
		TRACE(traceAppMsg, 0, "Warning: Uncaught exception in WindowProc (returning %ld).\n",
			lResult);
		DELETE_EXCEPTION(e);
	}
	END_CATCH_ALL

	pThreadState->m_lastSentMsg = oldState;
	return lResult;
}
////////////////////////////////////////////////////////////////////////////
// The WndProc for all CWnd's and derived classes
/*wincore.cpp全局域的AfxWndProc(HWND hWnd,UINT nMsg,
WPARAM wParam,LPARAM lParam)函数返回传入窗口句柄hWnd
message消息对应的窗口过程函数,异常情况下调用
DefWindowProc(hWnd,nMsg,wParam,lParam)返回默认窗口
过程函数,正常情况下调用AfxCallWndProc(pWnd,hWnd,nMsg,
wParam,lParam)返回pWnd->WindowProc(nMsg,wParam,lParam)
即传入窗口的WindowProc()窗口过程函数*/
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* pWnd = CWnd::FromHandlePermanent(hWnd); //句柄转指针
	ASSERT(pWnd != NULL);					
	ASSERT(pWnd==NULL || pWnd->m_hWnd == hWnd); //CWnd窗口类对象的内存可能被移动 所以存储有对象句柄m_hWnd 
	if (pWnd == NULL || pWnd->m_hWnd != hWnd)
		return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
	return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}
////////////////////////////////
HRESULT PostMessageLoop() throw()
{
	HRESULT hr = S_OK;

#ifndef _ATL_NO_COM_SUPPORT

	T* pT = static_cast<T*>(this);
	hr = pT->RevokeClassObjects();
	if (m_bDelayShutdown)
		Sleep(m_dwPause); //wait for any threads to finish

#endif	// _ATL_NO_COM_SUPPORT

	return hr;
}

void RunMessageLoop() throw()
{
	MSG msg;
	while (GetMessage(&msg, 0, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}
const MSG* PASCAL CWnd::GetCurrentMessage()
{
	// fill in time and position when asked for
	_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
	pThreadState->m_lastSentMsg.time = ::GetMessageTime();
	pThreadState->m_lastSentMsg.pt = CPoint(::GetMessagePos());
	return &pThreadState->m_lastSentMsg;
}
BOOL CWnd::PreTranslateMessage(MSG* pMsg)
{
	// handle tooltip messages (some messages cancel, some may cause it to popup)
	AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
	if (pModuleState->m_pfnFilterToolTipMessage != NULL)
		(*pModuleState->m_pfnFilterToolTipMessage)(pMsg, this);

	// no default processing
	return FALSE;
}
//****************************************************
typedef struct tagMSG {  //MSG消息结构体
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam; //对WM_COMMAND消息 其WPARAM表示消息来自哪一个菜单项
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

// pointer to afx_msg member function
#ifndef AFX_MSG_CALL
#define AFX_MSG_CALL
#endif
typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
                         /*所有能处理消息的类的父类CCmdTarget的成员函数指针
                           (从而可以被派生类继承并在派生类重定义)*/
struct AFX_MSGMAP_ENTRY  //消息映射结构体
{
	UINT nMessage;   // windows message
	UINT nCode;      // control code or WM_NOTIFY code
	UINT nID;        // control ID (or 0 for windows messages)
	UINT nLastID;    // used for entries specifying a range of control id's
	UINT_PTR nSig;       // signature type (action) or pointer to message #
	AFX_PMSG pfn;    // routine to call (or special value)
};
#define PASCAL      __stdcall                    //相当于递归地返回上一个基类的消息映射结构体数组指针
struct AFX_MSGMAP                                //由于包含有返回指向上一个基类的该AFX_MSGMAP结构体
{                                                //通常是上一个基类的&TheBaseClass::GetThisMessageMap
	const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)(); //返回指向AFX_MSGMAP结构体的指针的函数指针pfnGetBaseMap
	const AFX_MSGMAP_ENTRY* lpEntries; //指向AFX_MSGMAP_ENTRY消息映射结构体(数组)的指针
};

#define DECLARE_MESSAGE_MAP() \   
protected: \
	static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \
	virtual const AFX_MSGMAP* GetMessageMap() const; \
//声明了两个成员函数 其中GetMessageMap()调用并返回GetThisMessageMap()的返回值 return GetThisMessageMap();
//*************************************************
#define PTM_WARNING_DISABLE \
	__pragma(warning( push )) \
	__pragma(warning( disable : 4867 ))
#define PTM_WARNING_RESTORE \
	__pragma(warning( pop ))


#define BEGIN_MESSAGE_MAP(theClass, baseClass) \    //该宏的两个参数分别是拥有此消息映射结构体数组的类及其父类
	PTM_WARNING_DISABLE \                           //用于链接本类与其上层类(派生类)的消息映射链 
	   /*定义了接收消息的CCmdTarget派生类theClass的GetMessageMap()函数
         调用GetThisMessageMap() 返回AFX_MSGMAP*  */
	const AFX_MSGMAP* theClass::GetMessageMap() const \   
		{ return GetThisMessageMap(); } \           
	const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \   //该函数定义消息映射数组攒进并返回当前文件定义的AFX_MSGMAP结构体地址
	{ \
		typedef theClass ThisClass;						   \
		typedef baseClass TheBaseClass;					   \
		static const AFX_MSGMAP_ENTRY _messageEntries[] =  \   //构造消息映射结构体数组_messageEntries[]
		{                 /*定义为本类成员函数theClass::GetThisMessageMap()
						    中的static静态常数组 确保本类的所有对象当进入这里
							查找消息响应函数时均面对的是同一个消息映射结构体
							数组 即这里的静态消息映射结构体数组是属于本类的 所有
							对象公用的*/
			/*
			#define WM_PAINT                        0x000F
			#define WM_SETFOCUS                     0x0007
			enum AfxSig
			{
			    AfxSig_end = 0,     // [marks end of message map]

				AfxSig_v_v_v =19 ,				// void ()
				AfxSig_vv = AfxSig_v_v_v,      // void (void)
				AfxSig_v_W_v=35,				// void (CWnd*)
				AfxSig_vW = AfxSig_v_W_v,      // void (CWnd*)
			}

			// pointer to afx_msg member function
			#ifndef AFX_MSG_CALL
			#define AFX_MSG_CALL     //占位符 没有替换文本 啥也不替换 相当于注释 为以后可能的作用埋藏下
			#endif
			typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);   //AFX_PMSG CCmdTarget类的函数指针
			typedef void (AFX_MSG_CALL CWnd::*AFX_PMSGW)(void);        //AFX_PMSGW CWnd类的函数指针
				// like 'AFX_PMSG' but for CWnd derived classes only
			*/ 
			/*能产生命令消息的用户界面对象有菜单项、工具栏项和快捷键 它们都有有可自定义的ID来标识 
			  这里也用ID标识匹配响应函数*/
			#define ON_COMMAND(id, memberFxn) \  //COMMAND命令消息映射宏需指定传入的菜单项ID|工具栏项ID 以及响应函数
				{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, \  //(不重写基类已命名的响应函数)
					static_cast<AFX_PMSG> (memberFxn) },
					// ON_COMMAND(id, OnBar) is the same as
					//   ON_CONTROL(0, id, OnBar) or ON_BN_CLICKED(0, id, OnBar)
			#define ON_WM_PAINT() \                         //一个消息映射结构体 (不指定响应函数 说明要重写基类
				{ WM_PAINT, 0, 0, 0, AfxSig_vv, \  //已命名的响应函数 这个消息映射宏(单纯地文本替换)可以指定自定义
					(AFX_PMSG)(AFX_PMSGW) \ //函数名的响应函数并在其中调用基类已命名的同消息响应函数CWnd::OnPaint())
					(static_cast< void (AFX_MSG_CALL CWnd::*)(void) > ( &ThisClass :: OnPaint)) },  
			#define ON_WM_SETFOCUS() \
				{ WM_SETFOCUS, 0, 0, 0, AfxSig_vW, \        //一个消息映射结构体
					(AFX_PMSG)(AFX_PMSGW) \
					(static_cast< void (AFX_MSG_CALL CWnd::*)(CWnd*) > ( &ThisClass :: OnSetFocus)) },
		    // update ui's are listed as WM_COMMAND's so they get routed like commands
			/*当点击某菜单项|工具栏按钮|快捷键后更新显示本身或其他用户界面对象(启用或禁用用户界面对象)*/
			#define ON_UPDATE_COMMAND_UI(id, memberFxn) \  
				{ WM_COMMAND, CN_UPDATE_COMMAND_UI, (WORD)id, (WORD)id, AfxSigCmdUI, \
					(AFX_PMSG) \
					(static_cast< void (AFX_MSG_CALL CCmdTarget::*)(CCmdUI*) > \
					(memberFxn)) },

#define END_MESSAGE_MAP() \
				{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \   //一个消息映射结构体 (AfxSig_end = 0)
		}; \      //结束压栈消息映射结构体数组_messageEntries[]
		static const AFX_MSGMAP messageMap = \       //构造AFX_MSGMAP结构体
		{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \  
		return &messageMap; \                 //返回当前文件定义的AFX_MSGMAP结构体地址 (AFX_MSGMAP*)
		/*Windows消息只能由CWnd对象来处理 采用向基类直线上溯的方式查找消息对应的响应函数
		  一旦找到消息响应函数(若有返回值且为TRUE),就停止上溯。
		  返回基类CDialogEx的GetThisMessageMap()函数地址 是在theClass类的GetThisMessageMap()
		  函数体内消息映射数组_messageEntries[]中未找到该消息时前往基类CDialogEx的
		  GetThisMessageMap()函数体内消息映射数组_messageEntries[]继续寻找匹配传入消息
		  若仍未找到 则到CDialogEx的GetThisMessageMap()返回的基类CDialog::GetThisMessageMap()的
		  函数体内消息映射数组_messageEntries[]中继续寻找匹配传入消息
		  若仍未找到 则到CWnd的GetThisMessageMap()返回的基类CCmdTarget::GetThisMessageMap()的
		  函数体内消息映射数组_messageEntries[]中继续寻找匹配传入消息
		  若仍未找到 由于基类CObject已经没有声明有消息响应等函数和DECLARE_MESSAGE_MAP()宏
		  可能也就没有消息映射可寻了
		  */
		/*首元素是基类(CDialogEx)的GetThisMessageMap()函数地址、二元素是指向AFX_MSGMAP_ENTRY
		  消息映射结构体数组(就定义在GetThisMessageMap()函数里面) 的指针 相当于theClass的函数
		  GetThisMessageMap()返回了(其基类的GetThisMessageMap()函数地址,与在其函数域内定义的
		  消息映射结构体数组(栈内存?)的地址)共同构造的AFX_MSGMAP结构体(栈内存?)的地址

		  基类CDialogEx类的声明中也有DECLARE_MESSAGE_MAP()并且在此前声明了OnActivate()、
		  OnDestroy()等函数 那其实现文件肯定也声明有BEGIN_MESSAGE_MAP(CDialogEx,CDialog).....

		  的基类CDialog类的声明中也有DECLARE_MESSAGE_MAP()并且在此前声明了OnPaint()、
		  OnOK()等函数 那其实现文件肯定也声明有BEGIN_MESSAGE_MAP(CDialog,CWnd).....

		  的基类CWnd类的声明中也有DECLARE_MESSAGE_MAP()并且在此前声明了OnSetFocus()、
		  OnPaint()等函数 那其实现文件肯定也声明有BEGIN_MESSAGE_MAP(CWnd,CCmdTarget).....

		  的基类CCmdTarget类的声明中也有DECLARE_MESSAGE_MAP()但已经没有在此前声明消息响应等函数 
		   .....
		*/
	}								  \       //theClass::GetThisMessageMap()函数结束
PTM_WARNING_RESTORE
//************************************************
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值