經常見到有人問怎麼屏蔽html的右鍵菜單,有人答用PreTranslateMessage函數攔截wm_rbuttondown消息,於是總會有人說這種方法怎麼爛,@_@,我真不知道爲什麼,不過我想這也是一種方法呀,而且非常簡單,所以還是列出來吧:)
BOOL CPreTranslateMsgView::PreTranslateMessage(MSG* pMsg)
{
if ((pMsg->message == WM_RBUTTONDOWN)||(pMsg->message == WM_RBUTTONDBLCLK)){
CPoint point(pMsg->pt);
ScreenToClient(&point);
IHTMLDocument2* pdoc2=NULL;
IHTMLElement* pElement=NULL;
IDispatch* pDisp=NULL;
pDisp=GetHtmlDocument();
pDisp->QueryInterface(IID_IHTMLDocument2,(void**)&pdoc2);
pDisp->Release();
pdoc2->elementFromPoint(point.x,point.y,&pElement);
pdoc2->Release();
if(pElement){
BSTR ID;
pElement->get_id(&ID);
pElement->Release();
CString str=(LPCTSTR)(_bstr_t)ID;
if(str=="Layer1"){
CMenu menu;
menu.LoadMenu(IDR_MENU1 );
CMenu* pmenu=menu.GetSubMenu(0);
pmenu->TrackPopupMenu(0,pMsg->pt.x,pMsg->pt.y,this);
}
}
return TRUE;//如果想完全屏蔽掉,不顯示任何菜單,直接返回TRUE就行,上面這些代碼演示了怎麼對html中特定ID的元素彈出自己想要顯示的菜單
}else
return CHtmlView::PreTranslateMessage(pMsg);
}
2.通過子類化IE控件的窗口並處理WM_CONTEXTMENU消息
這是MSDN上介紹的方法,111222翻譯了那文章,大家自己去看:
屏蔽CHtmlViewCWebBrower2右鍵菜單的非官方方法 111222(翻譯)。
http://www.csdn.net/develop/Read_Article.asp?Id=10427
3.利用IDocHostUIHandler接口(官方提供的方法)
VC.net中的CDHtmlDialog就是這種方法了,想自己實現的可以參考這篇文章:
在對話框中顯示網頁,並屏蔽掉IE的彈出式菜單 wuya(原作)
http://www.csdn.net/develop/Read_Article.asp?Id=8813
4.利用COM的連接點機制,直接處理html元素的事件
我們先看看在VB中想屏蔽掉右鍵菜單是怎麼做的:
Dim WithEvents m_doc As HTMLDocument
Private Function m_doc_oncontextmenu() As Boolean
m_doc_oncontextmenu = False
End Function
Private Sub WebBrowser1_DownloadComplete()
Set m_doc = WebBrowser1.Document
End Sub
呵呵,非常簡單吧?處理HTMLDocument的oncontextmenu事件,視具體需要彈出自己的菜單,然後返回true或false就可以了。
同理,我們在VC中如果能響應html頁面元素對象的事件並做出處理的話也可以達到屏蔽右鍵菜單的目的了,在VB中響應COM的事件被封裝起來,用一個WithEvents關鍵字就輕鬆搞定,在VC中怎麼實現??
我們知道COM是通過連接點機制來實現事件的,VC中你得在程序中實現一個特定的接口,並把這個接口的指針通過一定的途徑傳送給COM對象並通知它需要訂閱該對象的消息。
下面通過處理HTMLDocument2的oncontextmenu事件來演示具體怎麼在MFC程序中實現屏蔽掉右鍵菜單,同理你可以處理其它的像DIV,Button等元素的事件來制定相應的右鍵菜單。
通過查閱MSDN,可以知道要響應HTMLDocument2的事件必須在程序中實現HTMLDocumentEvents2接口,這個接口是Dispinterface類型的,而在MFC想實現一個IDispatch接口就簡單的就是從CCmdTarget類派生一個新類並用DECLARE_DISPATCH_MAP,BEGIN_DISPATCH_MAP,DISP_FUNCTION_ID,END_DISPATCH_MAP等宏來添加接口函數,由於CHtmlView或是CDialog都是間接派生自CCmdTarget的,所以直接在這些類上實現這個接口就可以了,以對話框加IE控件爲例(稍微改動可用於CHtmlView),實現如下:
1.新建基於對話框工程命名爲HtmlDemoDialog,在主對話框中加入Microsoft Web Browser控件並生成包裝類等。
2.在主對話框類頭文件CHtmlDemoDialogDlg.h中加入
#include <MsHTML.h>//定義了IHTMLDocument2等接口
#include <mshtmdid.h>//定義了HTMLDocumentEvents2接口的方法DISPID
class CCHtmlDemoDialogDlg : public CDialog
{
...
DECLARE_DISPATCH_MAP()//聲明dispatch map表
public:
BOOL onHtmlContextMenu(IHTMLEventObj *pEvtObj);
//事件處理函數,原型可以參考MSDN中關於HTMLDocumentEvents2的說明
DWORD m_dwCookie;
//用於標記一個連接點
IHTMLDocument2* pDoc2;
//想要處理事件的COM對象的指針
...
}
2.在對話框類實現文件CHtmlDemoDialogDlg.cpp中加入
#include <afxctl.h>//定義了AfxConnectionAdvise、AfxConnectionUnadvise等函數,等會連接到事件源時要用到
...
//填充dispatch map表,以供Invoke()調用
BEGIN_DISPATCH_MAP(CCHtmlDemoDialogDlg, CDialog)
DISP_FUNCTION_ID(CCHtmlDemoDialogDlg, "oncontextmenu", DISPID_HTMLDOCUMENTEVENTS2_ONCONTEXTMENU, onHtmlContextMenu, VT_BOOL, VTS_DISPATCH)
END_DISPATCH_MAP()
...
CWebbrowserDlg::CWebbrowserDlg(CWnd* pParent /*=NULL*/)
: CDialog(CWebbrowserDlg::IDD, pParent)
{
EnableAutomation();//必須有,否則等會用GetIDispatch()時會失敗.
...
}
BOOL CCHtmlDemoDialogDlg::onHtmlContextMenu(IHTMLEventObj *pEvtObj)
{
//在成功連接上事件源後,每次用戶右擊都會調用這個函數,你可以根據pEvtObj來判斷當前光標位置等,然後決定是自己彈出菜單,讓IE彈出菜單,還是什麼都不做...
return FALSE;
}
void CCHtmlDemoDialogDlg::OnDocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT FAR* URL)
{
//處理WebBrowser控件的DocumentComplete事件,並初始化pDoc2指針和連接到事件源
HRESULT hr=m_wb.GetDocument()->QueryInterface(IID_IHTMLDocument2,(void**)&pDoc2);
BOOL Ret = AfxConnectionAdvise(
pDoc2, //可連接對象的接口指針
DIID_HTMLDocumentEvents2, //連接接口ID
GetIDispatch(FALSE), //把內嵌的IDispatch實現類的一個對象實例m_xDispatch傳了出去
FALSE, //donod addref
&m_dwCookie ); //cookie to break connection later...
if(Ret){
AfxMessageBox("成功掛接上");
}
}
3.到這裏,基本步驟都以完成,運行後如果沒有什麼災難發生的話可以看到"成功掛接上"的消息框,並且在IE控件中點擊右鍵不會彈出菜單,斷開事件連接的代碼如下:
AfxConnectionUnadvise(pDoc2,
DIID_HTMLDocumentEvents2 ,
GetIDispatch(FALSE),
FALSE,
m_dwCookie );
其餘的善後工作交給你去處理了.
(轉載)