您的位置:首页 > 其它

MFC DLL PreTranslateMessage 导致的快捷键不响应的问题?

2015-06-04 16:35 375 查看
解决办法:
http://blog.sina.com.cn/s/blog_53d9f7e901000aef.html http://zhidao.baidu.com/link?url=wl3LlUGz_oCQplgHV6vyf-c0dOsBW4xNa68dQJJL_KH1WcjaETEdTvPRlf3ZgdXQ3vKpKRKmHYYOL02mW2vDGtbVrc-4pJuvPXDB_tnJSKu
上面贴出了方法,自己也验证了。

但这篇文章说不解决的问题的方法,而是说说MFC 为什么要用PreTranslateMessage原因!

故事开始:最近在视频播放器的界面,界面用DUILIB开发,界面全部封装在DLL里面,发现不能过滤快捷键,当时也没有想为什么?,那问题来了,窗口消息只会发送对应的窗口处理函数里面去,那我怎么在一个窗口统一处理呢?这个时候我想到用键盘钩子去处理。直接用HOOK 键盘钩子获取按键消息,比喻回车全屏,空格暂定。后面想想其实想想 PreTranslateMessage其实也是做同样事情,你是否有感觉了,你仔细想你就会发现为什么MFC 里面有一个afxMapHWND
这个东西了,因为保存整个 window hwnd的列表。

因为HWND 只是窗口句柄,但并没用,我们处理所有事情都是在窗口类中处理,所以我们通过afxMapHWND  获取对应的实体类。

说了这个么多,我直接用代码说事情,

我们window核心 消息循环来说:

BOOL AFXAPI AfxInternalPumpMessage()
{
_AFX_THREAD_STATE *pState = AfxGetThreadState();

if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
{
#ifdef _DEBUG
TRACE(traceAppMsg, 1, "CWinThread::PumpMessage - Received WM_QUIT.\n");
pState->m_nDisablePumpCount++; // application must die
#endif
// Note: prevents calling message loop things in 'ExitInstance'
// will never be decremented
return FALSE;
}

#ifdef _DEBUG
if (pState->m_nDisablePumpCount != 0)
{
TRACE(traceAppMsg, 0, "Error: CWinThread::PumpMessage called when not permitted.\n");
ASSERT(FALSE);
}
#endif

#ifdef _DEBUG
_AfxTraceMsg(_T("PumpMessage"), &(pState->m_msgCur));
#endif

// process this message

if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))
{
::TranslateMessage(&(pState->m_msgCur));
::DispatchMessage(&(pState->m_msgCur));
}
return TRUE;
}


这个代码和我们常写的win32代码和类似吧。

AfxPreTranslateMessage(&(pState->m_msgCur)


BOOL AfxInternalPreTranslateMessage(MSG* pMsg)
{
//	ASSERT_VALID(this);

CWinThread *pThread = AfxGetThread();
if( pThread )
{
// if this is a thread-message, short-circuit this function
if (pMsg->hwnd == NULL && pThread->DispatchThreadMessageEx(pMsg))
return TRUE;
}

// walk from target to main window
CWnd* pMainWnd = AfxGetMainWnd();
if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
return TRUE;

// in case of modeless dialogs, last chance route through main
//   window's accelerator table
if (pMainWnd != NULL)
{
CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
if (pWnd->GetTopLevelParent() != pMainWnd)
return pMainWnd->PreTranslateMessage(pMsg);
}

return FALSE;   // no special processing
}


BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
{
ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
ASSERT(pMsg != NULL);

// walk from the target window up to the hWndStop window checking
//  if any window wants to translate this message

for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL)
{
// target window is a C++ window
if (pWnd->PreTranslateMessage(pMsg))
return TRUE; // trapped by target window (eg: accelerators)
}

// got to hWndStop window without interest
if (hWnd == hWndStop)
break;
}
return FALSE;       // no special processing
}


CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg)
从pMsg->hwnd 
处理这个消息,如果自己不处理,就要爸爸窗口处理,爸爸窗口不处理,就要爷爷窗口处理,如果都没有返回FALSE,另外的代码块处理。

如果窗口类实在exe里面这里就会正常处理了。但在DLL 里面 

CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); 代码就会问题了,因为MFC是模块分开的不同的。比喻DLL1 是模块1 DLL2模块2 exe也是另一个模块。每个模块都有自己的窗口类列表。。。所以我在exe不能遍历到你的dll里面的窗口的。所以才不能运行。
</pre><p></p><p></p><p>上面的<pre name="code" class="cpp">AfxInternalPreTranslateMessage


// in case of modeless dialogs, last chance route through main
// window's accelerator table
if (pMainWnd != NULL)
{
CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
if (pWnd->GetTopLevelParent() != pMainWnd)
return pMainWnd->PreTranslateMessage(pMsg);
}如果上面还是没有处理,检测这个窗口不是WS_CHILD窗口的话就找他的归属的窗口去处理。
如果还没有归属者就找到最顶层窗口处理,反正就MFC就尽量找一个合适窗口来处理,总会找到一个合适来处理。

看代码还是看框架代码,一些代码细节代码看的真累,我现在看chromuni代码真新感觉有点累。。还是找自己感兴趣的模块看吧。

其实上面书了那么多,总结是 MFC 每一个模块保存窗口列表模块,每个模块独立。

______________________________________________________________________________________________

如果是我纯win32 去写这样的PreTranslateMessage 方式函数会怎么做呢? 我不用列表,在HWND 创建绑定一个数据结构,如果是用c++ 绑定 一个窗口c++ 类,如果c就绑定一个c的指针,这样就不会出现上面的模块的问题,但要考虑线程竞争的问题。所以MFC为什么要线程独立,模块独立的原因了。一旦多线程搞进来,很多东西就不能掌控了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: