您的位置:首页 > 编程语言 > C#

C#中webBrowser加载页面中访问不同域的iFrame引发System.UnauthorizedAccessException异常的解决办法

2012-01-15 17:57 1676 查看
使用WebBrowser打开一个页面,在该页面中有一个iFrame,在WebBrowser完全打开页面后,获取该iFrame的时候总是引发System.UnauthorizedAccessException异常。

Console.WriteLine(this.webMain.Document.Window.Frames[0].Url);

“this.webMain.Document.Window.Frames[0].Url”引发了“System.UnauthorizedAccessException”类型的异常

base {System.SystemException}: {"拒绝访问。 (异常来自 HRESULT:0x80070005 (E_ACCESSDENIED))"}

最近这个跨域的安全问题很困扰,搞了好久,终于在朋友的帮助下找到了一个C++的方法HtmlWindowToHtmlWebBrowser

CComPtr<IWebBrowser2> CTimerSerachDlg::HtmlWindowToHtmlWebBrowser(CComPtr<IHTMLWindow2> spWindow)
{
ATLASSERT(spWindow != NULL);
CComQIPtr<IServiceProvider>  spServiceProvider = spWindow;
if (spServiceProvider == NULL)
{
return CComPtr<IWebBrowser2>();
}
CComPtr<IWebBrowser2> spWebBrws;
HRESULT hRes = spServiceProvider->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (void**)&spWebBrws);
if (hRes != S_OK)
{
return CComPtr<IWebBrowser2>();
}
return spWebBrws;
}

// Converts a IHTMLWindow2 object to a IHTMLDocument2. Returns NULL in case of failure.
// It takes into account accessing the DOM across frames loaded from different domains.
CComPtr<IHTMLDocument2> CTimerSerachDlg::HtmlWindowToHtmlDocument(CComPtr<IHTMLWindow2> spWindow)
{
ATLASSERT(spWindow != NULL);
CComPtr<IHTMLDocument2> spDocument;
HRESULT hRes = spWindow->get_document(&spDocument);
if ((S_OK == hRes) && (spDocument != NULL))
{
// The html document was properly retrieved.
return spDocument;
}
// hRes could be E_ACCESSDENIED that means a security restriction that
// prevents scripting across frames that loads documents from different internet domains.
CComPtr<IWebBrowser2>  spBrws = HtmlWindowToHtmlWebBrowser(spWindow);
if (spBrws == NULL)
{
return CComPtr<IHTMLDocument2>();
}
// Get the document object from the IWebBrowser2 object.
CComPtr<IDispatch> spDisp;     hRes = spBrws->get_Document(&spDisp);
spDocument = spDisp;
return spDocument;
}


在后来找到了作者的Blog,但是国内屏蔽了blogspot,直接不能够访问。

然后发现了作者的另外一篇文章:http://codecentrix.blogspot.com/2008/02/when-ihtmlwindow2document-throws.html

C# 跨域访问iframe的办法:http://www.codecentrix.com/blog/wnd2doc_csharp/GetDocumentFromWindowCsharp.zip

mshtml.HTMLDocumentClass htmlDoc = this.webMain.Document.DomDocument as mshtml.HTMLDocumentClass;
object index = 0;
mshtml.IHTMLWindow2 frameWindow = htmlDoc.frames.item(ref index) as mshtml.IHTMLWindow2;

Console.WriteLine( CodecentrixSample.CrossFrameIE.GetDocumentFromWindow(frameWindow).activeElement.innerHTML);


接口转换的代码:

using System;
using System.Runtime.InteropServices;
using mshtml;

namespace CodecentrixSample
{
public class CrossFrameIE
{
// Returns null in case of failure.
public static IHTMLDocument2 GetDocumentFromWindow(IHTMLWindow2 htmlWindow)
{
if (htmlWindow == null)
{
return null;
}

// First try the usual way to get the document.
try
{
IHTMLDocument2 doc = htmlWindow.document;
return doc;
}
catch (COMException comEx)
{
// I think COMException won't be ever fired but just to be sure ...
if (comEx.ErrorCode != E_ACCESSDENIED)
{
return null;
}
}
catch (System.UnauthorizedAccessException)
{
}
catch
{
// Any other error.
return null;
}

// At this point the error was E_ACCESSDENIED because the frame contains a document from another domain.
// IE tries to prevent a cross frame scripting security issue.
try
{
// Convert IHTMLWindow2 to IWebBrowser2 using IServiceProvider.
IServiceProvider sp = (IServiceProvider)htmlWindow;

// Use IServiceProvider.QueryService to get IWebBrowser2 object.
Object brws = null;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out brws);

// Get the document from IWebBrowser2.
SHDocVw.IWebBrowser2 browser = (SHDocVw.IWebBrowser2)(brws);

return (IHTMLDocument2)browser.Document;
}
catch
{
}

return null;
}

private const int  E_ACCESSDENIED      = unchecked((int)0x80070005L);
private static Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
private static Guid IID_IWebBrowser2   = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
}

// This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface!
[ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