CefGlue Documentation
repository·main·Indexed 19 days ago
https://github.com/outsystems/cefglueA .NET binding for the Chromium Embedded Framework (CEF) that allows developers to embed Chromium-based web browsers into .NET applications using Avalonia or WPF. It provides a .NET wrapper compatible with C# and other CLR languages, supporting Windows, macOS, and Linux on x64 and ARM64 architectures. The library includes a MessageRouter for asynchronous communication between JavaScript in the renderer process and C++ in the browser process.
What's inside CefGlue
- CefGlue is a .NET binding for The Chromium Embedded Framework (CEF), allowing you to embed Chromium in .NET applications. It acts as a .NET wrapper around CEF and is compatible with C# or any other CLR language. It provides web browser control implementations for both Avalonia and WPF frameworks.
How the MessageRouter works
mainThe
MessageRouterenables asynchronous message routing between JavaScript in the renderer process and C++ in the browser process.Core Workflow
- JavaScript Side: The renderer-side router exposes
window.cefQueryandwindow.cefQueryCancelto the JavaScript environment. - Browser Side: The browser-side router receives these requests and passes them to one or more registered C++
Handlerinstances via theHandler::OnQuerycallback. - Handling: A
Handlercan choose to handle a query (returningtrueinOnQuery) or ignore it (returningfalse).- If handled, the handler calls
Callback::SuccessorCallback::Failureto trigger the corresponding JavaScript callback. - If unhandled by all C++ handlers, the query is automatically canceled, and the JavaScript
onFailurecallback is executed with an error code of-1.
- If handled, the handler calls
Query Persistence
- Non-persistent queries: The registration is removed automatically after the JavaScript callback is executed once.
- Persistent queries: The registration remains active until:
- The query is canceled in JavaScript via
window.cefQueryCancel. - The query is canceled in C++ via
Callback::Failure. - The context is released (browser destruction, navigation, or renderer process termination).
- The query is canceled in JavaScript via
Common Patterns
- One-time Request: Use a non-persistent query for a single request/response cycle.
- Broadcast: Use a persistent query to register a receiver. The C++ handler manages multiple registered
Callbackobjects and executes them sequentially to deliver messages. - Subscription: Use a persistent query to register a subscriber. The handler manages the feed and cancels it when no more JavaScript receivers are registered.
// JavaScript usage example var request_id = window.cefQuery({ request: 'my_request', persistent: false, onSuccess: function(response) { /* handle success */ }, onFailure: function(error_code, error_message) { /* handle error */ } }); // Optionally cancel window.cefQueryCancel(request_id);- JavaScript Side: The renderer-side router exposes
Check platform and framework compatibility
mainBefore integrating CefGlue, verify that your target operating system, architecture, and UI framework are supported.
OS x64 ARM64 WPF Avalonia Windows ✔️ ✔️ ✔️ ✔️ macOS ✔️ ✔️ ❌ ✔️ Linux ✔️ 🔘 ❌ ✔️ *Note: ARM64 on Linux is marked as 'Works with issues'. See
LINUX.mdfor details on tested distributions and known issues. Only x64 and ARM64 architectures are supported.Install CefGlue via NuGet
mainStable binaries containing all necessary components to embed Chromium are available on NuGet. Choose the package that matches your target framework and architecture:
Avalonia Support:
CefGlue.Avalonia(Standard)CefGlue.Avalonia.ARM64(ARM64 architecture)
WPF Support:
CefGlue.WPF(Standard)CefGlue.WPF.ARM64(ARM64 architecture)
Core/Common Components:
CefGlue.Common(Standard)CefGlue.Common.ARM64(ARM64 architecture)
Setup the MessageRouter in C++
mainIntegrating the
MessageRouterrequires configuration in both the browser and renderer processes. The configuration must be identical in both processes.1. Define Configuration
Use
CefMessageRouterConfigto specify the JavaScript function names. If you use multiple routers, ensure the function names are unique.CefMessageRouterConfig config; config.js_query_function = "cefQuery"; config.js_cancel_function = "cefQueryCancel";2. Browser Process Setup
- Create the router instance using
CefMessageRouterBrowserSide::Create(config). - Register handlers using
AddHandler(handler). - Call required lifecycle methods (e.g.,
OnBeforeClose) from yourCefClientimplementation.
3. Renderer Process Setup
- Create the router instance using
CefMessageRouterRendererSide::Create(config). - Call required lifecycle methods (e.g.,
OnContextCreated) from yourCefRenderProcessHandlerimplementation.
Note: Handlers must outlive the router or be removed before the router is destroyed.
// 1. Define config CefMessageRouterConfig config; config.js_query_function = "cefQuery"; config.js_cancel_function = "cefQueryCancel"; // 2. Browser side browser_side_router_ = CefMessageRouterBrowserSide::Create(config); browser_side_router_->AddHandler(my_handler); // 5. Renderer side renderer_side_router_ = CefMessageRouterRendererSide::Create(config);- Create the router instance using
View CefGlue usage examples
mainTo understand how to implement a web browser using CefGlue, refer to the following sample projects in the repository:
- Avalonia:
CefGlue.Demo.Avalonia - WPF:
CefGlue.Demo.WPF
These samples demonstrate the available features and how to integrate the controls into your application.
- Avalonia:
Resolve ARM64 dynamic loading issues with LD_PRELOAD
mainOn ARM64 platforms, dynamic loading of CEF may fail with the error
cannot allocate memory in static TLS block. This is suspected to be caused by the CLR using excessive Thread Local Storage (TLS).You can resolve this by using the
LD_PRELOADenvironment variable to ensurelibHarfBuzzSharp.sois loaded beforelibcef.so.LD_PRELOAD=/path/to/libHarfBuzzSharp.so:/path/to/libcef.soFix ARM64 CEF loading by modifying ELF files with patchelf
mainIf you cannot use
LD_PRELOAD, you can modify the ELF files of your application to ensure the required libraries are loaded correctly on ARM64.For the Avalonia-based application, you must add both
libHarfBuzzSharp.soandlibcef.so. For the standalone Browser process, you only need to addlibcef.soas it does not use Avalonia.# For the Avalonia application patchelf --add-needed libHarfBuzzSharp.so --add-needed libcef.so path/to/Xilium.CefGlue.Demo.Avalonia # For the Browser process patchelf --add-needed libcef.so path/to/Xilium.CefGlue.BrowserProcessImplement a C++ MessageRouter Handler
mainTo process messages in the browser process, you must implement the
Handler::OnQuerymethod. This method is called by theCefMessageRouterBrowserSidefor every query received from JavaScript.Method Signature:
void OnQuery(int64 query_id, CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& request, bool persistent, CefRefPtr<Callback> callback);Implementation Rules:
- Return
trueif your handler successfully processed the request. - Return
falseif your handler did not process the request (allowing other handlers a chance). - Use
callback->Success(response)orcallback->Failure(error_code, error_message)to communicate back to JavaScript. - If a query is canceled for reasons other than
Callback::Failure, the handler'sOnQueryCanceledmethod will be called.
void MyHandler::OnQuery(int64 query_id, CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& request, bool persistent, CefRefPtr<Callback> callback) { if (request == "my_request") { callback->Success("my_response"); return true; } return false; // Not handled. }- Return
JavaScript API for MessageRouter
mainThe renderer-side router exposes two primary functions on the JavaScript
windowobject:window.cefQuery(options)Creates and sends a new asynchronous query to the C++ browser process.
Options Object:
request(string): The payload/command to send.persistent(boolean): Iftrue, the callbacks remain registered until explicitly canceled or the context is destroyed.onSuccess(function): Callback executed when the C++ handler callsCallback::Success.onFailure(function): Callback executed when the C++ handler callsCallback::Failureor if the query is unhandled (error code-1).
Returns:
request_id(integer) used for cancellation.window.cefQueryCancel(request_id)Cancels a pending persistent query using its ID.
// Create and send a new query. var request_id = window.cefQuery({ request: 'my_request', persistent: false, onSuccess: function(response) {}, onFailure: function(error_code, error_message) {} }); // Optionally cancel the query. window.cefQueryCancel(request_id);