Vc++编程技术.docx
- 文档编号:29407184
- 上传时间:2023-07-23
- 格式:DOCX
- 页数:101
- 大小:113.21KB
Vc++编程技术.docx
《Vc++编程技术.docx》由会员分享,可在线阅读,更多相关《Vc++编程技术.docx(101页珍藏版)》请在冰豆网上搜索。
Vc++编程技术
[MFC][MFC][MFC][MFC]消息机制消息机制消息机制消息机制
首先,让我们看一下MFC的消息循环部分:
(程序取自MFC源程序,由于篇幅,我删去了一些非重要的部分。
)
MFC的WinMain函数:
[c]extern"C"intWINAPI_tWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPTSTRlpCmdLine,intnCmdShow)
{//callshared/exportedWinMainreturnAfxWinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow);}
intAFXAPIAfxWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPTSTRlpCmdLine,intnCmdShow){intnReturnCode=-1;CWinApp*pApp=AfxGetApp();//……//Performspecificinitializationsif(!
pApp->InitInstance()){//……//初始化实例不成功,通常一个DialogBasedMFC程序必须返回FALSE//这样就可以跳过消息循环。
nReturnCode=pApp->ExitInstance();gotoInitFailure;}nReturnCode=pApp->Run();//进入消息循环部分InitFailure:
//……//程序结束AfxWinTerm();returnnReturnCode;}
intCWinApp:
:
Run(){//……returnCWinThread:
:
Run();//消息循环被封装在CWinThread类里。
}intCWinThread:
:
Run(){BOOLbIdle=TRUE;LONGlIdleCount=0;//死循环,只有收到WM_QUIT消息后才会退出。
for(;;){while(bIdle&&!
:
:
PeekMessage(&m_msgCur,NULL,NULL,NULL,PM_NOREMOVE)){if(!
OnIdle(lIdleCount++))bIdle=FALSE;}//如果消息队列中没有消息,那么就调用OnIdle函数//否则,发送消息do{if(!
PumpMessage())//PumpMessage函数仅在收到WM_QUIT消息才返回FALSEreturnExitInstance();//退出死循环if(IsIdleMessage(&m_msgCur)){bIdle=TRUE;lIdleCount=0;}}while(:
:
PeekMessage(&m_msgCur,NULL,NULL,NULL,PM_NOREMOVE));//这段程序不仅完成了消息的发送,还实现了Idle功能。
//GetMessage函数在消息队列中没有消息时,将不会返回,//而是将控制权交给操作系统,直到消息队列中有消息为止。
//这段程序在一开始就调用PeekMessage函数来检测消息队列中//是否有消息存在,如果存在就发送消息,//否则就意味着空闲,那么就调用OnIdle函数,//这样做,控制权永远不会交给操作系统。
//由于Windows95,NT都是抢占式的操作系统,//系统会自动进行任务切换。
//所以不用担心别的程序不会被运行。
}}BOOLCWinThread:
:
PumpMessage(){if(!
:
:
GetMessage(&m_msgCur,NULL,NULL,NULL)){//收到WM_QUIT消息,就返回FALSE。
returnFALSE;}//否则就发送消息if(m_msgCur.message!
=WM_KICKIDLE&&!
PreTranslateMessage(&m_msgCur)){:
:
TranslateMessage(&m_msgCur);:
:
DispatchMessage(&m_msgCur);}returnTRUE;}[/c]主程序的流程:
[text](程序开始)||vWinMain||vAfxWinMain||vFALSECWinApp:
:
InitInstance——->退出程序||TRUE|vCWinApp:
:
Run||vCWinThread:
:
Run
||<—————————-+vFALSE|PeekMessage——->OnIdle——–+|TRUE||<————————-+|v||GetMessage||||||||YESv||+—–WM_QUIT消息?
||||||||NO|||v|||TranslateMessage|||||||||||v|||DispatchMessage|||||||||||vTRUE|||PeekMessage——————>+||||||FALSE||+—————————–+|v(程序结束)[/text]现在,再让我们来看一下MFC的窗口是如何响应消息的。
我们先来看一段建立一个窗口的代码.[c]classCMsgWnd:
publicCWnd{public:
CMsgWnd(){}//ClassWizardgeneratedvirtualfunctionoverrides//{{AFX_VIRTUAL(CMsgWnd)virtualBOOLCreate(CWnd*pParentWnd);//}}AFX_VIRTUALvirtual~CMsgWnd(){}
protected:
//{{AFX_MSG(CMsgWnd)afx_msgvoidOnPaint();afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);//}}AFX_MSGDECLARE_MESSAGE_MAP()};BEGIN_MESSAGE_MAP(CMsgWnd,CWnd)//{{AFX_MSG_MAP(CMsgWnd)ON_WM_PAINT()ON_WM_LBUTTONDOWN()//}}AFX_MSG_MAPEND_MESSAGE_MAP()BOOLCMsgWnd:
:
Create(CWnd*pParentWnd){returnCWnd:
:
Create(AfxRegisterWndClass(CS_DBLCLKS),"MessageWindow",WS_VISIBLE|WS_CHILD,CRect(0,0,100,100),pParentWnd,12345);}voidCMsgWnd:
:
OnPaint(){CPaintDCdc(this);//devicecontextforpaintingdc.TextOut(0,0,"hello");}voidCMsgWnd:
:
OnLButtonDown(UINTnFlags,CPointpoint){MessageBox("OnLButtonDown");CWnd:
:
OnLButtonDown(nFlags,point);}[/c]以上是一段标准的CWnd窗口类的子类实现代码.我想大家应该是可以看的懂的.注意到CMsgWnd类中有一句代码DECLARE_MESSAGE_MAP()我们来看看这个宏是如何定义的:
[c]typedefvoid(AFX_MSG_CALLCCmdTarget:
:
*AFX_PMSG)(void);//这是一个指向CCmdTarget类成员函数的指针类型.
structAFX_MSGMAP_ENTRY//消息映射表之消息入口{UINTnMessage;//消息UINTnCode;//控制码或者是WM_NOTIFY消息的通知码UINTnID;//控件的ID,如果是窗口消息则为0UINTnLastID;//如果是一个范围的消息,那么这是最后一个控件的IDUINTnSig;//消息处理类型AFX_PMSGpfn;//消息处理函数};structAFX_MSGMAP//消息映射表{#ifdef_AFXDLL//如果MFC是动态连接的,//就是编译时选择UseMFCinasharedDLLconstAFX_MSGMAP*(PASCAL*pfnGetBaseMap)();#else//MFC是静态连接的,编译时选择UseMFCinastaticlibrary.constAFX_MSGMAP*pBaseMap;#endif//如果MFC是动态连接的,就用pfnGetBaseMap函数返回基类的消息映射表//否则pBaseBap指向基类的消息映射表constAFX_MSGMAP_ENTRY*lpEntries;//指向消息入口的指针};#ifdef_AFXDLL//如果MFC是动态连接的#defineDECLARE_MESSAGE_MAP()\private:
\staticconstAFX_MSGMAP_ENTRY_messageEntries[];\//消息入口protected:
\staticAFX_DATAconstAFX_MSGMAPmessageMap;\//消息映射表staticconstAFX_MSGMAP*PASCAL_GetBaseMessageMap();\//该函数返回基类的消息映射表virtualconstAFX_MSGMAP*GetMessageMap()const;\//该函数返回当前类的消息映射表#else//静态连接的#defineDECLARE_MESSAGE_MAP()\private:
\staticconstAFX_MSGMAP_ENTRY_messageEntries[];\protected:
\staticAFX_DATAconstAFX_MSGMAPmessageMap;\virtualconstAFX_MSGMAP*GetMessageMap()const;\#endif//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//以上这段代码实际上是嵌入在你的类中.
在.CPP文件中我们看到还有这段宏,BEGIN_MESSAGE_MAP(CMsgWnd,CWnd)//{{AFX_MSG_MAP(CMsgWnd)ON_WM_PAINT()ON_WM_LBUTTONDOWN()//}}AFX_MSG_MAPEND_MESSAGE_MAP()现在我们再来看看它是被如何定义的.#ifdef_AFXDLL#defineBEGIN_MESSAGE_MAP(theClass,baseClass)\constAFX_MSGMAP*PASCALtheClass:
:
_GetBaseMessageMap()\{return&baseClass:
:
messageMap;}\//返回基类的消息映射表^^^^^^^^^^^^^^^^^^^^^^constAFX_MSGMAP*theClass:
:
GetMessageMap()const\{return&theClass:
:
messageMap;}\//返回当前类的消息映射表AFX_DATADEFconstAFX_MSGMAPtheClass:
:
messageMap=\//消息映射表{&theClass:
:
_GetBaseMessageMap,&theClass:
:
_messageEntries[0]};\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^constAFX_MSGMAP_ENTRYtheClass:
:
_messageEntries[]=\{\#else#defineBEGIN_MESSAGE_MAP(theClass,baseClass)\constAFX_MSGMAP*theClass:
:
GetMessageMap()const\{return&theClass:
:
messageMap;}\//返回当前类的消息映射表AFX_DATADEFconstAFX_MSGMAPtheClass:
:
messageMap=\//消息映射表{&baseClass:
:
messageMap,&theClass:
:
_messageEntries[0]};\^^^^^^^^^^^^^^^^^^^^^^可以看到这是MFC动态连接与静态连接的区别所在动态连接时使用函数_GetBaseMessageMap返回&baseClass:
:
messageMap而静态连接是直接使用.至于Microsoft为什么要这样做,好像没有什么很好的理由.当然这个并不重要,我们暂且不用理会.constAFX_MSGMAP_ENTRYtheClass:
:
_messageEntries[]=\//开始初始化消息入口{\#endif#defineEND_MESSAGE_MAP()\{0,0,0,0,AfxSig_end,(AFX_PMSG)0}\};\^^^^^^^^^^^^^^^^^^^^^^指示消息映射结束.
在这两个宏之间还有ON_WM_PAINT()ON_WM_LBUTTONDOWN()它们是我们在ClassWizard中选择了WM_PAINT和WM_LBUTTONDOWN消息后,MFC自动加入的,那么这两个又是如何定义的呢?
……#defineON_WM_PAINT()\{WM_PAINT,0,0,0,AfxSig_vv,\^^^^^^^^^^^^||||+————-消息处理类型|||+——————-LastID||+———————-ID=0,窗口消息|+————————-控制码+——————————–WM_PAINT消息(AFX_PMSG)(AFX_PMSGW)(void(AFX_MSG_CALLCWnd:
:
*)(void))&OnPaint},^^^^^^^^^^^^^^^消息处理函数…..#defineON_WM_LBUTTONDOWN()\{WM_LBUTTONDOWN,0,0,0,AfxSig_vwp,\^^^^^^^^^^^^^^WM_LBUTTON消息(AFX_PMSG)(AFX_PMSGW)(void(AFX_MSG_CALLCWnd:
:
*)(UINT,CPoint))&OnLButtonDown},^^^^^^^^^^^^^消息处理函数……现在我们差不多可以看得出来了,消息处理函数可以靠_messageEntries来找到每个消息的处理函数.我们可以再看看CWnd类来验证我们的想法.先看一下窗口的建立过程:
BOOLCWnd:
:
Create(LPCTSTRlpszClassName,LPCTSTRlpszWindowName,DWORDdwStyle,constRECT&rect,CWnd*pParentWnd,UINTnID,CCreateContext*pContext){//can’tusefordesktoporpop-upwindows(useCreateExinstead)ASSERT(pParentWnd!
=NULL);ASSERT((dwStyle&WS_POPUP)==0);returnCreateEx(0,lpszClassName,lpszWindowName,dwStyle|WS_CHILD,
rect.left,rect.top,rect.right–rect.left,rect.bottom–rect.top,pParentWnd->GetSafeHwnd(),(HMENU)nID,(LPVOID)pContext);}BOOLCWnd:
:
CreateEx(DWORDdwExStyle,LPCTSTRlpszClassName,LPCTSTRlpszWindowName,DWORDdwStyle,intx,inty,intnWidth,intnHeight,HWNDhWndParent,HMENUnIDorHMenu,LPVOIDlpParam){//allowmodificationofseveralcommoncreateparametersCREATESTRUCTcs;cs.dwExStyle=dwExStyle;cs.lpszClass=lpszClassName;cs.lpszName=lpszWindowName;cs.style=dwStyle;cs.x=x;cs.y=y;cs.cx=nWidth;cs.cy=nHeight;cs.hwndParent=hWndParent;cs.hMenu=nIDorHMenu;cs.hInstance=AfxGetInstanceHandle();cs.lpCreateParams=lpParam;if(!
PreCreateWindow(cs)){PostNcDestroy();returnFALSE;}AfxHookWindowCreate(this);^^^^^^^^^^^^^^^^^^^^^^^^^^函数见后HWNDhWnd=:
:
CreateWindowEx(cs.dwExStyle,cs.lpszClass,cs.lpszName,cs.style,cs.x,cs.y,cs.cx,cs.cy,cs.hwndParent,cs.hMenu,cs.hInstance,cs.lpCreateParams);if(!
AfxUnhookWindowCreate())PostNcDestroy();//cleanupifCreateWindowExfailstoosoonif(hWnd==NULL)returnFALSE;ASSERT(hWnd==m_hWnd);//shouldhavebeensetinsendmsghookreturnTRUE;}
//forchildwindowsBOOLCWnd:
:
PreCreateWindow(CREATESTRUCT&cs){if(cs.lpszClass==NULL){//makesurethedefaultwindowclassisregisteredif(!
AfxDeferRegisterClass(AFX_WND_REG))returnFALSE;//noWNDCLASSprovided–usechildwindowdefaultASSERT(cs.style&WS_CHILD);cs.lpszClass=_afxWnd;}returnTRUE;}voidAFXAPIAfxHookWindowCreate(CWnd*pWnd){_AFX_THREAD_STATE*pThreadState=_afxThreadState.GetData();if(pThreadState->m_pWndInit==pWnd)return;if(pThreadState->m_hHookOldCbtFilter==NULL){pThreadState->m_hHookOldCbtFilter=:
:
SetWindowsHookEx(WH_CBT,^^^^^^Computer-basedTraining,当建立、删除、移动、最大化、最小化窗口时,将会调用钩子函数。
_AfxCbtFilterHook,NULL,:
:
GetCurrentThreadId());^^^^^^^^^^^^^^^^^钩子函数if(pThreadState->m_hHookOldCbtFilter==NULL)AfxThrowMemoryException();}ASSERT(pThreadState->m_hHookOldCbtFilter!
=NULL);ASSERT(pWnd!
=NULL);ASSERT(pWnd->m_hWnd==NULL);//onlydoonceASSERT(pThreadState->m_pWndInit==NULL);//hooknotalreadyinprogresspThreadState->m_pWndInit=pWnd;}BOOLAFXAPIAfxUnhookWindowCreate(){_AFX_THREAD_STATE*pThreadState=_afxThreadState.GetData();
#ifndef_AFXDLLif(afxContextIsDLL&&pThreadState->m_hHookOldCbtFilter!
=NULL){:
:
UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^删除钩子函数pThreadState->m_hHookOldCbtFilter=NULL;}#endifif(pThreadState->m_pWndInit!
=NULL){pThreadState->m_pWndInit=NULL;returnFALSE;//wasnotsuccessfullyhooked}returnTRUE;}//WindowcreationhooksLRESULTCALLBACK_AfxCbtFilterHook(intcode,WPARAMwParam,LPARAMlParam){_AFX_THREAD_STATE*pThreadState=_afxThreadState.GetData();if(code!
=HCBT
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Vc 编程 技术