Search code examples
c#cefsharpcefsharp.offscreen

Cefsharp Shutdown incorrect


Exception: Cef.Shutdown must be called on the same thread that Cef.Initialize was called - typically your UI thread. If you called Cef.Initialize on a Thread other than the UI thread then you will need to call Cef.Shutdown on the same thread. Cef.Initialize was called on ManagedThreadId: 1where Cef.Shutdown is being called on ManagedThreadId: 4

class Program
{
    static void Main(string[] args)
    {
        MainAsync().Wait();
    }

    private static async Task MainAsync()
    {
        List<string> urls = new List<string>();
        urls.Add("https://google.com");

        CefSharpWrapper wrapper = new CefSharpWrapper();

        wrapper.InitializeBrowser();

        foreach (string url in urls)
        {
            await wrapper.GetResultAfterPageLoad(url);
        }
        wrapper.ShutdownBrowser();
    }
}

public sealed class CefSharpWrapper
{
    private ChromiumWebBrowser _browser;

    public void InitializeBrowser()
    {
        Cef.Initialize(new CefSettings());

        _browser = new ChromiumWebBrowser();

        AutoResetEvent waitHandleOnBrowserInitialized = new AutoResetEvent(false);

        EventHandler onBrowserInitialized = null;

        onBrowserInitialized = async (sender, e) =>
        {
            _browser.BrowserInitialized -= onBrowserInitialized;

            waitHandleOnBrowserInitialized.Set();
        };

        _browser.BrowserInitialized += onBrowserInitialized;

        waitHandleOnBrowserInitialized.WaitOne();

    }

    public Task<bool> GetResultAfterPageLoad(string pageUrl)
    {

        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
        EventHandler<LoadingStateChangedEventArgs> onPageLoaded = null;

        // An event that is fired when the first page is finished loading.
        // This returns to us from another thread.
        onPageLoaded = async (sender, args) =>
        {
            // Check to see if loading is complete - this event is called twice, one when loading starts
            // second time when it's finished
            // (rather than an iframe within the main frame).
            if (!args.IsLoading)
            {
                // Remove the load event handler, because we only want one snapshot of the initial page.
                _browser.LoadingStateChanged -= onPageLoaded;

                tcs.SetResult(true);
            }
        };

        _browser.LoadingStateChanged += onPageLoaded;

        _browser.Load(pageUrl);

        return tcs.Task;

    }

    public void ShutdownBrowser()
    {
        // Clean up Chromium objects.  You need to call this in your application otherwise
        // you will get a crash when closing.
        Cef.Shutdown();
    }
}

Solution

  • Amaitland, thanks for the reply.

    class Program
    {
      static void Main(string[] args)
      {
          CefSharpWrapper.InitializeBrowser();
          MainAsync().Wait();
          CefSharpWrapper.ShutdownBrowser();
      }
    
      private static async Task MainAsync()
      {
          List<string> urls = new List<string>();
          urls.Add("https://google.com");
    
          CefSharpWrapper wrapper = new CefSharpWrapper();
    
          foreach (string url in urls)
          {
            await wrapper.GetResultAfterPageLoad(url);
          }
      }
    }
    
    public sealed class CefSharpWrapper
    {
      private static ChromiumWebBrowser _browser;
    
      public static void InitializeBrowser()
      {
          Cef.Initialize(new CefSettings());
    
          _browser = new ChromiumWebBrowser();
    
          AutoResetEvent waitHandleOnBrowserInitialized = new AutoResetEvent(false);
    
          EventHandler onBrowserInitialized = null;
    
          onBrowserInitialized = async (sender, e) =>
          {
              _browser.BrowserInitialized -= onBrowserInitialized;
    
              waitHandleOnBrowserInitialized.Set();
          };
    
          _browser.BrowserInitialized += onBrowserInitialized;
    
          waitHandleOnBrowserInitialized.WaitOne();
    
      }
    
      public Task<bool> GetResultAfterPageLoad(string pageUrl)
      {
    
          TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
          EventHandler<LoadingStateChangedEventArgs> onPageLoaded = null;
    
        // An event that is fired when the first page is finished loading.
        // This returns to us from another thread.
          onPageLoaded = async (sender, args) =>
          {
            // Check to see if loading is complete - this event is called twice, one when loading starts
            // second time when it's finished
            // (rather than an iframe within the main frame).
              if (!args.IsLoading)
              {
                // Remove the load event handler, because we only want one snapshot of the initial page.
                  _browser.LoadingStateChanged -= onPageLoaded;
    
                  tcs.SetResult(true);
              }
          };
    
          _browser.LoadingStateChanged += onPageLoaded;
    
          _browser.Load(pageUrl);
    
          return tcs.Task;
    
      }
    
      public static void ShutdownBrowser()
      {
        // Clean up Chromium objects.  You need to call this in your application otherwise
        // you will get a crash when closing.
          Cef.Shutdown();
      }
    }