开发基于MFC的ActiveX控件的时候的一些消息处理

来源:互联网 发布:达芬奇调色软件官方 编辑:程序博客网 时间:2024/06/05 04:56

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
Accelerator keys, such as ARROW keys, are first received by the message pump of the ActiveX control's container. Even if the control has the focus, it does not receive messages for keystrokes that have special meaning to control containers, such as ARROW and TAB keys. MFC ActiveX controls have a chance to intercept these messages by overriding their PreTranslateMessage function. 

However, PreTranslateMessage is not always called for an MFC ActiveX control.
CAUSE
PreTranslateMessage in an MFC ActiveX control is called by the TranslateAccelerator method of the IOleInPlaceActiveObject interface of the control. Internet Explorer only calls this method for the control that is currently UI-Active. Only one control can be UI-Active at a time. 

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.
RESOLUTION
Here is a typical PreTranslateMessage. This code forwards ARROW, HOME, and END keys back to the control so that they can be received using a MESSAGE_MAP entry:
   // 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);   }
If you have a child control within your ActiveX control, you need to UI-Activate the whole control whenever that child control is activated. For example, if you have an edit control inside your ActiveX control, add a handler as follows to your ActiveX control class:
   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);   }
Because Internet Explorer may not immediately UI-Activate a control, even if that is the only control on the page, it may be desirable to automatically request a UI-Activation when the control is created. This can be done during the COleControl::OnCreate (WM_CREATE) handler. Windowless controls do not get WM_CREATE or any windows messages; therefore, this code won't work in a windowless control. Also note that this does not guarantee that a control will remain UI-Activated. If there are other controls on a page that request UI-Activation in a similar manner, only one will eventually be UI-Activated and receive keystroke messages as described. And if the user TABs away from an ActiveX Control, Internet Explorer will automatically UI-deactivate the control.
   int CMyActiveXCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)   {      if (COleControl::OnCreate(lpCreateStruct) == -1)         return -1;      OnActivateInPlace (TRUE, NULL); // == UI-Activate the control      return 0;   }
MORE INFORMATION
The following sample shows a way to install the Windows message hook to a modeless CPropertySheet-derived class:

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

  1. Select the MFC ActiveX ControlWizard to create an ActiveX control. Accept all the default settings.
  2. Display a modeless dialog box or propertysheet window when double-clicking inside the control.
RESULTS: When the modeless dialog box or propertysheet window is shown, pressing the TAB key or accelerator keys has no effect.
大致流程是 ,需要在CxxxCtrl的OnInit 函数内注册全局钩子(参数中传入消息回调函数) 截获消息

在消息回调函数中调用PreTranslateMessage()  处理对话框消息,加速键消息,然后处理特殊按键

最后调用COleControl::PreTranslateMessage(pMsg);  如果该ActiveX控件内包含其他MFC类的子控件

若经过PreTranslateMessage处理以后把消息全部置空,这样这些消息就不会再被容器应用程序所处理。

0 0
原创粉丝点击