2010年10月8日 星期五

c# webbrowser跨域存取iframe的方法

這問題有點麻煩 在使用.net內建的webbrowser時
如果同個document下有個frame 但是frame是跟主頁面是不同的domain 那存取frame的內容時會出問題

例如
webBrowser1.Document的domain是aaa.com
底下有個frame的domain是bbb.com
那碰到這行時
HtmlDocument doc = webBrowser1.Document.Window.Frames[1].Document;
就會回傳錯誤:
"Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"

總結一下網路上的解決方法是使用mshtml的IHTMLWindow2來解決
我寫了一小段demo code如下 經過測試確實可繞過webbrowser內建cross domain的限制:

using System.Reflection;
using mshtml;

HtmlDocument main_formDoc = webBrowser1.Document;
IHTMLDocument2 main_mshtmlIHTMLDoc = (IHTMLDocument2)main_formDoc.DomDocument;
Object frame_index = 1;
IHTMLWindow2 target_mshtmlIHTMLWindow = (IHTMLWindow2)main_mshtmlIHTMLDoc.frames.item(ref frame_index);
IHTMLDocument2 target_mshtmlIHTMLDoc = CodecentrixSample.CrossFrameIE.GetDocumentFromWindow(target_mshtmlIHTMLWindow);

其中CodecentrixSample是從http://codecentrix.blogspot.com/2008/02/when-ihtmlwindow2document-throws.html載下來的一個類別 主要原理是透過COM界面將IHTMLWindow2 轉成IHTMLDocument2繞過安全性檢查

依照上面的範例code 最後拿出來的target_mshtmlIHTMLDoc內容就等同於我們本來一開始想拿的webBrowser1.Document.Window.Frames[1].Document
(其實精確的說是webBrowser1.Document.Window.Frames[1].Document.DomDocument)

但是我最後並沒有用上面這方法
因為我所要寫的程式大架構已經定了
跟其他函式的接口都是要使用本來原生的HtmlDocument而不能用IHTMLDocument2
然後找了老半天又找不到方法把IHTMLDocument2轉回成HtmlDocument 因此只好忍痛放棄這條路
我之後的解決的方法那就是另外一回事了跟本篇主題沒有關係 (剛好我的目標網站有另外一個界面可以是讓主document和frame是同個網域的 因此自然就沒有cross domain的限制)
但是還是紀錄下來解決的方法給有需要的人使用