FIX: MFC ActiveX Control May Flicker Excessively When it Is Overlapped By an IFRAME (310384)
The information in this article applies to:
- Microsoft Internet Explorer (Programming) 4.01 SP1
- Microsoft Internet Explorer (Programming) 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. STATUSMicrosoft
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: - Override COleControl::OnSetObjectRects.
- Copy the code.
- 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
#include <afxpriv2.h>
#include <..\src\mfc\afximpl.h>
#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 "true" 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("WM_PAINT : %d", 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:
<html>
<body>
<textarea style="width: 100%; height: 10%">You can type in this text area</textarea>
<iframe src="mfctest.htm" style="top: 300; left: 0; position:absolute"></iframe>
<iframe src="about:blank" style="top: 300; left: 200; position: absolute"></iframe>
</body>
</html>
Name the newly created HTML file Test.htm, and
then put it on the Web server. - Create an HTML file to display the MFC control that uses
the following code:
<html>
<body>
<object
classid="clsid:9BAA02AE-5877-4261-8F35-8831CE25BDD9"
height = "100%"
width = "100%">
</object>
</body>
</html>
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.
- 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.
Modification Type: | Major | Last Reviewed: | 5/12/2003 |
---|
Keywords: | kbbug kbfix kbMSHTML KB310384 |
---|
|