我如何在工作线程上创建和使用WebBrowser控件?

我正在创建一个应用程序,使用以下方法对网站进行屏幕截图http://pietschsoft.com/post/2008/07/C-Generate-WebPage-Thumbmail-Screenshot-Image.aspx

我试图使应用程序multithreading,但我遇到了以下错误:

[ActiveX控件’8856f961-340a-11d0-a96b-00c04fd705a2’无法实例化,因为当前线程不在单线程单元中。

有任何建议如何解决这个问题? 我的代码基本如下:

List lststrWebSites = new List(); lststrWebSites.Add("http://stackoverflow.com"); lststrWebSites.Add("http://www.cnn.com"); foreach (string strWebSite in lststrWebSites) { System.Threading.ThreadStart objThreadStart = delegate { Bitmap bmpScreen = GenerateScreenshot(strWebSite, -1, -1); bmpScreen.Save(@"C:\" + strWebSite + ".png", System.Drawing.Imaging.ImageFormat.Png); }; new System.Threading.Thread(objThreadStart).Start(); } 

从上面的URL复制GenerateScreenShot()函数实现:

 public Bitmap GenerateScreenshot(string url) { // This method gets a screenshot of the webpage // rendered at its full size (height and width) return GenerateScreenshot(url, -1, -1); } public Bitmap GenerateScreenshot(string url, int width, int height) { // Load the webpage into a WebBrowser control WebBrowser wb = new WebBrowser(); wb.ScrollBarsEnabled = false; wb.ScriptErrorsSuppressed = true; wb.Navigate(url); while (wb.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); } // Set the size of the WebBrowser control wb.Width = width; wb.Height = height; if (width == -1) { // Take Screenshot of the web pages full width wb.Width = wb.Document.Body.ScrollRectangle.Width; } if (height == -1) { // Take Screenshot of the web pages full height wb.Height = wb.Document.Body.ScrollRectangle.Height; } // Get a Bitmap representation of the webpage as it's rendered in // the WebBrowser control Bitmap bitmap = new Bitmap(wb.Width, wb.Height); wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height)); wb.Dispose(); return bitmap; } 

尝试设置托管浏览器控件的线程的ApartmentState :

 var thread = new Thread(objThreadStart); thread.SetApartmentState(ApartmentState.STA); thread.Start(); 

与许多ActiveX控件一样,WebBrowser具有严格的线程要求。 必须使用Thread.SetApartmentState()初始化创建它的线程,以将其切换到STA。 并且线程必须泵出一个消息循环,你从Application.Run()得到一个。

这使得与浏览器交谈非常棘手。 这是让你入门的代码。 请注意,已完成的回调在后台线程上运行。 不要忘记调用Dispose()来关闭线程。

 using System; using System.Threading; using System.ComponentModel; using System.Windows.Forms; class WebPagePump : IDisposable { public delegate void CompletedCallback(WebBrowser wb); private ManualResetEvent mStart; private SyncHelper mSyncProvider; public event CompletedCallback Completed; public WebPagePump() { // Start the thread, wait for it to initialize mStart = new ManualResetEvent(false); Thread t = new Thread(startPump); t.SetApartmentState(ApartmentState.STA); t.IsBackground = true; t.Start(); mStart.WaitOne(); } public void Dispose() { // Shutdown message loop and thread mSyncProvider.Terminate(); } public void Navigate(Uri url) { // Start navigating to a URL mSyncProvider.Navigate(url); } void mSyncProvider_Completed(WebBrowser wb) { // Navigation completed, raise event CompletedCallback handler = Completed; if (handler != null) handler(wb); } private void startPump() { // Start the message loop mSyncProvider = new SyncHelper(mStart); mSyncProvider.Completed += mSyncProvider_Completed; Application.Run(mSyncProvider); } class SyncHelper : Form { WebBrowser mBrowser = new WebBrowser(); ManualResetEvent mStart; public event CompletedCallback Completed; public SyncHelper(ManualResetEvent start) { mBrowser.DocumentCompleted += mBrowser_DocumentCompleted; mStart = start; } public void Navigate(Uri url) { // Start navigating this.BeginInvoke(new Action(() => mBrowser.Navigate(url))); } void mBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { // Generated completed event Completed(mBrowser); } public void Terminate() { // Shutdown form and message loop this.Invoke(new Action(() => this.Close())); } protected override void SetVisibleCore(bool value) { if (!IsHandleCreated) { // First-time init, create handle and wait for message pump to run this.CreateHandle(); this.BeginInvoke(new Action(() => mStart.Set())); } // Keep form hidden value = false; base.SetVisibleCore(value); } } } 

Main方法的属性从STAThread更改为MTAThread帮助?

例:

 [STAThread] public static void Main() { 

更改为:

 [MTAThread] public static void Main() {