http://support.microsoft.com/kb/195188
1. 问题描述:
最近做一个项目,需要将一个基于MFC的ActiveX嵌入到网页中。在嵌入过程中出现了这样一种情况:在Debug模式下,先执行OnCreate(),再执行对外的接口函数fun()(此函数页面会调用,函数内部会用到窗口句柄);在Release模式下,却先调用fun(),后调用OnCreate()。在Release横式下页面会崩溃,一时难以找到解决办法。后来在网上找了一些资料,是说IE浏览器采用了一种内存优化机制,即控件不可见时控件不会激活,即不会调用OnCreate()函数,控件的窗口句柄就为空。
2. 解决办法:
MFC
MFC 提供了一个函数称为 COleControl::CreateControlWindow() 创建控件的窗口。MFC的IOleObject::SetClientSite() 会调用 COleControl::OnSetClientSite(), 因此控件在加载后就会调用OnSetClientSite函数。将以下代码添加到您 COleControl 派生的类:
// CMyControl is derived from COleControl.
void CMyControl::OnSetClientSite()
{
if (m_pClientSite)
// It doesn't matter who the parent window is or what the size of
// the window is because the control's window will be reparented
// and resized correctly later when it's in-place activated.
VERIFY (CreateControlWindow (::GetDesktopWindow(), CRect(0,0,0,0),
CRect(0,0,0,0)));
COleControl::OnSetClientSite();
}
ATL:
ATL 还提供了一个函数称为 CComControl::CreateControlWindow()。但是,它将不会 re-parent 窗口以后这样,控件都需要手动执行此操作在就地激活 (CComControlBase::InPlaceActivate) 过程中。将以下代码添加到您 CComControl 派生的类 (通常是在类的头文件) 的声明:
// CMyControl is derived from CComControl
STDMETHOD(SetClientSite)(IOleClientSite *pClientSite)
{
if (pClientSite)
{
RECT rc = {0,0,0,0};
// Don't have access to the container's window so just use the
// desktop. Window will be resized correctly during in-place
// activation.
HWND hWnd = CreateControlWindow(::GetDesktopWindow(), rc);
_ASSERT (hWnd);
}
return IOleObjectImpl
}
HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect)
{
// Get the container's window.
_ASSERT (m_spClientSite);
LPOLEINPLACESITE pInPlaceSite = NULL;
HRESULT hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSite,
(void **)&pInPlaceSite);
_ASSERT (SUCCEEDED (hr) && pInPlaceSite);
HWND hParent = NULL;
hr = pInPlaceSite->GetWindow (&hParent);
_ASSERT (SUCCEEDED (hr) && hParent);
pInPlaceSite->Release ();
// Set container window as our parent window
SetParent (hParent);
return CComControlBase::InPlaceActivate(iVerb, prcPosRect);
}