I create an instance of IE outside my program, which the program finds and attaches to correctly. I set up my event handler and tell the program to advance to the login screen. The DocumentCompleted handle is supposed to fire when the web page is completely loaded, but mine seems to be firing before the new page has appeared.. The handle only fires once (meaning there is only one frame?).
This code executes fine if I modify it to work straight from the login page also.. Am I doing something wrong? Thanks for any assistance :)
Process.Start(#"IESpecial.exe");
SHDocVw.ShellWindows allBrowsers = new SHDocVw.ShellWindows();
while (true)
{
foreach (SHDocVw.WebBrowser ie in allBrowsers)
{
if (ie.LocationURL == "http://website/home.asp")
{
loggingIn = true;
webBrowser = ie;
webBrowser.DocumentComplete += new SHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler(webBrowser1_DocumentCompleted);
webBrowser.Navigate("http://website/logon.asp");
return;
}
}
Thread.Sleep(10);
}
}
private void webBrowser1_DocumentCompleted(object pDisp, ref object URL)
{
//we are attempting to log in
if (loggingIn)
{
mshtml.HTMLDocumentClass doc = (mshtml.HTMLDocumentClass)webBrowser.Document;
mshtml.HTMLWindow2 window = (mshtml.HTMLWindow2)doc.IHTMLDocument2_parentWindow;
doc.getElementById("Username").setAttribute("value", "MLAPAGLIA");
doc.getElementById("Password").setAttribute("value", "PASSWORD");
window.execScript("SubmitAction()", "javascript");
loggingIn = false;
return;
}
Related
I have used this method i found online, which will take a Uri then check if the uri is opened in an IE browser if it is opened it will prevent the opening of new tab or instance of the same site, if not a new IE tab will open which is great for what i was looking for the method is bellow:
public static void LaunchSite(Uri sitUrl)
{
SHDocVw.ShellWindows w = new SHDocVw.ShellWindows();
bool found = false;
foreach (SHDocVw.ShellBrowserWindow item in w)
{
var doc = item.LocationURL;
if (!string.IsNullOrEmpty(doc))
if (doc == sitUrl.AbsoluteUri)
{
found = true;
break;
}
}
if (!found)
Process.Start(sitUrl.AbsoluteUri);
}
Then used the method in a button_click event handler as follow:
private void btnSubs_Click(object sender, RoutedEventArgs e)
{
Uri oxfArt = new Uri(#"http://www.somesite.com/subscriber/");
StartProcess.LaunchSite(oxfArt);
}
my questions are :
within the method how can i check if there is already an instance of IE open, if it is i need to open the site within that IE window not as a new tab or new IE instance, basically i need to be able to have one instance and one windows of all my sites to be opened in current window?.
within the button event handler i need to use switch statement that uses different URI to save me creating different button event handler for each URI, How would I be able to achieve that
The answer to my 2nd question has 2 option for solution:
Button btnSub = e.Source as Button;
if (btnSub != null)
{
Uri uri = new Uri((string)btnSub.Tag);
StartProcess.LaunchSite(uri);
}
within the butonn click event handler.
then in the button triggered the event we need to set the tag to the desired Uri as follow:
<Button x:Name="theorytst" Cursor="Hand" Tag="http://theorytestpro.co.uk/">
the 2nd solution is to use the switch statement using the button x:Name and the button tag property as before then cast button tag as Uri to pass to the calling method StartProcess.LaunchSite(uri);
switch (btnSub.Name)
{
case "oxfArt":
Uri uri = new Uri((string)btnSub.Tag);
StartProcess.LaunchSite(uri);
break;
case "theorytst":
Uri uri1 = new Uri((string)btnSub.Tag);
StartProcess.LaunchSite(uri1);
break;
default:
break;
}
I need to be able to have one instance and one windows of all my sites to be opened in current window?
Process[] pname = Process.GetProcessesByName("iexplore");
if (pname.Length == 0)
{
Process.Start("IEXPLORE.EXE", "http://www.somesite.com/subscriber/");
}
else
{
try
{
foreach (Process proc in Process.GetProcessesByName("iexplore"))
{
proc.Kill();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Within the button event handler i need to use switch statement that uses different URI to save me creating different button event handler for each URI, How would I be able to achieve that
As I understand correctly you want to call various button handlers. You can do it using switch statement. For example:
string input="http://getyourURI.com"; //you should set your own http address.
//It is just an example
Uri uri = new Uri(input);
string address = uri.OriginalString;
switch(address)
{
case "hey.com":
btnExcel_Click(null, null);
break;
case "another.com":
callAnotherBtn_Click(null, null);
break;
}
public static User registerUser()
{
Uri test = new Uri("https://www.example.com/signup");
HtmlDocument testdoc = runBrowserThread(test);
string tosend = "test";
User user = new User();
user.apikey = tosend;
return user;
}
public static HtmlDocument runBrowserThread(Uri url)
{
HtmlDocument value = null;
var th = new Thread(() =>
{
var br = new WebBrowser();
br.DocumentCompleted += browser_DocumentCompleted;
br.Navigate(url);
value = br.Document;
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join(8000);
return value;
}
static void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var br = sender as WebBrowser;
if (br.Url == e.Url)
{
Console.WriteLine("Natigated to {0}", e.Url);
Console.WriteLine(br.Document.Body.InnerHtml);
System.Console.ReadLine();
Application.ExitThread(); // Stops the thread
}
}
I am trying to scan this page, and while it does get the HTML it does not pass it back in to the function call, but instead sends back null (I presume that is post processing).
How can I make it so that the new thread passes back its result?
There are several problems with your approach.
You're not waiting till the webpage is navigated, I mean till Navigated event. So document could be null till then.
You're quitting after 8 seconds, if page takes more than 8 seconds to load you won't get the document.
If document isn't properly loaded, you're leaving the thread alive.
I guess WebBrowser control will not work as expected unless you add it into a form and show it(it needs to be visible in screen).
Etc..
Don't mix up things. Your goal can't be to use WebBrowser. If you need to just download the string from webpage, use HttpClient.GetStringAsync.
Once you get the page as string format, If you want to manipulate the html, use HtmlAgilityPack.
Moved over to using WaitN instead of the default browser model. A bit buggy but now works like it should do.
using (var browser = new FireFox("https://www.example.com/signup"))
{
browser.GoTo("https://example.com/signup");
browser.WaitForComplete();
}
I asked this question a while ago but seems that there are no answers, so i tried to go with an alternative solution but i am stuck now, please see the following code:
WebBrowser objWebBrowser = new WebBrowser();
objWebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(objWebBrowser_DocumentCompleted);
objWebBrowser.Navigate("http://www.website.com/login.php?user=xxx&pass=xxx");
objWebBrowser.Navigate("http://www.website.com/page.php?link=url");
And here is the event code:
WebBrowser objWebBrowser = (WebBrowser)sender;
String data = new StreamReader(objWebBrowser.DocumentStream).ReadToEnd();
Since it's impossible for me to use the WebBrowser.Document.Cookies before a document is loaded, i have first to navigate the login page, that will store a cookie automatically, but after that i want to call the other navigate in order to get a result. Now using the above code it doesn't work cause it always takes the second one, and it won't work for me to put it in the event cause what i want is like this:
Navigate with the login page and store cookie for one time only.
Pass a different url each time i want to get some results.
Can anybody give a solution ?
Edit:
Maybe the sample of code i provided was misleading, what i want is:
foreach(url in urls)
{
Webborwser1.Navigate(url);
//Then wait for the above to complete and get the result from the event, then continue
}
I think you want to simulate a blocking call to Navigate if you are not authorized. There are probably many ways to accomplish this and other approaches to get what you want, but here's some code I wrote up quickly that might help you get started.
If you have any questions about what I'm trying to do here, let me know. I admit it feels like "a hack" which makes me think there's a smarter solution, but anyway....
bool authorized = false;
bool navigated;
WebBrowser objWebBrowser = new WebBrowser();
void GetResults(string url)
{
if(!authorized)
{
NavigateAndBlockWithSpinLock("http://www.website.com/login.php?user=xxx&pass=xxx");
authorized = true;
}
objWebBrowser.Navigate(url);
}
void NavigateAndBlockWithSpinLock(string url)
{
navigated = false;
objWebBrowser.DocumentCompleted += NavigateDone;
objWebBrowser.Navigate(url);
int count = 0;
while(!navigated && count++ < 10)
Thread.Sleep(1000);
objWebBrowser.DocumentCompleted -= NavigateDone;
if(!navigated)
throw new Exception("fail");
}
void NavigateDone(object sender, WebBrowserDocumentCompletedEventArgs e)
{
navigated = true;
}
void objWebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if(authorized)
{
WebBrowser objWebBrowser = (WebBrowser)sender;
String data = new StreamReader(objWebBrowser.DocumentStream).ReadToEnd();
}
}
I have a C# form with a web browser control on it.
I am trying to visit different websites in a loop.
However, I can not control URL address to load into my form web browser element.
This is the function I am using for navigating through URL addresses:
public String WebNavigateBrowser(String urlString, WebBrowser wb)
{
string data = "";
wb.Navigate(urlString);
while (wb.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
data = wb.DocumentText;
return data;
}
How can I make my loop wait until it fully loads?
My loop is something like this:
foreach (string urlAddresses in urls)
{
WebNavigateBrowser(urlAddresses, webBrowser1);
// I need to add a code to make webbrowser in Form to wait till it loads
}
Add This to your code:
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
Fill in this function
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
//This line is so you only do the event once
if (e.Url != webBrowser1.Url)
return;
//do you actual code
}
After some time of anger of the crappy IE functionality I've came across making something which is the most accurate way to judge page loaded complete.
Never use the WebBrowserDocumentCompletedEventHandler event
use WebBrowserProgressChangedEventHandler with some modifections seen below.
//"ie" is our web browser object
ie.ProgressChanged += new WebBrowserProgressChangedEventHandler(_ie);
private void _ie(object sender, WebBrowserProgressChangedEventArgs e)
{
int max = (int)Math.Max(e.MaximumProgress, e.CurrentProgress);
int min = (int)Math.Min(e.MaximumProgress, e.CurrentProgress);
if (min.Equals(max))
{
//Run your code here when page is actually 100% complete
}
}
Simple genius method of going about this, I found this question googling "How to sleep web browser or put to pause"
According to MSDN (contains sample source) you can use the DocumentCompleted event for that. Additional very helpful information and source that shows how to differentiate between event invocations can be found here.
what you experiencend happened to me . readyStete.complete doesnt work in some cases. here i used bool in document_completed to check state
button1_click(){
//go site1
wb.Navigate("site1.com");
//wait for documentCompleted before continue to execute any further
waitWebBrowserToComplete(wb);
// set some values in html page
wb.Document.GetElementById("input1").SetAttribute("Value", "hello");
// then click submit. (submit does navigation)
wb.Document.GetElementById("formid").InvokeMember("submit");
// then wait for doc complete
waitWebBrowserToComplete(wb);
var processedHtml = wb.Document.GetElementsByTagName("HTML")[0].OuterHtml;
var rawHtml = wb.DocumentText;
}
// helpers
//instead of checking readState . we get state from DocumentCompleted Event via bool value
bool webbrowserDocumentCompleted = false;
public static void waitWebBrowserToComplete(WebBrowser wb)
{
while (!webbrowserDocumentCompleted )
Application.DoEvents();
webbrowserDocumentCompleted = false;
}
form_load(){
wb.DocumentCompleted += (o, e) => {
webbrowserDocumentCompleted = true;
};
}
I am wondering if BeforeNavigate2 or DocumentComplete events should fire on pages with AJAX. For example google maps. When I put something in addressbar everything is ok, but when I move the map and resizing it nothing happens (DocumentComplete and BeforeNavigate2 does not fire), but data is sent to and from Internet.
The a in ajax stands for asynchronous. These events fire in response to synchronous methods completing. Since an asynchronous request can be made at any time the browser has no way of knowing when they are all completed.
I think you need to handle ajax request and you can Handle with DownloadBegin and DownloadComplete Event.
In Code:
public int SetSite(object site)
{
if (site != null)
{
webBrowser = (WebBrowser)site;
webBrowser.DownloadComplete += new DWebBrowserEvents2_DownloadCompleteEventHandler(DownloadComplete);
webBrowser.DownloadBegin += new DWebBrowserEvents2_DownloadBeginEventHandler(DownloadBegin);
}
else
{
webBrowser.DownloadComplete += new DWebBrowserEvents2_DownloadCompleteEventHandler(DownloadComplete);
webBrowser.DownloadBegin += new DWebBrowserEvents2_DownloadBeginEventHandler(DownloadBegin);
webBrowser = null;
}
return 0;
}
Events:
private void DownloadBegin()
{
MessageBox.Show("Download Begin");
}
private void DownloadComplete()
{
MessageBox.Show("Download Complete");
}
it's work for me.
I monitor download begin and download complete events to process pages which include ajax codes.
Also need program logic to control the flow, e.g.. set/check flags.