Microsoft KB Archive/318034

= PRB: Windowless ATL Control Does Not Receive Focus Messages in Internet Explorer =

Article ID: 318034

Article Last Modified on 5/12/2003

-

APPLIES TO


 * Microsoft Internet Explorer 5.0
 * Microsoft Internet Explorer 5.01
 * Microsoft Internet Explorer 5.5

-



This article was previously published under Q318034



SYMPTOMS
When you run Active Template Library (ATL) windowless ActiveX controls in Internet Explorer, you receive the WM_SETFOCUS message, but you do not receive the WM_KILLFOCUS message when you press the TAB key to move out of the control or out of the application.



CAUSE
By design, Internet Explorer forwards the WM_SETFOCUS message to the windowless ActiveX control, but it does not forward the WM_KILLFOCUS message. The specifications for windowless ActiveX controls (in the IOleInPlaceObjectWindowless::OnWindowMessage method documentation) state that windowless ActiveX control containers do not have to forward either of these messages.



RESOLUTION
You can handle the state changes if you implement the following methods:


 * IOleInPlaceObject::UIDeactivate
 * IOleObject::DoVerb
 * IOleInPlaceActiveObject::OnFrameWindowActivate



MORE INFORMATION
This section includes a code sample that you can add to an ATL windowless control. Notice the following features in the code sample:


 * IOleInPlaceObject::UIDeactivate is called if you press TAB or click another control in Internet Explorer. This is where you can handle the equivalent of a WM_KILLFOCUS event.
 * IOleObject::DoVerb is called with OLEIVERB_UIACTIVATE if you press TAB or click your control. You must not call IOleInPlaceSiteWindowless::SetFocus(TRUE) from here because that function calls the DoVerb method and causes a stack overflow.
 * IOleInPlaceActiveObject::OnFrameWindowActivate is called on the user interface (UI) active control whenever the hosting application switches in and out of focus. If you want to receive keyboard messages, you must call IOleInPlaceSiteWindowless::SetFocus(TRUE) when your control is being activated.
 * The OnKeyDown function is added to demonstrate when the keyboard messages are received.
 * The OnLButtonDown function is added to show that you must call the SetFocus method when you click the control. If you do not call SetFocus, you do not receive keyboard messages.

class ATL_NO_VTABLE CAtlFocusTest : ... { public: ...   STDMETHOD(UIDeactivate)(void) {       ATLTRACE(&quot;CAtlFocusTest::UIDeactivate - handle kill focus event\n&quot;); return IOleInPlaceObjectWindowlessImpl::UIDeactivate; }

STDMETHOD(DoVerb)(LONG iVerb, LPMSG pMsg, IOleClientSite* pActiveSite, LONG lindex,                                    HWND hwndParent, LPCRECT lprcPosRect) {       if (iVerb == OLEIVERB_UIACTIVATE) {           ATLTRACE(&quot;CAtlFocusTest::DoVerb(iVerb=%d) - handle set focus event\n&quot;, iVerb); // Do not call IOleInPlaceSiteWindowless::SetFocus(TRUE) here because // it will call DoVerb again! }       else ATLTRACE(&quot;CAtlFocusTest::DoVerb(iVerb=%d) - handle some other event\n&quot;, iVerb); return IOleObjectImpl::DoVerb(iVerb, pMsg, pActiveSite, lindex, hwndParent, lprcPosRect); }

STDMETHOD(OnFrameWindowActivate)(BOOL fActivate) {       if (fActivate) {           ATLTRACE(&quot;CAtlFocusTest::OnFrameWindowActivate(fActivate=%d) - handle set focus event (switching app)\n&quot;, fActivate); if (m_spInPlaceSite) m_spInPlaceSite->SetFocus(TRUE); }       else {           ATLTRACE(&quot;CAtlFocusTest::OnFrameWindowActivate(fActivate=%d) - handle kill focus event (switching app)\n&quot;, fActivate); if (m_spInPlaceSite) m_spInPlaceSite->SetFocus(FALSE); }       return IOleInPlaceActiveObjectImpl::OnFrameWindowActivate(fActivate); }   LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {       ATLTRACE(&quot;CAtlFocusTest::OnKeyDown(%d, %d, %d, %d)\n&quot;,            uMsg, wParam, lParam, bHandled); return 0; }   LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {       if (m_spInPlaceSite) m_spInPlaceSite->SetFocus(TRUE); return 0; } ... }; This code can be added to both the ATL full control and the ATL lite control.

