0531 VC DLL 消息循环 消息泵
揭开CWinApp::Run()的皮--何谓“消息泵”
wwwsq (wwwsq) 2002-01-29 19:43:53 在VC/MFC/非技术类提问
int CWinApp::Run()
&leftsign;
if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
&leftsign;
// Not launched /Embedding or /Automation, but has no main window!
TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run – quitting application.\\n");
AfxPostQuitMessage(0);
&rightsign;
return CWinThread::Run();
&rightsign;
// main running routine until thread exits
int CWinThread::Run()
&leftsign;
ASSERT_VALID(this);
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
&leftsign;
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
&leftsign;
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume "no idle" state
&rightsign;
// phase2: pump messages while available
do
&leftsign;
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset "no idle" state after pumping "normal" message
if (IsIdleMessage(&m_msgCur))
&leftsign;
bIdle = TRUE;
lIdleCount = 0;
&rightsign;
&rightsign; while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
&rightsign;
ASSERT(FALSE); // not reachable
&rightsign;
能否在dll中建立计时器?
后台线程()
&leftsign;
while(not_quit)
&leftsign;
得到当前时间t1;
处理。。。。
得到当前时间t2;
发消息给主窗口,,,
Sleep(period – (t2-t1) );
&rightsign;
&rightsign;
while(1)
&leftsign;
…
if(WaitForSingleObject(OBJECT_CONTROLED, ANY_TIME_YOU_WANT) == WAIT_TIMEOUT)
&leftsign;
//SendSomeMessageHere
continue;
&rightsign;
else
break;
…
&rightsign;
其中,OBJECT_CONTROLED可以是外部控制的一个CEvent或其他任何好用的东东
其实使用SetTimer就可以了,窗口句柄设为NULL,并给出“TimerProc”函数指针就行了
怎么在dll里写消息循环,处理别的dll发送过来消息?对消息绝望了,改用回调函数了。
5,消息循环在很多地方都有应用。比如应用在线程池中。一个线程的执行周期一般在线程函数返回之后结束,那么怎么延长线程的生命周期呢?一种方法就是按照消息循环的思想,在线程中加入消息循环,不断地从线程队列读取消息,并处理消息,线程的生命周期就保持着直到这个消息循环的退出。
NOTE:只要线程有界面元素或者调用GetMessage,或者有线程消息发送过来,系统就会为线程创建一个消息队列。
6,在单线程程序中,如果要执行一个长时间的复杂操作而且界面要有相应的话,可以考虑用自己的消息泵。比如,可以将一个阻塞等待操作放在一个循环中,并将超时值设置得比较小,然后每个等待的片段中用消息泵继续消息循环,使界面能够响应用户操作。等等之类,都可以应用消息泵
一开始的确在DLL与消息循环的确有点糊涂,而且将DLL与线程搞混了,后来清醒起来,后来自己用一段代码澄清了一些想法,也从大家的回贴中明白很多。
一个类放在DLL,寻址也会映射到同一个进程地址空间,这种寻址是透明的,与一般没有什么区别。DLL中函数的代码创建的任何对象均由调用线程所拥有,而不是由DLL本身从不拥
有任何东西,所以问题不在于与DLL的关系。
消息队列,消息循环与消息函数的关系:
消息队列只与线程有关,只要线程中有检查消息队列或建立窗口,就会有一个消息队列,否则不会有任何消息队列。这个是由操作系统完成的。
如果有消息队列就应该有一个消息循环,有一个与UI有关的线程就应该有一个消息循环。而且每一个窗口都应该有一个能处理自己的消息的消息函数。
所以无论是不是在DLL中,如果开一个UI线程,就应该加一个消息循环处理,否则一个程序中应该不需要多个消息循环。一个线程中有多个消息循环,不会阻塞(这个不是多线程),
而且它们的关系是嵌套的,只可能从一个消息循环引发的消息函数进入到另一个消息循环,这样会存在对WM_QUIT处理的问题,程序不能正常结束,除非你自己再发WM_QUIT消息,
所以最好不要用一个线程中多个消息循环的设计。
其实经过测试在DLL中有消息循环,它也能DispatchMessage出来给调用它的程序,这个是DispatchMessage的作用,与MFC的钩子无关(用pureAPI试过)。但是这样多循环的设计总
是古怪的。
而且在DLL中创建一个窗口,只要注册了自己的消息处理函数DispatchMessage一样可以去调用你的消息处理函数,根本不用消息循环,当时同事的程序有问题是因为没有将自己的
窗口给SetFocus所以没有办法得到消息,而我也没有查觉,本能的以为是DLL的内部寻址或是与AFX_MANAGE_STATE(AfxGetStaticModuleState());相关的问题,看来是犯了一个低级
错误。
历史博文
- 20080218 c# 固定格式 协议解析 资料 - 2008
- 20070619 Ruby or rails 初步 - 2007
- 微软 LIVE DOMAIN EMAIL 3 域名结尾 邮箱 免费 失败 - 2005
- VC6 VC7 DDK 2000 XP SP1 vccheck - 2005