Vc++编程技术.docx

上传人:b****2 文档编号:17221737 上传时间:2023-07-23 格式:DOCX 页数:101 大小:113.21KB
下载 相关 举报
Vc++编程技术.docx_第1页
第1页 / 共101页
Vc++编程技术.docx_第2页
第2页 / 共101页
Vc++编程技术.docx_第3页
第3页 / 共101页
Vc++编程技术.docx_第4页
第4页 / 共101页
Vc++编程技术.docx_第5页
第5页 / 共101页
Vc++编程技术.docx_第6页
第6页 / 共101页
Vc++编程技术.docx_第7页
第7页 / 共101页
Vc++编程技术.docx_第8页
第8页 / 共101页
Vc++编程技术.docx_第9页
第9页 / 共101页
Vc++编程技术.docx_第10页
第10页 / 共101页
Vc++编程技术.docx_第11页
第11页 / 共101页
Vc++编程技术.docx_第12页
第12页 / 共101页
Vc++编程技术.docx_第13页
第13页 / 共101页
Vc++编程技术.docx_第14页
第14页 / 共101页
Vc++编程技术.docx_第15页
第15页 / 共101页
Vc++编程技术.docx_第16页
第16页 / 共101页
Vc++编程技术.docx_第17页
第17页 / 共101页
Vc++编程技术.docx_第18页
第18页 / 共101页
Vc++编程技术.docx_第19页
第19页 / 共101页
Vc++编程技术.docx_第20页
第20页 / 共101页
亲,该文档总共101页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Vc++编程技术.docx

《Vc++编程技术.docx》由会员分享,可在线阅读,更多相关《Vc++编程技术.docx(101页珍藏版)》请在冰点文库上搜索。

Vc++编程技术.docx

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

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2