17

I want to use it to invoke some JS scripts on the webpage. I have this:

    static void Stuff()
    {
        WebBrowser browser = new WebBrowser();
        browser.Navigate("http://www.iana.org/domains/example/");
        HtmlDocument doc = browser.Document;
        //doc.InvokeScript("someScript");
        Console.WriteLine(doc.ToString());
    }

    static void Main(string[] args)
    {
        Console.WriteLine("hi");
        var t = new Thread(Stuff);
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }

Question 1: I get an "object reference not set" exception when I try to get doc.ToString(). Why?

Question 2: How do I get some data from the HTML document into the main program? WebBrowser requires a separate thread, which requires a static method which can't return any value. How do I return, say, doc to the Main() so I can do something with it?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Hui
  • 13,887
  • 8
  • 25
  • 20
  • Static methods actually can return a value. It's threads that can't. Also, threads *can* use a non-static method. – icktoofay Jun 12 '11 at 21:44

1 Answers1

15

Right idea, wrong execution. The WebBrowser.Navigate() only tells the web browser to start navigating to the web page you asked for. That takes time, hundreds of milliseconds typically. Internet Explorer internally starts threads to get the job done. It tells you when it is done by raising the DocumentCompleted event. You don't wait for that so that's crash city first.

Next problem is that the DocumentCompleted event won't be raised in your code. You have to honor the STA contract, it requires you to pump a message loop. That's the all-mighty way that a background thread, like the one that IE uses to retrieve a web page, tells your thread that the job is done.

The boilerplate code you need is available in this answer.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • How would you go about chaining activities? You want to navigate to some page, then enter some text in a text box, and click search, or go. Do you need to just make the WebBrowser object global, and then chain together 4 methods, navigate, navigate's document completed, enter text and hit go, entertextandhitgo's document completed event? – NathanTempelman Mar 21 '13 at 15:42
  • 1
    A state machine is the simple solution to asynchronous programming problems. Just keep track of the state with an integer or an enum. – Hans Passant Mar 21 '13 at 15:52
  • 2
    Just a side-note: when trying to automate a WebBrowser control with no user interaction, you will run into serious issues with popup-dialogs unless you set `webBrowser.ScriptErrorsSuppressed = true` *(which, despite its name, suppresses all dialogs, not just script errors)*. [See also](http://stackoverflow.com/a/20612526/238419). – BlueRaja - Danny Pflughoeft Dec 16 '13 at 14:06