• <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、概述

              調(diào)用“添加到收藏夾”對話框(如下)與調(diào)用“整理收藏夾”對話框有不同之處,前者所做的工作比后者要來得復(fù)雜。將鏈接添加到收藏夾除了將鏈接保存之外,還可能會有脫機訪問的設(shè)置,從IE 4.0到IE 5.0,處理的方式也發(fā)生了一些變化。




              2、IShellUIHelper接口

              微軟專門提供了一個接口IShellUIHelper來實現(xiàn)對Windows Shell API一些功能的訪問,將鏈接添加到收藏夾也是其中之一,就是下面的AddFavorite函數(shù)。


              HRESULT IShellUIHelper::AddFavorite(BSTR URL, VARIANT *Title);

              實例代碼如下:


              void CMyHtmlView::OnAddToFavorites()
              {
              IShellUIHelper* pShellUIHelper;
              HRESULT hr = CoCreateInstance(CLSID_ShellUIHelper, NULL,
              CLSCTX_INPROC_SERVER, IID_IShellUIHelper,(LPVOID*)&pShellUIHelper);

              if (SUCCEEDED(hr))
              {
              _variant_t vtTitle(GetTitle().AllocSysString());
              CString strURL = m_webBrowser.GetLocationURL();

              pShellUIHelper->AddFavorite(strURL.AllocSysString(), &vtTitle);
              pShellUIHelper->Release();
              }
              }

              我們注意到這里的“AddFavorite”函數(shù)并沒有像“DoOrganizeFavDlg”那樣需要一個父窗口句柄。這也導(dǎo)致與在IE中打 開不同,通過IShellUIHelper接口顯示出來的“添加到收藏夾”對話框是“非模態(tài)”的,有一個獨立于我們應(yīng)用程序的任務(wù)欄按鈕,這使我們的瀏覽 器顯得非常不專業(yè)(我是個追求完美的人,這也是我的瀏覽器遲遲不能發(fā)布的原因之一)。

              于是我們很自然地想到“shdocvw.dll”中除了“DoOrganizeFavDlg”外,應(yīng)該還有一個類似的函數(shù),可以傳入一個父窗口句柄用以顯示模態(tài)窗口,也許就像這樣:


              typedef UINT (CALLBACK* LPFNADDFAV)(HWND, LPTSTR, LPTSTR);

              事實上,這樣的函數(shù)確實存在于“shdocvw.dll”中,那就是“DoAddToFavDlg”。


              3、DoAddToFavDlg函數(shù)

              “DoAddToFavDlg”函數(shù)也是“shdocvw.dll”暴露出來的函數(shù)之一,其原型如下:


              typedef BOOL (CALLBACK* LPFNADDFAV)(HWND, TCHAR*, UINT, TCHAR*, UINT,LPITEMIDLIST);

              第一個參數(shù)正是我們想要的父窗口句柄,第二和第四個參數(shù)分別是初始目錄(一般來說就是收藏夾目錄)和要添加的鏈接的名字(比如網(wǎng)頁的 Title),第三和第五個參數(shù)分別是第二和第四兩個緩沖區(qū)的長度,而最后一個參數(shù)則是指向與第二個參數(shù)目錄相關(guān)的item identifier list的指針(PIDL)。但最奇怪的是這里并沒有像“AddFavorite”函數(shù)一樣的鏈接URL,那鏈接是怎樣添加的呢?答案是“手動創(chuàng)建”。

            第二個參數(shù)在函數(shù)調(diào)用返回后會包含用戶在“添加到收藏夾”對話框中選擇或創(chuàng)建的完整鏈接路徑名(如“X:\XXX\mylink.url”),我們就根 據(jù)這個路徑和網(wǎng)頁的URL來創(chuàng)建鏈接,代碼如下(為簡化,此處省去檢查"shdocvw.dll"是否已在內(nèi)存中的代碼,參見《Internet Explorer 編程簡述(三)“整理收藏夾”對話框》):


              void CMyHtmlView::OnFavAddtofav()
              {
              typedef BOOL (CALLBACK* LPFNADDFAV)(HWND, TCHAR*, UINT, TCHAR*, UINT,LPITEMIDLIST);

              HMODULE hMod = (HMODULE)LoadLibrary("shdocvw.dll");
              if (hMod)
              {
              LPFNADDFAV lpfnDoAddToFavDlg = (LPFNADDFAV)GetProcAddress( hMod, "DoAddToFavDlg");
              if (lpfnDoAddToFavDlg)
              {
              TCHAR szPath[MAX_PATH];
              LPITEMIDLIST pidlFavorites;

              if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, TRUE) &&
              (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidlFavorites))))
              {
              TCHAR szTitle[MAX_PATH];
              strcpy(szTitle, GetLocationName());

              TCHAR szURL[MAX_PATH];
              strcpy(szURL, GetLocationURL());

              BOOL bOK = lpfnDoAddToFavDlg(m_hWnd, szPath,
              sizeof(szPath)/sizeof(szPath[0]), szTitle,
              sizeof(szTitle)/sizeof(szTitle[0]), pidlFavorites);
              CoTaskMemFree(pidlFavorites);

              if (bOK)
              CreateInternetShortcut( szURL, szPath, "");  //創(chuàng)建Internet快捷方式
              }
              }
              FreeLibrary(hMod);
              }
              return;
              }

              實現(xiàn)CreateInternetShortcut函數(shù)創(chuàng)建Internet快捷方式,可以用讀寫INI文件的方法,但更好的則是利用IUniformResourceLocator接口。


              HRESULT CMyHtmlView::CreateInternetShortcut(LPCSTR pszURL, LPCSTR pszURLfilename,
              LPCSTR szDescription,LPCTSTR szIconFile,int nIndex)
              {
              HRESULT hres;

              CoInitialize(NULL);

              IUniformResourceLocator *pHook;

              hres = CoCreateInstance (CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
              IID_IUniformResourceLocator, (void **)&pHook);

              if (SUCCEEDED (hres))
              {
              IPersistFile *ppf;
              IShellLink *psl;

              // Query IShellLink for the IPersistFile interface for
              hres = pHook->QueryInterface (IID_IPersistFile, (void **)&ppf);
              hres = pHook->QueryInterface (IID_IShellLink, (void **)&psl);

              if (SUCCEEDED (hres))
              {
              WORD wsz [MAX_PATH]; // buffer for Unicode string

              // Set the path to the shortcut target.
              pHook->SetURL(pszURL,0);

              hres = psl->SetIconLocation(szIconFile,nIndex);

              if (SUCCEEDED (hres))
              {
              // Set the description of the shortcut.
              hres = psl->SetDescription (szDescription);

              if (SUCCEEDED (hres))
              {
              // Ensure that the string consists of ANSI characters.
              MultiByteToWideChar (CP_ACP, 0, pszURLfilename, -1, wsz, MAX_PATH);

              // Save the shortcut via the IPersistFile::Save member function.
              hres = ppf->Save (wsz, TRUE);
              }
              }

              // Release the pointer to IPersistFile.
              ppf->Release ();
              psl->Release ();
              }

              // Release the pointer to IShellLink.
              pHook->Release ();

              }
              return hres;
              }

              好,上面的方法雖然麻煩一點,但總算解決了“模態(tài)窗口”的問題,使得我們的程序不至于讓用戶鄙視。但是問題又來了,我們發(fā)現(xiàn)“允許脫機使用”是Disabled的,那“自定義”也就無從談起了,盡管90%的人都沒有使用過IE提供的脫機瀏覽。

              難道我們的希望要破滅嗎?我們一方面想像調(diào)用“AddFavorite”函數(shù)一樣的不必手動創(chuàng)建鏈接,一方面又要模態(tài)顯示窗口,就像IE那樣,還能自定義脫機瀏覽。

              3、腳本方式

              許多網(wǎng)頁上都會有一個按鈕或鏈接“添加本頁到收藏夾”,實際上通過下面的腳本顯示模態(tài)的“添加到收藏夾”對話框?qū)⒕W(wǎng)頁加入到收藏夾。


              window.external.AddFavorite(location.href, document.title);

              這里的external對象是WebBrowser內(nèi)置的COM自動化對象,以實現(xiàn)對文檔對象模型(DOM)的擴展(我們也可以通過 IDocHostUIHandler實現(xiàn)自己的擴展).查閱MSDN可以得知external對象的的方法與IShellUIHelper接口提供的方法 是一樣的。我們有理由相信,IShellUIHelper提供了對WebBrowser內(nèi)置的external對象的訪問,如果在適當(dāng)?shù)牡胤絼?chuàng)建 IShellUIHelper接口的實例,也許調(diào)用“AddFavorite”函數(shù)顯示出來的就是模態(tài)對話框了。問題是我們還沒有找到這樣的地方。

              從上面的腳本,我們很自然地又想到另一個方法。如果能夠讓網(wǎng)頁來執(zhí)行上面的腳本,豈不是問題就解決了?說做就做,如下:


              void CMyHtmlView::OnFavAddtofav()
              {
              CString strUrl = GetLocationURL();
              CString strTitle = GetLocationName();
              CString strjs = "javascript:window.external.AddFavorite('" + strUrl + "'," + "'" + strTitle + "');";
              ExecScript(strjs);
              }

              void CMIEView::ExecScript(CString strjs)
              {
              CComQIPtr<IHTMLDocument2>   pHTMLDoc = (IHTMLDocument2*)GetHtmlDocument();
              if ( pHTMLDoc != NULL  )
              {
              CComQIPtr<IHTMLWindow2>   pHTMLWnd;
              pHTMLDoc->get_parentWindow( &pHTMLWnd );

              if ( pHTMLWnd != NULL  )
              {
              CComBSTR bstrjs = strjs.AllocSysString();
              CComBSTR bstrlan = SysAllocString(L"javascript");
              VARIANT varRet;
              pHTMLWnd->execScript(bstrjs, bstrlan, &varRet);
              }
              }
              }

              先從CHtmlView獲得文檔的父窗口window對象的指針,再調(diào)用其方法execScript來執(zhí)行腳本(事實上可以執(zhí)行任意的腳本)。 試驗發(fā)現(xiàn),這個方法非常有效,不僅窗口是模態(tài)的,而且不需要手動創(chuàng)建鏈接,更重要的是“允許脫機使用”和“自定義”按鈕也可以用了。

              4、問題仍舊沒有解決

              執(zhí)行腳本的方式看起來有效,可一旦我們的程序?qū)崿F(xiàn)了IDocHostUIHandler接口對WebBrowser進行高級控制,就會發(fā)現(xiàn)一旦 執(zhí)行的腳本包含有對“external”對象的調(diào)用,就會出現(xiàn)“找不到對象”的腳本錯誤。原因是當(dāng)MSHTML解析引擎(并非WebBrowser)檢查 到宿主實現(xiàn)了IDocHostUIHandler接口,就會調(diào)用其GetExternal方法以獲得一個用以擴展DOM的自動化接口的引用。


              HRESULT IDocHostUIHandler::GetExternal(IDispatch **ppDispatch)

              但有時候我們并沒有想要擴展DOM,同時我們還希望WebBrowser使用它自己的DOM擴展。糟糕的是GetExternal方法的文檔中 說這種情況下必須把ppDispatch設(shè)置為NULL,換句話說,WebBrowser連它內(nèi)置的external對象也不用了,那我們的 window.external.AddFavorite就變得無處為家了。

              我曾多方嘗試將WebBrowser內(nèi)置的external對象找出來,雖然都沒有成功,但是解決問題的方法卻被我找到了。

              5、完美的方案

              WebBrowser內(nèi)置的external對象我們雖然找不到,但它肯定存在,我們只要想辦法讓W(xué)ebBrowser自己完成對其調(diào)用即可。 實現(xiàn)非常簡單,找到WebBrowser中包含的“Internet Explorer_Server”窗口的句柄,發(fā)一個消息就完成了。下面的代碼中假設(shè)m_hWndIE就是“Internet Explorer_Server”窗口的句柄。


              #define ID_IE_ID_ADDFAV 2261
              ::SendMessage( m_hWndIE, WM_COMMAND, MAKEWPARAM(LOWORD(ID_IE_ID_ADDFAV), 0x0), 0 );

              試一試成果,是不是和在Internet Explorer中選擇“添加到收藏夾”的效果一模一樣。

              至于為什么這樣做,后續(xù)文章再說。


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

            色99久久久久高潮综合影院| 欧美午夜精品久久久久免费视 | 亚洲国产精品久久久久| 久久婷婷国产综合精品| 久久免费视频网站| 国产69精品久久久久APP下载| 久久综合狠狠色综合伊人| 精品国产乱码久久久久久郑州公司 | 色综合久久中文字幕无码| 国内精品久久久人妻中文字幕| 久久亚洲综合色一区二区三区| 久久人人爽人人精品视频| 波多野结衣久久精品| 色综合久久精品中文字幕首页 | 久久精品国产亚洲AV忘忧草18 | 久久久久人妻一区二区三区| 国产人久久人人人人爽| 久久伊人精品一区二区三区| 久久精品国产99久久丝袜| 人妻无码αv中文字幕久久| 欧美久久久久久精选9999| 成人免费网站久久久| 亚洲国产视频久久| 精品久久人人妻人人做精品| 99久久婷婷免费国产综合精品| 性做久久久久久久| 一本久久综合亚洲鲁鲁五月天| 精品蜜臀久久久久99网站| 久久久久久久免费视频| 亚洲国产精品成人久久蜜臀| 久久精品国产亚洲7777| 精品欧美一区二区三区久久久| 婷婷五月深深久久精品| 久久久久久亚洲精品不卡| 国产成人精品白浆久久69| 久久AV高清无码| 成人国内精品久久久久一区| 99久久精品午夜一区二区| 久久99热精品| 久久久久久青草大香综合精品| 久久青青国产|