MFC ocx IE中应用相关问题
一、IE中调用控件时碰到过的问题
1、控件发消息让IE退出
::PostMessage(m_hwnd, WM_DESTROY, 0, 0); //m_hwnd为ie的窗口句柄
::PostMessage(m_hwnd, WM_CLOSE, 0, 0); //但是对于整个ie都会退出,而不仅仅是关闭该选项卡。
2、去掉IE滚动条,并且让控件充满整个IE客户区的方法如下。
控件无法覆盖整个客户区的原因是因为IE页面有默认的边距,将其设为0即可。可以让控件覆盖掉IE的滚动条,而不用在body中将其scroll="no"。
html代码如下:
<style type="text/css"> <!-- body { margin-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; } --> </style> <body style="overflow:hidden"> <OBJECT classid="clsid:22841351-AA11-4288-9FCD-F6CF96973265" id=HWPdfReader width=100% height=100%></object>
3、参考链接:http://blog.sina.com.cn/s/blog_57421ff80100dc0q.html
( 3.1) 网页刷新
当ocx加载在网页上时,如果F5刷新, ocx控件会销毁ocx的窗口类,但是ocx的app类是不销毁的。只有当网页关闭时,才销毁app类。
当app类中有成员变量时,请注意刷新回来后变量的值还是刷新前的值。
利用刷新app类的不析构恢复刷新前的状态:可在控件的app类中保存刷新前的值,刷新后恢复刷新前的状态。
(3.2)一个网页中加载2次(或者多次)ocx控件
同一个进程加载2次控件时,app类调用1次,ocx窗口类调用2次。也就是说2个控件实例使用的是同一个app类的实例,只是有各自的窗口。这时如果app类中有成员变量,值得注意。
4、在OnDestory函数中释放资源,跟踪发现函数未执行; ATL中CAxWindow Create控件,程序异常,跟踪发现此时控件WM_CREATE未执行,窗口句柄为空导致。
大多数ActiveX控件框架,例如MFC和ATL,在本地激活ActiveX控件时创建控件。基于性能上的考虑,直到控件第一次可见的时候,IE才本地激活ActiveX控件。这样包含ActiveX控件的网页载入更加迅速,占用内存更少。这也使得ActiveX控件的WM_CREATE处理代码直到控件第一次可见的时候才被调用。
控件支持非窗口激活,那么IE会以非窗口激活方式创建控件,这样在离开或者关闭页面的时候控件的WM_DESTORY处理代码不会被调用。
解决方法: IE在初始化或者退出页面时,会调ActiveX的IOleObject::SetClientSite实现,无论控件是否被本地激活。在初始化页面的时候,传递的指针是宿主的IOleClientSite接口指针,在离开或者关闭页面的时候,传递的指针是空指针。可以根据这个指针来判断控件的状态,并且执行初始化或者清除的代码。
MFC MFC对IOleObject::SetClientSite()的实现包含对虚函数COleControl::OnSetClientSite()的调用。这时候可以根据m_pClientSite是否为空指针来判断控件是被加载还是被清除。 // CMyControl 派生于COleControl. void CMyControl::OnSetClientSite() { if (m_pClientSite) //父窗口及其大小并不重要,因为控件在本地激活时会自动重画和重新定位。 VERIFY (CreateControlWindow (::GetDesktopWindow(), CRect(0,0,0,0), CRect(0,0,0,0))); else DestroyWindow(); COleControl::OnSetClientSite(); } ATL ATL对IOleObject::SetClientSite()的实现有一个IOleClientSite类型的参数(MFC在对IOleObject::SetClientSite()的实现中保存这个指针到COleControl::m_pClientSite),直接拿来判断就行了。
同时,ATL没有重新设置控件的父窗口,所以控件需要手动进行本地激活。 // CMyControl 派生于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); } else ::DestroyWindow(m_hWnd); return IOleObjectImpl::SetClientSite (pClientSite); }
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); < BR > return CComControlBase::InPlaceActivate(iVerb, prcPosRect); < BR > }
参考链接:https://www.cnblogs.com/wainiwann/p/7059064.html
https://blog.csdn.net/u012425536/article/details/51487442