I've been having a bunch of exceptions when trying to use a WebBrowser on a multithread application. COM component, protected memory and开发者_如何学JAVA other exceptions everywhere I do stuff with the WebBrowser. I just gave up and went back to my single thread version which works fine. I would post code but it's hard to localize the cause of the problem when I get exceptions at so many spots. So, if as a single thread application it runs fine, and if when I run several instances of the same application it also works fine, there should be a way to simulate several applications running from a single application without having to actually make a separated application that I would run from the main application. My question, then, is how can I make Windows treat my threads as if they were different instances? This should eliminate the problem, since, as I said, when they ARE different instances I don't get any exception. Hope I'm being clear enough.
WebBrowser is a COM component under the hood, Internet Explorer. Like many COM components, it requires a 'single threaded apartment'. You have to create one to make it a hospitable home for the component. Basically two essential requirements: the thread needs to be initialized as an STA and it needs to pump a message loop.
Here's one that uses the plumbing provided by Windows Forms:
private void runBrowserThread(Uri url) {
var th = new Thread(() => {
var br = new WebBrowser();
br.DocumentCompleted += browser_DocumentCompleted;
br.Navigate(url);
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
var br = sender as WebBrowser;
if (br.Url == e.Url) {
Console.WriteLine("Natigated to {0}", e.Url);
Application.ExitThread();
}
}
Beware that the DocumentCompleted event gets raised on that worker thread. I arbitrarily used that event to also make the thread terminate.
I think your issue may have something to do with the way Microsoft.NET handles UI controls. Basically, any method for a control must be called from the thread that created it (perhaps even the main UI thread exclusively). Otherwise, you will get a bunch of access-related exceptions. I believe you will need to use the InvokeRequired property and Invoke method to call into the control, which also means that you will have to define a delgate function that wraps each method you want to call. Using the WebBroweser.Url property as an example, you could write something like this:
public delegate void SetWebAddressDelegate ( WebBrowser browser, Uri newUrl);
public void SetWebAddress ( WebBrowser browser, Uri newUrl )
{
if (browser.InvokeRequired)
browser.Invoke(new SetWebAddressDelegate(SetWebAddress), browser, newUrl);
else
browser.Url = newUrl;
}
It sounds like you might be sharing a single WebBrowser instance across threads. If each thread has its own instance, and the threads aren't communicating with each other, I would expect that to be equivalent to running multiple instances of the process.
精彩评论