My application needs to invoke (off screen) browser on request and cleanup once it is done.
So I created an offscreen browser
public class OffScreenBrowser
{
private static ChromiumWebBrowser _browser;
private static CefSettings _settings;
public void Load(string url,System.Drawing.Size size)
{
if (Cef.IsInitialized) return;
Init(new BrowserProcessHandler());
_browser = new ChromiumWebBrowser(url) {Size = size};
_browser.NewScreenshot += _browser_NewScreenshot;
}
public System.Windows.Controls.Image BrowserImage { get; set; }
public Action NewScreenShotAction { get; set; }
private void _browser_NewScreenshot(object sender, EventArgs e)
{
var bitmap = _browser.ScreenshotOrNull();
Application.Current.Dispatcher.Invoke(new Action(() =>
{
using (MemoryStream memory = new MemoryStream())
{
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
BrowserImage = new System.Windows.Controls.Image() {Source = bitmapImage};
NewScreenShotAction();
}
}));
}
public void Close()
{
_browser.NewScreenshot -= _browser_NewScreenshot;
_browser.Dispose();
_settings.Dispose();
Cef.Shutdown();
}
public static void Init(IBrowserProcessHandler browserProcessHandler)
{
_settings = new CefSettings();
if (!Cef.Initialize(_settings, true, browserProcessHandler))
throw new Exception("Unable to Initialize Cef");
}
}
The idea is-on clicking a button create browser and on clicking another button close the browser
private OffScreenBrowser offScreenBrowser;
private void OPen_OnClick(object sender, RoutedEventArgs e)
{
var address = @"https://www.google.co.uk";
var width = 200;
var height = 100;
var windowSize = new System.Drawing.Size(width, height);
offScreenBrowser = new OffScreenBrowser();
offScreenBrowser.Load(address, windowSize);
offScreenBrowser.NewScreenShotAction = () =>
{
Browser.Content = offScreenBrowser.BrowserImage;
};
}
private void Close_OnClick(object sender, RoutedEventArgs e)
{
offScreenBrowser.Close();
}
On the first click it all works fine. On clicking close it seems like the cleanup is fine.
But when I click the open button for the second time I am getting an exception as below
"An unhandled exception of type 'System.AccessViolationException' occurred in CefSharp.Core.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
What am I doing wrong?
This is a limitation in Chromium framework.
CEF can only be Initialized/Shutdown once per process, See Need to Know/Limitations for more details, this is a limitation of the underlying Chromium framework.
In my case I had a similar situation. But for me, I just needed the same app to have multiple instances so that it can be runned in different screens at the same time.
The solution I found is really simple; you just need to change the "RootCachePath" on CefSettings. The reason for this is that the cache path of each instance cannot be the same.
Finally, I delete the folder created for this purpose when the app is closed.
Here an example:
Program.rootPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Program.rootPath + DateTime.Now.Ticks;
CefSettings settings = new CefSettings();
settings.IgnoreCertificateErrors = true;
settings.RootCachePath = Program.rootPath;
Cef.Initialize(settings);
browser = new ChromiumWebBrowser(url);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With