mfc第三天

消息映射机制

1)必须继承自CCmdTarget

2)类中药添加声明宏 DECLARE_MESSAGE_MAP()

3)类外添加实现宏

BEGIN_MESSAGE_MAP(theClass,baseClass)////本类,基类

ON_MESSAGE(msg,functionname)

END_MESSAGE_MAP()

3宏展开各部分的作用

_messageEntries[]--静态数组

保存了消息ID和处理这个消息的函数的对应关系

messageMap-静态变量

1- 保存父类的静态变量地址

2- 保存本类的静态数组首地址

GetMessageMap---虚函数

获取本类静态变量地址(链表的头结点)

4关系

GetMessageMap()

|->CMyFrameWnd::_messageEntries[]

|->消息ID.....处理函数地址

......................................    //不论写不写消息宏,父类..的消息链表都存在

|->CFrameWnd::messageMap        //加宏实为加节点

|->CFrameWnd::_messageEntries[]

|->消息ID...处理函数地址

....................................

|->CWnd::messageMap

|->CWnd::_messageEntries[]

|->消息ID....处理函数地址

|->CCmdTarget::messageMap

|->CCmdTarget::_messageEntries[]

|->消息ID...处理函数地址

|->NULL

5消息处理过程

1)利用GetMessageMap函数获取本类静态变量地址(链表头结点)pMessageMap

2)利用pMessageMap头结点的第二个语速获取对应静态数组,然后在数组中

查找对应消息函数地址的地址,如果找到执行3,未找到则执行4

3)使用找到的数组元素的最后一个成员(成员函数的地址),并调用这个函数完成消息处理

4)利用pMessageMap的第一个元素获取父类的静态变量地址,并重新给pMessageMap赋值为

父类的静态变量地址执行2

5)遍历整个链表都未找到则调用DefWindowProc给消息做默认处理.

二MFC消息分类

1)标准消息

ON_WM_XXX

2)命令消息(WM_COMMAND)    //菜单  加速键  通知消息

ON_COMMAND(命令ID,处理函数)

ON_COMMAND_RANGE(起始ID,终止ID,处理函数)    //往数组中扔通知消息

//从起始ID到终止ID都由这个函数处理

3)自定义消息

#define WM_MYMESSAGE WM_USER+n  WM_USER==0x400 n<=

没有专门处理自定义消息的宏    由通用消息宏处理

ON_MESSAGE(消息ID,处理函数)

4)通知消息

ON_EN_CHANGE        //EN---EDIT_NOTIFY

WM_COMMAND WM_NOTIFY 消息另行处理

**********************************************************************

封装好的消息映射宏    标准消息

ON_WM_CREATE()

#define ON_WM_CREATE() \

{ WM_CREATE, 0, 0, 0, AfxSig_is, \        //AfxSig_is--->int

(AFX_PMSG)(AFX_PMSGW)(int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT))&OnCreate },

ON_WM_CREATE( ) afx_msg int OnCreate( LPCREATESTRUCT );     //afx_msg 占位符 提高可读性

控件通知消息

#define ON_COMMAND(id, memberFxn) \

{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)&memberFxn },

CN_COMMAND通知码  都是0

afx_msg void memberFxn( );    //MSDN声明

#define CN_COMMAND              0               // void ()

#define CN_UPDATE_COMMAND_UI    ((UINT)(-1))    // void (CCmdUI*)

#define CN_EVENT                ((UINT)(-2))    // OLE event

#define CN_OLECOMMAND           ((UINT)(-3))    // OLE document command

#define CN_OLE_UNREGISTER       ((UINT)(-4))    // OLE unregister

#define ON_COMMAND_RANGE(id, idLast, memberFxn) \            //不建议使用,if else switch case

{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)idLast, AfxSig_vw, \    //容易扰乱程序结构,降低可读性

(AFX_PMSG)(void (AFX_MSG_CALL CCmdTarget::*)(UINT))&memberFxn },

MSDN中的例子

// The code fragment below shows how to use ON_COMMAND_RANGE macro

// to map a contiguous range of command IDs to a single message

// handler function (i.e. OnFileMenuItems() is the sample below). In

// addition, it also shows how to use CheckMenuRadioItem() to check a

// selected menu item and makes it a radio item.

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)

// ...

//}}AFX_MSG_MAP

ON_COMMAND_RANGE(ID_FILE_MENUITEM1, ID_FILE_MENUITEM3, OnFileMenuItems)

END_MESSAGE_MAP()

void CMainFrame::OnFileMenuItems(UINT nID)

{

CMenu* mmenu = GetMenu();

CMenu* submenu = mmenu->GetSubMenu(0);

submenu->CheckMenuRadioItem(ID_FILE_MENUITEM1, ID_FILE_MENUITEM3,

nID, MF_BYCOMMAND);

}

#define ON_MESSAGE(message, memberFxn) \

