亚冠

深入剖析MFC中Windows消息处理机制

2019-09-11 12:39:28来源:励志吧0次阅读

当bidle=0或消息队例中有消息时,程序又执行到哪了呢?

do

{

// pump message, but quit on WM_QUIT

if (!PumpMessage())

return ExitInstance();

// reset "no idle" state after pumping "normal" message

if (IsIdleMessage(&m_msgCur))

{

bIdle = TRUE;

lIdleCount = 0;

}

} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));

看啊,又进入一个循环!

其中有个重要的函数,PumpMessage,内容如下:

BOOL CWinThread::PumpMessage()

{

ASSERT_VALID(this);

if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))

{

#ifdef _DEBUG

if (afxTraceFlags & traceAppMsg)

TRACE0("CWinThread::PumpMessage - Received WM_QUIT.\n");

m_nDisablePumpCount++; // application must die

// Note: prevents calling message loop things in ’ExitInstance’

// will never be decremented

#endif

return FALSE;

}

#ifdef _DEBUG

if (m_nDisablePumpCount != 0)

{

TRACE0("Error: CWinThread::PumpMessage called when not permitted.\n");

ASSERT(FALSE);

}

#endif

#ifdef _DEBUG

if (afxTraceFlags & traceAppMsg)

_AfxTraceMsg(_T("PumpMessage"), &m_msgCur);

#endif

// process this message

if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))

{

::TranslateMessage(&m_msgCur);

::DispatchMessage(&m_msgCur);

}

return TRUE;

}

如你所想,这才是MFC消息处理的核心基地[也是我个人认为的]。

GetMessage不同于PeekMessae,它是不得到消息不罢体,PeekMessage如果发现消息队列中没有消息会返回0,而GetMessage如果发现没有消息,等,直到有了消息,而且,GetMessage不同于PeekMessage,它会将消息移走[当然,PeekMessage也可以做到这点]。我想当你读了这个函数后,你应明白PreTranslateMessage函数的用法了吧[我比较喜欢在程序中充分利用这个函数]。

::TranslateMessage(&m_msgCur);

::DispatchMessage(&m_msgCur);

将消息发送到窗口的处理函数[它是由窗口类指定的],之后的动作一直到你的程序做出反映的过程,你可以在《深入》一书中得到完美的解释。我们还是通过reurn TRUE;回到CWinThread::Run()中的Do{}while;循环。然后还是对IDLE的处理,即便刚才你的ONIDLE返回了FALSE,在这里你看到,你的程序还是有机会执行它的。然后又是利用PeekMessage检测消息队列:

如果有消息[这个消息不被移动的原因是因为它要为PumpMessage内的GetMessage所利用。]再次进入PumpMessage[叫它“消息泵”吧]。

如果没有消息,退出DO循环,但它还在FOR内部,所以又执行第一个While循环。

这是CwinThread::Run的一个执行过程。

不用担心退不出for(;;)如果你的消息队列中有一条WM_QUIT,会使GetMessage返回0,然后PumpMessage返回0而RUN()内部:

if (!PumpMessage())

return ExitInstance();

SDI就说到这,下面我来谈一下模式对话框。我分2种情况讨论:

一当你的工程以模式对话框为基础时[没父窗口,或为桌面]。

与SDI不同处在于,在应用程序类的InItInstance内部:

BOOL CComboBoxApp::InitInstance()

{

AfxEnableControlContainer();

// Standard initialization

// If you are not using these features and wish to reduce the size

// of your final executable, you should remove from the following

// the specific initialization routines you do not need.

#ifdef _AFXDLL

Enable3dControls(); // Call this when using MFC in a shared DLL

#else

Enable3dControlsStatic(); // Call this when linking to MFC statically

#endif

this->m_nCmdShow = SW_HIDE;

CComboBoxDlg dlg;

m_pMainWnd = &dlg;

int nResponse = dlg.DoModal();

if (nResponse == IDOK)

{

// TODO: Place code here to handle when the dialog is

// dismissed with OK

}

else if (nResponse == IDCANCEL)

{

// TODO: Place code here to handle when the dialog is

// dismissed with Cancel

}

// Since the dialog has been closed, return FALSE so that we exit the

// application, rather than start the application’s message pump.

return FALSE;

}

int nResponse = dlg.DoModal();一句使你的整个程序都在DoModal()内部进行。而且,你退出DoMal()时[你一定结束了你的对话框],InitInstance返回的是False,我们知道,这样,CwinThread::Run是不会执行的。

但对话框程序是在哪里进行消息处理的呢。

原来,dlg.DoModal()内部会调用CwinThread::RunModalLoop,它起到的作用和RUN()是一样的[当然内部有细小差别,请参考MSDN]!!!

第二种情况,你是在SDI[或其它]程序中调用Dlg.DoModal() 产生了一模式对话框[有父窗口].

这又是如何运作的呢?

建了这样一个工程做为例子。

SDI,在View中处理LBUTTONDOWN:

MyDLg.DoModal();

MyDLg内有按钮,以惫后用.

没有显示模式对话框前,消息处理一直在Cthread::Run()中进行.

你单击后,程序执行点进入DoModal()内部的RunModalLoop,这又是一个消息处理机制.

不过DoModal()中调用RunModalLoop,前会Disable掉它的父窗口.从RunModalLoop中出来后,再 Enable它.

模式对话框和非模式对话框都是通过调用CreateDialogIndirect()产生创建对话框.那它和非模式对话框区别是什么造成的呢?

1 模式对话框将父窗口DISABLE掉.

我原以为被Disable的窗口是不接收消息的.但后来我马上发现我是错的.但,为什么你对被Disable的窗口进行KeyBorad,Mouse动作时,窗口没反映呢,我想,这可能是操作系统从中搞的鬼.我在本文一开始,就写出操作系统向窗口发送消息的过程,我想当它发现目标窗口处理Disabled状态时,不会将消息发送给它,但这不能说窗口不接收消息,其它程序[或它本身]发送给它的消息还是可以接收并处理的.

2 模式对话框本身有消息处理机制 RunModalLoop.

对以上两点加以实验.

我在我的刚才建的项目中的模式对话框中加上一个BUTTON,其中加入如下代码:

OnButton1()

{

GetParaent()->EnableWindow(1);

}

单击,后我们发现,此时它已经不再表现为”模态”,我试着点击菜单,还是会作出正常反映.

我想这此消息[对于父窗口的,如:菜单动作]的处理也应是在模式对话框中的RunModalLoop中进行处理的吧[这点我不能确定].

查看本文来源

小孩脸色发黄如何调理
宝宝感冒发烧咳嗽流鼻涕怎么办
宝宝吃什么降火最快
小孩腹胀不爱吃饭
分享到: