MFC ActiveX 控件在IE下闪烁的问题

来源:互联网 发布:通用字体软件下载 编辑:程序博客网 时间:2024/04/30 09:30

这周打算发布公司新版本的OCX,忽然又收到客户报的一个很老的bug,公司的OCX在IE下使用的时候,拉动滚动条会重叠,而且还有很严重的闪烁的现象。上半年的时候已经查过相关资料,没有找到解决方法,而且老大也说这个是微软的一个bug,我们无法解决。有些戏剧性的是,林mm发了一个微软的网页,称那篇文章详细说明了那个bug的问题,让我看一下,再和客户解释我们为什么不能解决。那个链接是:

http://support.microsoft.com/kb/233391

认真看了一下,微软是声称那个bug在IE5下是有问题的,可是在IE6下,是已经有办法解决了。

解决第一步,依葫芦画瓢,根据微软说的方法重载了OnSetObjectRects,但是实现为空的,代码如下:

BOOL CmfcaxCtrl::OnSetObjectRects(LPCRECT lpRectPos, LPCRECT lpRectClip) 
{

 return TRUE; 
}

兴致勃勃的rebuild all,再用IE测试。发现是不闪烁了,可是初始化时被隐藏的那部分照样没刷新,-_-失败告终。

冲击第二步,再认真看了那篇文章,发现有一个注意项:

注意 已更改解决以下 Microsoft 知识库 (KB) 文章中描述的问题: 在 Internet Explorer 中

307978  FIX: 重叠 IFRAME 中的 MFC 控件收到不必要的 WM _ PAINT 消息

点击进去,第二篇文章讲述了OnSetObjectRects的重载方法:

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 CTmpCtrl::OnSetObjectRects(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
{
// return COleControl::OnSetObjectRects(lprcPosRect, lprcClipRect);
ASSERT(lprcPosRect != NULL);

// Remember the position rectangle.
m_rcPos = *lprcPosRect;

// Calculate complete rectangle, include the tracker if it is 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 the rectangle as appropriate.
CRect rectClip;
MyGetClippingCoordinates(rectPos, lprcClipRect, rectClip, &m_ptOffset);

// Move the outer window first, and then move the inner window.

if (!m_bInPlaceSiteWndless)
{
CWnd* pWndOuter = GetOuterWindow();

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

return TRUE;
}

再rebuild下,发现外框是不会闪了,但是中间那些view窗口还是能感觉到闪烁,那个方法只是对IE下闪烁问题做了一些缓解,效果还不是很理想。继续再baidu和google,很难找到最有效的解决方法。继续做其他尝试,还是毫无结果。

冲击三,今天无意间又搜到一篇文章,内容和第一篇很像,也是说了OnSetObjectRects的重载方法,代码几乎一模一样,原先还以为微软弄了个冗余的网页,差点忽略过去。那个网页地址为:

http://support.microsoft.com/kb/310384/zh-cn

本着死马当活马医的思想,又试了一下,原以为会和第二次的结果是一样的,令人惊奇的事情就在意外中发生了。用IE测试的时候,没有闪烁,最小化,很自然的平铺过去了。正当我要欢呼的时候,在StatusBar下面出现了令人恶心的重叠。。。。。继续baidu&&google,无果。。。

在msdn上发现了一个人说把

pOffsetPoint->x = min(0, pPosRect->left - clipLeft);
       pOffsetPoint->y = min(0, pPosRect->top - clipTop);
改一下,改成(0,0)的效果更好些。尝试下,果然,效果非常好。闪烁+重叠的现象都没发现,顿时感到人生真是美好。

那个bug貌似解决了,等测试结果吧。心情一下子开朗了很多,就一个字,爽