Reputation: 3264
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?
Upvotes: 3
Views: 5598
Reputation: 11
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);
Upvotes: 1
Reputation: 73
to solve this you can call the Cef.Initialize
in the start form and you need to call it only once in your application
the you can call ChromiumWebBrowser
many times inside any for of your application forms
it worked for me
Upvotes: 0
Reputation: 21
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.
Upvotes: 2