方案一:external對象
經常有人用CDHtmlDialog開發純網頁的對話方塊。這裡首先要解決的是“程式”與“網頁”之間的通訊問題。“程式”訪問“網頁”可以使用IWebBrowser2介面。“網頁”訪問“程式”可以在指令碼中調用window.external的方法。對於“網頁”而言,暫且將前者稱為“被動模式”,後者稱為“主動模式”。於是,“程式”在建立一個“網頁”對話方塊時,向“網頁”提供一個自訂的external對象,就解決了二者之間的通訊問題了。
在簡單的應用中,上述方案是有效。但有一個約束性條件:就是“網頁”中的代碼都是可控的。如果“網頁”允許通過iframe元素載入其他來源的子頁面時,就會出現安全隱患了。因為當前網頁中所有iframe中的子頁面也都能訪問window.external的方法。那可不可以為每一個“網頁”建立一個單獨的external對象呢?經測試是不行的。也就是說,“程式”內嵌的“WebBrowser控制項”一次只能設定一個external對象,為當前“網頁”和其下所有的“子頁面”服務。而且,在external對象內部也無法判斷此次調用的來源。
方案二:直接提供類似window的全域對象
因為“程式”可以使用IWebBrowser2介面訪問“網頁”,那麼我們可以直接建立一個自訂對象,並將其設為“網頁”的全域對象,就像window一樣。下面示範如何為“網頁”提供一個page對象。
- //IWebBrowser2介面是已知的
- CComPtr<IWebBrowser2> m_pWebBrowser2;
- //得到document
- CComPtr<IDispatch> pDocDisp;
- m_pWebBrowser2->get_Document(&pDocDisp);
- CComQIPtr<IHTMLDocument2> pDoc=pDocDisp;
- //得到window
- CComPtr<IHTMLWindow> pWindow;
- pDoc->get_parentWindow(&pWindow);
- //取得window的IDispatchEx介面 (IDispatchEx是動態指令碼語言的基礎,請參閱:http://blog.csdn.net/pimshell/archive/2008/08/04/2768182.aspx)
- CComQIPtr<IDispatchEx> pObject=pWindow;
- //建立page對象
- CComObject<CPage>* pPage;
- CComObject<CPage>::CreateInstance(&pPage);
- //為pObject產生 page變數 的 dispid
- DISPID dispid;
- CComBSTR bstrName=L"page";
- pObject->GetDispID(bstrName,fdexNameEnsure,&dispid);
- //為page變數賦值
- VARIANT var;
- DISPID putid;
- DISPPARAMS dispparams, dispparamsNoArgs = {NULL, NULL, 0, 0};
- putid = DISPID_PROPERTYPUT;
- var.vt = VT_DISPATCH;
- var.pdispVal = (IDispatch*)pPage;
- dispparams.rgvarg = &var;
- dispparams.rgdispidNamedArgs = &putid;
- dispparams.cArgs = 1;
- dispparams.cNamedArgs = 1;
- pObject->InvokeEx(dispid, LOCALE_USER_DEFAULT,
- DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF,
- &dispparams,
- NULL, NULL, NULL);
- //這樣在指令碼中就可以直接使用page了。如,page.dosomething(params);
這種方案的好處是可以為每個網頁及其下的子版面設定單獨的自訂對象,從而細緻的控制安全性問題。
弊端:設定“全域對象”的時機不好把握。如果是在OnDocumentComplete事件中執行,當使用者重新整理頁面時,這個事件不會被再次調用。而且,也沒有資料表明可以截獲“重新整理”事件。這樣的話,“網頁”也就無法通過“全域對象”來訪問“程式”了。
方案三:主動模式--控制項(ActiveX)和行為(Behavior)
一開始我們說了,對於“網頁”而言,“程式”訪問“網頁”稱為“被動模式”,反之稱為“主動模式”。前面的兩個方案都是“被動模式”,由“程式”提供路徑,以便可以被“網頁”訪問。
而“主動模式”是由“網頁”在內部建立“程式”的自訂對象。自訂對象可以針對網頁單獨建立,而且也可以設定“全域對象”,這樣就自然避免了“被動模式”的弊端。“主動模式”主要有兩種方式:控制項(ActiveX)和行為(Behavior)。Adobe AIR和MS Silverlight採用的是ActiveX。這種方式就是為網頁提供了一個功能豐富的DOM元素。優點是效能高,缺點是ActiveX的介面與html的介面並不一致,體驗也不同,需要額外的開發技術。PIMShell採用的是Behavior。這種方式就是為網頁現有的DOM元素提供額外的屬性、方法和事件。比如,為DIV元素附加一個HTMLEditor行為,就可以通過DIV元素實現網頁編輯器的功能了。優點是,繼續沿用現有的html/javascript技術,缺點是效能略遜於ActiveX。