{ message, 0, 0, 0, AfxSig_lwl, \

(AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&memberFxn },

// Edit Control Notification Codes

#define ON_EN_SETFOCUS(id, memberFxn) \

ON_CONTROL(EN_SETFOCUS, id, memberFxn)

#define O

**********************************************************************
伪代码
以WM_CREATE消息为例
AfxWndProc(....){
	CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
	//获取和窗口句柄绑定在一起的框架类对象地址(pFrame)
	ASSERT(pWnd != NULL);
	ASSERT(pWnd->m_hWnd == hWnd);
	if (pWnd == NULL || pWnd->m_hWnd != hWnd)
		return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
&&&	return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);	//pWnd==pFrame
	lResult = pWnd->WindowProc(nMsg, wParam, lParam);	//pWnd==pFrame
		LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
		{
			OnWndMsg(message, wParam, lParam, &lResult){
				const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();{
					//进入宏展开  返回链表头结点地址(本类静态变量)
					return &CMyFrameWnd::messageMap;
				}
				const AFX_MSGMAP_ENTRY* lpEntry;
					for (; pMessageMap != NULL;
					pMessageMap = pMessageMap->pBaseMap)//遍历链表
						(lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
					message, 0, 0)) != NULL)
					///用WM_CREATE匹配消息链表,找到处理函数(查找本类静态数组)
					///如果没找到则去父类找,找到返回匹配到的数组元素的地址
					///没找到则默认处理
					if(lpEntry!=NULL){
						goto LDispatch;		//跳出for循环
						一旦找到跳出for循环,不在变量链表
					}
					LDispatch:
						union MessageMapFunctions mmf;	//lpEntry为消息数组中WM_CREATE的地址
						mmf.pfn = lpEntry->pfn;		//pfn=CMyFrameWnd::OnCreate
						//pfn结构体最后一个成员
						int nSig;			//
						nSig = lpEntry->nSig;		//
						switch(nSig){		//联合体有多少成员就有多少种情况
							......
							case AfxSig_lwl:
								lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
								break;
								......
	此时mmf.pfn_lwl=&OnCreate 因为其类型为联合体,先前赋值为&OnCreate而后未覆盖.所有成员公用此值
						}
			}

		}
**********************************************************************
LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
		{
			// OnWndMsg does most of the work, except for DefWindowProc call
			LRESULT lResult = 0;
			//this=pFrame
			if (!OnWndMsg(message, wParam, lParam, &lResult))	----------->
				lResult = DefWindowProc(message, wParam, lParam);
			return lResult;
		}
**********************************************************************
CWnd* PASCAL CWnd::FromHandlePermanent(HWND hWnd)
{
	CHandleMap* pMap = afxMapHWND();
	CWnd* pWnd = NULL;
	if (pMap != NULL)
	{
		// only look in the permanent map - does no allocations
		pWnd = (CWnd*)pMap->LookupPermanent(hWnd);
		ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
	}
	return pWnd;
}
**********************************************************************
CHandleMap* PASCAL afxMapHWND(BOOL bCreate)
{
	AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
	if (pState->m_pmapHWND == NULL && bCreate)
	{
		BOOL bEnable = AfxEnableMemoryTracking(FALSE);
#ifndef _AFX_PORTABLE
		_PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler);
#endif
		pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CTempWnd),
			offsetof(CWnd, m_hWnd));

#ifndef _AFX_PORTABLE
		AfxSetNewHandler(pnhOldHandler);
#endif
		AfxEnableMemoryTracking(bEnable);
	}
	return pState->m_pmapHWND;
}
**********************************************************************
inline CObject* CHandleMap::LookupPermanent(HANDLE h)
	{ return (CObject*)m_permanentMap.GetValueAt((LPVOID)h); }
**********************************************************************

**********************************************************************
union MessageMapFunctions
{
	AFX_PMSG pfn;   // generic member function pointer

