WTL的消息机制
一、SDI流程
Run全局线程
1、 Module.AddMessageLoop(&theLoop), 保存CMessageLoop与一个线程id的对应,Module是全局变量。
2、 wndMain的构造,初始化变量
3、 wndMain的CreateEx
wndMain的Create
注册窗口类(窗口过程的地址是StartWindowProc)
调用基类CframeWindowImplBase的Create
保存实例的this到_module中_Module.AddCreateWndData(&m_thunk.cd, this);
Win32的CreateWindow函数
CreateWindow将触发第一个WM_XXX消息,从而调用StartWindowProc
StartWindowProc主要是初始化一个thunk代码,并将窗口过程修改为thunk的开始处,thunk代码先将堆栈中保存HWND的位值中放入this指针,然后用jmp跳到WndProc函数进行处理
4、调用wndMain.ShowWindow(nCmdShow);
5、int nRet = theLoop.Run();
6、_Module.RemoveMessageLoop();
线程结束
二、消息循环
// theLoop.Run();
int Run()
{
BOOL bDoIdle = TRUE;
int nIdleCount = 0;
BOOL bRet;
for(;;)
{
//检测队列中有无消息
while(!::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE) && bDoIdle)
{
if(!OnIdle(nIdleCount++))
bDoIdle = FALSE;
}
//得到消息并从队列中去除
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(bRet == -1)
{
ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
continue; // error, don't process
}
//bRet是0表示收到WM_QUIT
else if(!bRet)
{
ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n"));
break; // WM_QUIT, exit message loop
}
//PreTranslateMessage遍历CMessageFilter如果有一个则调用并返回TRUE
//如果在窗口类中定义这个函数并且加入了filter他将不被发到窗口过程中去。
//注意这个函数是虚函数
if(!PreTranslateMessage(&m_msg))
{
::TranslateMessage(&m_msg);
::DispatchMessage(&m_msg);
}
if(IsIdleMessage(&m_msg))
{
bDoIdle = TRUE;
nIdleCount = 0;
}
}
return (int)m_msg.wParam;
}
三、ProcessMessage
ProcessMessage是一个虚函数,由派生类中通过宏定义实现被
WndProc调用。
参考文章