
本文共 7154 字,大约阅读时间需要 23 分钟。
MFC有PreTranslageMessage() 可以处理一些基于MFC的消息处理。
可是有时候如果你开发一个基于MFC的ActiveX作为容器,内部实现是Win32 或者其他框架会发现,好多消息都不能正常收到。
除非把你现有的内部的控件基于各种MFC的基类实现(会重载各种MFC的PreTranslateMessage)才能收到各种消息。
根本原因是基于MFC的ActiveX控件没有自己的消息循环,要基于使用ActiveX的容器来处理消息。这样有时候会忽略掉一些我们需要的消息。
微软官方有出过KB来解决问题,这里贴出了备忘一下。
PRB: MFC ActiveX Control in IE Doesn't Detect Keystrokes
https://support.microsoft.com/en-us/kb/168777
The TAB key, arrow keys, and accelerator keys do not work as expected when an ActiveX control is the parent window of a modeless dialog box or of a propertysheet window
https://support.microsoft.com/en-us/kb/187988
SYMPTOMS
However, PreTranslateMessage is not always called for an MFC ActiveX control.
CAUSE
Internet Explorer does not automatically UI-Activate any controls when a page is first loaded. Internet Explorer waits until the user tabs to an ActiveX control on the page to UI-Activate it. Also, MFC ActiveX controls UI-Activate themselves when they are clicked with the mouse. In an MFC ActiveX control, this is done in COleControl::OnLButtonUp.
If you have a child control inside your COleControl, mouse-click messages on the child control are not sent to the COleControl and MFC does not UI- Activate the ActiveX control, even though the child control has just been given the keyboard focus. Internet Explorer intercepts the keystrokes and does not give the control a chance to filter them in PreTranslateMessage.
// trap keys and forward on to the control BOOL CMyActiveXCtrl::PreTranslateMessage(MSG* pMsg) { switch (pMsg->message) { case WM_KEYDOWN: case WM_KEYUP: switch (pMsg->wParam) { case VK_UP: case VK_DOWN: case VK_LEFT: case VK_RIGHT: case VK_HOME: case VK_END: SendMessage (pMsg->message, pMsg->wParam, pMsg->lParam); // Windowless controls won't be able to call SendMessage. // Instead, just respond to the message here. return TRUE; } break; } return COleControl::PreTranslateMessage(pMsg); }
int CMyActiveXCtrl::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) { if (!m_bUIActive) OnActivateInPlace (TRUE, NULL); // == UI-Activate the control return COleControl::OnMouseActivate(pDesktopWnd, nHitTest, message); }
int CMyActiveXCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (COleControl::OnCreate(lpCreateStruct) == -1) return -1; OnActivateInPlace (TRUE, NULL); // == UI-Activate the control return 0; }
MORE INFORMATION
Sample Code
// Handle to the Windows Message hook. It can be a global variable or a // member variable in your CPropertySheet-derived class. HHOOK hHook = NULL; // Hook procedure for WH_GETMESSAGE hook type. LRESULT CALLBACK GetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) { // Switch the module state for the correct handle to be used. AFX_MANAGE_STATE(AfxGetStaticModuleState( )); // If this is a keystrokes message, translate it in controls' // PreTranslateMessage(). LPMSG lpMsg = (LPMSG) lParam; if( (nCode >= 0) && PM_REMOVE == wParam && (lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST) && AfxGetApp()->PreTranslateMessage((LPMSG)lParam) ) { // The value returned from this hookproc is ignored, and it cannot // be used to tell Windows the message has been handled. To avoid // further processing, convert the message to WM_NULL before // returning. lpMsg->message = WM_NULL; lpMsg->lParam = 0L; lpMsg->wParam = 0; } // Passes the hook information to the next hook procedure in // the current hook chain. return ::CallNextHookEx(hHook, nCode, wParam, lParam); } // Declare and define the following two functions: BOOL CModelessPropertySheet::OnInitDialog() { CPropertySheet::OnInitDialog(); // Install the WH_GETMESSAGE hook function. hHook = ::SetWindowsHookEx( WH_GETMESSAGE, GetMessageProc, AfxGetInstanceHandle(), GetCurrentThreadId()); ASSERT (hHook); return TRUE; // Return TRUE unless you set the focus to a control. // EXCEPTION: OCX Property Pages should return FALSE. } void CModelessPropertySheet::OnClose() { // Uninstall the WH_GETMESSAGE hook function. VERIFY (::UnhookWindowsHookEx (hHook)); CPropertySheet::OnClose(); }
Steps to Reproduce the Problem
- Select the MFC ActiveX ControlWizard to create an ActiveX control. Accept all the default settings.
- Display a modeless dialog box or propertysheet window when double-clicking inside the control.
在消息回调函数中调用PreTranslateMessage() 处理对话框消息,加速键消息,然后处理特殊按键
最后调用COleControl::PreTranslateMessage(pMsg); 如果该ActiveX控件内包含其他MFC类的子控件
若经过PreTranslateMessage处理以后把消息全部置空,这样这些消息就不会再被容器应用程序所处理。
发表评论
最新留言
关于作者
