SIGN IN SIGN UP
cefsharp / CefSharp UNCLAIMED

.NET (WPF and Windows Forms) bindings for the Chromium Embedded Framework

0 0 0 C#
// Copyright © 2014 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#pragma once
#include "Stdafx.h"
#include "CefBrowserWrapper.h"
#include "CefAppUnmanagedWrapper.h"
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
#include "RegisterBoundObjectHandler.h"
#include "BindObjectAsyncHandler.h"
#include "JavascriptPostMessageHandler.h"
#include "JavascriptRootObjectWrapper.h"
#include "JavascriptPromiseHandler.h"
#include "JavascriptPromiseResolverCatch.h"
#include "JavascriptPromiseResolverThen.h"
#include "Async\JavascriptAsyncMethodCallback.h"
#include "Serialization\V8Serialization.h"
#include "Serialization\JsObjectsSerialization.h"
#include "Wrapper\V8Context.h"
#include "Wrapper\Frame.h"
#include "Wrapper\Browser.h"
Refactor CefSharp.Core into CefSharp.Core.Runtime (#3311) * Net Core - Rename CefSharp.Core.dll to CefSharp.Core.Runtime.dll Partial rename, only Net Core, folder not renamed * Net Core - Rename CefSharp.Core.RefAssembly to CefSharp.Core.netcore Remove GenApi * Core - Rename CefDragDataWrapper to DragData Move into CefSharp.Core namespace * WinForms/WPF/OffScreen - Migrate from GitLink command line to Nuget package * Net Core - Refactor to have CefSharp.Core.dll contain only public Api * Net Core - Remove CefSharp.Core.RefAssembly * Net Core - Change CefSharp.Core.netcore output folder * Net Core - Restructure nuget packages * Net Core - Add Cefsharp.Core.Runtime.RefAssembly * Net Core - Hide CLI/C++ classes from intellisense Make sure users don't attempt to load them directly * Rename CefSharp.Core to CefSharp.Core.Runtime * Core - Restructure Net 4.5.2 packages to use CefSharp.Core.dll anycpu variant Attempt to load CefSharp.Core.Runtime at runtime rather than having to use msbuild to copy the correct version * Rename CefSharp.Core.netcore to CefSharp.Core * WPF/WinForms/OffScreen - Change from x86/64 to AnyCPU As they are all managed assemblies they can target AnyCPU. Includes CefSharp.dll * Convert RequestContextBuilder from C++ to C# Now part of the CefSharp.Core PublicApi * Update version number to 87.1.11 * Migrate more of the public Api to C# * Net Core - Basic restructure complete * Net Core - ModuleInitializer (Doesn't work yet) * Remove direct references to BrowserSettings * Net Core - ModuleInitializer load CefShar.Core.Runtime.dl * Net Core - Load libcef.dll via CLR Module initializer If no RID is specified then we can load libcef.dll using the module initializer * Add version to CefSharp.Core * Remove dependency on CefSharp.Core.Runtime Rewrite common targets * AnyCPU app.config transform Improve AnyCPU support * Improve Net Core 3 support Only delete CefSharp.Core.Runtime.dll when AnyCPU * Nuget - Add CefSharp.Core.Runtime reference when TargetFramework = NetCore * Fix Typos Based on #3306 * Net Core - Rename CefSharp.Core.Runtime RefAssembly source file * Net Full - Generate CefSharp.Core.Runtime Ref Assembly For now the powershell build script generates the .cs file based on a x86 release build.ps1 It's not possible to directly install GenApi as it requires a Sdk style project * Net Core - Old packages copy files to required folders * Test - Install newer .Net Compiler and set Lang Version to 7.3 * Net Core - Exclude Net 452 Runtime generated reference source * Core - Add Refactoring TODO * Ref Assembly - Generate source as part of build - Move ref assembly source generate into GenerateRefAssemblySource.ps1 - Call before project build Runs locally, see if Appveyor has a problem with the powershell script execution * Core - Add more factory methods to create instances of managed wrappers * Net Core - Make Initialzier properties internal Not quite sure what the public API should look like as yet, so making internal for now.
2020-12-16 10:47:34 +10:00
#include "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
#include <include/cef_parser.h>
using namespace System;
using namespace System::Diagnostics;
using namespace System::Collections::Generic;
using namespace CefSharp::BrowserSubprocess::Serialization;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
namespace BrowserSubprocess
{
const CefString CefAppUnmanagedWrapper::kPromiseCreatorScript = ""
"(function()"
"{"
" var result = {};"
" var promise = new Promise(function(resolve, reject) {"
" result.res = resolve; result.rej = reject;"
" });"
" result.p = promise;"
" return result;"
"})();";
const CefString kRenderProcessId = CefString("RenderProcessId");
const CefString kRenderProcessIdCamelCase = CefString("renderProcessId");
CefRefPtr<CefRenderProcessHandler> CefAppUnmanagedWrapper::GetRenderProcessHandler()
{
return this;
};
// CefRenderProcessHandler
void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extraInfo)
{
auto wrapper = gcnew CefBrowserWrapper(browser);
_onBrowserCreated->Invoke(wrapper);
//Multiple CefBrowserWrappers created when opening popups
_browserWrappers->TryAdd(browser->GetIdentifier(), wrapper);
if (!extraInfo.get())
{
return;
}
//For the main browser only we check LegacyBindingEnabled and
//load the objects. Popups don't send this information and checking
//will override the _legacyBindingEnabled field
if (!browser->IsPopup())
{
_legacyBindingEnabled = extraInfo->GetBool("LegacyBindingEnabled");
if (_legacyBindingEnabled)
{
auto objects = extraInfo->GetList("LegacyBindingObjects");
if (objects.get() && objects->IsValid())
{
auto javascriptObjects = DeserializeJsObjects(objects, 0);
for each (JavascriptObject ^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
{
//Using LegacyBinding with multiple ChromiumWebBrowser instances that share the same
//render process and using LegacyBinding will cause problems for the limited caching implementation
//that exists at the moment, for now we'll remove an object if already exists, same behaviour
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
//as the new binding method.
//TODO: This should be removed when https://github.com/cefsharp/CefSharp/issues/2306
//Is complete as objects will be stored at the browser level
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
{
_javascriptObjects->Remove(obj->JavascriptName);
}
_javascriptObjects->Add(obj->JavascriptName, obj);
}
}
}
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
}
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
if (extraInfo->HasKey("JavascriptBindingApiEnabled"))
{
wrapper->JavascriptBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
}
if (extraInfo->HasKey("JavascriptBindingApiHasAllowOrigins"))
{
wrapper->JavascriptBindingApiHasAllowOrigins = extraInfo->GetBool("JavascriptBindingApiHasAllowOrigins");
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
if (wrapper->JavascriptBindingApiHasAllowOrigins)
{
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
auto allowOrigins = extraInfo->GetList("JavascriptBindingApiAllowOrigins");
if (allowOrigins.get() && allowOrigins->IsValid())
{
wrapper->JavascriptBindingApiAllowOrigins = allowOrigins->Copy();
}
}
}
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
if (extraInfo->HasKey("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
{
//TODO: Create constant for these and legacy binding strings above
_jsBindingPropertyName = extraInfo->GetString("JsBindingPropertyName");
_jsBindingPropertyNameCamelCase = extraInfo->GetString("JsBindingPropertyNameCamelCase");
}
}
void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
{
CefBrowserWrapper^ wrapper;
if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
{
_onBrowserDestroyed->Invoke(wrapper);
delete wrapper;
}
};
void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
if (!Object::ReferenceEquals(_handler, nullptr))
{
Browser browserWrapper(browser);
Frame frameWrapper(frame);
V8Context contextWrapper(context);
_handler->OnContextCreated(% browserWrapper, % frameWrapper, % contextWrapper);
}
//Skip additional contexts (DevTools, extensions) to avoid
//double binding and duplicate calls to IRenderProcessMessageHandler.OnContextCreated
//https://github.com/chromiumembedded/cef/issues/3867
bool isSameContext = frame->GetV8Context()->IsSame(context);
if (!isSameContext)
return;
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
if (_legacyBindingEnabled)
{
if (_javascriptObjects->Count > 0 && rootObject != nullptr)
{
rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
}
}
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
if (browserWrapper != nullptr && browserWrapper->JavascriptBindingApiEnabled && IsJavascriptBindingApiAllowed(browserWrapper, frame))
{
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
auto global = context->GetGlobal();
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
//TODO: JSB: Split functions into their own classes
//Browser wrapper is only used for BindObjectAsync
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, rootObject));
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
//By default We'll support both CefSharp and cefSharp, for those who prefer the JS style
auto createCefSharpObj = !_jsBindingPropertyName.empty();
auto createCefSharpObjCamelCase = !_jsBindingPropertyNameCamelCase.empty();
if (createCefSharpObj)
{
auto cefSharpObj = CefV8Value::CreateObject(nullptr, nullptr);
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
}
if (createCefSharpObjCamelCase)
{
auto cefSharpObjCamelCase = CefV8Value::CreateObject(nullptr, nullptr);
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kRemoveObjectFromCacheCamelCase, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kIsObjectCachedCamelCase, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kPostMessageCamelCase, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kSendEvalScriptResponseCamelCase, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kRenderProcessIdCamelCase, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
}
}
//Send a message to the browser processing signaling that OnContextCreated has been called
//only param is the FrameId. Previous sent only for main frame, now sent for all frames
//Message sent after legacy objects have been bound and the CefSharp bind async helper methods
//have been created
auto contextCreatedMessage = CefProcessMessage::Create(kOnContextCreatedRequest);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextCreatedMessage);
};
void CefAppUnmanagedWrapper::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
if (!Object::ReferenceEquals(_handler, nullptr))
{
Browser browserWrapper(browser);
Frame frameWrapper(frame);
V8Context contextWrapper(context);
_handler->OnContextReleased(% browserWrapper, % frameWrapper, % contextWrapper);
}
auto contextReleasedMessage = CefProcessMessage::Create(kOnContextReleasedRequest);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextReleasedMessage);
auto rootObjectWrappers = _jsRootObjectWrappersByFrameId;
//If we no longer have a _jsRootObjectWrappersByFrameId reference then there's nothing we can do
if (Object::ReferenceEquals(rootObjectWrappers, nullptr))
{
return;
}
2014-11-25 09:34:15 -05:00
JavascriptRootObjectWrapper^ wrapper;
if (rootObjectWrappers->TryRemove(StringUtils::ToClr(frame->GetIdentifier()), wrapper))
{
delete wrapper;
}
};
void CefAppUnmanagedWrapper::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefDOMNode> node)
{
if (!_focusedNodeChangedEnabled)
{
return;
}
auto focusedNodeChangedMessage = CefProcessMessage::Create(kOnFocusedNodeChanged);
auto list = focusedNodeChangedMessage->GetArgumentList();
// The node will be empty if an element loses focus but another one
// doesn't gain focus. Only transfer information if the node is an
// element.
if (node != nullptr && node->IsElement())
{
// True when a node exists, false if it doesn't.
list->SetBool(0, true);
// Store the tag name.
list->SetString(1, node->GetElementTagName());
// Transfer the attributes in a Dictionary.
auto attributes = CefDictionaryValue::Create();
CefDOMNode::AttributeMap attributeMap;
node->GetElementAttributes(attributeMap);
for (auto iter : attributeMap)
{
attributes->SetString(iter.first, iter.second);
}
list->SetDictionary(2, attributes);
}
else
{
list->SetBool(0, false);
}
frame->SendProcessMessage(CefProcessId::PID_BROWSER, focusedNodeChangedMessage);
}
void CefAppUnmanagedWrapper::OnUncaughtException(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context, CefRefPtr<CefV8Exception> exception, CefRefPtr<CefV8StackTrace> stackTrace)
{
auto uncaughtExceptionMessage = CefProcessMessage::Create(kOnUncaughtException);
auto list = uncaughtExceptionMessage->GetArgumentList();
list->SetString(0, exception->GetMessage());
auto frames = CefListValue::Create();
for (auto i = 0; i < stackTrace->GetFrameCount(); i++)
{
auto stackTraceFrame = CefListValue::Create();
auto frameArg = stackTrace->GetFrame(i);
stackTraceFrame->SetString(0, frameArg->GetFunctionName());
stackTraceFrame->SetInt(1, frameArg->GetLineNumber());
stackTraceFrame->SetInt(2, frameArg->GetColumn());
stackTraceFrame->SetString(3, frameArg->GetScriptNameOrSourceURL());
frames->SetList(i, stackTraceFrame);
}
list->SetList(1, frames);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, uncaughtExceptionMessage);
}
2026-02-20 21:08:41 +10:00
JavascriptRootObjectWrapper^ CefAppUnmanagedWrapper::GetJsRootObjectWrapper(int browserId, const CefString& frameId)
{
auto rootObjectWrappers = _jsRootObjectWrappersByFrameId;
if (Object::ReferenceEquals(rootObjectWrappers, nullptr))
{
return nullptr;
}
auto frameIdClr = StringUtils::ToClr(frameId);
JavascriptRootObjectWrapper^ rootObject;
if (!rootObjectWrappers->TryGetValue(frameIdClr, rootObject))
{
#ifdef NETCOREAPP
rootObject = gcnew JavascriptRootObjectWrapper();
#else
auto browserWrapper = FindBrowserWrapper(browserId);
rootObject = gcnew JavascriptRootObjectWrapper(browserWrapper == nullptr ? nullptr : browserWrapper->BrowserProcess);
#endif
rootObjectWrappers->TryAdd(frameIdClr, rootObject);
}
return rootObject;
}
Javascript Binding - Finalize JavascriptBindingApiAllowOrigins: Per-browser isolation and origin normalization (#5218) * Javascript Binding - Add Ability to limit origins * Move JS binding settings to CefBrowserWrapper and optimize origin validation * Initialize origins to null * Normalize allowed origins * Optimize origin validation * Add null check for origin compare * Fix JavaScript Binding API settings for popups Move the JS binding API configuration block out of the !browser->IsPopup() scope in OnBrowserCreated. This ensures that IsJavascriptBindingApiAllowed() enforces configured restrictions for popups as well. * Fix possible null deref for JavascriptBindingApiAllowOrigins In IsJavascriptBindingApiAllowed, added a null check for JavascriptBindingApiAllowOrigins to prevent a potential null dereference if JavascriptBindingApiHasAllowOrigins is true but the allowOrigins list itself was null. * Simplify origin normalization and add null check * Add more test cases * Refactor IsJavascriptBindingApiAllowed signature Refactored IsJavascriptBindingApiAllowed to accept a CefBrowserWrapper^ parameter directly, eliminating redundant lookups and improving clarity. Updated all call sites to pass the browser wrapper explicitly. * Clarify summary for HasJavascriptBindingApiAllowOrigins Clarify documentation for HasJavascriptBindingApiAllowOrigins method to specify zero or more origins * Simplify origin comparison logic in CefAppUnmanagedWrapper Refactored code to directly compare wide string origins using _wcsicmp, removing unnecessary pointer casts and null checks. This streamlines the logic and improves readability. * Add tests for JavaScript binding API behavior across cross-origin navigation --------- Co-authored-by: amaitland <307872+amaitland@users.noreply.github.com> Co-authored-by: Luca Sonntag <luca.sonntag@cgm.com>
2026-03-21 22:35:54 +01:00
bool CefAppUnmanagedWrapper::IsJavascriptBindingApiAllowed(CefBrowserWrapper^ browserWrapper, CefRefPtr<CefFrame> frame)
{
if (browserWrapper == nullptr || !browserWrapper->JavascriptBindingApiHasAllowOrigins)
{
return true;
}
auto allowOrigins = browserWrapper->JavascriptBindingApiAllowOrigins;
if (!allowOrigins.get())
{
return false;
}
auto frameUrl = frame->GetURL();
CefURLParts frameUrlParts;
if (CefParseURL(frameUrl, frameUrlParts))
{
auto originStr = frameUrlParts.origin.str;
auto originLen = frameUrlParts.origin.length;
if (originLen > 0 && originStr[originLen - 1] == L'/')
{
originLen--;
}
auto frameUrlOrigin = CefString(originStr, originLen);
auto size = static_cast<int>(allowOrigins->GetSize());
for (int i = 0; i < size; i++)
{
auto origin = allowOrigins->GetString(i);
if (_wcsicmp(frameUrlOrigin.ToWString().c_str(), origin.ToWString().c_str()) == 0)
{
return true;
}
}
}
return false;
}
CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId)
{
CefBrowserWrapper^ wrapper = nullptr;
_browserWrappers->TryGetValue(browserId, wrapper);
if (wrapper == nullptr)
{
//TODO: Find the syntax for delcaring the native string directly
LOG(ERROR) << StringUtils::ToNative("Failed to identify BrowserWrapper in OnContextCreated BrowserId:" + browserId).ToString();
}
return wrapper;
}
bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId sourceProcessId, CefRefPtr<CefProcessMessage> message)
{
auto handled = false;
auto name = message->GetName();
auto argList = message->GetArgumentList();
//these messages are roughly handled the same way
if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest)
{
bool sendResponse = true;
bool success = false;
CefRefPtr<CefV8Value> result;
CefString errorMessage;
CefRefPtr<CefProcessMessage> response;
if (name == kEvaluateJavascriptRequest)
{
response = CefProcessMessage::Create(kEvaluateJavascriptResponse);
}
else
{
response = CefProcessMessage::Create(kJavascriptCallbackResponse);
}
//both messages have callbackId stored at index 0
auto frameId = StringUtils::ToClr(frame->GetIdentifier());
int64_t callbackId = GetInt64(argList, 0);
//NOTE: In the rare case when when OnContextCreated hasn't been called we need to manually create the rootObjectWrapper
//It appears that OnContextCreated is only called for pages that have javascript on them, which makes sense
//as without javascript there is no need for a context.
JavascriptRootObjectWrapper^ rootObjectWrapper = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
if (name == kEvaluateJavascriptRequest)
{
auto script = argList->GetString(1);
auto scriptUrl = argList->GetString(2);
auto startLine = argList->GetInt(3);
if (frame.get() && frame->IsValid())
{
auto context = frame->GetV8Context();
if (context.get() && context->Enter())
{
try
{
CefRefPtr<CefV8Exception> exception;
success = context->Eval(script, scriptUrl, startLine, result, exception);
//we need to do this here to be able to store the v8context
if (success)
{
//If the response is a string of CefSharpDefEvalScriptRes then
//we don't send the response, we'll let that happen when the promise has completed.
if (result->IsString() && result->GetStringValue() == "CefSharpDefEvalScriptRes")
{
sendResponse = false;
}
else if (result->IsPromise())
{
sendResponse = false;
auto promiseThen = result->GetValue("then");
auto promiseCatch = result->GetValue("catch");
auto promiseThenFunc = CefV8Value::CreateFunction("promiseResolverThen", new JavascriptPromiseResolverThen(callbackId, false));
auto promiseCatchFunc = CefV8Value::CreateFunction("promiseResolverCatch", new JavascriptPromiseResolverCatch(callbackId, false));
CefV8ValueList promiseThenArgs;
promiseThenArgs.push_back(promiseThenFunc);
promiseThen->ExecuteFunction(result, promiseThenArgs);
CefV8ValueList promiseCatchArgs;
promiseCatchArgs.push_back(promiseCatchFunc);
promiseCatch->ExecuteFunction(result, promiseCatchArgs);
}
else
{
auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
if (callbackRegistry == nullptr)
{
errorMessage = StringUtils::ToNative("The callback registry for Frame " + frameId + " is no longer available.");
}
else
{
auto responseArgList = response->GetArgumentList();
SerializeV8Object(result, responseArgList, 2, callbackRegistry);
}
}
}
else
{
errorMessage = StringUtils::CreateExceptionString(exception);
}
}
finally
{
context->Exit();
}
}
else
{
errorMessage = "Unable to Enter Context";
}
}
else
{
errorMessage = StringUtils::ToNative("Frame " + frameId + " is no longer available, most likely the Frame has been Disposed or Removed.");
}
}
else
{
auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
if (callbackRegistry == nullptr)
{
errorMessage = StringUtils::ToNative("The callback registry for Frame " + frameId + " is no longer available, most likely the Frame has been Disposed.");
}
else
{
auto jsCallbackId = GetInt64(argList, 1);
auto callbackWrapper = callbackRegistry->FindWrapper(jsCallbackId);
if (callbackWrapper == nullptr)
{
errorMessage = StringUtils::ToNative("Unable to find JavascriptCallback with Id " + jsCallbackId + " for Frame " + frameId);
}
else
{
auto context = callbackWrapper->GetContext();
auto value = callbackWrapper->GetValue();
if (context.get() && context->Enter())
{
try
{
auto parameterList = argList->GetList(2);
CefV8ValueList params;
//Needs to be called within the context as for Dictionary (mapped to struct)
//a V8Object will be created
for (CefV8ValueList::size_type i = 0; i < parameterList->GetSize(); i++)
{
params.push_back(DeserializeV8Object(parameterList, static_cast<int>(i)));
}
result = value->ExecuteFunction(nullptr, params);
success = result.get() != nullptr;
//we need to do this here to be able to store the v8context
if (success)
{
//If the response is a string of CefSharpDefEvalScriptRes then
//we don't send the response, we'll let that happen when the promise has completed.
if (result->IsString() && result->GetStringValue() == "CefSharpDefEvalScriptRes")
{
sendResponse = false;
}
else if (result->IsPromise())
{
sendResponse = false;
auto promiseThen = result->GetValue("then");
auto promiseCatch = result->GetValue("catch");
auto promiseThenFunc = CefV8Value::CreateFunction("promiseResolverThen", new JavascriptPromiseResolverThen(callbackId, true));
auto promiseCatchFunc = CefV8Value::CreateFunction("promiseResolverCatch", new JavascriptPromiseResolverCatch(callbackId, true));
CefV8ValueList promiseThenArgs;
promiseThenArgs.push_back(promiseThenFunc);
promiseThen->ExecuteFunction(result, promiseThenArgs);
CefV8ValueList promiseCatchArgs;
promiseCatchArgs.push_back(promiseCatchFunc);
promiseCatch->ExecuteFunction(result, promiseCatchArgs);
}
else
{
auto responseArgList = response->GetArgumentList();
SerializeV8Object(result, responseArgList, 2, callbackRegistry);
}
}
else
{
auto exception = value->GetException();
errorMessage = StringUtils::CreateExceptionString(exception);
}
}
finally
{
context->Exit();
}
}
else
{
errorMessage = "Unable to Enter Context";
}
}
}
}
if (sendResponse)
{
auto responseArgList = response->GetArgumentList();
responseArgList->SetBool(0, success);
SetInt64(responseArgList, 1, callbackId);
if (!success)
{
responseArgList->SetString(2, errorMessage);
}
frame->SendProcessMessage(sourceProcessId, response);
}
handled = true;
}
else if (name == kJavascriptCallbackDestroyRequest)
{
if (frame.get() && frame->IsValid())
{
auto jsCallbackId = GetInt64(argList, 0);
JavascriptRootObjectWrapper^ rootObjectWrapper;
_jsRootObjectWrappersByFrameId->TryGetValue(StringUtils::ToClr(frame->GetIdentifier()), rootObjectWrapper);
if (rootObjectWrapper != nullptr && rootObjectWrapper->CallbackRegistry != nullptr)
{
rootObjectWrapper->CallbackRegistry->Deregister(jsCallbackId);
}
}
handled = true;
}
else if (name == kJavascriptRootObjectResponse)
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
{
if (browser.get() && frame.get() && frame->IsValid())
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
{
auto callbackId = GetInt64(argList, 0);
auto javascriptObjects = DeserializeJsObjects(argList, 1);
//Caching of JavascriptObjects
//TODO: JSB Should caching be configurable? On a per object basis?
for each (JavascriptObject ^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
{
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
{
_javascriptObjects->Remove(obj->JavascriptName);
}
_javascriptObjects->Add(obj->JavascriptName, obj);
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
}
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
if (rootObject == nullptr)
{
return false;
}
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
auto context = frame->GetV8Context();
if (context.get() && context->Enter())
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
{
JavascriptAsyncMethodCallback^ callback;
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
try
{
rootObject->Bind(javascriptObjects, context->GetGlobal());
if (_registerBoundObjectRegistry->TryGetAndRemoveMethodCallback(callbackId, callback))
{
//Response object has no Accessor or Interceptor
auto response = CefV8Value::CreateObject(nullptr, nullptr);
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
response->SetValue("Count", CefV8Value::CreateInt(javascriptObjects->Count), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
if (javascriptObjects->Count > 0)
{
//TODO: JSB Should we include a list of successfully bound object names?
response->SetValue("Success", CefV8Value::CreateBool(true), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
response->SetValue("Message", CefV8Value::CreateString("OK"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
callback->Success(response);
}
else
{
response->SetValue("Success", CefV8Value::CreateBool(false), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
response->SetValue("Message", CefV8Value::CreateString("Zero objects bounds"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
callback->Success(response);
}
//Send message notifying Browser Process of which objects were bound
//We do this after the objects have been created in the V8Context to gurantee
//they are accessible.
auto msg = CefProcessMessage::Create(kJavascriptObjectsBoundInJavascript);
auto args = msg->GetArgumentList();
auto boundObjects = CefListValue::Create();
2026-02-20 21:08:41 +10:00
auto i = 0;
for each (auto jsObject in javascriptObjects)
{
auto dict = CefDictionaryValue::Create();
2026-02-20 21:08:41 +10:00
auto objectName = jsObject->JavascriptName;
dict->SetString("Name", StringUtils::ToNative(objectName));
dict->SetBool("IsCached", false);
dict->SetBool("AlreadyBound", false);
2026-02-20 21:08:41 +10:00
boundObjects->SetDictionary(i++, dict);
}
args->SetList(0, boundObjects);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, msg);
}
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
}
finally
{
context->Exit();
delete callback;
}
}
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
}
else
{
LOG(INFO) << "CefAppUnmanagedWrapper Frame Invalid";
}
Implement Javascript Binding v2 (#2247) * JSB Rewrite - Add CefSharp.RegisterBoundObject javascript method To get around the problem of IPC timing, I've reversed the communication, now it's the render process requesting the bound objects, the implementation is incomplete at this stage, more just a basic proof of concept Rewrite BindingTest.html using QUnit One of the tests doesn't map correctly as it requires def user interaction TODO: - Get objects by name - Rename Messages.h values that relate to this change so they are more descriptive - Better error handling - Caching of objects within a render process - Investigate global context options, don't think it's possible to call an async method directly in the global context # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB Improve Request/Response message names * BindingTest.html - Output stress test results * Remove JavascriptRootObject was leftover from time we used WCF to transmit objects * JavascriptObjectRepository - Objects are now sent in the same list with an IsAsync flag Separation when sending over IPC with two unique lists isn't necessary * JavascriptObjectRepository - Return objects by name or return all by default Untabify CefAppUnmanagedWrapper.cpp Add minor comment to CefBrowserWrapper for a reminder that we use Frame Identifier as dictionary key * Add //TODO: JSB comments for work that's left to be done Ideally within a render process we cache bound objects once they've been communicated, It would also be nice to make multiple binding requests so objects can later be added dynamically * JSB Allow multiple calls to CefSharp.RegisterBoundObject Update BindingTest.html to name two distinct calls to different bound objects * JSB - Add some notes about caching, no working implementation yet * JSB - Dynamically Register object on Request * JSB Add ability to unbind an object and rename RegisterBoundObject to BindObjectAsync # Conflicts: # CefSharp.Example/Resources/BindingTest.html * JSB BindObjectAsync - if objects already bound then return false * JSB - Ignore Indexer properties Were previously throwing an exception * JSB - Add LegacyJavascriptBindingEnabled option so preserve existing behaviour This is only useful for SPA application and those that only navigate to pages hosting within a single domain. Any sort of cross-site navigation and a new render process will be spawned and objects won't be bound automatically (You can use the new methods to request they're bound yourself, at least in theory, more testing required on this) * Add LegacyBindingTest.html Current disabled by default. To enable uncomment CefSharpSettings.LegacyJavascriptBindingEnabled = true; in CefExample.cs * RegisterJsObject and RegisterAsyncJsObject can now only be used when CefSharpSettings.LegacyJavascriptBindingEnabled = true See https://github.com/cefsharp/CefSharp/issues/2246 for details
2018-01-22 10:24:25 +10:00
handled = true;
}
else if (name == kJavascriptAsyncMethodCallResponse)
{
if (frame.get() && frame->IsValid())
{
auto frameId = StringUtils::ToClr(frame->GetIdentifier());
auto callbackId = GetInt64(argList, 0);
JavascriptRootObjectWrapper^ rootObjectWrapper;
_jsRootObjectWrappersByFrameId->TryGetValue(frameId, rootObjectWrapper);
if (rootObjectWrapper != nullptr)
{
JavascriptAsyncMethodCallback^ callback;
if (rootObjectWrapper->TryGetAndRemoveMethodCallback(callbackId, callback))
{
try
{
auto context = frame->GetV8Context();
if (context.get() && context->Enter())
{
try
{
auto success = argList->GetBool(1);
if (success)
{
callback->Success(DeserializeV8Object(argList, 2));
}
else
{
callback->Fail(argList->GetString(2));
}
}
finally
{
context->Exit();
}
}
else
{
callback->Fail("Unable to Enter Context");
}
}
finally
{
//dispose
delete callback;
}
}
}
}
handled = true;
}
return handled;
};
void CefAppUnmanagedWrapper::OnWebKitInitialized()
{
if (!Object::ReferenceEquals(_handler, nullptr))
{
_handler->OnWebKitInitialized();
}
}
}
}