Search code examples
c#multithreadingcom

Multithreading locking up with InternetExplorer object


I am attempting to get the document from an InternetExplorer object.

I have been having an issue with my code getting stuck in a function call for very long periods of time - lasting several hours. This issue is only happens rarely. I have tracked the issue back to how my code interacts with InternetExplorer. In an attempt to rule out accessing InternetExplorer.Document I have put that code into a separate thread.

However, it now fails 100% of the time. I have broken out the code as much as possible within the thread to track the exact issue and it is object objDoc = win.Document; below. The debugger gets to that line but never past it. Without the threading it generally took milliseconds to return the Document, though occasionally seconds. With the threading it now is taking more than 5 mintues which is when I have the code throw an exception in the main thread.

Does anyone have any ideas where the issue is with the threaded code I have written?

private InternetExplorer window;
private object lockObject = new object();
private HTMLDocument childThreadDocument;
private Thread childThread;

public HTMLDocument GetDocument()
{
    DateTime start = DateTime.Now;
    childThread = new Thread(() => threadedGetDocument());
    childThread.Start();
    while (true)
    {
        if ((DateTime.Now - start).TotalMinutes > 5) throw new Exception();
        lock (lockObject)
        {
            if (childThreadDocument != null) return childThreadDocument;
        }
    }
}

private void threadedGetDocument()
{
    InternetExplorer win = window;
    object objDoc = win.Document;
    HTMLDocument doc = (HTMLDocument)objDoc;
    lock (lockObject)
    {
        childThreadDocument = doc;
    }
}

Solution

  • I was finally able to resolve the issue. Someone who understands threading better than I do may be able to explain the why. I would guess however switching threads while attempting to access the COM caused it to hang - forcing the main thread to wait for the child thread to finish fixed the problem.

    public HTMLDocument GetDocument()
    {
        DateTime start = DateTime.Now;
        childThread = new Thread(() => threadedGetDocument());
        childThread.Start();
        childThread.Join(new TimeSpan(0, 5, 0));
        lock (lockObject)
        {
            if (childThreadDocument != null)
                return childThreadDocument;
            else 
                throw new ExecutionEngineException("Failed to open IE Document");
        }
    }
    

    Note if you're creating an application that needs to be responsive this would be a terrible idea as implemented. If a call like this were made in a GUI thread then the application wouldn't respond to user input for up to five minutes. However, my application is a console app that quietly works away on a VM to process and distribute incoming work. A short pause doesn't cause any harm.