轉帖|其它|編輯:郝浩|2010-09-01 14:27:36.000|閱讀 1345 次
概述:正如VC ++ 6.0的演示程序MFCIE所示,用應用程序向導創建一個具有Web導航能力的MFC應用可謂輕而易舉。本文在此基礎上,進一步討論兩個問題:資源自包含的實現,上下文菜單以及快捷鍵的完全控制。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
正如VC ++ 6.0的演示程序MFCIE所示,用應用程序向導創建一個具有Web導航能力的MFC應用可謂輕而易舉。本文在此基礎上,進一步討論兩個問題:資源自包含的實現,上下文菜單以及快捷鍵的完全控制。
一、資源自包含及res協議
所謂的資源自包含,指的是在最終產品中HTML文檔(包括相關資源如腳本、圖片)成為執行文件的一部分,就象其它資源(如應用程序圖標)一樣,而不是以獨立文件形式分發。
資源自包含不僅使產品分發更為方便,而且在最終用戶面前隱藏了更多的實現細節,具有一定的現實意義。
MFC類CHtmlView不僅把WebBrowser控件的所有功能(如導航,用戶接口配置等)重新整理成為C++方法和MFC事件映射,還提供了許多“原創”的功能。其中之一便是從包含它的應用程序中讀取Web頁面的能力。完成這個任務的主要方法為CHtmlView::LoadFromResource(),其原型如下:
BOOL LoadFromResource( LPCTSTR lpszResource ); //用字符串指定資源ID
BOOL LoadFromResource( UINT nRes ); //用數字指定資源ID
LoadFromResource()依賴于res://協議(IE在找不到URL指定的服務器時,所顯示的錯誤提示頁面即使用res協議引出。)res協議的URL和常見的http或ftp協議所用URL格式不同,它的完整語法為:
res://resource_file[/resource_type]/resource_id
其中resource_file為包含目標資源的執行文件名字。resource_type為資源類型,它可能用數字表示,也可能用字符串表示。當資源為定制或不直接支持類型時用字符串指出資源類型(如GIF,JPEG等,可在.RC文件中定義);當資源為已知類型時該值往往用數字表示(如位圖為2,HTML為23)。已知資源類型的完整列表可以參見winuser.h,它是一組RT_常量。
CHtmlView::LoadFromResource()總是假定目標資源所在的執行文件為當前模塊。但在實際應用中,我們往往要把資源分類放在不同文件中。為解決此問題,可以定義一個派生類CHtmlViewEx覆蓋此方法,只需要對原方法略作修改引入模塊參數即可:
『清單1』
BOOL CHtmlViewEx::LoadFromResource(LPCTSTR lpszModule, LPCTSTR lpszResource)
{
CString strResourceURL;
strResourceURL.Format(_T(" res://%s/%s" ), lpszModule, lpszResource);
Navigate(strResourceURL, 0, 0, 0);
return TRUE;
}
二、上下文菜單和快捷鍵控制
在實際應用中,為了避免用戶查看頁面源文件或防止用戶用快捷鍵打開當前頁面的另外一個窗口,我們往往要對由WebBrowser控件提供的上下文菜單(在頁面上按鼠標右鍵)或快捷鍵(如Ctrl+N打開新窗口)加以定制。
無論是WebBrowser控件還是CHtmlView類都沒有直接提供定制上述操作的方法,因而必須通過實現IDocHostUIHandler接口來完成。在該接口中,可以實現上下文菜單和快捷鍵控制的方法分別為ShowContextMenu()和TranslateAccelerator()。
由于使用MFC封裝類CHtmlView比直接應用WebBrowser控件更為方便,因而可以考慮把定制之后的接口支持功能集成到MFC框架內。具體實現的基本思路如下:
創建一個新的OLE客戶站并在其中實現接口IDocUIHandler
在InitInstance()中用一個新的管理類取代缺省配置以引入該客戶站
基于以上思路,我們可以從COleControlSite創建派生類CCustomWebBrowserSite,并在派生類中實現IDocHostUIHandler。COleControlSite在V的mfcsrcoccimpl.h中定義,用于封裝控件客戶站。新的客戶站定義為:
『清單2』
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()的實現代碼為:
『清單3』
STDMETHODIMP CCustomWebBrowserSite::XDocHostUIHandler::ShowContextMenu(
DWORD, POINT*, IUnknown*, IDispatch*)
{
METHOD_PROLOGUE(CCustomWebBrowserSite, DocHostUIHandler)
return S_OK; // 禁止菜單顯示
}
用類似的方法可以關閉由控件直接響應的快捷鍵:
『清單4』
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中定義:
『清單5』
class CCustomOccManager : public COccManager
{
public:
CCustomOccManager() { }
COleControlSite* CreateSite(COleControlContainer* pCC)
{
CCustomWebBrowserSite *pSite = new CCustomWebBrowserSite(pCC);
return pSite;
}
} ;
到此為止,我們可以使用新的控件管理類CCustomOccManager了。在應用程序類的InitInstance()中找到AfxEnableControlContainer()調用,將它替換為:
『清單6』
CCustomOccManager *pMgr = new CCustomOccManager;
AfxEnableControlContainer(pMgr);
CHtmlView::Create()函數將再次調用AfxEnableControlContainer(),這個調用使得我們原先對控件客戶站的聲明無效。我們可以在派生類中將CHtmlView::Create()代碼拷貝一份,并刪除對AfxEnableControlContainer()的調用:
『清單7』
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;
}
三、一個示例程序
本示例MyBrowser具體演示以上討論的技術,它顯示一個包含在MyBrowser.exe中的HTML頁面,并通過IDocHostUIHandler接口關閉控件的上下文菜單和快捷鍵,
程序在Visual C++ 6.0企業版中調試通過,以下列出具體步驟:
創建MFC EXE工程MyBrowser,選項依次為:單文檔界面(步驟1)、不需要數據庫支持(步驟2)需要ActiveX控件支持(步驟3)、不需要復合文檔支持(步驟3)、步驟4采用缺省值、步驟5采用缺省值、將視圖基類改為CHtmlView(步驟6);
加入HTML文件及相關資源(如HTML文件“DEFAULT.HTM”);
加入類CCustomWebBrowserSite和CCustomOccManager,文件為CustomWebBrowserSite.h和CustomWebBrowser.cpp;
修改MyBrowser.cpp文件,在消息映射聲明之前加入:
#include < ..srcoccimpl.h >
#include " CustomWebBrowserSite.h"
修改CMyBrowserApp::InitInstance(),用清單6替換AfxEnableControlContainer();
用類向導創建CHtmlView的派生類CHtmlViewEx,覆蓋Create()和LoadFromResource(),文件為HtmlViewEx.h和HtmlViewEx.cpp;
修改CMyBrowserView聲明,在類聲明之前加入#include " HtmlViewEx.h" ,使CMyBrowserView從CHtmlViewEx繼承;
修改CMyBrowserView:: OnInitialUpdate(),在這里運行初始界面,如:
CHtmlView::LoadFromResource(_T(" DEFAULT.HTM" ))。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:網絡轉載