创建线程就好像它是C#中的独立应用程序一样

时间:2010-09-04 07:26:13

标签: c# .net windows

尝试在多线程应用程序上使用WebBrowser时,我遇到了很多异常。 COM组件,受保护的内存和其他各种异常我用WebBrowser做的事情。我只是放弃了,回到我的单线程版本,工作正常。我会发布代码但是当我在很多地方遇到异常时很难定位问题的原因。因此,如果作为单个线程应用程序运行正常,并且当我运行同一应用程序的多个实例时它也可以正常工作,应该有一种方法来模拟从单个应用程序运行的多个应用程序,而无需实际创建单独的应用程序我会从主应用程序运行。那么,我的问题是,如何让Windows将我的线程视为不同的实例?这应该可以消除这个问题,因为正如我所说,当它们是不同的实例时,我没有任何例外。希望我足够清楚。

3 个答案:

答案 0 :(得分:2)

WebBrowser是一个引擎盖下的COM组件,Internet Explorer。像许多COM组件一样,它需要一个“单线程公寓”。你必须创建一个使它成为组件的好客家。基本上有两个基本要求:线程需要初始化为STA,并且需要抽取消息循环。

这是使用Windows窗体提供的管道的一个:

    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();
        }
    }

请注意,在该工作线程上引发了DocumentCompleted事件。我任意使用该事件也使线程终止。

答案 1 :(得分:1)

我认为您的问题可能与Microsoft.NET处理UI控件的方式有关。基本上,控件的任何方法都必须从创建它的线程中调用(甚至可能只是主UI线程)。否则,您将获得一堆与访问相关的异常。我相信你需要使用InvokeRequired属性和Invoke方法来调用控件,这也意味着你必须定义一个包含你想要调用的每个方法的delgate函数。以WebBroweser.Url属性为例,您可以编写如下内容:

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;
}

答案 2 :(得分:0)

听起来您可能跨线程共享一个WebBrowser实例。如果每个线程都有自己的实例,并且线程没有相互通信,我希望这相当于运行该进程的多个实例。