使用GeckoWebBrowser时出现InvalidComObjectException

时间:2017-08-20 11:03:21

标签: c# winforms exception geckofx

我正在使用GeckoFx45的GeckoWebBrowser在网页完全加载后提取网页的来源。

只有在一切运行正常后才能运行我的代码,但是当它多次运行时会抛出InvalidComObjectException

  

System.Runtime.InteropServices.InvalidComObjectException:       '已与基础RCW分离的COM对象无法使用。'

代码:

public static async Task<string> LoadDomSourceAsync(string url, CancellationToken cancellationToken) {
    using (var apartment = new MessageLoopApartment())
        return await apartment.Run(async () => {
            using (var wb = new GeckoWebBrowser()) {
                var tcs = new TaskCompletionSource<string>();
                try {
                    wb.DocumentCompleted += (s, a) => tcs.TrySetResult(((GeckoHtmlHtmlElement)wb.Document.DocumentElement).OuterHtml);
                    wb.NavigationError += (s, a) => tcs.TrySetException(new GeckoNetworkException());
                    wb.Navigate(url);
                    return await tcs.Task;
                } catch (Exception e) { tcs.TrySetException(e); }
                finally {
                    wb.Stop();
                }
                return null;
            }
        }, cancellationToken);
}

MessageLoopApartment:

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace StreamLinkExtract {
    /// <summary>
    /// MessageLoopApartment
    /// STA thread with message pump for serial execution of tasks
    /// by Noseratio - http://stackoverflow.com/a/22262976/1768303
    /// </summary>
    public class MessageLoopApartment : IDisposable {
        Thread _thread; // the STA thread

        TaskScheduler _taskScheduler; // the STA thread's task scheduler

        public TaskScheduler TaskScheduler { get { return _taskScheduler; } }

        /// <summary>MessageLoopApartment constructor</summary>
        public MessageLoopApartment() {
            var tcs = new TaskCompletionSource<TaskScheduler>();

            // start an STA thread and gets a task scheduler
            _thread = new Thread(startArg => {
                EventHandler idleHandler = null;

                idleHandler = (s, e) => {
                    // handle Application.Idle just once
                    Application.Idle -= idleHandler;
                    // return the task scheduler
                    tcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext());
                };

                // handle Application.Idle just once
                // to make sure we're inside the message loop
                // and SynchronizationContext has been correctly installed
                Application.Idle += idleHandler;
                Application.Run();
            });

            _thread.SetApartmentState(ApartmentState.STA);
            _thread.IsBackground = true;
            _thread.Start();
            _taskScheduler = tcs.Task.Result;
        }

        /// <summary>shutdown the STA thread</summary>
        public void Dispose() {
            if (_taskScheduler != null) {
                var taskScheduler = _taskScheduler;
                _taskScheduler = null;

                // execute Application.ExitThread() on the STA thread
                Task.Factory.StartNew(
                    () => Application.ExitThread(),
                    CancellationToken.None,
                    TaskCreationOptions.None,
                    taskScheduler).Wait();

                _thread.Join();
                _thread = null;
            }
        }

        /// <summary>Task.Factory.StartNew wrappers</summary>
        public void Invoke(Action action) {
            Task.Factory.StartNew(action,
                CancellationToken.None, TaskCreationOptions.None, _taskScheduler).Wait();
        }

        public TResult Invoke<TResult>(Func<TResult> action) {
            return Task.Factory.StartNew(action,
                CancellationToken.None, TaskCreationOptions.None, _taskScheduler).Result;
        }

        public Task Run(Action action, CancellationToken token) {
            return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler);
        }

        public Task<TResult> Run<TResult>(Func<TResult> action, CancellationToken token) {
            return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler);
        }

        public Task Run(Func<Task> action, CancellationToken token) {
            return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler).Unwrap();
        }

        public Task<TResult> Run<TResult>(Func<Task<TResult>> action, CancellationToken token) {
            return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler).Unwrap();
        }
    }
}

0 个答案:

没有答案