Hi,
We are trying to use the CefSharp Offscreen Browser to load an HTML file (from memory string) and execute some JavaScript on the DOM to extract some information from the file. We have not been completely successful in getting this to work. We have some issues with synchronization and load errors:
In pseudocode, our code looks like:
// Browser Initialization (once from a class ctor)
CefSettings.RegisterScheme(new CefCustomSceme()
{
SchemeName = "myscheme",
SchemeHandlerFactory = new MySchemeHandlerFactory()
}
// Event for syncing between the worker threads and the main thread.
ManualResetEvent sync = new ManualResetEvent(false);
// Create new browser and listen for status events
ChromiumWebBrowser browser = new ChromiumWebBrowser();
browser.FrameLoadEnd += Browser_FrameLoadEnd;
browser.LoadError += Browser_LoadError;
// Load the HTML document
browser.LoadHtml("<html>...", "myscheme://web/test/_Mem_Doc_.html")
// Wait for the load to complete! THIS WAITS FOREVER!!!
sync.WaitOne();
// ... if we ever get here, we'll execute some JavaScript .... and return the result from it.
// Handler for error ... only for diag purposes
Browser_LoadError(object sender, Args e)
{
// WE GET A LOAD ERROR !!! We ignore this (if error is Aborted)
e.ErrorCode == "Aborted"
e.ErrorText == ""
e.FailedUrl == "myscheme://web/test/_Mem_Doc_.html"
}
Browser_FrameLoadEnd(object sender, Args e)
{
// Load ended ... tell the main thread to continue ... SOMETIMES THIS NEVER HAPPENS!
sync.Set();
}
The above is basically what our code does. The LoadError is always raised with "Aborted" and our own URL as the failed document. In some scenarios (same document, on one machine always, on other machine often) we don't get the FrameLoadEnd event. Without the FrameLoadEnd event, the main thread will be blocked forever. Our first attempt was to signal the sync event from the LoadError handler and set a flag that the document load has failed. However, since this event is apparently always triggered, that won't help us, so we chose to ignore it.
What are we doing wrong? Is our document always fail to load? Why are we getting the LoadError events? And is the FrameLoadEnd event the correct way to know that the document is ready to process our JavaScript? Or have we completely misunderstood the logic of the Offscreen Browser and need a completely different strategy?
Can someone with knowledge explain why the LoadError / Aborted event is raised?
Thanks!
PS: Below is a stack trace from the Browser_LoadError with the reason for the load error.
> MyApp.Offscreen.exe!MyApp.Offscreen.CefSharpOffScreenHelper.Browser_LoadError(object sender, CefSharp.LoadErrorEventArgs e) Line 135 C#
CefSharp.OffScreen.dll!CefSharp.OffScreen.ChromiumWebBrowser.CefSharp.Internals.IWebBrowserInternal.OnLoadError(string url, CefSharp.CefErrorCode errorCode, string errorText) Line 466 + 0x2f bytes C#
CefSharp.Core.dll!CefSharp::Internals::ClientAdapter::OnLoadError(CefRefPtr<CefBrowser>* browser, CefRefPtr<CefFrame>* frame, errorCode, CefStringBase<CefStringTraitsUTF16>& errorText, CefStringBase<CefStringTraitsUTF16>& failedUrl) Line 172 + 0x3e bytes C++
CefSharp.Core.dll!load_handler_on_load_error() + 0x281 bytes
libcef.dll!CefLoadHandlerCToCpp::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, cef_errorcode_t errorCode, const CefStringBase<CefStringTraitsUTF16> & errorText, const CefStringBase<CefStringTraitsUTF16> & failedUrl) Line 113 + 0x3c bytes C++
libcef.dll!CefBrowserHostImpl::OnLoadError(CefRefPtr<CefFrame> frame, const GURL & url, int error_code, const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > & error_description) Line 2832 + 0x8b bytes C++
libcef.dll!CefBrowserHostImpl::DidFailProvisionalLoad(__int64 frame_id, const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > & frame_unique_name, bool is_main_frame, const GURL & validated_url, int error_code, const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > & error_description, content::RenderViewHost * render_view_host) Line 2385 C++
libcef.dll!content::WebContentsImpl::DidFailProvisionalLoadWithError(content::RenderFrameHostImpl * render_frame_host, const FrameHostMsg_DidFailProvisionalLoadWithError_Params & params) Line 2357 + 0xb0 bytes C++
libcef.dll!content::NavigatorImpl::DidFailProvisionalLoadWithError(content::RenderFrameHostImpl * render_frame_host, const FrameHostMsg_DidFailProvisionalLoadWithError_Params & params) Line 270 C++
libcef.dll!content::RenderFrameHostImpl::OnDidFailProvisionalLoadWithError(const FrameHostMsg_DidFailProvisionalLoadWithError_Params & params) Line 397 C++
libcef.dll!FrameHostMsg_DidFailProvisionalLoadWithError::Dispatch<content::RenderFrameHostImpl,content::RenderFrameHostImpl,void,void (__thiscall content::RenderFrameHostImpl::*)(FrameHostMsg_DidFailProvisionalLoadWithError_Params const &)>(const IPC::Message * msg, content::RenderFrameHostImpl * obj, content::RenderFrameHostImpl * sender, void * parameter, void (const FrameHostMsg_DidFailProvisionalLoadWithError_Params &)* func) Line 404 + 0x4b bytes C++
libcef.dll!content::RenderFrameHostImpl::OnMessageReceived(const IPC::Message & msg) Line 296 + 0x37 bytes C++
libcef.dll!content::RenderProcessHostImpl::OnMessageReceived(const IPC::Message & msg) Line 1416 + 0x7 bytes C++
libcef.dll!IPC::ChannelProxy::Context::OnDispatchMessage(const IPC::Message & message) Line 274 C++
libcef.dll!base::internal::Invoker<2,base::internal::BindState<base::internal::RunnableAdapter<void (__thiscall `anonymous namespace'::SelectFileDialogImpl::*)(A0x9ee13934::SelectFileDialogImpl::ExecuteSelectParams const &)>,void __cdecl(`anonymous namespace'::SelectFileDialogImpl *,A0x9ee13934::SelectFileDialogImpl::ExecuteSelectParams const &),void __cdecl(`anonymous namespace'::SelectFileDialogImpl *,A0x9ee13934::SelectFileDialogImpl::ExecuteSelectParams)>,void __cdecl(`anonymous namespace'::SelectFileDialogImpl *,A0x9ee13934::SelectFileDialogImpl::ExecuteSelectParams const &)>::Run(base::internal::BindStateBase * base) Line 1253 + 0x9 bytes C++
libcef.dll!base::MessageLoop::RunTask(const base::PendingTask & pending_task) Line 452 C++
libcef.dll!base::MessageLoop::DoWork() Line 577 C++
libcef.dll!base::MessagePumpForUI::DoRunLoop() Line 219 C++
libcef.dll!base::MessagePumpWin::Run(base::MessagePump::Delegate * delegate) Line 47 + 0x3d bytes C++
libcef.dll!base::MessageLoop::RunHandler() Line 400 + 0x9 bytes C++
libcef.dll!base::RunLoop::Run() Line 50 C++
libcef.dll!base::MessageLoop::Run() Line 294 C++
libcef.dll!base::Thread::Run(base::MessageLoop * message_loop) Line 173 C++
libcef.dll!base::Thread::ThreadMain() Line 229 C++
libcef.dll!base::`anonymous namespace'::ThreadFunc(void * params) Line 80 C++
kernel32.dll!@BaseThreadInitThunk@12() + 0x24 bytes
ntdll.dll!__RtlUserThreadStart() + 0x2f bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes