使用 CHtmlView 或 CHtmlCtrl 顯示 HTML 內容時,滑鼠右鍵會彈出 IE 預設選單(檢視原始碼、另存新檔等),存在資訊安全風險。本文提供兩種解決方案:簡單的 HTML 指令法與正規的 C++ 介面實作法。
在 HTML `
` 標籤加入屬性:<body oncontextmenu="return false">
<body oncontextmenu="ShowMyMenu(); return false">
瀏覽器引擎直接攔截右鍵事件,無需任何 C++ 程式碼修改。
Spy++ 觀察視窗階層:
Dialog
AfxFrameOrView42d // CHtmlCtrl
Shell Embedding
Shell DocObject View
Internet Explorer_Server ← 真正接收輸入的視窗
標準訊息(WM_CONTEXTMENU、WM_RBUTTONDOWN)送往最底層的 Internet Explorer_Server,CHtmlCtrl 無法攔截。
static HWND GetLastChild(HWND hwndParent) {
HWND hwnd = hwndParent;
while (TRUE) {
HWND hwndChild = ::GetWindow(hwnd, GW_CHILD);
if (hwndChild == NULL) return hwnd;
hwnd = hwndChild;
}
return NULL;
}
假設單一子視窗鏈結,取得最深層子視窗即為目標。
CMyIEWnd : public CWnd 重載 OnContextMenu 為空函數CHtmlCtrl 衍生類別加入 CMyIEWnd m_myIEWnd 成員OnNavigateComplete2 中子類化:
void CMyHtmlCtrl::OnNavigateComplete2(LPCTSTR strURL) {
if (!m_myIEWnd.m_hWnd) {
HWND hwnd = GetLastChild(m_hWnd);
m_myIEWnd.SubclassWindow(hwnd);
}
}「這是非常規方式,微軟明確禁止。子類化 IE_Server 等於押上所有賭注,不當使用會導致災難性後果。正式專案請實作
IDocHostUIHandler介面。」
UnsubclassWindow/ResubclassWindow 避免 HWND 變更導致崩潰實作 IDocHostUIHandler::ShowContextMenu 回傳 S_OK 並設定 pGuid 為 NULL 即可禁用預設選單,支援自訂選單。需透過 QueryInterface 取得介面指標,複雜度較高但穩定安全。
oncontextmenu="return false"IDocHostUIHandler