	// specific type safe variants for WM_COMMAND and WM_NOTIFY messages
	void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND)();
	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_bCOMMAND)();
	void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_RANGE)(UINT);
	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_EX)(UINT);

	void (AFX_MSG_CALL CCmdTarget::*pfn_UPDATE_COMMAND_UI)(CCmdUI*);
	void (AFX_MSG_CALL CCmdTarget::*pfn_UPDATE_COMMAND_UI_RANGE)(CCmdUI*, UINT);
	void (AFX_MSG_CALL CCmdTarget::*pfn_OTHER)(void*);
	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_OTHER_EX)(void*);

	void (AFX_MSG_CALL CCmdTarget::*pfn_NOTIFY)(NMHDR*, LRESULT*);
	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_bNOTIFY)(NMHDR*, LRESULT*);
	void (AFX_MSG_CALL CCmdTarget::*pfn_NOTIFY_RANGE)(UINT, NMHDR*, LRESULT*);
	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_NOTIFY_EX)(UINT, NMHDR*, LRESULT*);

	// type safe variant for thread messages

	void (AFX_MSG_CALL CWinThread::*pfn_THREAD)(WPARAM, LPARAM);

	// specific type safe variants for WM-style messages
	BOOL    (AFX_MSG_CALL CWnd::*pfn_bD)(CDC*);
	BOOL    (AFX_MSG_CALL CWnd::*pfn_bb)(BOOL);
	BOOL    (AFX_MSG_CALL CWnd::*pfn_bWww)(CWnd*, UINT, UINT);
	BOOL    (AFX_MSG_CALL CWnd::*pfn_bHELPINFO)(HELPINFO*);
	BOOL    (AFX_MSG_CALL CWnd::*pfn_bWCDS)(CWnd*, COPYDATASTRUCT*);
	HBRUSH  (AFX_MSG_CALL CWnd::*pfn_hDWw)(CDC*, CWnd*, UINT);
	HBRUSH  (AFX_MSG_CALL CWnd::*pfn_hDw)(CDC*, UINT);
	int     (AFX_MSG_CALL CWnd::*pfn_iwWw)(UINT, CWnd*, UINT);
	int     (AFX_MSG_CALL CWnd::*pfn_iww)(UINT, UINT);
	int     (AFX_MSG_CALL CWnd::*pfn_iWww)(CWnd*, UINT, UINT);
	int     (AFX_MSG_CALL CWnd::*pfn_is)(LPTSTR);
	LRESULT (AFX_MSG_CALL CWnd::*pfn_lwl)(WPARAM, LPARAM);
	LRESULT (AFX_MSG_CALL CWnd::*pfn_lwwM)(UINT, UINT, CMenu*);
	void    (AFX_MSG_CALL CWnd::*pfn_vv)(void);

	void    (AFX_MSG_CALL CWnd::*pfn_vw)(UINT);
	void    (AFX_MSG_CALL CWnd::*pfn_vww)(UINT, UINT);
	void    (AFX_MSG_CALL CWnd::*pfn_vvii)(int, int);
	void    (AFX_MSG_CALL CWnd::*pfn_vwww)(UINT, UINT, UINT);
	void    (AFX_MSG_CALL CWnd::*pfn_vwii)(UINT, int, int);
	void    (AFX_MSG_CALL CWnd::*pfn_vwl)(WPARAM, LPARAM);
	void    (AFX_MSG_CALL CWnd::*pfn_vbWW)(BOOL, CWnd*, CWnd*);
	void    (AFX_MSG_CALL CWnd::*pfn_vD)(CDC*);
	void    (AFX_MSG_CALL CWnd::*pfn_vM)(CMenu*);
	void    (AFX_MSG_CALL CWnd::*pfn_vMwb)(CMenu*, UINT, BOOL);

	void    (AFX_MSG_CALL CWnd::*pfn_vW)(CWnd*);
	void    (AFX_MSG_CALL CWnd::*pfn_vWww)(CWnd*, UINT, UINT);
	void    (AFX_MSG_CALL CWnd::*pfn_vWp)(CWnd*, CPoint);
	void    (AFX_MSG_CALL CWnd::*pfn_vWh)(CWnd*, HANDLE);
	void    (AFX_MSG_CALL CWnd::*pfn_vwW)(UINT, CWnd*);
	void    (AFX_MSG_CALL CWnd::*pfn_vwWb)(UINT, CWnd*, BOOL);
	void    (AFX_MSG_CALL CWnd::*pfn_vwwW)(UINT, UINT, CWnd*);
	void    (AFX_MSG_CALL CWnd::*pfn_vwwx)(UINT, UINT);
	void    (AFX_MSG_CALL CWnd::*pfn_vs)(LPTSTR);
	void    (AFX_MSG_CALL CWnd::*pfn_vOWNER)(int, LPTSTR);   // force return TRUE
	int     (AFX_MSG_CALL CWnd::*pfn_iis)(int, LPTSTR);
	UINT    (AFX_MSG_CALL CWnd::*pfn_wp)(CPoint);
	UINT    (AFX_MSG_CALL CWnd::*pfn_wv)(void);
	void    (AFX_MSG_CALL CWnd::*pfn_vPOS)(WINDOWPOS*);
	void    (AFX_MSG_CALL CWnd::*pfn_vCALC)(BOOL, NCCALCSIZE_PARAMS*);
	void    (AFX_MSG_CALL CWnd::*pfn_vwp)(UINT, CPoint);
	void    (AFX_MSG_CALL CWnd::*pfn_vwwh)(UINT, UINT, HANDLE);
	BOOL    (AFX_MSG_CALL CWnd::*pfn_bwsp)(UINT, short, CPoint);
	void    (AFX_MSG_CALL CWnd::*pfn_vws)(UINT, LPCTSTR);
};

**********************************************************************
BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	LRESULT lResult = 0;

	// special case for commands
	if (message == WM_COMMAND)
	{
		if (OnCommand(wParam, lParam))
		{
			lResult = 1;
			goto LReturnTrue;
		}
		return FALSE;
	}

	// 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;
	}

	const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
	this->GetMessageMap===pFrame->GetMessageMap	回到宏展开取链表的头结点
	UINT iHash; iHash = (LOWORD((DWORD)pMessageMap) ^ message) & (iHashMax-1);
	AfxLockGlobals(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;
		AfxUnlockGlobals(CRIT_WINMSGCACHE);
		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;

#ifdef _AFXDLL
		for (/* pMessageMap already init'ed */; pMessageMap != NULL;
			pMessageMap = (*pMessageMap->pfnGetBaseMap)())
#else
		for (/* pMessageMap already init'ed */; pMessageMap != NULL;
			pMessageMap = pMessageMap->pBaseMap)
#endif
		{
			// Note: catch not so common but fatal mistake!!
			//      BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd)
#ifdef _AFXDLL
			ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
#else
			ASSERT(pMessageMap != pMessageMap->pBaseMap);
#endif

			if (message < 0xC000)
			{
				// constant window message
				if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
					message, 0, 0)) != NULL)
				{
					pMsgCache->lpEntry = lpEntry;
					AfxUnlockGlobals(CRIT_WINMSGCACHE);
					goto LDispatch;		//跳出for循环
				}
			}
			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;
						AfxUnlockGlobals(CRIT_WINMSGCACHE);
						goto LDispatchRegistered;
					}
					lpEntry++;      // keep looking past this one
				}
			}
		}

		pMsgCache->lpEntry = NULL;
		AfxUnlockGlobals(CRIT_WINMSGCACHE);
		return FALSE;
	}
	ASSERT(FALSE);      // not reached

