• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            旅途

            如果想飛得高,就該把地平線忘掉

            Internet Explorer編程簡述(六)

            1、概述
            Internet Explorer提供了非常開發的接口,使開發人員不僅可以把其瀏覽器核心嵌入應用程序,還可以通過各種接口以實現更深層的控制。本文就將介紹對瀏覽器進行高級控制的話題之一——自定義上下文菜單。

            2、最簡單的情況
            自定義的IE及WebBrowser的上下文菜單,最簡單的方式就是在注冊表的HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt下添加自定義的鍵值,步驟如下:
            1) 添加一個新的鍵,其名稱即為將來顯示在上下文菜單中的菜單項名稱,如:
             HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\&Google Search
            2) 將新增的鍵的默認值設置為一個包含腳本的網頁的URL(或文件路徑全名),該網頁中的腳本將在用戶點擊上下文菜單中的“Google Search”后被瀏覽器執行。

            3)在新增的鍵下還可以新建一個二進制值Contexts,用以指定我們新增的菜單項針對特定的網頁對象是否出現,其取值可以是如下值的組合(邏輯或)

            Context     Value
            Default     0x1
            Images     0x2
            Controls    0x4
            Tables     0x8
            Text selection 0x10
            Anchor     0x20

            4) 還可以建立一個DWORD類型的Flags項并將其值設置為0x01,這將使得前述腳本在一個模態窗口中執行,就好像是通過window.showModalDialog調用的,但不同的是在腳本中仍然可以訪問window對象。
            5) 實例腳本如下:

            通過修改注冊表自定義菜單的方法適用于Internet Explorer和WebBrowser,也具有良好的擴展性。但我們如果希望執行的是不僅僅是腳本,二是自己的程序中代碼,這種方法就不適用了。

            3、使用完全自定義的菜單
            1)
            IDocHostUIhandler接口提供了一個ShowContextMenu方法,在需要顯示上下文菜單之前,MSHTML引擎就會調用實現了IDocHostUIHandler接口的
            宿主程序的ShowContextMenu方法。

            HRESULTIDocHostUIHandler::ShowContextMenu(
              DWORD dwID,
              POINT *ppt,
              IUnknown *pcmdtReserved,
              IDispatch *pdispReserved
            );

            dwID參數的意義與Contexts的組合類似;ppt為菜單的彈出點屏幕坐標;pcmdtReserved接口指向 IOleCommandTarget接口,可用于檢測網頁對象的狀態和執行命令等操作。pdispReserved在IE5以上版本中指向的是網頁對象的 IDispatch接口,用以區分不同對象,比如我們可以這樣來獲得網頁對象的指針:

            IHTMLElement *pElem;
            HRESULT hr;
            hr = pdispReserved->QueryInterface(IID_IHTMLElement, (void**)pElem);
            if(SUCCEEDED (hr)) {
              BSTR bstr;
              pElem->get_tagName(bstr);
              USES_CONVERSION;
              ATLTRACE("TagName:%s\n", OLE2T(bstr));
              SysFreeString(bstr);
              pElem->Release();
            }

            如果我們在該方法中返回S_OK,則告訴MSHTML我們將使用自己的菜單(界面),如果是S_FALSE,則彈出默認的菜單。

            2) 實現
            原理清楚之后,實現起來非常簡單,和彈出一般的菜單沒什么兩樣,舉例如下,顯示主框架的“文件菜單”:

            HRESULT CMyHtmlView::OnShowContextMenu(DWORD dwID, LPPOINT ppt, IUnknown * pcmdtReserved, IDispatch *)
            {
             // 載入主菜單
             HMENU hMenuParent = ::LoadMenu( ::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME) );
             if (hMenuParent)
             {
              HMENU hMenu = ::GetSubMenu( hMenuParent, 0 ); // 取得“文件”子菜單
              if (hMenu)
              {
               // 顯示菜單
               TrackPopupMenuEx( hMenu,
                TPM_LEFTALIGN | TPM_TOPALIGN,
                ppt->x,
                ppt->y,
                ::AfxGetMainWnd()->m_hWnd,
                NULL );
              }
              ::DestroyMenu( hMenuParent );
             }
             return S_OK;
            }

            4、自定義標準上下文菜單
            1)
            原理
            更多的時候我們希望能在瀏覽器原來菜單的基礎上作一些修改,如刪掉“查看源文件”,添加自己的菜單項,等等,而不是完全不要原始的菜單,怎么辦呢?借助MSDN提供的例子,我們來看看:

            HRESULT CBrowserHost::ShowContextMenu(DWORD dwID, POINT *ppt,IUnknown *pcmdTarget,IDispatch *pdispObject)
            {
             #define IDR_BROWSE_CONTEXT_MENU 24641
             #define IDR_FORM_CONTEXT_MENU 24640
             #define SHDVID_GETMIMECSETMENU 27
             #define SHDVID_ADDMENUEXTENSIONS 53

             HRESULT hr;
             HINSTANCE hinstSHDOCLC;
             HWND hwnd;
             HMENU hMenu;

             CComPtr spCT;
             CComPtr spWnd;

             MENUITEMINFO mii = {0};
             CComVariant var, var1, var2;
             hr = pcmdTarget->QueryInterface(IID_IOleCommandTarget, (void**)&spCT);
             hr = pcmdTarget->QueryInterface(IID_IOleWindow, (void**)&spWnd);
             hr = spWnd->GetWindow(&hwnd);//取得瀏覽器窗口句柄
             hinstSHDOCLC = LoadLibrary(TEXT("SHDOCLC.DLL"));
             if (hinstSHDOCLC == NULL)
             {
              // Error loading module -- fail as securely as possible
              return;
             }
             hMenu = LoadMenu(hinstSHDOCLC, MAKEINTRESOURCE(IDR_BROWSE_CONTEXT_MENU));
             hMenu = GetSubMenu(hMenu, dwID);
             // Get the language submenu
             hr = spCT->Exec(&CGID_ShellDocView, SHDVID_GETMIMECSETMENU, 0, NULL, &var);
             mii.cbSize = sizeof(mii);
             mii.fMask = MIIM_SUBMENU;
             mii.hSubMenu = (HMENU) var.byref;
             // Add language submenu to Encoding context item
             SetMenuItemInfo(hMenu, IDM_LANGUAGE, FALSE, &mii);
             // Insert Shortcut Menu Extensions from registry
             V_VT(&var1) = VT_INT_PTR;
             V_BYREF(&var1) = hMenu;
             V_VT(&var2) = VT_I4;
             V_I4(&var2) = dwID;
             hr = spCT->Exec(&CGID_ShellDocView, SHDVID_ADDMENUEXTENSIONS, 0, &var1, &var2);
             // Remove View Source
             DeleteMenu(hMenu, IDM_VIEWSOURCE, MF_BYCOMMAND);//刪除“查看源文件”菜單項
             // Show shortcut menu
             int iSelection = ::TrackPopupMenu(hMenu,
              TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD ,//返回用戶選擇的菜單命令ID
              ppt->x,
              ppt->y,
              0,
              hwnd,
              (RECT*)NULL);
             // Send selected shortcut menu item command to shell
             LRESULT lr = ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);//發送到Internet Explorer_Server進行內部處理。
             FreeLibrary(hinstSHDOCLC);
             return S_OK;
            }

            從 上面的例子我們看出,基本的方法就是根據“shdoclc.dll”文件中的菜單資源建立菜單,再通過來自pcmdTarget的 IOlcCommandTarget接口獲得“編碼”菜單以及HKEY_CURRENT_USER\Software\Microsoft\ Internet Explorer\MenuExt下的定義擴展菜單,然后以TPM_RETURNCMD標志調用TrackPopupMenu或 TrackPopupMenuEx彈出菜單,并將返回的菜單命令ID教給瀏覽器窗口進行處理。這種方法可以調用許多通過瀏覽器無法直接調用的命令和對話框 (參閱:《Internet Explorer 編程簡述(五)調用IE隱藏的命令》)。

            所以,我們只需要在彈出菜單之前做一些自定義操作即可達到修改默認菜單的目的,如上面代碼中就用刪除了“查看源文件”菜單項。

            2) 問題
            如果我們不僅僅是刪除默認的菜單項或是修改了默認的菜單項,還添加了自己的菜單項,會出現什么情況呢?由于使用了類似于MFC中UpdateUI的機制,遇到不認識的CommandID,瀏覽器就會將其狀態設置為Disabled,所以我們自己添加的菜單是無法被選擇的。
            可 以想到,如果把菜單狀態設置為Enabled,并通過TPM_RETURNCMD標志調用TrackPopupMenu或 TrackPopupMenuEx,再把返回的命令ID教給合適的窗口(如主框架窗口)去處理不就行了。關鍵點就在于如何把菜單狀態設置為 Enabled。

            3) 實現
            解決的辦法是截獲 WM_INITMENUPOPUP 消息,在菜單創建以后,尚未顯示之前修改菜單項狀態,那瀏覽器就沒有辦法了。截獲WM_INITMENUPOPUP消息則可使用子類化(subclass)的技術,前面通過IOleWindow接口我們得到了瀏覽器窗口的句柄hwnd,則可以這樣做:

            HMENU g_hPubMenu = NULL;
            WNDPROC g_lpPrevWndProc = NULL;

            LRESULT CALLBACK CustomMenuWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
            {
             if (uMsg == WM_INITMENUPOPUP)
             {
              if (wParam == (WPARAM) g_hPubMenu)
              {
               ::EnableMenuItem( 自定義的菜單命令ID, MF_ENABLED | MF_BYCOMMAND );
               ::CheckMenuItem( 自定義的菜單命令ID, MF_BYCOMMAND);
               return 0;
              }
             }
             return CallWindowProc(g_lpPrevWndProc, hwnd, uMsg, wParam, lParam);
            }

            HRESULT CMyHtmlView::OnShowContextMenu(DWORD dwID, LPPOINT ppt,
            LPUNKNOWN pcmdtReserved, LPDISPATCH pdispReserved)
            {
            //瀏覽器菜單句柄保存在g_hPubMenu中
            ......
            // subclass瀏覽器窗口
            g_lpPrevWndProc = (WNDPROC)::SetWindowLong(hwnd, GWL_WNDPROC, (LONG)CustomMenuWndProc);
            //m_SubclassWnd.SubclassWindow( hwnd );//MFC中用此方法更簡便

            // Show shortcut menu
            int iSelection = ::TrackPopupMenu(hSubMenu,
             TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
             ppt->x,
             ppt->y,
             0,
             hwnd,
             (RECT*)NULL);
            // Unsubclass瀏覽器窗口
            ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG)g_lpPrevWndProc);
            g_lpPrevWndProc = NULL;
            //m_SubclassWnd.UnsubclassWindow();

            if (iSelection == 自定義的菜單命令ID )
            {
             ::SendMessage( ::AfxGetMainWnd()->m_hWnd, WM_COMMAND, MAKEWPARAM(LOWORD(lResult), 0x0), 0 );
            }
            else
            {
             LRESULT lr = ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
            }
            ......
            }

            在MFC 中則更為方便,從CWnd繼承一個窗口類,假設為CWebBrowserSubclassWnd,為CMyHtmlView添加一個 CWebBrowserSubclassWnd類型的成員變量m_SubclassWnd,在子類化和去除子類化時調用 m_SubclassWnd.SubclassWindow( hwnd )和m_SubclassWnd.UnsubclassWindow()即可。相應的WM_INITMENUPOPUP消息處理函數如下所示:

            void CWebBrowserSubclassWnd::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
            {
             CWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);

             pPopupMenu->EnableMenuItem( 自定義的菜單命令ID, MF_ENABLED | MF_BYCOMMAND );
             pPopupMenu->CheckMenuItem( 自定義的菜單命令ID, MF_BYCOMMAND);
            }

            下面的圖片顯示了將“文字大小”菜單項添加到“編碼”菜單項的下面的效果。

            5、新的問題
            看完上面的代碼,我們又自然地想到瀏覽器編程中的另一個問題,那就是“編碼”菜單。我們指定,手動建立一個“編碼”菜單是比較麻煩的事,而且很難做到與瀏覽器上下文菜單上的“編碼”菜單一樣的效果。何不使用上述的方法讓瀏覽器自己建立“編碼”菜單和處理相應的命令呢?

            具體實現請看下一篇文章《Internet Explorer 編程簡述(七)完美的“編碼”菜單》


            參考資料
            MSDN:Adding Entries to the Standard Context Menu
            MSDN:How To Adding to the Standard Context Menus of the WebBrowser Control
            MSDN:IDocHostUIHandler::ShowContextMenu Method
            BeginThread.com:Custom WebBrowser Context Menus


            posted on 2007-07-29 15:17 旅途 閱讀(955) 評論(0)  編輯 收藏 引用 所屬分類: BHO

            国内精品伊人久久久久777| 亚洲国产成人精品91久久久| 伊人久久精品无码二区麻豆| 国产精品99久久久精品无码| 久久ZYZ资源站无码中文动漫| 国产精自产拍久久久久久蜜| 欧美777精品久久久久网| 免费精品久久久久久中文字幕| 久久久无码精品亚洲日韩蜜臀浪潮 | 亚洲国产精品18久久久久久| 亚洲中文字幕久久精品无码APP | 中文字幕无码免费久久| 久久99精品国产麻豆| 亚洲国产天堂久久综合网站| 久久九色综合九色99伊人| 三上悠亚久久精品| 久久久久久久国产免费看| 精品国产乱码久久久久久1区2区| 久久人人爽人人爽人人片AV麻豆| 亚洲精品99久久久久中文字幕| 久久久久久曰本AV免费免费| 2021少妇久久久久久久久久| 天堂无码久久综合东京热| 人人狠狠综合久久88成人| 色诱久久av| 国产精品美女久久久久AV福利 | 国产精品综合久久第一页| 欧美va久久久噜噜噜久久| 日韩AV毛片精品久久久| 99久久精品九九亚洲精品| 国产三级久久久精品麻豆三级| 亚洲国产成人久久综合碰| 国产国产成人久久精品| 久久精品亚洲中文字幕无码麻豆| 亚洲精品NV久久久久久久久久| 久久久九九有精品国产| 亚洲七七久久精品中文国产| 精品久久综合1区2区3区激情| 久久精品国产一区二区三区日韩| 久久精品亚洲中文字幕无码麻豆| 色综合久久无码五十路人妻|