|
在实际应用中,为了避免用户查看页面源文件或防止用户用快捷键打开当前页面的另外一个窗口,我们往往要对由WebBrowser控件提供的上下文菜单(在页面上按鼠标右键)或快捷键(如Ctrl+N打开新窗口)加以定制。
无论是WebBrowser控件还是CHtmlView类都没有直接提供定制上述操作的方法,因而必须通过实现IDocHostUIHandler接口来完成。在该接口中,可以实现上下文菜单和快捷键控制的方法分别为ShowContextMenu()和TranslateAccelerator()。
由于使用MFC封装类CHtmlView比直接应用WebBrowser控件更为方便,因而可以考虑把定制之后的接口支持功能集成到MFC框架内。具体实现的基本思路如下:
创建一个新的OLE客户站并在其中实现接口IDocUIHandler
在InitInstance()中用一个新的管理类取代缺省配置以引入该客户站
基于以上思路,我们可以从COleControlSite创建派生类CCustomWebBrowserSite,并在派生类中实现IDocHostUIHandler。COleControlSite在VC++的mfcsrcoccimpl.h中定义,用于封装控件客户站。新的客户站定义为:
清单
class CCustomWebBrowserSite : public COleControlSite
{
public:
CCustomWebBrowserSite(COleControlContainer *pCnt):
COleControlSite(pCnt){ }
protected:
DECLARE_INTERFACE_MAP();
BEGIN_INTERFACE_PART(DocHostUIHandler, IDocHostUIHandler)
STDMETHODIMP ShowContextMenu(DWORD, POINT*, IUnknown*, IDispatch*);
STDMETHODIMP TranslateAccelerator(LPMSG, const GUID*, DWORD);
STDMETHODIMP GetHostInfo(DOCHOSTUIINFO);
STDMETHODIMP EnableModeless(BOOL);
STDMETHODIMP OnDocWindowActivate(BOOL);
STDMETHODIMP OnFrameWindowActivate(BOOL);
STDMETHODIMP ResizeBorder(LPCRECT, IOleInPlaceUIWindow*, BOOL);
STDMETHODIMP GetOptionKeyPath(LPOLESTR*, DWORD);
STDMETHODIMP GetDropTarget(IDropTarget*, IDropTarget**);
STDMETHODIMP GetExternal(IDispatch**);
STDMETHODIMP TranslateUrl(DWORD, OLECHAR*, OLECHAR**);
STDMETHODIMP FilterDataObject(IDataObject*, IDataObject**);
STDMETHODIMP ShowUI(DWORD, IOleInPlaceActiveObject*,
IOleCommandTarget*, IOleInPlaceFrame*, IOleInPlaceUIWindow*);
STDMETHODIMP HideUI(void);
STDMETHODIMP UpdateUI(void);
END_INTERFACE_PART(DocHostUIHandler)
} ;
如上所介绍,在这个接口中我们感兴趣的方法主要有ShowContextMenu()和TranslateAccelerator()两个。以完全禁止上下文菜单显示为例,在派生类CCustomWebBrowserSite中ShowContextMenu()的实现代码为:
清单
STDMETHODIMP CCustomWebBrowserSite::XDocHostUIHandler::ShowContextMenu(
DWORD, POINT*, IUnknown*, IDispatch*)
{
METHOD_PROLOGUE(CCustomWebBrowserSite, DocHostUIHandler)
return S_OK; // 禁止菜单显示
}
用类似的方法可以关闭由控件直接响应的快捷键:
清单
STDMETHODIMP CustomWebBrowserSite::XDocHostUIHandler::TranslateAccelerator(LPMSG lpMsg,const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID)
{
METHOD_PROLOGUE(CCustomWebBrowserSite, DocHostUIHandler)
return S_OK; // 关闭快捷键
}
在IDocHostUIHandler接口实现之后,我们还需要一个管理类CCustomOccManager来支持CCustomWebBrowserSite,新的管理类CCustomOccManager从COccManager派生,COccManager也在mfcsrcoccimpl.h中定义:
清单
class CCustomOccManager : public COccManager
{
public:
CCustomOccManager() { }
COleControlSite* CreateSite(COleControlContainer* pCC)
{
CCustomWebBrowserSite *pSite = new CCustomWebBrowserSite(pCC);
return pSite;
}
} ;
到此为止,我们可以使用新的控件管理类CCustomOccManager了。在应用程序类的InitInstance()中找到AfxEnableControlContainer()调用,将它替换为:
清单
CCustomOccManager *pMgr = new CCustomOccManager;
AfxEnableControlContainer(pMgr);
CHtmlView::Create()函数将再次调用AfxEnableControlContainer(),这个调用使得我们原先对控件客户站的声明无效。我们可以在派生类中将CHtmlView::Create()代码拷贝一份,并删除对AfxEnableControlContainer()的调用:
清单
BOOL CHtmlViewEx::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
UINT nID, CCreateContext* pContext)
{
m_pCreateContext = pContext;
if (!CView::Create(lpszClassName, lpszWindowName,
dwStyle, rect, pParentWnd, nID, pContext))
{
return FALSE;
}
RECT rectClient;
GetClientRect(&rectClient);
if (!m_wndBrowser.CreateControl(CLSID_WebBrowser, lpszWindowName,
WS_VISIBLE | WS_CHILD, rectClient, this, AFX_IDW_PANE_FIRST))
{
DestroyWindow();
return FALSE;
}
LPUNKNOWN lpUnk = m_wndBrowser.GetControlUnknown();
HRESULT hr = lpUnk- > QueryInterface(IID_IWebBrowser2, (void**) &m_pBrowserApp);
if (!SUCCEEDED(hr))
{
m_pBrowserApp = NULL;
m_wndBrowser.DestroyWindow();
DestroyWindow();
return FALSE;
}
return TRUE;
} |
|