LDispatch:
	ASSERT(message < 0xC000);
	union MessageMapFunctions mmf;
	mmf.pfn = lpEntry->pfn;

	// if we've got WM_SETTINGCHANGE / WM_WININICHANGE, we need to
	// decide if we're going to call OnWinIniChange() or OnSettingChange()

	int nSig;
	nSig = lpEntry->nSig;
	if (lpEntry->nID == WM_SETTINGCHANGE)
	{
		DWORD dwVersion = GetVersion();
		if (LOBYTE(LOWORD(dwVersion)) >= 4)
			nSig = AfxSig_vws;
		else
			nSig = AfxSig_vs;
	}

	switch (nSig)
	{
	default:
		ASSERT(FALSE);
		break;

	case AfxSig_bD:
		lResult = (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam));
		break;

	case AfxSig_bb:     // AfxSig_bb, AfxSig_bw, AfxSig_bh
		lResult = (this->*mmf.pfn_bb)((BOOL)wParam);
		break;

	case AfxSig_bWww:   // really AfxSig_bWiw
		lResult = (this->*mmf.pfn_bWww)(CWnd::FromHandle((HWND)wParam),
			(short)LOWORD(lParam), HIWORD(lParam));
		break;

	case AfxSig_bWCDS:
		lResult = (this->*mmf.pfn_bWCDS)(CWnd::FromHandle((HWND)wParam),
			(COPYDATASTRUCT*)lParam);
		break;

	case AfxSig_bHELPINFO:
		lResult = (this->*mmf.pfn_bHELPINFO)((HELPINFO*)lParam);
		break;

	case AfxSig_hDWw:
		{
			// special case for OnCtlColor to avoid too many temporary objects
			ASSERT(message == WM_CTLCOLOR);
			AFX_CTLCOLOR* pCtl = (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)
			{
#ifndef _AFX_NO_OCC_SUPPORT
				// 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;
				}
#endif
				pWnd = &wndTemp;
			}
			HBRUSH hbr = (this->*mmf.pfn_hDWw)(&dcTemp, pWnd, nCtlType);
			// fast detach of temporary objects
			dcTemp.m_hDC = NULL;
			wndTemp.m_hWnd = NULL;
			lResult = (LRESULT)hbr;
		}
		break;

	case AfxSig_hDw:
		{
			// special case for CtlColor to avoid too many temporary objects
			ASSERT(message == WM_REFLECT_BASE+WM_CTLCOLOR);
			AFX_CTLCOLOR* pCtl = (AFX_CTLCOLOR*)lParam;
			CDC dcTemp; dcTemp.m_hDC = pCtl->hDC;
			UINT nCtlType = pCtl->nCtlType;
			HBRUSH hbr = (this->*mmf.pfn_hDw)(&dcTemp, nCtlType);
			// fast detach of temporary objects
			dcTemp.m_hDC = NULL;
			lResult = (LRESULT)hbr;
		}
		break;

	case AfxSig_iwWw:
		lResult = (this->*mmf.pfn_iwWw)(LOWORD(wParam),
			CWnd::FromHandle((HWND)lParam), HIWORD(wParam));
		break;

	case AfxSig_iww:
		lResult = (this->*mmf.pfn_iww)(LOWORD(wParam), HIWORD(wParam));
		break;

	case AfxSig_iWww:   // really AfxSig_iWiw
		lResult = (this->*mmf.pfn_iWww)(CWnd::FromHandle((HWND)wParam),
			(short)LOWORD(lParam), HIWORD(lParam));
		break;

	case AfxSig_is:
		lResult = (this->*mmf.pfn_is)((LPTSTR)lParam);
		break;

	case AfxSig_lwl:
		lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
		break;

	case AfxSig_lwwM:
		lResult = (this->*mmf.pfn_lwwM)((UINT)LOWORD(wParam),
			(UINT)HIWORD(wParam), (CMenu*)CMenu::FromHandle((HMENU)lParam));
		break;

	case AfxSig_vv:
		(this->*mmf.pfn_vv)();
		break;

	case AfxSig_vw: // AfxSig_vb, AfxSig_vh
		(this->*mmf.pfn_vw)(wParam);
		break;

	case AfxSig_vww:
		(this->*mmf.pfn_vww)((UINT)wParam, (UINT)lParam);
		break;

	case AfxSig_vvii:
		(this->*mmf.pfn_vvii)((short)LOWORD(lParam), (short)HIWORD(lParam));
		break;

	case AfxSig_vwww:
		(this->*mmf.pfn_vwww)(wParam, LOWORD(lParam), HIWORD(lParam));
		break;

	case AfxSig_vwii:
		(this->*mmf.pfn_vwii)(wParam, LOWORD(lParam), HIWORD(lParam));
		break;

	case AfxSig_vwl:
		(this->*mmf.pfn_vwl)(wParam, lParam);
		break;

	case AfxSig_vbWW:
		(this->*mmf.pfn_vbWW)(m_hWnd == (HWND)lParam,
			CWnd::FromHandle((HWND)lParam),
			CWnd::FromHandle((HWND)wParam));
		break;

	case AfxSig_vD:
		(this->*mmf.pfn_vD)(CDC::FromHandle((HDC)wParam));
		break;

	case AfxSig_vM:
		(this->*mmf.pfn_vM)(CMenu::FromHandle((HMENU)wParam));
		break;

	case AfxSig_vMwb:
		(this->*mmf.pfn_vMwb)(CMenu::FromHandle((HMENU)wParam),
			LOWORD(lParam), (BOOL)HIWORD(lParam));
		break;

	case AfxSig_vW:
		(this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)wParam));
		break;

	case AfxSig_vW2:
		(this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)lParam));
		break;

	case AfxSig_vWww:
		(this->*mmf.pfn_vWww)(CWnd::FromHandle((HWND)wParam), LOWORD(lParam),
			HIWORD(lParam));
		break;

	case AfxSig_vWp:
		{
			CPoint point((DWORD)lParam);
			(this->*mmf.pfn_vWp)(CWnd::FromHandle((HWND)wParam), point);
		}
		break;

	case AfxSig_vWh:
		(this->*mmf.pfn_vWh)(CWnd::FromHandle((HWND)wParam),
				(HANDLE)lParam);
		break;

	case AfxSig_vwW:
		(this->*mmf.pfn_vwW)(wParam, CWnd::FromHandle((HWND)lParam));
		break;

	case AfxSig_vwWb:
		(this->*mmf.pfn_vwWb)((UINT)(LOWORD(wParam)),
			CWnd::FromHandle((HWND)lParam), (BOOL)HIWORD(wParam));
		break;

	case AfxSig_vwwW:
	case AfxSig_vwwx:
		{
			// 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_vwwW)
				(this->*mmf.pfn_vwwW)(nScrollCode, nPos,
					CWnd::FromHandle((HWND)lParam));
			else
				(this->*mmf.pfn_vwwx)(nScrollCode, nPos);
		}
		break;

	case AfxSig_vs:
		(this->*mmf.pfn_vs)((LPTSTR)lParam);
		break;

	case AfxSig_vws:
		(this->*mmf.pfn_vws)((UINT) wParam, (LPCTSTR)lParam);
		break;

	case AfxSig_vOWNER:
		(this->*mmf.pfn_vOWNER)((int)wParam, (LPTSTR)lParam);
		lResult = TRUE;
		break;

	case AfxSig_iis:
		lResult = (this->*mmf.pfn_iis)((int)wParam, (LPTSTR)lParam);
		break;

	case AfxSig_wp:
		{
			CPoint point((DWORD)lParam);
			lResult = (this->*mmf.pfn_wp)(point);
		}
		break;

	case AfxSig_wv: // AfxSig_bv, AfxSig_wv
		lResult = (this->*mmf.pfn_wv)();
		break;

	case AfxSig_vCALC:
		(this->*mmf.pfn_vCALC)((BOOL)wParam, (NCCALCSIZE_PARAMS*)lParam);
		break;

	case AfxSig_vPOS:
		(this->*mmf.pfn_vPOS)((WINDOWPOS*)lParam);
		break;

	case AfxSig_vwwh:
		(this->*mmf.pfn_vwwh)(LOWORD(wParam), HIWORD(wParam), (HANDLE)lParam);
		break;

	case AfxSig_vwp:
		{
			CPoint point((DWORD)lParam);
			(this->*mmf.pfn_vwp)(wParam, point);
			break;
		}
	case AfxSig_vwSIZING:
		(this->*mmf.pfn_vwl)(wParam, lParam);
		lResult = TRUE;
		break;

	case AfxSig_bwsp:
		lResult = (this->*mmf.pfn_bwsp)(LOWORD(wParam), (short) HIWORD(wParam),
			CPoint(LOWORD(lParam), HIWORD(lParam)));
		if (!lResult)
			return FALSE;
	}
	goto LReturnTrue;

