Microsoft KB Archive/310384

= FIX: MFC ActiveX Control May Flicker Excessively When it Is Overlapped By an IFRAME =

Article ID: 310384

Article Last Modified on 5/12/2003

-

APPLIES TO


 * Microsoft Internet Explorer 4.01 Service Pack 1
 * Microsoft Internet Explorer 5.5
 * Microsoft Internet Explorer (Programming) 5.5 SP1
 * Microsoft Internet Explorer (Programming) 5.5 SP2

-



This article was previously published under Q310384



SYMPTOMS
When a Microsoft Foundation Class (MFC) ActiveX control appears in an IFRAME element and then another IFRAME covers it completely along its height and width, if you update other parts of the host page, an unnecessary redraw of the MFC control may result in an unwanted flicker.



CAUSE
This behavior is caused by a bug in the way that Microsoft Internet Explorer updates parented controls.



RESOLUTION
You can override the OnSetObjectRects method to prevent the outer window of the MFC control from resizing to the clip:rect value. MFC controls typically have an extra parent window to handle reflection.



STATUS
Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.



MORE INFORMATION
You typically create MFC ActiveX controls with a parent window to act as a reflector window. When the IFRAME element overlaps an MFC control completely in one dimension, the parent -- or outer -- window of the MFC control shrinks to the clip:rect (the displayed portion) while the true size of the control -- the child window -- stays the same size. When you update the Web page, Microsoft Internet Explorer incorrectly detects that the outer window is the wrong size and then tries to resize it back to the full size of the control. MFC then resizes it back to the clip:rect. This causes the control to conduct an extra paint operation.

To work around this behavior in MFC, you can prevent MFC from resizing its outer window to the smaller clip size. To do so, follow these steps:


 * 1) Override COleControl::OnSetObjectRects.
 * 2) Copy the code.
 * 3) Modify the code. To do so, tell the outer window to resize to the control size and not to the clip:rect size as shown in the OnSetObjectRects in the following code.

To implement the function, you must copy the _GetClippingCoordinates function from the MFC sources and then include some non-standard MFC include files, such as the following:

Header File
class CflickerCtrl : public COleControl { ... public: virtual BOOL OnSetObjectRects(LPCRECT lpRectPos, LPCRECT lpRectClip);

Implementation File

 * 1) include 
 * 2) include <..\src\mfc\afximpl.h>
 * 3) include <..\src\mfc\ctlimpl.h>

void MyGetClippingCoordinates(LPCRECT pPosRect, LPCRECT pClipRect,   LPRECT pIntersectRect, LPPOINT pOffsetPoint) {   int clipLeft = 0; int clipTop = 0;

if ((pClipRect == NULL) || IsRectEmpty(pClipRect)) {       CopyRect(pIntersectRect, pPosRect); }   else {       IntersectRect(pIntersectRect, pPosRect, pClipRect); clipLeft = pClipRect->left; clipTop = pClipRect->top; }

pOffsetPoint->x = min(0, pPosRect->left - clipLeft); pOffsetPoint->y = min(0, pPosRect->top - clipTop); }

BOOL CflickerCtrl::OnSetObjectRects(LPCRECT lprcPosRect, LPCRECT lprcClipRect) {   ASSERT(lprcPosRect != NULL);

// Remember the position rectangle for later m_rcPos = *lprcPosRect;

// Calculate complete rectangle including the tracker (if present) CRect rectPos = m_rcPos; if (m_bUIActive && m_pRectTracker != NULL) {       // Save new clipping rectangle (for DestroyTracker) if (lprcClipRect != NULL) m_pRectTracker->m_rectClip = *lprcClipRect;

// Adjust tracker rectangle to new dimensions CRect rectTmp = rectPos; rectTmp.OffsetRect(-rectTmp.left, -rectTmp.top); m_pRectTracker->m_rect = rectTmp;

// Adjust the &quot;true&quot; rectangle to include handles/hatching UINT nHandleSize = m_pRectTracker->m_nHandleSize - 1; rectPos.InflateRect(nHandleSize, nHandleSize); }

// Now clip that rectangle as appropriate CRect rectClip;

// CHANGE - call your own copy of _GetClippingCoordinates MyGetClippingCoordinates(rectPos, lprcClipRect, rectClip, &m_ptOffset);

// Move outer window first. then inner window

if (!m_bInPlaceSiteWndless) {       CWnd* pWndOuter = GetOuterWindow; //BEGIN CHANGE if (pWndOuter != NULL) {

//     ::MoveWindow(pWndOuter->m_hWnd, rectClip.left, rectClip.top,        //          rectClip.Width, rectClip.Height, TRUE); ::MoveWindow(pWndOuter->m_hWnd, rectPos.left, rectPos.top,                   rectPos.Width, rectPos.Height, TRUE); }       //END CHANGE if (pWndOuter != this) MoveWindow(m_ptOffset.x, m_ptOffset.y, rectPos.Width, rectPos.Height); }

return TRUE; }

Steps to Reproduce the Problem
 In Microsoft Visual Studio .NET, create a default MFC ActiveX control.  Modify the OnDraw code so that the number of times that you called the code appears. For example: void CflickerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) {  static int nCount = 0; nCount++;

CPen pen; CBrush brush; pen.CreatePen(PS_SOLID, 4, RGB(0,0,255)); brush.CreateSolidBrush(RGB(0,128,128)); CPen *pOldPen = pdc->SelectObject(&pen); CBrush *pOldBrush = pdc->SelectObject(&brush);

pdc->Rectangle(&rcBounds); CString strMsg; strMsg.Format(&quot;WM_PAINT : %d&quot;, nCount); CRect drawRect = rcBounds; pdc->DrawText(strMsg, &drawRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

pdc->SelectObject(pOldPen); pdc->SelectObject(pOldBrush); }                        Build the control. Registration will automatically occur.  Create an HTML file to display the iframe objects that use the following code: You can type in this text area <iframe src=&quot;mfctest.htm&quot; style=&quot;top: 300; left: 0; position:absolute&quot;> <iframe src=&quot;about:blank&quot; style=&quot;top: 300; left: 200; position: absolute&quot;> Name the newly created HTML file Test.htm, and then put it on the Web server. </li>  Create an HTML file to display the MFC control that uses the following code: <object classid=&quot;clsid:9BAA02AE-5877-4261-8F35-8831CE25BDD9&quot; height = &quot;100%&quot; width = &quot;100%&quot;> Name the newly created HTML file Mfctest.htm, and then put it on the Web server. Remember to change the CLSID value so that you can use the CLSID value from your MFC control.

</li> Start Internet Explorer and locate Test.htm. If you type inside the text area, the MFC control redraws every time you press a key. If you slightly misalign the two iframes, for example, if you set the top attribute for one of the iframes in Test.htm at 305, the problem does not occur.</li></ol>

Keywords: kbbug kbfix kbmshtml KB310384

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.