0

I have a global WebBrowser object which is initialized in my constructer. After I use that object in a thread - in order to turn my code into a synchronous state - I am not able to use it afterwards thread ends. Here is the error I receive:

COM object that has been separated from its underlying RCW cannot be used.

I generated an Windows Form class to re-produce the error;

public partial class Test : Form
{
    private WebBrowser _wb;

    public Test()
    {
        InitializeComponent();
        _wb = new WebBrowser();
    }

    private void NavigateThroughTread(string url)
    {
        var th = new Thread(() =>
        {
            _wb.DocumentCompleted += PageLoaded;
            _wb.Navigate(url);
            Application.Run();
        });
        th.SetApartmentState(ApartmentState.STA);
        th.Start();
        while (th.IsAlive) { }
    }

    private void PageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        //Page Loaded
        Application.ExitThread();   // Stops the thread
    }

    private void button_Click(object sender, System.EventArgs e)
    {
        NavigateThroughTread("http://www.example.com/");
        // Here the thread is finished

        MessageBox.Show(_wb.DocumentText); // error  <COM object that has been separated from its underlying RCW cannot be used.>
    }
}

So my question is, how can I use the object _wb after I use it in a thread.

0014
  • 893
  • 4
  • 13
  • 40
  • 1
    That is inevitable, a single-threaded COM object (like WebBrowser) is 'owned' by the thread that created it. When the thread ends, the object is dead as well. And you'll get this exception to remind you about it. Do not call Application.ExitThread() until you are done using it. The PageLoaded event is clearly not an ideal one here, not unless you obtain the info you need inside that event handler. You must also ensure that you actually *have* the info. You'll have more control over the lifetime of the thread with [code like this](http://stackoverflow.com/a/21684059/17034). – Hans Passant Mar 02 '16 at 14:30
  • @HansPassant Thanks for your valuable comment. `ExitThread()` helps me with the synchronization therefore I am afraid I have use it. As you said, I can fetch the information inside `PageLoaded` however, lets say I have to click a button after loading 3 different pages. Every time I have to click, I have to load all the pages from the beginning. I just wanted to avoid that. Might there be any work-around ? – 0014 Mar 02 '16 at 15:05
  • ExitThread() has nothing to do with synchronization, it simply ensures that the worker thread stops running. Telling the main thread that the worker has finished obtaining the document text requires a synchronization object like AutoResetEvent. Or raising an event on the UI thread, BeginInvoke() required. You'll only get to micro-optimize the code when you have a working version first. – Hans Passant Mar 02 '16 at 15:16
  • @HansPassant `while (th.IsAlive) { }` allows me to wait until the thread is finished that's why I said it helps me synchronizing my code. I posted a [question](http://stackoverflow.com/questions/35400849/wait-for-webbrowser-documentcompleted-using-autoresetevent) about synchronizing the `WebBrowser` object and this was the only way that worked for me. Can't remmember the reason but using `AutoResetEvent` and other synchronization functions wasn't suitable for me. – 0014 Mar 02 '16 at 15:25
  • Burning 100% core while waiting for another thread to finish the job is never the correct way to synchronize, it is the antipode of micro-optimizing code. – Hans Passant Mar 02 '16 at 15:46
  • @HansPassant, can you please provide the first comment as answer. Also if you have any workarounds in mind or a piece of code, attaching those info would also be great. – 0014 Mar 07 '16 at 01:43

0 Answers0