LDispatchRegistered:    // for registered windows messages
	ASSERT(message >= 0xC000);
	mmf.pfn = lpEntry->pfn;
	lResult = (this->*mmf.pfn_lwl)(wParam, lParam);

LReturnTrue:
	if (pResult != NULL)
		*pResult = lResult;
	return TRUE;
}
**********************************************************************

struct AFX_MSGMAP
{
#ifdef _AFXDLL
	const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
	const AFX_MSGMAP* pBaseMap;
#endif
	const AFX_MSGMAP_ENTRY* lpEntries;
};

struct AFX_MSGMAP_ENTRY{
	UINT nMessage;//消息ID
	UINT nCode;	//通知码
	UINT nID;	//命令ID/控件ID
	UINT nLastID;	//最后一个控件ID
	UINT nSig;	//消息处理函数的类型
	AFX_PMSG pfn;	//消息处理函数的地址(指针)
};

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 nSig;       // signature type (action) or pointer to message #
	AFX_PMSG pfn;    // routine to call (or special value)
};

*********************************************************************

#ifdef _AFXDLL			//定义动态库
#define DECLARE_MESSAGE_MAP() private: 	static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: 	static AFX_DATA const AFX_MSGMAP messageMap; 	static const AFX_MSGMAP* PASCAL _GetBaseMessageMap(); 	virtual const AFX_MSGMAP* GetMessageMap() const;
#else
#define DECLARE_MESSAGE_MAP() private: 	static const AFX_MSGMAP_ENTRY _messageEntries[]; \	//静态映射数组
protected: 	static AFX_DATA const AFX_MSGMAP messageMap; 	virtual const AFX_MSGMAP* GetMessageMap() const;
#endif	

