When we do a Web test, we often use WebBrowser for some automated tasks. And some pages will use IFrame to nest other pages, these pages may not be under the same domain name, then there will be cross-domain problems, can not directly in the WebBrowser to get the elements in the IFRAME. Here to do a test, write a page nested a Baidu homepage, and then on our own page to enter the word to query, and finally in Baidu to complete the search automatically.
Copy Code code as follows:
<! DOCTYPE html>
<meta charset= "Utf-8"/>
<title></title>
<body>
<iframe id= "Baidu" style= "Float:left" width= "" height= "" src= "" http://www.baidu.com "></iframe>
<div>
Test value: <input id= "Search" type= "text"/>
</div>
</body>
The following is a simple WinForm engineering test, the interface is as follows:
The following is the WebBrowser test code:
Copy Code code as follows:
Using System;
Using System.Windows.Forms;
Namespace Webbrowsertest
{
public partial class Form1:form
{
Public Form1 ()
{
InitializeComponent ();
}
private void Button1_Click (object sender, EventArgs e)
{
This.webBrowser1.Navigate (This.textBox1.Text);
}
private void Button2_Click (object sender, EventArgs e)
{
var doc = this.webBrowser1.Document;
var frames = doc. Window.frames;
String TestValue = doc. getElementById ("Search"). GetAttribute ("value");
Frames[0]. document.getElementById ("kw"). SetAttribute ("value", TestValue);
Frames[0]. document.getElementById ("Su"). InvokeMember ("click");
}
}
}
After we run our test program, after loading our own page, enter the words we want to query on our own page, click the Test button, and we will see that the program has not handled the UnauthorizedAccessException error:
Here's how to write a helper class to solve this problem, the main principle is to use IWebBrowser2 this interface to get Ifream in the Dom,iwebbrowser2 in the document can be converted to IHtmlDocument1, Ihtmldocument2,ihtmldocument3.
Copy Code code as follows:
Using System;
Using System.Runtime.InteropServices;
Using System.Windows.Forms;
Using Mshtml;
Namespace Webbrowsertest
{
This is the COM IServiceProvider interface and 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);
}
public enum Olecmdf
{
Olecmdf_defhideonctxtmenu = 0x20,
olecmdf_enabled = 2,
Olecmdf_invisible = 0x10,
olecmdf_latched = 4,
olecmdf_ninched = 8,
olecmdf_supported = 1
}
public enum Olecmdid
{
Olecmdid_pagesetup = 8,
Olecmdid_print = 6,
Olecmdid_printpreview = 7,
Olecmdid_properties = 10,
Olecmdid_saveas = 4
}
public enum Olecmdexecopt
{
Olecmdexecopt_dodefault,
Olecmdexecopt_promptuser,
Olecmdexecopt_dontpromptuser,
Olecmdexecopt_showhelp
}
[ComImport, Guid ("d30c1661-cdaf-11d0-8a3e-00c04fc9e26e"), TypeLibType (Typelibtypeflags.foleautomation | typelibtypeflags.fdual | Typelibtypeflags.fhidden)]
public interface IWebBrowser2
{
[DispId (100)]
void GoBack ();
[DispId (0X65)]
void GoForward ();
[DispId (0X66)]
void GoHome ();
[DispId (0X67)]
void Gosearch ();
[DispId (0x68)]
void Navigate ([in] string Url, [in] Ref object flags, [in] ref object Targetframename, [in] ref object PostData, [in] ref Object headers);
[DispId (-550)]
void Refresh ();
[DispId (0x69)]
void Refresh2 ([in] ref object level);
[DispId (0X6A)]
void Stop ();
[DispId (200)]
Object application {[Return:marshalas (unmanagedtype.idispatch)] get;}
[DispId (0XC9)]
Object Parent {[Return:marshalas (unmanagedtype.idispatch)] get;}
[DispId (0XCA)]
Object Container {[Return:marshalas (unmanagedtype.idispatch)] get;}
[DispId (0XCB)]
Object Document {[Return:marshalas (unmanagedtype.idispatch)] get;}
[DispId (0XCC)]
BOOL Toplevelcontainer {get;}
[DispId (0XCD)]
String Type {get;}
[DispId (0XCE)]
int left {get; set;}
[DispId (0XCF)]
int top {get; set;}
[DispId (0XD0)]
int Width {get; set;}
[DispId (0XD1)]
int Height {get; set;}
[DispId (210)]
String LocationName {get;}
[DispId (0XD3)]
String Locationurl {get;}
[DispId (0xd4)]
BOOL Busy {get;}
[DispId (300)]
void Quit ();
[DispId (0x12d)]
void Clienttowindow (out int pcx, out int pcy);
[DispId (0x12e)]
void PutProperty ([in] string, [in] object vtvalue);
[DispId (0x12f)]
Object GetProperty ([in] string property);
[DispId (0)]
String Name {get;}
[DispId (-515)]
int HWND {get;}
[DispId (400)]
String FullName {get;}
[DispId (0x191)]
String Path {get;}
[DispId (0x192)]
BOOL Visible {get; set;}
[DispId (0x193)]
BOOL StatusBar {get; set;}
[DispId (0x194)]
String StatusText {get; set;}
[DispId (0x195)]
int ToolBar {get; set;}
[DispId (0x196)]
BOOL MenuBar {get; set;}
[DispId (0x197)]
BOOL fullscreen {get; set;}
[DispId (500)]
void Navigate2 ([in] ref object URL, [in] Ref object flags, [in] ref object Targetframename, [in] ref object PostData, [in] Ref object headers);
[DispId (0X1F5)]
Olecmdf QUERYSTATUSWB ([in] Olecmdid CmdID);
[DispId (0X1F6)]
void ExecWB ([in] Olecmdid CmdID, [in] olecmdexecopt cmdexecopt, ref object Pvain, IntPtr pvaout);
[DispId (0X1F7)]
void Showbrowserbar ([in] ref object Pvaclsid, [in] ref object Pvarshow, [in] ref object pvarsize);
[DispId (-525)]
Webbrowserreadystate ReadyState {get;}
[DispId (550)]
BOOL Offline {get; set;}
[DispId (0x227)]
bool Silent {get; set;}
[DispId (0x228)]
BOOL RegisterAsBrowser {get; set;}
[DispId (0x229)]
BOOL Registerasdroptarget {get; set;}
[DispId (0X22A)]
BOOL Theatermode {get; set;}
[DispId (0x22b)]
BOOL Addressbar {get; set;}
[DispId (0x22c)]
BOOL resizable {get; set;}
}
Class Corssdomainhelper
{
private static Guid Iid_iwebbrowserapp = new Guid ("0002df05-0000-0000-c000-000000000046");
private static Guid Iid_iwebbrowser2 = new Guid ("d30c1661-cdaf-11d0-8a3e-00c04fc9e26e");
Utility for IE cross domain access
Returns NULL in case of failure.
public static IHTMLDocument3 Getdocumentfromwindow (IHTMLWindow2 HtmlWindow)
{
if (HtmlWindow = null)
{
return null;
}
The usual way to get the document.
Try
{
IHTMLDocument2 doc = htmlwindow.document;
Return (IHTMLDOCUMENT3) doc;
}
catch (COMException comEx)
{
I am COMException won ' t be ever fired but just to be sure ...
}
catch (UnauthorizedAccessException)
{
}
catch (Exception ex)
{
return null;
}
At this point the error is 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.
IWebBrowser2 browser = (IWebBrowser2) (BRWS);
Return (IHTMLDOCUMENT3) browser. Document;
}
catch (Exception ex)
{
Console.WriteLine (ex);
}
return null;
}
}
}
Finally, change our run code to the following form, calling the Getdocumentfromwindow method in the helper class:
Copy Code code as follows:
Using System;
Using System.Windows.Forms;
Using Mshtml;
Namespace Webbrowsertest
{
public partial class Form1:form
{
Public Form1 ()
{
InitializeComponent ();
}
private void Button1_Click (object sender, EventArgs e)
{
This.webBrowser1.Navigate (This.textBox1.Text);
}
private void Button2_Click (object sender, EventArgs e)
{
var doc = this.webBrowser1.Document;
var frames = doc. Window.frames;
String TestValue = doc. getElementById ("Search"). GetAttribute ("value");
IHTMLDocument3 Baidudoc = Corssdomainhelper.getdocumentfromwindow (frames[0). Domwindow as IHTMLWindow2);
Baidudoc.getelementbyid ("kw"). setattribute ("value", TestValue);
Baidudoc.getelementbyid ("su"). Click ();
}
}
}
Finally run the program can see that we can get to the normal Baidu element.
to add to the question of passing autumn,:
In fact, I do not have a very in-depth study of these interfaces, but the Internet can search a lot of relevant information about these interfaces, I give a link here:
Http://hi.baidu.com/christole/item/1c8dfd1a791a53643f87ced8
Then why do I use IHMLDOCUMENT3 for the code above, not the other two interfaces, because IHMLDocument3 this interface defines the getElementById method I need.
By looking at MSDN, you can find the attributes or methods you need, and then switch directly into the code to the type you need to use, and they can all be transformed into each other. For example, I used up the getElementById method, I need to view the title of the page, then I can force the Baidudoc variable to IHMLDocument2, and then you can directly use its Title property.
Reference Links:
http://msdn.microsoft.com/en-us/library/aa752052 (v=vs.85). aspx
Http://codecentrix.blogspot.com/2007/10/when-ihtmlwindow2getdocument-returns.html
http://msdn.microsoft.com/en-us/library/aa752641 (v=vs.85). aspx