#ifdef _AFXDLL
#define DECLARE_MESSAGE_MAP() private: 	static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: 	static AFX_DATA const AFX_MSGMAP messageMap; 	static const AFX_MSGMAP* PASCAL _GetBaseMessageMap(); 	virtual const AFX_MSGMAP* GetMessageMap() const;
#else
#define DECLARE_MESSAGE_MAP() private: 	static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: 	static AFX_DATA const AFX_MSGMAP messageMap; 	virtual const AFX_MSGMAP* GetMessageMap() const;
#endif

#ifdef _AFXDLL
#define BEGIN_MESSAGE_MAP(theClass, baseClass) 	const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() 		{ return &baseClass::messageMap; } 	const AFX_MSGMAP* theClass::GetMessageMap() const 		{ return &theClass::messageMap; } 	AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = 	{ &theClass::_GetBaseMessageMap, &theClass::_messageEntries[0] }; 	AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = 	{
#else
#define BEGIN_MESSAGE_MAP(theClass, baseClass) 	const AFX_MSGMAP* theClass::GetMessageMap() const 		{ return &theClass::messageMap; } 	AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = 	{ &baseClass::messageMap, &theClass::_messageEntries[0] }; 	AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = 	{
#endif

*********************************************************************
#ifdef _AFXDLL
#define BEGIN_MESSAGE_MAP(theClass, baseClass) 	const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() 		{ return &baseClass::messageMap; } 	const AFX_MSGMAP* theClass::GetMessageMap() const 		{ return &theClass::messageMap; } 	AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = 	{ &theClass::_GetBaseMessageMap, &theClass::_messageEntries[0] }; 	AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = 	{
#else
#define BEGIN_MESSAGE_MAP(theClass, baseClass) 	const AFX_MSGMAP* theClass::GetMessageMap() const 		{ return &theClass::messageMap; } 	AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = 	{ &baseClass::messageMap, &theClass::_messageEntries[0] }; 	AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = 	{
#endif
**********************************************************************
#define ON_MESSAGE(message, memberFxn) 	{ message, 0, 0, 0, AfxSig_lwl, 		(AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&memberFxn },

***********************************************************************

N_EN_KILLFOCUS(id, memberFxn) \

ON_CONTROL(EN_KILLFOCUS, id, memberFxn)

#define ON_EN_CHANGE(id, memberFxn) \

ON_CONTROL(EN_CHANGE, id, memberFxn)

#define ON_EN_UPDATE(id, memberFxn) \

ON_CONTROL(EN_UPDATE, id, memberFxn)

#define ON_EN_ERRSPACE(id, memberFxn) \

ON_CONTROL(EN_ERRSPACE, id, memberFxn)

#define ON_EN_MAXTEXT(id, memberFxn) \

ON_CONTROL(EN_MAXTEXT, id, memberFxn)

#define ON_EN_HSCROLL(id, memberFxn) \

ON_CONTROL(EN_HSCROLL, id, memberFxn)

#define ON_EN_VSCROLL(id, memberFxn) \

ON_CONTROL(EN_VSCROLL, id, memberFxn)

#define ON_CONTROL(wNotifyCode, id, memberFxn) \

{ WM_COMMAND, (WORD)wNotifyCode, (WORD)id, (WORD)id, AfxSig_vv, \

(AFX_PMSG)&memberFxn },

**********************************************************************

进程间通信

HWND FindWindow(

LPCTSTR lpClassName,  // class name

LPCTSTR lpWindowName  // window name

);

//注意窗口标题栏不可同名

创建一个按钮,按钮被点击时,向另一个进程窗口发送自定义消息

接收发送的消息,并处理。。弹出提示框。

**********************************************************************

struct AFX_MSGMAP_ENTRY{

UINT nMessage;//消息ID

UINT nCode;    //通知码

UINT nID;    //命令ID/控件ID

UINT nLastID;    //最后一个控件ID

UINT nSig;    //消息处理函数的类型

AFX_PMSG pfn;    //消息处理函数的地址(指针)

};

struct AFX_MSGMAP

{

const AFX_MSGMAP* pBaseMap;

const AFX_MSGMAP_ENTRY* lpEntries;

};

两个简单的win32模拟mfc程序 (工程均是链接mfc静态库)

// MFCMessage.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
class CMyFrameWnd:public CFrameWnd{
//	DECLARE_MESSAGE_MAP()
///////////////////////////////////////
//	replace DECLARE_MESSAGE_MAP()

private:
		 static const AFX_MSGMAP_ENTRY _messageEntries[];
		 //
protected:
		   static AFX_DATA const AFX_MSGMAP messageMap;
	       virtual const AFX_MSGMAP* GetMessageMap() const;
		   /*
*/
////////////////////////////////////////
public:
	int m_xPos;
	int m_yPos;
	CMyFrameWnd(int x=100,int y=100);
	LRESULT OnCreate(WPARAM wParam,LPARAM lParam);
	LRESULT OnPaint(WPARAM wParam,LPARAM lParam);
	LRESULT OnMouseMove(WPARAM wParam,LPARAM lParam);
};
CMyFrameWnd::CMyFrameWnd(int x,int y){
	m_xPos=x;
	m_yPos=y;
}
LRESULT CMyFrameWnd::OnCreate(WPARAM wParam,LPARAM lParam){
	AfxMessageBox("CMyframeWnd::OnCreate");
	return 0;
}
LRESULT CMyFrameWnd::OnMouseMove(WPARAM wParam,LPARAM lParam){
	m_xPos=LOWORD(lParam);
	m_yPos=HIWORD(lParam);
//	m_xPos = ::GET_X_LPARAM(lParam);
//	m_yPos = ::GET_Y_LPARAM(lParam);
	::InvalidateRect(m_hWnd,NULL,TRUE);
	return 0;
}
LRESULT CMyFrameWnd::OnPaint(WPARAM wParam,LPARAM lParam){
	PAINTSTRUCT ps={0};
	HDC hDC=::BeginPaint(m_hWnd,&ps);
	::TextOut(hDC,m_xPos,m_yPos,"hello",5);
	::EndPaint(m_hWnd,&ps);
	return 0;
}
class CMyWinApp:public CWinApp{
public:
	virtual BOOL InitInstance();
	CMyWinApp(){}
};

//	BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)////本类,基类

const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const {
	return &CMyFrameWnd::messageMap;
}
AFX_COMDAT AFX_DATADEF const AFX_MSGMAP CMyFrameWnd::messageMap = {
	&CFrameWnd::messageMap, &CMyFrameWnd::_messageEntries[0]
};
AFX_COMDAT const AFX_MSGMAP_ENTRY CMyFrameWnd::_messageEntries[] = {
  /*
*/
//	ON_MESSAGE(WM_MOUSEMOVE,OnMouseMove)
//	ON_MESSAGE(WM_CREATE,OnCreate)
//	ON_MESSAGE(WM_PAINT,OnPaint)	//add to the array
		{
			WM_CREATE, 0, 0, 0, AfxSig_lwl,
			(AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)			(WPARAM, LPARAM))&OnCreate
		},
/*		*/
END_MESSAGE_MAP()
/*
//#define END_MESSAGE_MAP()
		{
			0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0
		}
	};
	*/
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance(){
	CMyFrameWnd *pFrame=new CMyFrameWnd();
	pFrame->Create(NULL,"MFCMsg");
	m_pMainWnd=pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

下面是第二个程序
// MFCMsg.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#define WM_MYMESSAGE WM_USER+10001
class CMyFrameWnd:public CFrameWnd{
	DECLARE_MESSAGE_MAP()
public:
	afx_msg int OnCreate(LPCREATESTRUCT cs);
	afx_msg void OnPaint(void);
	afx_msg void OnTest1();
	afx_msg void OnTest(UINT nID);
	afx_msg LRESULT OnMyMessage(WPARAM, LPARAM);
	afx_msg void OnEnChange( );
};
BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)

ON_WM_CREATE()
ON_WM_PAINT()
ON_COMMAND(1001,OnTest1)
ON_COMMAND_RANGE(1002,1003,OnTest)
ON_MESSAGE(WM_MYMESSAGE,OnMyMessage)
ON_EN_CHANGE(1004,OnEnChange)

END_MESSAGE_MAP()

int CMyFrameWnd::OnCreate(LPCREATESTRUCT cs){
//	AfxMessageBox("WM_CREATE");
	CreateWindowEx(0,"BUTTON","Test1",WS_CHILD|WS_VISIBLE,100,100,100,40,
		m_hWnd,(HMENU)1001,AfxGetInstanceHandle(),NULL);
	CreateWindowEx(0,"BUTTON","Test2",WS_CHILD|WS_VISIBLE,100,200,100,40,
		m_hWnd,(HMENU)1002,AfxGetInstanceHandle(),NULL);
	CreateWindowEx(0,"BUTTON","Test3",WS_CHILD|WS_VISIBLE,100,300,100,40,
		m_hWnd,(HMENU)1003,AfxGetInstanceHandle(),NULL);
	CreateWindowEx(0,"EDIT","Test4",WS_CHILD|WS_VISIBLE|WS_BORDER,300,100,200,100,
		m_hWnd,(HMENU)1004,AfxGetInstanceHandle(),NULL);
	return CFrameWnd::OnCreate(cs);
}
void CMyFrameWnd::OnPaint(void){
	PAINTSTRUCT ps={0};
	HDC hDC=::BeginPaint(m_hWnd,&ps);
	::TextOut(hDC,100,100,"hello",5);
	::EndPaint(m_hWnd,&ps);
//	return (void)(CFrameWnd::OnPaint());
}
void CMyFrameWnd::OnTest1(){
	AfxMessageBox("Test1");
//	SendMessage(WM_MYMESSAGE,0,1);	//this=pFrame
	HWND hWnd=::FindWindow(NULL,"MFCCreate");
	::SendMessage(hWnd,WM_MYMESSAGE,0,1);
}
void CMyFrameWnd::OnTest(UINT nID){
	if(1002==nID){
		AfxMessageBox("Test2 clicked!");
	}else if(1003==nID){
		AfxMessageBox("Test3 clicked!");
	}
}
LRESULT CMyFrameWnd::OnMyMessage(WPARAM wParam, LPARAM lParam){
	CString str;
	str.Format("wParam=%d\tlParam=%d",wParam,lParam);
	AfxMessageBox(str);
	return 0;
}
void CMyFrameWnd::OnEnChange(){
	AfxMessageBox("content changed!");
}
class CMyWinApp:public CWinApp{
public:
	virtual BOOL InitInstance();
};
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance(){
	CMyFrameWnd *pFrame=new CMyFrameWnd();
	pFrame->Create(NULL,"MFCMsg");
	m_pMainWnd=pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}
时间: 2024-10-31 13:34:51

mfc第三天的相关文章

VC学习笔记---ATL MFC CLR三个库的区别

MFC.ATL和CLR是VC2005内置的三大库,涵盖了Windows的各种开发方法和开发应用.当然关于C++开发的库不止这三个,不过这三个是微软推荐. 从编程所处层次而言,WIN32为最底层,其次是MFC,然后是CLR.WIN32 winAPI MFC MFC类库 CLR .net库 WIN32常规就是不用MFC,使用API函数编的程序. MFC库有很多年的历史了,MFC是基于Windows API 的简单封装.其核心架构基于"Document/View"架构(20年前被认为很潮流的

MFC线程(三):线程同步事件(event)与互斥(mutex)

前面讲了临界区可以用来达到线程同步.而事件(event)与互斥(mutex)也同样可以做到. Win32 API中的线程事件 HANDLE hEvent = NULL; void MainTestFun{ hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); SetEvent(hEvent); char g_charArray[4]; CString szResult; //下面三个线程中的任意一个访问g_charArray的时候其他线程都不能访问 AfxBe

MFC ODBC(三)

4.SQL查询 记录集的建立实际上是一个查询过程,SQL的SELECT语句用来查询数据源.在建立记录集时,CRecordset会根据一些参数构造一个SELECT语句来查询数据源,并用查询的结果创建记录集.SELECT语句的句法如下: SELECT rfx-field-list FROM table-name [WHERE m_strFilter][ORDER BY m_strSort] 其中table-name是表名,rfx-field-list是选择的列(字段),WHERE和ORDER BY是

《深入浅出MFC》第九章 消息映射与命令传递

Windows程序的本质是借着消息来维持脉动.每个消息都有一个代码,并以WM_开头的常量表示.来自菜单和工具栏者,都以WM_COMMAND表示,参数wParam记录消息的发出者. MFC的消息分为三大类,命令消息(WM_COMMAND),凡派生自CCmdTarget的类都有资格接收命令消息.除WM_COMMAND外,所有以WM_开头的都属于标准消息,派生自CWnd的类可接收此类消息.由控件产生的消息,为的是向父窗口传递某种情况,这种消息是以WM_COMMAND形式呈现. MFC通过三个宏来进行消

CSDN回帖得分大全(近两年)

CSDN回帖得分大全(近两年) √ vs2005调用dll的时候Initialize()函数返回错误[VC/MFC 基础类] √ 为什么我创建登陆框之后,然后获取登陆框的数据时候总是出现非法操作![VC/MFC 界面] √ CFileFind::FindFile   支持通配符么?[VC/MFC 基础类] √ vc++   浮动窗口联动的实现[VC/MFC 界面] √ VC   从数据库中读出数据流后怎么判断文件格式[VC/MFC 数据库] √ windows   7接硬體,不會自動刷新   請

mfc 在VC的两个对话框类中传递参数的三种方法

弄了好久,今天终于把在VC中的对话框类之间传递参数的问题解决了,很开心,记录如下: 1. 我所建立的工程是一个基于MFC对话框的应用程序,一共有三个对话框,第一个对话框为主对话框,所对应的类为CTMDDDlg类.在主对话框上我放置了一个标签页(Tab Control)控件,其实现的功能是当单击标签提示A时进入页面A,即对话框A(所对应的类为CDialogChild1),单击B时进入对话框B(CDialogChild2). 整个工程的框架已经设计好了,在对话框A和对话框B上放置了许多控件,现在我想

VS2013 MFC ODBC连接SQL SERVER数据库编程(三)

VS2013 MFC ODBC连接SQL SERVER数据库编程(三) 转载请注明:http://blog.csdn.net/my_acm/article/category/2616577 继上一篇讲完对数据库的链接以及一些说明之后,本文将实现对数据库的增删查改等操作. 如上图所示就是最终完成的一个简单的小程序. 首先添加列表框的NM_CLICK响应程序.鼠标放在列表框上,右键->添加事件处理程序,找到MN_CLICK消息,添加并编辑,如下图所示. 在响应函数里面添加如下代码: 这样就实现了,点

MFC 三种消息

在MFC应用程序中传输的消息有三种类型:窗口消息.命令消息和控件通知. (1)窗口消息:WM_XXX 窗口消息(Window Message)一般与窗口的内部运作有关,如:创建窗口.绘制窗口和销毁窗口等.通常,消息是从系统发送到窗口,或从窗口发送到窗口. (2)命令消息:WM_COMMAND 命令消息一般与处理用户请求相关,当用户单击一个菜单项或工具栏时,命令消息产生,并被发送到能处理该请求的类对象(如:装载文件.编辑文本和保存选项等). (3)控件通知:有多种格式       通常,控件通知在

OpenGL在MFC中的使用总结(三)

有些时候直接创建OpenGL窗口不适合,或者根本不允许再创建窗口,就像我现在的这个项目,创建的窗口显示不出来,被主框架限定,而我只能在ActiveX控件的子类里做一些相关工作,那只能用到OpenGL的离屏渲染技术了~即不直接绘制到窗口上,而是绘制到一张位图上,然后再次调用这张位图实现后续的工作. 下面就总结怎么使用所谓的"离屏渲染". const int WIDTH = 500; const int HEIGHT = 500; // Create a memory DC compati