diff --git a/.editorconfig b/.editorconfig
index 47a17f8513..92683c27e2 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -156,3 +156,5 @@ csharp_space_between_square_brackets =
# Modifier order
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async : error
+# CA2247: Argument passed to TaskCompletionSource constructor should be TaskCreationOptions enum instead of TaskContinuationOptions enum
+dotnet_diagnostic.CA2247.severity = error
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index b136eb38e1..b55aeeadbe 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -8,6 +8,6 @@
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#custom: # Replace with a single custom sponsorship URL
-#github: amaitland
-patreon: alexmaitland
+github: amaitland
+#patreon: alexmaitland
custom: https://paypal.me/AlexMaitland
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index aa70ab651b..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-name: Bug report
-about: Create a report for a reproducible bug
-title: ''
-labels: ''
-assignees: ''
-
----
-
-### Please only open an issue if you have a BUG to report, if you simply have a question or require some assistance keep reading for info. If you do have a BUG to report, please use the Bug Report template below.
-
-So you have a question to ask, where can you look for answers? Read on. Think you've found a bug? Please take the time to fill out the bug report below, provide as much information as you can, make sure you provide information for every heading. Thank you! We'd like to keep issues exclusively for **bug reports**, so please ask your questions on `Gitter`
-
-- Start by reading the General Usage guide, it answers all the common questions https://github.com/cefsharp/CefSharp/wiki/General-Usage
-- Check out the FAQ, lots of useful information there, specially if your having trouble deploying to a different machine : https://github.com/cefsharp/CefSharp/wiki/Frequently-asked-questions
-- GitHub proves a fantastic search feature, it'll search through past issues and code. So check that out (Search box at the top of this page) : https://github.com/cefsharp/CefSharp
-- You can see all the `CefSharp` tagged issues on `Stackoverflow`, some useful stuff there : http://stackoverflow.com/questions/tagged/cefsharp
-- You can search the `Gitter Chat Channel` for past questions/conversations, you can search through every discussion from the beginning : https://gitter.im/cefsharp/CefSharp
-
-Still have a question? Great, ask it on `Gitter`. https://gitter.im/cefsharp/CefSharp
-
-**Note: CefSharp is just a wrapper around the Chromium Embedded Project, it's worth searching http://magpcss.org/ceforum/index.php if your problem involves a low level Chromium error message**
-
-We ask that you put in a reasonable amount of effort in searching through the resources listed above. The developers have full time jobs, they have lives, families, the time they have available to contribute this project is a precious resource, make sure you use it wisely! Remember the more time we spend answering the same questions over and over again, less time goes into writing code, adding new features, actually fixing bugs!
-
-Still have a question to ask or unsure where to go next? Start with the Gitter Chat room : https://gitter.im/cefsharp/CefSharp
-
---
-### Bug Report
-Delete this line and everything above, and then fill in the details below.
-
-- **What version of the product are you using?**
- - What version are you using? Nuget? CI Nuget? build from a branch? If so which branch? Please include the exact version number you are using (no ambiguous statements like `Latest from Nuget`)
-e.g. 57.0.0 or 63.0.0-pre01
- - Please only create an issue if you can reproduce the problem with the latest version. (If you are using the latest stable release please check to see if there is a newer `-pre` release and test with that also).
-
-- **What architecture x86 or x64?**
-
-- **On what operating system?**
- - Win7, Win 8, Win10, etc?
-
-- **Are you using `WinForms`, `WPF` or `OffScreen`?**
-
-- **What steps will reproduce the problem?**
- - Please provide detailed information here, enough for someone else to reprodce your problem.
- - Please no binary (zip, etc) links, fork the [MinimalExample](https://github.com/cefsharp/CefSharp.MinimalExample) and push your changes to `GitHub`. (Alternatively use a code sharing service list `Gist` or `Pastebin`).
-
-- **What is the expected output? What do you see instead?**
-
-- **Please provide any additional information below.**
- - A stack trace if available, any Exception information.
-
- - Does the cef log provide any relevant information? (By default there should be a debug.log file in your bin directory)
-
- - Any other background information that's relevant? Are you doing something out of the ordinary? 3rd party controls?
-
-- **Does this problem also occur in the `CEF` Sample Application from http://opensource.spotify.com/cefbuilds/index.html?**
-
- - To compare with WPF run cefclient --multi-threaded-message-loop --off-screen-rendering-enabled --enable-gpu
- - To compare with WinForms run cefclient --multi-threaded-message-loop
- - If you can reproduce the problem with `cefclient` then you'll need to report the bug on https://bitbucket.org/chromiumembedded/cef/overview there is no point opening an issue here. (Make sure you search before opening an issue)
- - Please include the version you tested with e.g. `cef_binary_3.3029.1611.g44e39a8_windows64_client.tar.bz2`. It's important to you test with the same version that `CefSharp` is based on. Check the release notes to determine the version (https://github.com/cefsharp/CefSharp/releases) or load `chrome://version` in the browser.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000000..61d10684a4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,155 @@
+name: Bug Report
+description: Create a report for a reproducible bug
+labels: []
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Please only open an issue if you have a **BUG** to report. for questions/assistance use [Discussions](https://github.com/cefsharp/CefSharp/discussions). If you are new to the project then please review the following:
+ 1. [General Usage guide](https://github.com/cefsharp/CefSharp/wiki/General-Usage) includes examples and details of many common questions.
+ 2. [Frequently Asked Questions](https://github.com/cefsharp/CefSharp/wiki/Frequently-asked-questions), lots of useful information there, specially if your having trouble deploying to a different machine.
+ 3. GitHub has a fantastic search feature, it'll search through past issues/code. Use the Search box at the top of this page).
+ 4. You can see all the `CefSharp` tagged issues on [Stackoverflow](http://stackoverflow.com/questions/tagged/cefsharp), lots of questions/answers.
+ - type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ description: Please search to see if an issue already exists for the bug you encountered.
+ options:
+ - label: I have searched both open/closed issues, no issue already exists.
+ required: true
+ - type: input
+ id: cefsharp-version
+ attributes:
+ label: CefSharp Version
+ description: What version are you using? Please only open an issue if you can reproduce the problem with version 145.0.260 or later.
+ placeholder: 145.0.260
+ validations:
+ required: true
+ - type: dropdown
+ id: operating-system
+ attributes:
+ label: Operating System
+ multiple: false
+ options:
+ - Windows 10
+ - Windows 11
+ - Windows Server 2016
+ - Windows Server 2019
+ - Windows Server 2022
+ - Windows Server 2025
+ validations:
+ required: true
+ - type: dropdown
+ id: architecture
+ attributes:
+ label: Architecture
+ multiple: false
+ options:
+ - x64
+ - x86
+ - arm64
+ - AnyCPU
+ validations:
+ required: true
+ - type: input
+ id: dotnet-version
+ attributes:
+ label: .Net Version
+ description: |
+ What .Net version are you using?
+ placeholder: e.g. .Net 4.8 or .Net 6.0
+ validations:
+ required: true
+ - type: dropdown
+ id: cefsharp-implementation
+ attributes:
+ label: Implementation
+ multiple: false
+ options:
+ - WinForms
+ - WPF
+ - WPF HwndHost
+ - OffScreen
+ validations:
+ required: true
+ - type: textarea
+ id: repro-steps
+ attributes:
+ label: Reproduction Steps
+ description: |
+ Please include minimal steps to reproduce the problem. E.g.: the smallest possible code snippet; or a small example project here on GitHub, with steps to run it. Include text/code as text rather than screenshots (so it shows up in searches and can copy/paste).
+ Does the problem reproduce using the [MinimalExample](https://github.com/cefsharp/CefSharp.MinimalExample)? You can fork the MinimalExample and use this as a base for your example.
+ placeholder: Minimal Reproduction
+ validations:
+ required: true
+ - type: textarea
+ id: expected-behavior
+ attributes:
+ label: Expected behavior
+ description: |
+ Provide a description of the expected behavior.
+ placeholder: Expected behavior
+ validations:
+ required: true
+ - type: textarea
+ id: actual-behavior
+ attributes:
+ label: Actual behavior
+ description: |
+ Provide a description of the actual behavior observed. If applicable please include any error messages, exception or stacktraces.
+ placeholder: Actual behavior
+ validations:
+ required: true
+ - type: textarea
+ id: regression
+ attributes:
+ label: Regression?
+ description: |
+ Did this work in a previous build or release of CefSharp? If you can try a previous release or build to find out, that can help us narrow down the problem. If you don't know, that's OK.
+ placeholder: Regression?
+ validations:
+ required: false
+ - type: textarea
+ id: known-workarounds
+ attributes:
+ label: Known Workarounds
+ description: |
+ Please provide a description of any known workarounds.
+ placeholder: Known Workarounds
+ validations:
+ required: false
+ - type: markdown
+ attributes:
+ value: |
+ To help determine where the problem needs to be fixed please download and test using the `CEF Sample Application(cefclient)`.
+ 1. Download for [x86](https://cef-builds.spotifycdn.com/cef_binary_146.0.7%2Bga6b143f%2Bchromium-146.0.7680.165_windows32_client.tar.bz2) or [x64](https://cef-builds.spotifycdn.com/cef_binary_146.0.7%2Bga6b143f%2Bchromium-146.0.7680.165_windows64_client.tar.bz2) or [arm64](https://cef-builds.spotifycdn.com/cef_binary_146.0.7%2Bga6b143f%2Bchromium-146.0.7680.165_windowsarm64_client.tar.bz2).
+ 2. Extract tar.bz2 file
+ 3. Execute cefclient.exe using the **command line args below**:
+
+ For WPF/OffScreen `cefclient.exe --multi-threaded-message-loop --no-sandbox --off-screen-rendering-enabled --enable-gpu`
+ For WinForms `cefclient.exe --multi-threaded-message-loop --no-sandbox --use-alloy-style`
+ - type: dropdown
+ id: cefclient-testing
+ attributes:
+ label: Does this problem also occur in the CEF Sample Application
+ multiple: false
+ options:
+ - 'Yes using WPF/OffScreen command line args'
+ - 'Yes using WinForms command line args'
+ - 'No'
+ - Not Tested
+ description: |
+ If you can reproduce the problem with `cefclient` then please report the issue on [CEF Issue Tracker](https://github.com/chromiumembedded/cef/issues) (Make sure you search before opening an issue). If you open an issue here it will most likely be closed as `upstream` as the bug needs to be fixed in `CEF`.
+ validations:
+ required: true
+ - type: textarea
+ id: other-info
+ attributes:
+ label: Other information
+ description: |
+ If you are seeing a crash in `libcef.dll` then please download `libcef.dll.pdb` and place it next to `libcef.dll` to obtain a detailed stack trace, see [FAQ](https://github.com/cefsharp/CefSharp/wiki/Trouble-Shooting#loading-native-symbols-for-easier-diagnosis) for details.
+ Does the cef log provide any relevant information? (By default there should be a debug.log file in your bin directory)
+ Any other background information that's relevant? Are you doing something out of the ordinary? 3rd party controls?
+ placeholder: Other information
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..800264224b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,9 @@
+# https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
+blank_issues_enabled: false
+contact_links:
+ - name: stackoverflow
+ url: http://stackoverflow.com/questions/tagged/cefsharp
+ about: Please ask and answer questions here.
+ - name: Chromium Embedded Framework(CEF) Forum
+ url: https://magpcss.org/ceforum/index.php
+ about: Please ask your non CefSharp specific CEF questions here
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 7acd16f28d..d643b03239 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,13 +1,18 @@
---
name: Feature request
-about: Suggest an idea for this project
+about: Suggest an idea for this project, please don't use this template to ask questions, thank you.
title: Feature Request - My Feature
labels: feature-request
assignees: ''
---
-`CefSharp` is a wrapper around the [Chromium Embedded Framework](https://bitbucket.org/chromiumembedded/cef/overview) in a lot of cases a feature must be added to `CEF` first before it can be used in `CefSharp`. `CEF` has it's own `Feature Request Forum` at https://magpcss.org/ceforum/viewforum.php?f=7
+Please ask your questions under the Discussions section here on GitHub
+- https://github.com/cefsharp/CefSharp/discussions
+
+---
+
+`CefSharp` is a wrapper around the [Chromium Embedded Framework](https://github.com/chromiumembedded/cef) in a lot of cases a feature must be added to `CEF` first before it can be used in `CefSharp`. `CEF` has its own `Feature Request Forum` at https://magpcss.org/ceforum/viewforum.php?f=7
---
@@ -23,4 +28,4 @@ Add any other context or screenshots about the feature request here.
**Checklist:**
- [ ] I have reviewed the [CEF API](https://magpcss.org/ceforum/apidocs3/index-all.html) and have confirmed the feature I'm requesting is possible.
- [ ] The Feature I'm requesting is an improvement to Async Javascript Binding (No new feature are being added to the Sync Javascript binding)
-- [ ] An open `PR` exists on the [CEF Pull Requests](https://bitbucket.org/chromiumembedded/cef/pull-requests/) and I'd like to propose this feature is added to `CefSharp` when/if it's merged.
+- [ ] An open `PR` exists on the [CEF Pull Requests](https://github.com/chromiumembedded/cef/pulls) and I'd like to propose this feature is added to `CefSharp` when/if it's merged.
diff --git a/.github/config.yml b/.github/config.yml
index 9dab6a46eb..eb54eb44bd 100644
--- a/.github/config.yml
+++ b/.github/config.yml
@@ -9,7 +9,7 @@ newIssueWelcomeComment: >
It's also important to remember that `CefSharp` is just a wrapper around the `Chromium Embedded Framework(CEF)`, a lot of questions people
- have aren't actually `CefSharp` specific, they're generic to `CEF` and for those `CEF` has it's own support forum at http://magpcss.org/ceforum/index.php and issue tracker at https://bitbucket.org/chromiumembedded/cef
+ have aren't actually `CefSharp` specific, they're generic to `CEF` and for those `CEF` has it's own support forum at http://magpcss.org/ceforum/index.php and issue tracker at https://github.com/chromiumembedded/cef/issues
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index f86f1e261e..c2d7925c5e 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,29 +1,30 @@
-Fixes [issue-number]
- - e.g Fixes #2345
+**Fixes:** [issue-number]
+
**Summary:** [summary of the change and which issue is fixed here]
- e.g. I have added a new feature to the Javascript Binding implementation
**Changes:** [specify the structures changed]
- - e.g. I have modified the Javascript Bindign Implementation
+ - e.g. I have modified the Javascript Binding Implementation
- Added support for Async binding to return Task
- Added new QUnit Test cases
-## How Has This Been Tested?
-
-
-
+**How Has This Been Tested?**
+
+
+
-## Screenshots (if appropriate):
+**Screenshots (if appropriate):**
-## Types of changes
-
+**Types of changes**
+
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Updated documentation
**Checklist:**
+
- [ ] Tested the code(if applicable)
- [ ] Commented my code
- [ ] Changed the documentation(if applicable)
diff --git a/.github/workflows/codeql-analysis.yml.bak b/.github/workflows/codeql-analysis.yml.bak
new file mode 100644
index 0000000000..e66bab1453
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml.bak
@@ -0,0 +1,62 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+name: "CodeQL"
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [master]
+ schedule:
+ - cron: '0 4 * * 5'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: windows-latest
+
+ strategy:
+ fail-fast: true
+ matrix:
+ # Override automatic language detection by changing the below list
+ # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
+ language: ['csharp']
+ # Learn more...
+ # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v1
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v1
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v1
diff --git a/.gitignore b/.gitignore
index 2dd9e157d8..e92d3bb6b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,7 +21,9 @@
_ReSharper*
bin/
+bin.netcore/
obj/
+obj.netcore/
packages/
Debug/
Release/
@@ -39,3 +41,4 @@ x64/Release
Win32/Release
.vs/
/Help
+/tools
diff --git a/.vsconfig b/.vsconfig
index de99aea1cd..9c22b175de 100644
--- a/.vsconfig
+++ b/.vsconfig
@@ -4,26 +4,30 @@
"Microsoft.VisualStudio.Component.CoreEditor",
"Microsoft.VisualStudio.Workload.CoreEditor",
"Microsoft.VisualStudio.Component.NuGet",
- "Microsoft.Net.Component.4.6.1.TargetingPack",
+ "Microsoft.Net.Component.4.7.2.TargetingPack",
"Microsoft.VisualStudio.Component.Roslyn.Compiler",
"Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
"Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
"Microsoft.Component.MSBuild",
"Microsoft.VisualStudio.Component.ManagedDesktop.Core",
- "Microsoft.Net.Component.4.5.2.TargetingPack",
+ "Microsoft.Net.Component.4.6.2.TargetingPack",
"Microsoft.VisualStudio.Component.IntelliCode",
"Microsoft.Net.ComponentGroup.TargetingPacks.Common",
"Microsoft.VisualStudio.Component.Debugger.JustInTime",
"Microsoft.VisualStudio.Component.VC.CoreIde",
"Microsoft.VisualStudio.Component.Windows10SDK",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
+ "Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
"Microsoft.ComponentGroup.Blend",
"Microsoft.VisualStudio.Workload.ManagedDesktop",
"Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
"Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
"Microsoft.VisualStudio.Component.VC.CLI.Support",
- "Microsoft.VisualStudio.Component.Windows10SDK.17763",
- "Microsoft.VisualStudio.Workload.NativeDesktop"
+ "Microsoft.VisualStudio.Component.Windows10SDK.19041",
+ "Microsoft.VisualStudio.Workload.NativeDesktop",
+ "Microsoft.NetCore.Component.DevelopmentTools",
+ "Microsoft.NetCore.Component.Runtime.6.0",
+ "Microsoft.NetCore.Component.SDK"
]
}
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5b05a5f0ad..281ae9dda1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -13,16 +13,24 @@ Thanks for your interest in contributing to the project! Please follow these sim
### `CefSharp` vs `Chromium Embedded Framework(CEF)`
-`CefSharp` simply takes the building blocks provided by `CEF` and attempts to provide a usable '.Net' implementation.
+`CefSharp` simply takes the building blocks provided by the [Chromium Embedded Framework(CEF)](https://github.com/chromiumembedded/cef) and provides a usable '.Net' implementation.
The upstream [`CEF` forum](http://magpcss.org/ceforum/) is a valuable resource, if your issues seems fairly low level, then please conduct some research before posting.
It maybe helpful to run the `cefclient` application and compare output with `CefSharp`. The `WinForms` and `WPF` versions use two different rendering modes, `WPF` uses Offscreen Rendering (`OSR`). `OffScreen` also uses `OSR` mode.
-- Download **Sample Application** from http://opensource.spotify.com/cefbuilds/index.html
-- To compare with WPF run `cefclient --multi-threaded-message-loop --off-screen-rendering-enabled --enable-gpu`
-- To compare with WinForms `cefclient --multi-threaded-message-loop`
-
-To determine which version of `CEF` your build is running, open `chrome://version` and you'll see a number similar to `3.2987.1597.gffc5773`. Open http://opensource.spotify.com/cefbuilds/index.html and download the `Sample Application` that exactly matches. If your using an older build click `Show More Builds`.
+ - Download and run the `CEF Sample Application(cefclient)`:
+ - Download for [x86](https://cef-builds.spotifycdn.com/cef_binary_146.0.7%2Bga6b143f%2Bchromium-146.0.7680.165_windows32_client.tar.bz2) or [x64](https://cef-builds.spotifycdn.com/cef_binary_146.0.7%2Bga6b143f%2Bchromium-146.0.7680.165_windows64_client.tar.bz2) or [arm64](https://cef-builds.spotifycdn.com/cef_binary_146.0.7%2Bga6b143f%2Bchromium-146.0.7680.165_windowsarm64_client.tar.bz2).
+ - Extract and run cefclient.exe
+ - If you are using WPF/OffScreen run
+ ```
+ cefclient.exe --multi-threaded-message-loop --no-sandbox --off-screen-rendering-enabled --enable-gpu
+ ```
+ - If you are using WinForms run
+ ```
+ cefclient.exe --multi-threaded-message-loop --no-sandbox --use-alloy-style
+ ```
+ - **MAKE SURE TO TEST WITH THE COMMAND LINE ARGS LISTED ABOVE**
+ - If you can reproduce the problem with `cefclient` then you'll need to report the bug on https://github.com/chromiumembedded/cef there is no point opening an issue here. (Make sure you search before opening an issue)
### What should I include when creating an `Issue`?
@@ -37,12 +45,12 @@ Your bug report should **always follow this template**:
- **Are you using `WinForms`, `WPF` or `OffScreen`?**
- **What version of the product are you using? On what operating system? x86 or x64?**
- What version are you using? Nuget? CI Nuget? build from a branch? If so which branch?
- - Win7, Win 8, Win10, etc?
+ - Win10/11, etc?
- **Please provide any additional information below.**
- A stack trace if available, any Exception information.
- Does the cef log provide any relevant information? (By default there should be a debug.log file in your bin directory)
- Any other background information that's relevant? Are you doing something out of the ordinary? 3rd party controls?
-- **Does this problem also occur in the `CEF Sample Application` from http://opensource.spotify.com/cefbuilds/index.html?**
+- **Does this problem also occur in the `CEF Sample Application` from https://cef-builds.spotifycdn.com/index.html?**
Your bug report should include **what you were doing** in the software when you encountered it, **what you were expecting** to happen and **what happened instead**.
diff --git a/CefSharp.AfterBuild.targets b/CefSharp.AfterBuild.targets
new file mode 100644
index 0000000000..f26ed0b382
--- /dev/null
+++ b/CefSharp.AfterBuild.targets
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ locales\%(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+ Included
+ false
+ true
+
+
+
+
+
+
+ locales\%(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+ Included
+ false
+ true
+
+
+
+
+
+
+ locales\%(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+ Included
+ false
+ true
+
+
+
+
+
diff --git a/CefSharp.BrowserSubprocess.Core/Assembly.manifest b/CefSharp.BrowserSubprocess.Core/Assembly.manifest
new file mode 100644
index 0000000000..01c92358c2
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Assembly.manifest
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp
index 124db6b9c9..b7c6b55967 100644
--- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp
@@ -7,7 +7,7 @@
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
namespace Async
{
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h
index 46cceae496..27411d722b 100644
--- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h
@@ -8,7 +8,7 @@
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
namespace Async
{
@@ -44,4 +44,4 @@ namespace CefSharp
};
}
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp
index 7c45a4b01f..71628d738f 100644
--- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp
@@ -4,17 +4,18 @@
#include "stdafx.h"
#include "JavascriptAsyncMethodHandler.h"
-#include "../CefSharp.Core/Internals/Messaging/Messages.h"
-#include "../CefSharp.Core/Internals/Serialization/Primitives.h"
+#include "../CefSharp.Core.Runtime/Internals/Messaging/Messages.h"
+#include "../CefSharp.Core.Runtime/Internals/Serialization/Primitives.h"
#include "Serialization/V8Serialization.h"
#include "CefAppUnmanagedWrapper.h"
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
+using namespace CefSharp::BrowserSubprocess::Serialization;
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
namespace Async
{
@@ -37,9 +38,9 @@ namespace CefSharp
//when refreshing the browser this is sometimes null, in this case return true and log message
//https://github.com/cefsharp/CefSharp/pull/2446
- if (promiseData == NULL)
+ if (promiseData == nullptr)
{
- LOG(WARNING) << "JavascriptAsyncMethodHandler::Execute promiseData returned NULL";
+ LOG(WARNING) << "JavascriptAsyncMethodHandler::Execute promiseData returned nullptr";
return true;
}
@@ -54,7 +55,7 @@ namespace CefSharp
auto request = CefProcessMessage::Create(kJavascriptAsyncMethodCallRequest);
auto argList = request->GetArgumentList();
auto params = CefListValue::Create();
- for (auto i = 0; i < arguments.size(); i++)
+ for (size_t i = 0; i < arguments.size(); i++)
{
SerializeV8Object(arguments[i], params, i, _callbackRegistry);
}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.h
index 5c95020aa3..aa315f69c9 100644
--- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.h
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.h
@@ -10,7 +10,7 @@
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
namespace Async
{
@@ -18,11 +18,11 @@ namespace CefSharp
{
private:
gcroot _callbackRegistry;
- gcroot^> _methodCallbackSave;
- int64 _objectId;
+ gcroot^> _methodCallbackSave;
+ int64_t _objectId;
public:
- JavascriptAsyncMethodHandler(int64 objectId, JavascriptCallbackRegistry^ callbackRegistry, Func^ methodCallbackSave)
+ JavascriptAsyncMethodHandler(int64_t objectId, JavascriptCallbackRegistry^ callbackRegistry, Func^ methodCallbackSave)
:_callbackRegistry(callbackRegistry), _objectId(objectId), _methodCallbackSave(methodCallbackSave)
{
@@ -38,7 +38,7 @@ namespace CefSharp
_methodCallbackSave = nullptr;
}
- IMPLEMENT_REFCOUNTING(JavascriptAsyncMethodHandler);
+ IMPLEMENT_REFCOUNTINGM(JavascriptAsyncMethodHandler);
};
}
}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.cpp
index faba260a30..9d60fc2cfd 100644
--- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.cpp
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.cpp
@@ -8,7 +8,7 @@
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
namespace Async
{
@@ -21,4 +21,4 @@ namespace CefSharp
}
}
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.h
index 8bf108f369..876aa52026 100644
--- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.h
@@ -9,7 +9,7 @@
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
namespace Async
{
@@ -19,7 +19,7 @@ namespace CefSharp
MCefRefPtr _javascriptMethodHandler;
public:
- JavascriptAsyncMethodWrapper(int64 ownerId, JavascriptCallbackRegistry^ callbackRegistry, Func^ methodCallbackSave)
+ JavascriptAsyncMethodWrapper(int64_t ownerId, JavascriptCallbackRegistry^ callbackRegistry, Func^ methodCallbackSave)
: _javascriptMethodHandler(new JavascriptAsyncMethodHandler(ownerId, callbackRegistry, methodCallbackSave))
{
@@ -29,4 +29,4 @@ namespace CefSharp
};
}
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.cpp
index 737ea87f9a..401b85a643 100644
--- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.cpp
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.cpp
@@ -11,7 +11,7 @@ using namespace System::Linq;
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
namespace Async
{
@@ -32,4 +32,4 @@ namespace CefSharp
}
}
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.h
index fd449ce8d7..f42ac60e42 100644
--- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.h
@@ -10,7 +10,7 @@
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
namespace Async
{
@@ -18,11 +18,11 @@ namespace CefSharp
{
private:
initonly List^ _wrappedMethods;
- Func^ _methodCallbackSave;
+ Func^ _methodCallbackSave;
JavascriptCallbackRegistry^ _callbackRegistry;
public:
- JavascriptAsyncObjectWrapper(JavascriptCallbackRegistry^ callbackRegistry, Func^ saveMethod)
+ JavascriptAsyncObjectWrapper(JavascriptCallbackRegistry^ callbackRegistry, Func^ saveMethod)
: _wrappedMethods(gcnew List()), _methodCallbackSave(saveMethod), _callbackRegistry(callbackRegistry)
{
@@ -42,4 +42,4 @@ namespace CefSharp
};
}
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h b/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h
index c3ccd05d85..1a99952071 100644
--- a/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h
+++ b/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h
@@ -6,307 +6,312 @@
#include "include/cef_v8.h"
#include "RegisterBoundObjectRegistry.h"
-#include "..\CefSharp.Core\Internals\Messaging\Messages.h"
-#include "..\CefSharp.Core\Internals\Serialization\Primitives.h"
+#include "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
+#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
using namespace System;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
+using namespace CefSharp::BrowserSubprocess;
namespace CefSharp
{
- const CefString kBindObjectAsync = CefString("BindObjectAsync");
- const CefString kBindObjectAsyncCamelCase = CefString("bindObjectAsync");
-
- private class BindObjectAsyncHandler : public CefV8Handler
+ namespace BrowserSubprocess
{
- private:
- gcroot _callbackRegistry;
- gcroot^> _javascriptObjects;
- gcroot _browserWrapper;
-
- public:
- BindObjectAsyncHandler(RegisterBoundObjectRegistry^ callbackRegistery, Dictionary^ javascriptObjects, CefBrowserWrapper^ browserWrapper)
- {
- _callbackRegistry = callbackRegistery;
- _javascriptObjects = javascriptObjects;
- _browserWrapper = browserWrapper;
- }
+ const CefString kBindObjectAsync = CefString("BindObjectAsync");
+ const CefString kBindObjectAsyncCamelCase = CefString("bindObjectAsync");
- ~BindObjectAsyncHandler()
+ private class BindObjectAsyncHandler : public CefV8Handler
{
- _callbackRegistry = nullptr;
- _javascriptObjects = nullptr;
- _browserWrapper = nullptr;
- }
+ private:
+ gcroot _callbackRegistry;
+ gcroot^> _javascriptObjects;
+ gcroot _javascriptRootObjectWrapper;
- bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) OVERRIDE
- {
- auto context = CefV8Context::GetCurrentContext();
+ public:
+ BindObjectAsyncHandler(RegisterBoundObjectRegistry^ callbackRegistery, Dictionary^ javascriptObjects, JavascriptRootObjectWrapper^ javascriptRootObjectWrapper)
+ {
+ _callbackRegistry = callbackRegistery;
+ _javascriptObjects = javascriptObjects;
+ _javascriptRootObjectWrapper = javascriptRootObjectWrapper;
+ }
- if (context.get() && context->Enter())
+ ~BindObjectAsyncHandler()
{
- try
- {
- auto params = CefListValue::Create();
+ _callbackRegistry = nullptr;
+ _javascriptObjects = nullptr;
+ _javascriptRootObjectWrapper = nullptr;
+ }
- auto boundObjectRequired = false;
- auto notifyIfAlreadyBound = false;
- auto ignoreCache = false;
- auto cachedObjects = gcnew List();
- //TODO: Create object to represent this information
- auto objectNamesWithBoundStatus = gcnew List^>();
- auto objectCount = 0;
+ bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) override
+ {
+ auto context = CefV8Context::GetCurrentContext();
- if (arguments.size() > 0)
+ if (context.get() && context->Enter())
+ {
+ try
{
- objectCount = (int)arguments.size();
-
- //If first argument is an object, we'll see if it contains config values
- if (arguments[0]->IsObject())
+ auto params = CefListValue::Create();
+ //We need to store a seperate index into our params as
+ //there are instances we skip over already cached objects
+ //and end up with empty strings in the list.
+ //e.g. first object is already bound/cached, we previously
+ //second object isn't we end up with a list of "", "secondObject"
+ int paramsIndex = 0;
+
+ auto boundObjectRequired = false;
+ auto notifyIfAlreadyBound = false;
+ auto ignoreCache = false;
+ auto cachedObjects = gcnew List();
+ //TODO: Create object to represent this information
+ auto objectNamesWithBoundStatus = gcnew List^>();
+ auto objectCount = 0;
+
+ if (arguments.size() > 0)
{
- //Upper and camelcase options are supported
- notifyIfAlreadyBound = GetV8BoolValue(arguments[0], "NotifyIfAlreadyBound", "notifyIfAlreadyBound");
- ignoreCache = GetV8BoolValue(arguments[0], "IgnoreCache", "ignoreCache");
+ objectCount = (int)arguments.size();
- //If we have a config object then we remove that from the count
- objectCount = objectCount - 1;
- }
+ //If first argument is an object, we'll see if it contains config values
+ if (arguments[0]->IsObject())
+ {
+ //Upper and camelcase options are supported
+ notifyIfAlreadyBound = GetV8BoolValue(arguments[0], "NotifyIfAlreadyBound", "notifyIfAlreadyBound");
+ ignoreCache = GetV8BoolValue(arguments[0], "IgnoreCache", "ignoreCache");
+
+ //If we have a config object then we remove that from the count
+ objectCount = objectCount - 1;
+ }
- auto global = context->GetGlobal();
+ auto global = context->GetGlobal();
- //Loop through all arguments and ignore anything that's not a string
- for (auto i = 0; i < arguments.size(); i++)
- {
- //Validate arg as being a string
- if (arguments[i]->IsString())
+ //Loop through all arguments and ignore anything that's not a string
+ for (size_t i = 0; i < arguments.size(); i++)
{
- auto objectName = arguments[i]->GetStringValue();
- auto managedObjectName = StringUtils::ToClr(objectName);
- auto alreadyBound = global->HasValue(objectName);
- auto cached = false;
-
- //Check if the object has already been bound
- if (alreadyBound)
+ //Validate arg as being a string
+ if (arguments[i]->IsString())
{
- cached = _javascriptObjects->ContainsKey(managedObjectName);
- }
- else
- {
- //If no matching object found then we'll add the object name to the list
- boundObjectRequired = true;
- params->SetString(i, objectName);
+ auto objectName = arguments[i]->GetStringValue();
+ auto managedObjectName = StringUtils::ToClr(objectName);
+ auto alreadyBound = global->HasValue(objectName);
+ auto cached = false;
- JavascriptObject^ obj;
- if (_javascriptObjects->TryGetValue(managedObjectName, obj))
+ //Check if the object has already been bound
+ if (alreadyBound)
+ {
+ cached = _javascriptObjects->ContainsKey(managedObjectName);
+ }
+ else
{
- cachedObjects->Add(obj);
+ //If no matching object found then we'll add the object name to the list
+ boundObjectRequired = true;
+ params->SetString(paramsIndex++, objectName);
+
+ JavascriptObject^ obj;
+ if (_javascriptObjects->TryGetValue(managedObjectName, obj))
+ {
+ cachedObjects->Add(obj);
- cached = true;
+ cached = true;
+ }
}
- }
- objectNamesWithBoundStatus->Add(Tuple::Create(managedObjectName, alreadyBound, cached));
+ objectNamesWithBoundStatus->Add(Tuple::Create(managedObjectName, alreadyBound, cached));
+ }
}
}
- }
- else
- {
- //No objects names were specified so we default to makeing the request
- boundObjectRequired = true;
- }
+ else
+ {
+ //No objects names were specified so we default to makeing the request
+ boundObjectRequired = true;
+ }
- auto frame = context->GetFrame();
+ auto frame = context->GetFrame();
- if (frame.get() && frame->IsValid())
- {
- if (boundObjectRequired || ignoreCache)
+ if (frame.get() && frame->IsValid())
{
- //If the number of cached objects matches the number of args
- //(we have a cached copy of all requested objects)
- //then we'll immediately bind the cached objects
- if (cachedObjects->Count == objectCount && ignoreCache == false)
+ if (boundObjectRequired || ignoreCache)
{
- if (Object::ReferenceEquals(_browserWrapper, nullptr))
+ //If the number of cached objects matches the number of args
+ //(we have a cached copy of all requested objects)
+ //then we'll immediately bind the cached objects
+ //If objectCount and cachedObject count are both 0 then we'll
+ //send the kJavascriptRootObjectRequest message
+ //https://github.com/cefsharp/CefSharp/issues/3470
+ if (objectCount > 0 && cachedObjects->Count == objectCount && ignoreCache == false)
{
- exception = "BindObjectAsyncHandler::Execute - Browser wrapper null, unable to bind objects";
+ if (Object::ReferenceEquals(_javascriptRootObjectWrapper, nullptr))
+ {
+ exception = "BindObjectAsyncHandler::Execute - _javascriptRootObjectWrapper null, unable to bind objects";
- return true;
- }
+ return true;
+ }
- auto browser = context->GetBrowser();
+ auto browser = context->GetBrowser();
- auto rootObjectWrappers = _browserWrapper->JavascriptRootObjectWrappers;
+ JavascriptRootObjectWrapper^ rootObject = _javascriptRootObjectWrapper;
- JavascriptRootObjectWrapper^ rootObject;
- if (!rootObjectWrappers->TryGetValue(frame->GetIdentifier(), rootObject))
- {
- rootObject = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier(), _browserWrapper->BrowserProcess);
- rootObjectWrappers->TryAdd(frame->GetIdentifier(), rootObject);
- }
+ //Cached objects only contains a list of objects not already bound
+ rootObject->Bind(cachedObjects, context->GetGlobal());
- //Cached objects only contains a list of objects not already bound
- rootObject->Bind(cachedObjects, context->GetGlobal());
+ //Objects already bound or ignore cache
+ CefRefPtr promiseResolve;
+ CefRefPtr promiseException;
- //Objects already bound or ignore cache
- CefRefPtr promiseResolve;
- CefRefPtr promiseException;
+ auto promiseResolveScript = StringUtils::ToNative("Promise.resolve({Success:true, Count:" + cachedObjects->Count + ", Message:'OK'});");
- auto promiseResolveScript = StringUtils::ToNative("Promise.resolve({Success:true, Count:" + cachedObjects->Count + ", Message:'OK'});");
+ if (context->Eval(promiseResolveScript, CefString(), 0, promiseResolve, promiseException))
+ {
+ retval = promiseResolve;
+ }
+ else
+ {
+ exception = promiseException->GetMessage();
- if (context->Eval(promiseResolveScript, CefString(), 0, promiseResolve, promiseException))
- {
- retval = promiseResolve;
- }
- else
- {
- exception = promiseException->GetMessage();
+ return true;
+ }
- return true;
+ NotifyObjectBound(frame, objectNamesWithBoundStatus);
}
-
- NotifyObjectBound(frame, objectNamesWithBoundStatus);
- }
- else
- {
- CefRefPtr promiseData;
- CefRefPtr promiseException;
- //this will create a promise and give us the reject/resolve functions {p: Promise, res: resolve(), rej: reject()}
- if (!context->Eval(CefAppUnmanagedWrapper::kPromiseCreatorScript, CefString(), 0, promiseData, promiseException))
+ else
{
- exception = promiseException->GetMessage();
+ CefRefPtr promiseData;
+ CefRefPtr promiseException;
+ //this will create a promise and give us the reject/resolve functions {p: Promise, res: resolve(), rej: reject()}
+ if (!context->Eval(CefAppUnmanagedWrapper::kPromiseCreatorScript, CefString(), 0, promiseData, promiseException))
+ {
+ exception = promiseException->GetMessage();
- return true;
- }
+ return true;
+ }
- //when refreshing the browser this is sometimes null, in this case return true and log message
- //https://github.com/cefsharp/CefSharp/pull/2446
- if (promiseData == NULL)
- {
- LOG(WARNING) << "BindObjectAsyncHandler::Execute promiseData returned NULL";
+ //when refreshing the browser this is sometimes null, in this case return true and log message
+ //https://github.com/cefsharp/CefSharp/pull/2446
+ if (promiseData == nullptr)
+ {
+ LOG(WARNING) << "BindObjectAsyncHandler::Execute promiseData returned nullptr";
- return true;
- }
+ return true;
+ }
- //return the promose
- retval = promiseData->GetValue("p");
+ //return the promose
+ retval = promiseData->GetValue("p");
- //References to the promise resolve and reject methods
- auto resolve = promiseData->GetValue("res");
- auto reject = promiseData->GetValue("rej");
+ //References to the promise resolve and reject methods
+ auto resolve = promiseData->GetValue("res");
+ auto reject = promiseData->GetValue("rej");
- auto callback = gcnew JavascriptAsyncMethodCallback(context, resolve, reject);
+ auto callback = gcnew JavascriptAsyncMethodCallback(context, resolve, reject);
- auto request = CefProcessMessage::Create(kJavascriptRootObjectRequest);
- auto argList = request->GetArgumentList();
+ auto request = CefProcessMessage::Create(kJavascriptRootObjectRequest);
+ auto argList = request->GetArgumentList();
- //Obtain a callbackId then send off the Request for objects
- auto callbackId = _callbackRegistry->SaveMethodCallback(callback);
+ //Obtain a callbackId then send off the Request for objects
+ auto callbackId = _callbackRegistry->SaveMethodCallback(callback);
- SetInt64(argList, 0, callbackId);
- argList->SetList(1, params);
+ SetInt64(argList, 0, callbackId);
+ argList->SetList(1, params);
- frame->SendProcessMessage(CefProcessId::PID_BROWSER, request);
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, request);
+ }
}
- }
- else
- {
- //Objects already bound or ignore cache
- CefRefPtr promiseResolve;
- CefRefPtr promiseException;
+ else
+ {
+ //Objects already bound or ignore cache
+ CefRefPtr promiseResolve;
+ CefRefPtr promiseException;
- auto promiseResolveScript = CefString("Promise.resolve({Success:false, Count:0, Message:'Object(s) already bound'});");
+ auto promiseResolveScript = CefString("Promise.resolve({Success:false, Count:0, Message:'Object(s) already bound'});");
- if (context->Eval(promiseResolveScript, CefString(), 0, promiseResolve, promiseException))
- {
- retval = promiseResolve;
+ if (context->Eval(promiseResolveScript, CefString(), 0, promiseResolve, promiseException))
+ {
+ retval = promiseResolve;
- if (notifyIfAlreadyBound)
+ if (notifyIfAlreadyBound)
+ {
+ NotifyObjectBound(frame, objectNamesWithBoundStatus);
+ }
+ }
+ else
{
- NotifyObjectBound(frame, objectNamesWithBoundStatus);
+ exception = promiseException->GetMessage();
}
}
- else
- {
- exception = promiseException->GetMessage();
- }
+ }
+ else
+ {
+ exception = "BindObjectAsyncHandler::Execute - Frame is invalid.";
}
}
- else
+ finally
{
- exception = "BindObjectAsyncHandler::Execute - Frame is invalid.";
+ context->Exit();
}
}
- finally
+ else
{
- context->Exit();
+ exception = "BindObjectAsyncHandler::Execute - Unable to Get or Enter Context";
}
- }
- else
- {
- exception = "BindObjectAsyncHandler::Execute - Unable to Get or Enter Context";
- }
- return true;
- }
+ return true;
+ }
- private:
- void NotifyObjectBound(const CefRefPtr frame, List^>^ objectNamesWithBoundStatus)
- {
- //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();
+ private:
+ void NotifyObjectBound(const CefRefPtr frame, List^>^ objectNamesWithBoundStatus)
+ {
+ //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();
- auto index = 0;
+ auto boundObjects = CefListValue::Create();
+ auto index = 0;
- for each(auto obj in objectNamesWithBoundStatus)
- {
- auto dict = CefDictionaryValue::Create();
+ for each (auto obj in objectNamesWithBoundStatus)
+ {
+ auto dict = CefDictionaryValue::Create();
- auto name = obj->Item1;
- auto alreadyBound = obj->Item2;
- auto isCached = obj->Item3;
- dict->SetString("Name", StringUtils::ToNative(name));
- dict->SetBool("IsCached", isCached);
- dict->SetBool("AlreadyBound", alreadyBound);
+ auto name = obj->Item1;
+ auto alreadyBound = obj->Item2;
+ auto isCached = obj->Item3;
+ dict->SetString("Name", StringUtils::ToNative(name));
+ dict->SetBool("IsCached", isCached);
+ dict->SetBool("AlreadyBound", alreadyBound);
- boundObjects->SetDictionary(index++, dict);
- }
+ boundObjects->SetDictionary(index++, dict);
+ }
- args->SetList(0, boundObjects);
+ args->SetList(0, boundObjects);
- frame->SendProcessMessage(CefProcessId::PID_BROWSER, msg);
- }
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, msg);
+ }
- bool GetV8BoolValue(const CefRefPtr val, const CefString key, const CefString camelCaseKey)
- {
- if (val->HasValue(key))
+ bool GetV8BoolValue(const CefRefPtr val, const CefString key, const CefString camelCaseKey)
{
- auto obj = val->GetValue(key);
- if (obj->IsBool())
+ if (val->HasValue(key))
{
- return obj->GetBoolValue();
+ auto obj = val->GetValue(key);
+ if (obj->IsBool())
+ {
+ return obj->GetBoolValue();
+ }
}
- }
- if (val->HasValue(camelCaseKey))
- {
- auto obj = val->GetValue(camelCaseKey);
- if (obj->IsBool())
+ if (val->HasValue(camelCaseKey))
{
- return obj->GetBoolValue();
+ auto obj = val->GetValue(camelCaseKey);
+ if (obj->IsBool())
+ {
+ return obj->GetBoolValue();
+ }
}
- }
-
- return false;
- }
+ return false;
+ }
- IMPLEMENT_REFCOUNTING(BindObjectAsyncHandler);
- };
+ IMPLEMENT_REFCOUNTINGM(BindObjectAsyncHandler);
+ };
+ }
}
diff --git a/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h b/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h
index 2eb318e515..f4f9ca45be 100644
--- a/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h
+++ b/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h
@@ -7,7 +7,6 @@
#include "Stdafx.h"
#include "SubProcess.h"
-#include "WcfEnabledSubProcess.h"
using namespace System;
using namespace CefSharp::Internals;
@@ -29,9 +28,48 @@ namespace CefSharp
}
+#ifdef NETCOREAPP
///
/// This function should be called from the application entry point function (typically Program.Main)
- /// to execute a secondary process e.g. gpu, plugin, renderer, utility
+ /// to execute a secondary process e.g. gpu, renderer, utility
+ /// This overload is specifically used for .Net Core. For hosting your own BrowserSubProcess
+ /// it's preferable to use the Main method provided by this class.
+ ///
+ ///
+ /// If called for the browser process (identified by no "type" command-line value) it will return immediately
+ /// with a value of -1. If called for a recognized secondary process it will block until the process should exit
+ /// and then return the process exit code.
+ /// ^ args)
+ {
+ auto subProcess = gcnew BrowserSubprocessExecutable();
+ return subProcess->Main(args, nullptr);
+ }
+#endif
+
+ ///
+ /// This function should be called from the application entry point function (typically Program.Main)
+ /// to execute a secondary process e.g. gpu, renderer, utility
+ /// This overload is specifically used for .Net Core. For hosting your own BrowserSubProcess
+ /// it's preferable to use the Main method provided by this class.
+ /// - Obtains the command line args via a call to Environment::GetCommandLineArgs
+ ///
+ ///
+ /// If called for the browser process (identified by no "type" command-line value) it will return immediately
+ /// with a value of -1. If called for a recognized secondary process it will block until the process should exit
+ /// and then return the process exit code.
+ /// Main(args, nullptr);
+ }
+
+ ///
+ /// This function should be called from the application entry point function (typically Program.Main)
+ /// to execute a secondary process e.g. gpu, renderer, utility
/// It can be used to run secondary processes (BrowserSubProcess) from your main applications executable
/// or from a separate executable specified by the CefSettings.BrowserSubprocessPath value.
/// CefSharp defaults to using the latter approach, a default implementation (CefSharp.BrowserSubProcess.exe) is
@@ -50,7 +88,7 @@ namespace CefSharp
///
/// This function should be called from the application entry point function (typically Program.Main)
- /// to execute a secondary process e.g. gpu, plugin, renderer, utility
+ /// to execute a secondary process e.g. gpu, renderer, utility
/// It can be used to run secondary processes (BrowserSubProcess) from your main applications executable
/// or from a separate executable specified by the CefSettings.BrowserSubprocessPath value.
/// CefSharp defaults to using the latter approach, a default implementation (CefSharp.BrowserSubProcess.exe) is
@@ -67,12 +105,31 @@ namespace CefSharp
{
auto type = CommandLineArgsParser::GetArgumentValue(args, CefSharpArguments::SubProcessTypeArgument);
+ if (String::IsNullOrEmpty(type))
+ {
+ //If --type param missing from command line CEF/Chromium assums
+ //this is the main process (as all subprocesses must have a type param).
+ //Return -1 to indicate this behaviour.
+ return -1;
+ }
+
auto parentProcessId = -1;
// The Crashpad Handler doesn't have any HostProcessIdArgument, so we must not try to
// parse it lest we want an ArgumentNullException.
- if (type != "crashpad-handler")
+ if (type == "crashpad-handler")
{
+ //Lower the shutdown priority so the browser process is shutdown first (Issue #3155)
+ //The system terminates the process without displaying a retry dialog box for the user.
+ //Crashpad is lower than other sub processes so it can still monitor process exit crashes.
+ SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY);
+ }
+ else
+ {
+ //Lower the shutdown priority so the browser process is shutdown first (Issue #3155)
+ //The system terminates the process without displaying a retry dialog box for the user.
+ SetProcessShutdownParameters(0x200, SHUTDOWN_NORETRY);
+
parentProcessId = int::Parse(CommandLineArgsParser::GetArgumentValue(args, CefSharpArguments::HostProcessIdArgument));
if (CommandLineArgsParser::HasArgument(args, CefSharpArguments::ExitIfParentProcessClosed))
{
diff --git a/CefSharp.BrowserSubprocess.Core/Cef.h b/CefSharp.BrowserSubprocess.Core/Cef.h
new file mode 100644
index 0000000000..61187e8762
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Cef.h
@@ -0,0 +1,34 @@
+// Copyright © 2020 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 "include\cef_v8.h"
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ ///
+ /// Global CEF methods are exposed through this class. e.g. CefRegisterExtension maps to Cef.RegisterExtension
+ /// Only methods relevant to the Render Process are included in this class.
+ /// CEF API Doc https://magpcss.org/ceforum/apidocs3/projects/(default)/(_globals).html
+ /// This class cannot be inherited.
+ ///
+ public ref class Cef sealed
+ {
+ public:
+ ///
+ /// Register a new V8 extension with the specified JavaScript extension code.
+ ///
+ /// name
+ /// JavaScript code
+ static void RegisterExtension(String^ name, String^ javascriptCode)
+ {
+ CefRegisterExtension(StringUtils::ToNative(name), StringUtils::ToNative(javascriptCode), nullptr);
+ }
+ };
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp
index e2d0f91670..05ec2fbefc 100644
--- a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp
+++ b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp
@@ -12,683 +12,816 @@
#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"
-#include "..\CefSharp.Core\Internals\Messaging\Messages.h"
-#include "..\CefSharp.Core\Internals\Serialization\Primitives.h"
+#include "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
+#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
+#include
using namespace System;
using namespace System::Diagnostics;
using namespace System::Collections::Generic;
-using namespace CefSharp::BrowserSubprocess;
+using namespace CefSharp::BrowserSubprocess::Serialization;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
- 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;"
- "})();";
-
- CefRefPtr CefAppUnmanagedWrapper::GetRenderProcessHandler()
+ namespace BrowserSubprocess
{
- return this;
- };
+ 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 CefAppUnmanagedWrapper::GetRenderProcessHandler()
+ {
+ return this;
+ };
- // CefRenderProcessHandler
- void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr browser, CefRefPtr extraInfo)
- {
- auto wrapper = gcnew CefBrowserWrapper(browser);
- _onBrowserCreated->Invoke(wrapper);
+ // CefRenderProcessHandler
+ void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr browser, CefRefPtr extraInfo)
+ {
+ auto wrapper = gcnew CefBrowserWrapper(browser);
+ _onBrowserCreated->Invoke(wrapper);
- //Multiple CefBrowserWrappers created when opening popups
- _browserWrappers->TryAdd(browser->GetIdentifier(), wrapper);
+ //Multiple CefBrowserWrappers created when opening popups
+ auto browserId = browser->GetIdentifier();
+ _browserWrappers->TryAdd(browserId, wrapper);
- //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");
+ static gcroot^> factory =
+ gcnew Func(CefAppUnmanagedWrapper::JavascriptBindingSettingsFactory);
+
+ auto javascriptBindingSettings = _browserJavascriptBindingSettings->GetOrAdd(browserId, factory);
- if (_legacyBindingEnabled)
+ if (!extraInfo.get())
{
- auto objects = extraInfo->GetList("LegacyBindingObjects");
- if (objects.get() && objects->IsValid())
- {
- auto javascriptObjects = DeserializeJsObjects(objects, 0);
+ return;
+ }
- for each (JavascriptObject^ obj in Enumerable::OfType(javascriptObjects))
+ //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())
+ {
+ javascriptBindingSettings->LegacyBindingEnabled = extraInfo->GetBool("LegacyBindingEnabled");
+
+ if (javascriptBindingSettings->LegacyBindingEnabled)
+ {
+ auto objects = extraInfo->GetList("LegacyBindingObjects");
+ if (objects.get() && objects->IsValid())
{
- //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
- //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))
+ auto javascriptObjects = DeserializeJsObjects(objects, 0);
+
+ for each (JavascriptObject ^ obj in Enumerable::OfType(javascriptObjects))
{
- _javascriptObjects->Remove(obj->JavascriptName);
+ //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
+ //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);
}
- _javascriptObjects->Add(obj->JavascriptName, obj);
}
}
}
- }
- }
- void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr browser)
- {
- CefBrowserWrapper^ wrapper;
- if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
- {
- _onBrowserDestroyed->Invoke(wrapper);
- delete wrapper;
- }
- };
+ if (extraInfo->HasKey("JavascriptBindingApiEnabled"))
+ {
+ javascriptBindingSettings->JavascriptBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
+ }
- void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context)
- {
- if (!Object::ReferenceEquals(_handler, nullptr))
- {
- Browser browserWrapper(browser);
- Frame frameWrapper(frame);
- V8Context contextWrapper(context);
+ if (extraInfo->HasKey("JavascriptBindingApiHasAllowOrigins"))
+ {
+ javascriptBindingSettings->JavascriptBindingApiHasAllowOrigins = extraInfo->GetBool("JavascriptBindingApiHasAllowOrigins");
- _handler->OnContextCreated(%browserWrapper, %frameWrapper, %contextWrapper);
- }
+ if (javascriptBindingSettings->JavascriptBindingApiHasAllowOrigins)
+ {
+ auto allowOrigins = extraInfo->GetList("JavascriptBindingApiAllowOrigins");
+ if (allowOrigins.get() && allowOrigins->IsValid())
+ {
+ javascriptBindingSettings->JavascriptBindingApiAllowOrigins = allowOrigins->Copy();
+ }
+ }
+ }
- auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
+ if (extraInfo->HasKey("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
+ {
+ //TODO: Create constant for these and legacy binding strings above
+ javascriptBindingSettings->JavascriptBindingPropertyName = StringUtils::ToClr(extraInfo->GetString("JsBindingPropertyName"));
+ javascriptBindingSettings->JavascriptBindingPropertyNameCamelCase = StringUtils::ToClr(extraInfo->GetString("JsBindingPropertyNameCamelCase"));
+ }
+ }
- if (_legacyBindingEnabled)
+ void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr browser)
{
- if (_javascriptObjects->Count > 0 && rootObject != nullptr)
+ CefBrowserWrapper^ wrapper;
+ if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
{
- rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
+ _onBrowserDestroyed->Invoke(wrapper);
+ delete wrapper;
}
- }
- //TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
- auto global = context->GetGlobal();
- auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
-
- auto cefSharpObj = CefV8Value::CreateObject(NULL, NULL);
- global->SetValue("CefSharp", cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
-
- //We'll support both CefSharp and cefSharp, for those who prefer the JS style
- auto cefSharpObjCamelCase = CefV8Value::CreateObject(NULL, NULL);
- global->SetValue("cefSharp", cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
-
- //TODO: JSB: Split functions into their own classes
- //Browser wrapper is only used for BindObjectAsync
- auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
- 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));
-
- 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);
-
- 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);
-
- //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 browser, CefRefPtr frame, CefRefPtr context)
- {
- if (!Object::ReferenceEquals(_handler, nullptr))
+ // Don't remove javascript settings because cef is unreliable in calling OnBrowserCreated/OnBrowserDestroyed consistently:
+ // https://github.com/cefsharp/CefSharp/issues/5228
+ };
+
+ void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context)
{
- Browser browserWrapper(browser);
- Frame frameWrapper(frame);
- V8Context contextWrapper(context);
+ if (!Object::ReferenceEquals(_handler, nullptr))
+ {
+ Browser browserWrapper(browser);
+ Frame frameWrapper(frame);
+ V8Context contextWrapper(context);
- _handler->OnContextReleased(%browserWrapper, %frameWrapper, %contextWrapper);
- }
+ _handler->OnContextCreated(% browserWrapper, % frameWrapper, % contextWrapper);
+ }
- auto contextReleasedMessage = CefProcessMessage::Create(kOnContextReleasedRequest);
+ //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;
- frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextReleasedMessage);
+ JavascriptBindingSettings^ javascriptBindingSettings = nullptr;
+ _browserJavascriptBindingSettings->TryGetValue(browser->GetIdentifier(), javascriptBindingSettings);
- auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
+ if (!Object::ReferenceEquals(javascriptBindingSettings, nullptr))
+ {
+ auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
- //If we no longer have a browser wrapper reference then there's nothing we can do
- if (browserWrapper == nullptr)
- {
- return;
- }
+ if (javascriptBindingSettings->LegacyBindingEnabled)
+ {
+ if (_javascriptObjects->Count > 0 && rootObject != nullptr)
+ {
+ rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
+ }
+ }
- auto rootObjectWrappers = browserWrapper->JavascriptRootObjectWrappers;
+ if (IsJavascriptBindingApiAllowed(javascriptBindingSettings, 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 = !String::IsNullOrEmpty(javascriptBindingSettings->JavascriptBindingPropertyName);
+ auto createCefSharpObjCamelCase = !String::IsNullOrEmpty(javascriptBindingSettings->JavascriptBindingPropertyNameCamelCase);
+
+ 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(StringUtils::ToNative(javascriptBindingSettings->JavascriptBindingPropertyName), cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
+ }
- JavascriptRootObjectWrapper^ wrapper;
- if (rootObjectWrappers->TryRemove(frame->GetIdentifier(), wrapper))
- {
- delete wrapper;
- }
- };
+ 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(StringUtils::ToNative(javascriptBindingSettings->JavascriptBindingPropertyNameCamelCase), cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
+ }
+ }
+ }
- void CefAppUnmanagedWrapper::OnFocusedNodeChanged(CefRefPtr browser, CefRefPtr frame, CefRefPtr node)
- {
- if (!_focusedNodeChangedEnabled)
- {
- return;
- }
+ //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);
- auto focusedNodeChangedMessage = CefProcessMessage::Create(kOnFocusedNodeChanged);
- auto list = focusedNodeChangedMessage->GetArgumentList();
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextCreatedMessage);
+ };
- // 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())
+ void CefAppUnmanagedWrapper::OnContextReleased(CefRefPtr browser, CefRefPtr frame, CefRefPtr context)
{
- // True when a node exists, false if it doesn't.
- list->SetBool(0, true);
+ if (!Object::ReferenceEquals(_handler, nullptr))
+ {
+ Browser browserWrapper(browser);
+ Frame frameWrapper(frame);
+ V8Context contextWrapper(context);
+
+ _handler->OnContextReleased(% browserWrapper, % frameWrapper, % contextWrapper);
+ }
+
+ auto contextReleasedMessage = CefProcessMessage::Create(kOnContextReleasedRequest);
- // Store the tag name.
- list->SetString(1, node->GetElementTagName());
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextReleasedMessage);
- // Transfer the attributes in a Dictionary.
- auto attributes = CefDictionaryValue::Create();
- CefDOMNode::AttributeMap attributeMap;
- node->GetElementAttributes(attributeMap);
- for (auto iter : attributeMap)
+ auto rootObjectWrappers = _jsRootObjectWrappersByFrameId;
+
+ //If we no longer have a _jsRootObjectWrappersByFrameId reference then there's nothing we can do
+ if (Object::ReferenceEquals(rootObjectWrappers, nullptr))
{
- attributes->SetString(iter.first, iter.second);
+ return;
}
- list->SetDictionary(2, attributes);
- }
- else
+ JavascriptRootObjectWrapper^ wrapper;
+ if (rootObjectWrappers->TryRemove(StringUtils::ToClr(frame->GetIdentifier()), wrapper))
+ {
+ delete wrapper;
+ }
+ };
+
+ void CefAppUnmanagedWrapper::OnFocusedNodeChanged(CefRefPtr browser, CefRefPtr frame, CefRefPtr node)
{
- list->SetBool(0, false);
- }
+ if (!_focusedNodeChangedEnabled)
+ {
+ return;
+ }
- frame->SendProcessMessage(CefProcessId::PID_BROWSER, focusedNodeChangedMessage);
- }
+ auto focusedNodeChangedMessage = CefProcessMessage::Create(kOnFocusedNodeChanged);
+ auto list = focusedNodeChangedMessage->GetArgumentList();
- void CefAppUnmanagedWrapper::OnUncaughtException(CefRefPtr browser, CefRefPtr frame, CefRefPtr context, CefRefPtr exception, CefRefPtr stackTrace)
- {
- auto uncaughtExceptionMessage = CefProcessMessage::Create(kOnUncaughtException);
- auto list = uncaughtExceptionMessage->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);
- list->SetString(0, exception->GetMessage());
+ // Store the tag name.
+ list->SetString(1, node->GetElementTagName());
- auto frames = CefListValue::Create();
- for (auto i = 0; i < stackTrace->GetFrameCount(); i++)
- {
- auto frame = CefListValue::Create();
- auto frameArg = stackTrace->GetFrame(i);
+ // 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);
+ }
- frame->SetString(0, frameArg->GetFunctionName());
- frame->SetInt(1, frameArg->GetLineNumber());
- frame->SetInt(2, frameArg->GetColumn());
- frame->SetString(3, frameArg->GetScriptNameOrSourceURL());
+ list->SetDictionary(2, attributes);
+ }
+ else
+ {
+ list->SetBool(0, false);
+ }
- frames->SetList(i, frame);
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, focusedNodeChangedMessage);
}
- list->SetList(1, frames);
+ void CefAppUnmanagedWrapper::OnUncaughtException(CefRefPtr browser, CefRefPtr frame, CefRefPtr context, CefRefPtr exception, CefRefPtr stackTrace)
+ {
+ auto uncaughtExceptionMessage = CefProcessMessage::Create(kOnUncaughtException);
+ auto list = uncaughtExceptionMessage->GetArgumentList();
- frame->SendProcessMessage(CefProcessId::PID_BROWSER, uncaughtExceptionMessage);
- }
+ list->SetString(0, exception->GetMessage());
- JavascriptRootObjectWrapper^ CefAppUnmanagedWrapper::GetJsRootObjectWrapper(int browserId, int64 frameId)
- {
- auto browserWrapper = FindBrowserWrapper(browserId);
+ auto frames = CefListValue::Create();
+ for (auto i = 0; i < stackTrace->GetFrameCount(); i++)
+ {
+ auto stackTraceFrame = CefListValue::Create();
+ auto frameArg = stackTrace->GetFrame(i);
- if (browserWrapper == nullptr)
- {
- return nullptr;
- }
+ stackTraceFrame->SetString(0, frameArg->GetFunctionName());
+ stackTraceFrame->SetInt(1, frameArg->GetLineNumber());
+ stackTraceFrame->SetInt(2, frameArg->GetColumn());
+ stackTraceFrame->SetString(3, frameArg->GetScriptNameOrSourceURL());
+
+ frames->SetList(i, stackTraceFrame);
+ }
- auto rootObjectWrappers = browserWrapper->JavascriptRootObjectWrappers;
+ list->SetList(1, frames);
- JavascriptRootObjectWrapper^ rootObject;
- if (!rootObjectWrappers->TryGetValue(frameId, rootObject))
- {
- rootObject = gcnew JavascriptRootObjectWrapper(browserId, browserWrapper->BrowserProcess);
- rootObjectWrappers->TryAdd(frameId, rootObject);
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, uncaughtExceptionMessage);
}
- return rootObject;
- }
-
- CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId)
- {
- CefBrowserWrapper^ wrapper = nullptr;
+ JavascriptRootObjectWrapper^ CefAppUnmanagedWrapper::GetJsRootObjectWrapper(int browserId, const CefString& frameId)
+ {
+ auto rootObjectWrappers = _jsRootObjectWrappersByFrameId;
- _browserWrappers->TryGetValue(browserId, wrapper);
+ if (Object::ReferenceEquals(rootObjectWrappers, nullptr))
+ {
+ return nullptr;
+ }
- 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();
- }
+ auto frameIdClr = StringUtils::ToClr(frameId);
- return wrapper;
- }
+ 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);
+ }
- bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId sourceProcessId, CefRefPtr message)
- {
- auto handled = false;
- auto name = message->GetName();
- auto argList = message->GetArgumentList();
+ return rootObject;
+ }
- auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
- //Error handling for missing/closed browser
- if (browserWrapper == nullptr)
+ bool CefAppUnmanagedWrapper::IsJavascriptBindingApiAllowed(JavascriptBindingSettings^ javascriptBindingSettings, CefRefPtr frame)
{
- if (name == kJavascriptCallbackDestroyRequest ||
- name == kJavascriptRootObjectResponse ||
- name == kJavascriptAsyncMethodCallResponse)
+ if (javascriptBindingSettings == nullptr)
{
- //If we can't find the browser wrapper then we'll just
- //ignore this as it's likely already been disposed of
- return true;
+ return false;
}
- CefString responseName;
- if (name == kEvaluateJavascriptRequest)
+ if (!javascriptBindingSettings->JavascriptBindingApiEnabled)
{
- responseName = kEvaluateJavascriptResponse;
+ return false;
}
- else if (name == kJavascriptCallbackRequest)
+
+ if (!javascriptBindingSettings->JavascriptBindingApiHasAllowOrigins)
{
- responseName = kJavascriptCallbackResponse;
+ return true;
}
- else
+
+ auto allowOrigins = javascriptBindingSettings->JavascriptBindingApiAllowOrigins;
+ if (!allowOrigins.get())
{
- //TODO: Should be throw an exception here? It's likely that only a CefSharp developer would see this
- // when they added a new message and haven't yet implemented the render process functionality.
- throw gcnew Exception("Unsupported message type");
+ return false;
}
- auto callbackId = GetInt64(argList, 0);
- auto response = CefProcessMessage::Create(responseName);
- auto responseArgList = response->GetArgumentList();
- auto errorMessage = String::Format("Request BrowserId : {0} not found it's likely the browser is already closed", browser->GetIdentifier());
+ auto frameUrl = frame->GetURL();
- //success: false
- responseArgList->SetBool(0, false);
- SetInt64(responseArgList, 1, callbackId);
- responseArgList->SetString(2, StringUtils::ToNative(errorMessage));
- frame->SendProcessMessage(sourceProcessId, response);
+ CefURLParts frameUrlParts;
- return true;
+ 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(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;
}
- //these messages are roughly handled the same way
- if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest)
+ CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId)
{
- bool success = false;
- CefRefPtr result;
- CefString errorMessage;
- CefRefPtr response;
+ CefBrowserWrapper^ wrapper = nullptr;
- if (name == kEvaluateJavascriptRequest)
- {
- response = CefProcessMessage::Create(kEvaluateJavascriptResponse);
- }
- else
+ _browserWrappers->TryGetValue(browserId, wrapper);
+
+ if (wrapper == nullptr)
{
- response = CefProcessMessage::Create(kJavascriptCallbackResponse);
+ //TODO: Find the syntax for delcaring the native string directly
+ LOG(ERROR) << StringUtils::ToNative("Failed to identify BrowserWrapper in OnContextCreated BrowserId:" + browserId).ToString();
}
- //both messages have callbackId stored at index 0
- auto frameId = frame->GetIdentifier();
- int64 callbackId = GetInt64(argList, 0);
+ return wrapper;
+ }
+
+ bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId sourceProcessId, CefRefPtr message)
+ {
+ auto handled = false;
+ auto name = message->GetName();
+ auto argList = message->GetArgumentList();
- if (name == kEvaluateJavascriptRequest)
+ //these messages are roughly handled the same way
+ if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest)
{
- JavascriptRootObjectWrapper^ rootObjectWrapper;
- browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
+ bool sendResponse = true;
+ bool success = false;
+ CefRefPtr result;
+ CefString errorMessage;
+ CefRefPtr response;
- //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.
- if (rootObjectWrapper == nullptr)
+ if (name == kEvaluateJavascriptRequest)
{
- rootObjectWrapper = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier(), browserWrapper->BrowserProcess);
-
- browserWrapper->JavascriptRootObjectWrappers->TryAdd(frameId, rootObjectWrapper);
+ response = CefProcessMessage::Create(kEvaluateJavascriptResponse);
+ }
+ else
+ {
+ response = CefProcessMessage::Create(kJavascriptCallbackResponse);
}
- auto callbackRegistry = rootObjectWrapper->CallbackRegistry;
+ //both messages have callbackId stored at index 0
+ auto frameId = StringUtils::ToClr(frame->GetIdentifier());
+ int64_t callbackId = GetInt64(argList, 0);
- auto script = argList->GetString(1);
- auto scriptUrl = argList->GetString(2);
- auto startLine = argList->GetInt(3);
+ //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 (frame.get() && frame->IsValid())
+ if (name == kEvaluateJavascriptRequest)
{
- auto context = frame->GetV8Context();
+ auto script = argList->GetString(1);
+ auto scriptUrl = argList->GetString(2);
+ auto startLine = argList->GetInt(3);
- if (context.get() && context->Enter())
+ if (frame.get() && frame->IsValid())
{
- try
- {
- CefRefPtr exception;
- success = context->Eval(script, scriptUrl, startLine, result, exception);
+ auto context = frame->GetV8Context();
- //we need to do this here to be able to store the v8context
- if (success)
+ if (context.get() && context->Enter())
+ {
+ try
{
- auto responseArgList = response->GetArgumentList();
- SerializeV8Object(result, responseArgList, 2, callbackRegistry);
+ CefRefPtr 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);
+ }
}
- else
+ finally
{
- errorMessage = StringUtils::CreateExceptionString(exception);
+ context->Exit();
}
}
- finally
+ else
{
- context->Exit();
+ errorMessage = "Unable to Enter Context";
}
}
else
{
- errorMessage = "Unable to Enter Context";
+ errorMessage = StringUtils::ToNative("Frame " + frameId + " is no longer available, most likely the Frame has been Disposed or Removed.");
}
}
else
{
- errorMessage = StringUtils::ToNative("Frame " + frameId + " is no longer available, most likely the Frame has been Disposed or Removed.");
- }
- }
- else
- {
- JavascriptRootObjectWrapper^ rootObjectWrapper;
- browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
- 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)
+ auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
+ if (callbackRegistry == nullptr)
{
- errorMessage = StringUtils::ToNative("Unable to find JavascriptCallback with Id " + jsCallbackId + " for Frame " + frameId);
+ errorMessage = StringUtils::ToNative("The callback registry for Frame " + frameId + " is no longer available, most likely the Frame has been Disposed.");
}
else
{
- auto context = callbackWrapper->GetContext();
- auto value = callbackWrapper->GetValue();
+ auto jsCallbackId = GetInt64(argList, 1);
- if (context.get() && context->Enter())
+ auto callbackWrapper = callbackRegistry->FindWrapper(jsCallbackId);
+ if (callbackWrapper == nullptr)
{
- try
- {
- auto parameterList = argList->GetList(2);
- CefV8ValueList params;
+ errorMessage = StringUtils::ToNative("Unable to find JavascriptCallback with Id " + jsCallbackId + " for Frame " + frameId);
+ }
+ else
+ {
+ auto context = callbackWrapper->GetContext();
+ auto value = callbackWrapper->GetValue();
- //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++)
+ if (context.get() && context->Enter())
+ {
+ try
{
- params.push_back(DeserializeV8Object(parameterList, static_cast(i)));
- }
+ auto parameterList = argList->GetList(2);
+ CefV8ValueList params;
- result = value->ExecuteFunction(nullptr, params);
- success = result.get() != nullptr;
+ //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(i)));
+ }
- //we need to do this here to be able to store the v8context
- if (success)
- {
- auto responseArgList = response->GetArgumentList();
- SerializeV8Object(result, responseArgList, 2, callbackRegistry);
+ 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);
+ }
}
- else
+ finally
{
- auto exception = value->GetException();
- errorMessage = StringUtils::CreateExceptionString(exception);
+ context->Exit();
}
}
- finally
+ else
{
- context->Exit();
+ errorMessage = "Unable to Enter Context";
}
}
- else
- {
- errorMessage = "Unable to Enter Context";
- }
}
}
- }
- 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;
- browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frame->GetIdentifier(), rootObjectWrapper);
- if (rootObjectWrapper != nullptr && rootObjectWrapper->CallbackRegistry != nullptr)
+ if (sendResponse)
{
- rootObjectWrapper->CallbackRegistry->Deregister(jsCallbackId);
+ 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 == kJavascriptRootObjectResponse)
- {
- if (browser.get() && frame.get() && frame->IsValid())
+ handled = true;
+ }
+ else if (name == kJavascriptCallbackDestroyRequest)
{
- 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(javascriptObjects))
+ if (frame.get() && frame->IsValid())
{
- if (_javascriptObjects->ContainsKey(obj->JavascriptName))
+ auto jsCallbackId = GetInt64(argList, 0);
+ JavascriptRootObjectWrapper^ rootObjectWrapper;
+ _jsRootObjectWrappersByFrameId->TryGetValue(StringUtils::ToClr(frame->GetIdentifier()), rootObjectWrapper);
+ if (rootObjectWrapper != nullptr && rootObjectWrapper->CallbackRegistry != nullptr)
{
- _javascriptObjects->Remove(obj->JavascriptName);
+ rootObjectWrapper->CallbackRegistry->Deregister(jsCallbackId);
}
- _javascriptObjects->Add(obj->JavascriptName, obj);
}
- auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
-
- if (rootObject == nullptr)
+ handled = true;
+ }
+ else if (name == kJavascriptRootObjectResponse)
+ {
+ if (browser.get() && frame.get() && frame->IsValid())
{
- return false;
- }
+ auto callbackId = GetInt64(argList, 0);
+ auto javascriptObjects = DeserializeJsObjects(argList, 1);
- auto context = frame->GetV8Context();
+ //Caching of JavascriptObjects
+ //TODO: JSB Should caching be configurable? On a per object basis?
+ for each (JavascriptObject ^ obj in Enumerable::OfType(javascriptObjects))
+ {
+ if (_javascriptObjects->ContainsKey(obj->JavascriptName))
+ {
+ _javascriptObjects->Remove(obj->JavascriptName);
+ }
+ _javascriptObjects->Add(obj->JavascriptName, obj);
+ }
- if (context.get() && context->Enter())
- {
- JavascriptAsyncMethodCallback^ callback;
+ auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
- try
+ if (rootObject == nullptr)
{
- rootObject->Bind(javascriptObjects, context->GetGlobal());
+ return false;
+ }
- if (_registerBoundObjectRegistry->TryGetAndRemoveMethodCallback(callbackId, callback))
- {
- //Response object has no Accessor or Interceptor
- auto response = CefV8Value::CreateObject(NULL, NULL);
+ auto context = frame->GetV8Context();
- response->SetValue("Count", CefV8Value::CreateInt(javascriptObjects->Count), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
+ if (context.get() && context->Enter())
+ {
+ JavascriptAsyncMethodCallback^ callback;
- 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
+ try
+ {
+ rootObject->Bind(javascriptObjects, context->GetGlobal());
+
+ if (_registerBoundObjectRegistry->TryGetAndRemoveMethodCallback(callbackId, callback))
{
- 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);
- }
+ //Response object has no Accessor or Interceptor
+ auto response = CefV8Value::CreateObject(nullptr, nullptr);
+
+ response->SetValue("Count", CefV8Value::CreateInt(javascriptObjects->Count), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
- //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();
+ 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);
+ }
- auto boundObjects = CefListValue::Create();
+ //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();
- for (auto i = 0; i < javascriptObjects->Count; i++)
- {
- auto dict = CefDictionaryValue::Create();
- auto name = javascriptObjects[i]->JavascriptName;
- dict->SetString("Name", StringUtils::ToNative(name));
- dict->SetBool("IsCached", false);
- dict->SetBool("AlreadyBound", false);
+ auto boundObjects = CefListValue::Create();
- boundObjects->SetDictionary(i, dict);
- }
+ auto i = 0;
+
+ for each (auto jsObject in javascriptObjects)
+ {
+ auto dict = CefDictionaryValue::Create();
+ auto objectName = jsObject->JavascriptName;
+ dict->SetString("Name", StringUtils::ToNative(objectName));
+ dict->SetBool("IsCached", false);
+ dict->SetBool("AlreadyBound", false);
+
+ boundObjects->SetDictionary(i++, dict);
+ }
- args->SetList(0, boundObjects);
+ args->SetList(0, boundObjects);
- frame->SendProcessMessage(CefProcessId::PID_BROWSER, msg);
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, msg);
+ }
}
- }
- finally
- {
- context->Exit();
+ finally
+ {
+ context->Exit();
- delete callback;
+ delete callback;
+ }
}
}
- }
- else
- {
- LOG(INFO) << "CefAppUnmanagedWrapper Frame Invalid";
- }
+ else
+ {
+ LOG(INFO) << "CefAppUnmanagedWrapper Frame Invalid";
+ }
- handled = true;
- }
- else if (name == kJavascriptAsyncMethodCallResponse)
- {
- if (frame.get() && frame->IsValid())
+ handled = true;
+ }
+ else if (name == kJavascriptAsyncMethodCallResponse)
{
- auto frameId = frame->GetIdentifier();
- auto callbackId = GetInt64(argList, 0);
+ if (frame.get() && frame->IsValid())
+ {
+ auto frameId = StringUtils::ToClr(frame->GetIdentifier());
+ auto callbackId = GetInt64(argList, 0);
- JavascriptRootObjectWrapper^ rootObjectWrapper;
- browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
+ JavascriptRootObjectWrapper^ rootObjectWrapper;
+ _jsRootObjectWrappersByFrameId->TryGetValue(frameId, rootObjectWrapper);
- if (rootObjectWrapper != nullptr)
- {
- JavascriptAsyncMethodCallback^ callback;
- if (rootObjectWrapper->TryGetAndRemoveMethodCallback(callbackId, callback))
+ if (rootObjectWrapper != nullptr)
{
- try
+ JavascriptAsyncMethodCallback^ callback;
+ if (rootObjectWrapper->TryGetAndRemoveMethodCallback(callbackId, callback))
{
- auto context = frame->GetV8Context();
-
- if (context.get() && context->Enter())
+ try
{
- try
+ auto context = frame->GetV8Context();
+
+ if (context.get() && context->Enter())
{
- auto success = argList->GetBool(1);
- if (success)
+ try
{
- callback->Success(DeserializeV8Object(argList, 2));
+ auto success = argList->GetBool(1);
+ if (success)
+ {
+ callback->Success(DeserializeV8Object(argList, 2));
+ }
+ else
+ {
+ callback->Fail(argList->GetString(2));
+ }
}
- else
+ finally
{
- callback->Fail(argList->GetString(2));
+ context->Exit();
}
}
- finally
+ else
{
- context->Exit();
+ callback->Fail("Unable to Enter Context");
}
}
- else
+ finally
{
- callback->Fail("Unable to Enter Context");
+ //dispose
+ delete callback;
}
}
- finally
- {
- //dispose
- delete callback;
- }
}
}
+ handled = true;
}
- handled = true;
- }
- return handled;
- };
+ return handled;
+ };
- void CefAppUnmanagedWrapper::OnRenderThreadCreated(CefRefPtr extraInfo)
- {
- //Check to see if we have a list
- if (extraInfo.get())
+ void CefAppUnmanagedWrapper::OnWebKitInitialized()
{
- auto extensionList = extraInfo->GetList(0);
- if (extensionList.get())
+ if (!Object::ReferenceEquals(_handler, nullptr))
{
- for (size_t i = 0; i < extensionList->GetSize(); i++)
- {
- auto extension = extensionList->GetList(i);
- auto ext = gcnew V8Extension(StringUtils::ToClr(extension->GetString(0)), StringUtils::ToClr(extension->GetString(1)));
-
- _extensions->Add(ext);
- }
+ _handler->OnWebKitInitialized();
}
}
}
-
- void CefAppUnmanagedWrapper::OnWebKitInitialized()
- {
- for each(V8Extension^ extension in _extensions->AsReadOnly())
- {
- //only support extensions without handlers now
- CefRegisterExtension(StringUtils::ToNative(extension->Name), StringUtils::ToNative(extension->JavascriptCode), NULL);
- }
- }
}
diff --git a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h
index 5739ef9a84..a6d90755d1 100644
--- a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h
@@ -9,6 +9,7 @@
#include "SubProcessApp.h"
#include "CefBrowserWrapper.h"
+#include "JavascriptBindingSettings.h"
#include "RegisterBoundObjectRegistry.h"
using namespace System::Collections::Generic;
@@ -16,69 +17,98 @@ using namespace CefSharp::RenderProcess;
namespace CefSharp
{
- // This class is the native subprocess level CEF object wrapper.
- private class CefAppUnmanagedWrapper : SubProcessApp, CefRenderProcessHandler
+ namespace BrowserSubprocess
{
- private:
- gcroot _handler;
- gcroot^> _onBrowserCreated;
- gcroot^> _onBrowserDestroyed;
- gcroot^> _browserWrappers;
- gcroot^> _extensions;
- bool _focusedNodeChangedEnabled;
- bool _legacyBindingEnabled;
+ // This class is the native subprocess level CEF object wrapper.
+ private class CefAppUnmanagedWrapper : SubProcessApp, CefRenderProcessHandler
+ {
+ private:
+ gcroot _handler;
+ gcroot^> _onBrowserCreated;
+ gcroot^> _onBrowserDestroyed;
+ gcroot^> _browserWrappers;
+ gcroot^> _browserJavascriptBindingSettings;
+ gcroot^> _jsRootObjectWrappersByFrameId;
+ bool _focusedNodeChangedEnabled;
- // The serialized registered object data waiting to be used.
- gcroot^> _javascriptObjects;
+ // The serialized registered object data waiting to be used.
+ gcroot^> _javascriptObjects;
- gcroot _registerBoundObjectRegistry;
+ gcroot _registerBoundObjectRegistry;
- public:
- static const CefString kPromiseCreatorScript;
+ static bool IsJavascriptBindingApiAllowed(JavascriptBindingSettings^ javascriptBindingSettings, CefRefPtr frame);
- CefAppUnmanagedWrapper(IRenderProcessHandler^ handler, List^ schemes, bool enableFocusedNodeChanged, Action^ onBrowserCreated, Action^ onBrowserDestroyed) : SubProcessApp(schemes)
- {
- _handler = handler;
- _onBrowserCreated = onBrowserCreated;
- _onBrowserDestroyed = onBrowserDestroyed;
- _browserWrappers = gcnew ConcurrentDictionary();
- _extensions = gcnew List();
- _focusedNodeChangedEnabled = enableFocusedNodeChanged;
- _javascriptObjects = gcnew Dictionary();
- _registerBoundObjectRegistry = gcnew RegisterBoundObjectRegistry();
- _legacyBindingEnabled = false;
- }
-
- ~CefAppUnmanagedWrapper()
- {
- if (!Object::ReferenceEquals(_browserWrappers, nullptr))
+ static JavascriptBindingSettings^ JavascriptBindingSettingsFactory(int _)
{
- for each(CefBrowserWrapper^ browser in Enumerable::OfType(_browserWrappers))
+ return gcnew JavascriptBindingSettings();
+ }
+
+ public:
+ static const CefString kPromiseCreatorScript;
+
+ CefAppUnmanagedWrapper(IRenderProcessHandler^ handler, List^ schemes, bool enableFocusedNodeChanged, Action^ onBrowserCreated, Action^ onBrowserDestroyed) : SubProcessApp(schemes)
+ {
+ _handler = handler;
+ _onBrowserCreated = onBrowserCreated;
+ _onBrowserDestroyed = onBrowserDestroyed;
+ _browserWrappers = gcnew ConcurrentDictionary();
+ _browserJavascriptBindingSettings = gcnew ConcurrentDictionary();
+ _jsRootObjectWrappersByFrameId = gcnew ConcurrentDictionary();
+ _focusedNodeChangedEnabled = enableFocusedNodeChanged;
+ _javascriptObjects = gcnew Dictionary();
+ _registerBoundObjectRegistry = gcnew RegisterBoundObjectRegistry();
+ }
+
+ ~CefAppUnmanagedWrapper()
+ {
+ if (!Object::ReferenceEquals(_browserWrappers, nullptr))
+ {
+ for each (CefBrowserWrapper ^ browser in _browserWrappers->Values)
+ {
+ delete browser;
+ }
+
+ _browserWrappers = nullptr;
+ }
+
+ if (!Object::ReferenceEquals(_browserJavascriptBindingSettings, nullptr))
{
- delete browser;
+ for each (JavascriptBindingSettings ^ javascriptBindingSettings in _browserJavascriptBindingSettings->Values)
+ {
+ delete javascriptBindingSettings;
+ }
+
+ _browserJavascriptBindingSettings = nullptr;
}
- _browserWrappers = nullptr;
+ if (!Object::ReferenceEquals(_jsRootObjectWrappersByFrameId, nullptr))
+ {
+ for each (JavascriptRootObjectWrapper^ rootObject in _jsRootObjectWrappersByFrameId->Values)
+ {
+ delete rootObject;
+ }
+
+ _jsRootObjectWrappersByFrameId = nullptr;
+ }
+
+ delete _onBrowserCreated;
+ delete _onBrowserDestroyed;
}
- delete _onBrowserCreated;
- delete _onBrowserDestroyed;
- delete _extensions;
- }
-
- CefBrowserWrapper^ FindBrowserWrapper(int browserId);
- JavascriptRootObjectWrapper^ GetJsRootObjectWrapper(int browserId, int64 frameId);
-
- virtual DECL CefRefPtr GetRenderProcessHandler() OVERRIDE;
- virtual DECL void OnBrowserCreated(CefRefPtr browser, CefRefPtr extraInfo) OVERRIDE;
- virtual DECL void OnBrowserDestroyed(CefRefPtr browser) OVERRIDE;
- virtual DECL void OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) OVERRIDE;
- virtual DECL void OnContextReleased(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) OVERRIDE;
- virtual DECL bool OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId sourceProcessId, CefRefPtr message) OVERRIDE;
- virtual DECL void OnRenderThreadCreated(CefRefPtr extraInfo) OVERRIDE;
- virtual DECL void OnWebKitInitialized() OVERRIDE;
- virtual DECL void OnFocusedNodeChanged(CefRefPtr browser, CefRefPtr frame, CefRefPtr node) OVERRIDE;
- virtual DECL void OnUncaughtException(CefRefPtr browser, CefRefPtr frame, CefRefPtr context, CefRefPtr exception, CefRefPtr stackTrace) OVERRIDE;
-
- IMPLEMENT_REFCOUNTING(CefAppUnmanagedWrapper);
- };
+
+ CefBrowserWrapper^ FindBrowserWrapper(int browserId);
+ JavascriptRootObjectWrapper^ GetJsRootObjectWrapper(int browserId, const CefString& frameId);
+
+ virtual DECL CefRefPtr GetRenderProcessHandler() override;
+ virtual DECL void OnBrowserCreated(CefRefPtr browser, CefRefPtr extraInfo) override;
+ virtual DECL void OnBrowserDestroyed(CefRefPtr browser) override;
+ virtual DECL void OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) override;
+ virtual DECL void OnContextReleased(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) override;
+ virtual DECL bool OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId sourceProcessId, CefRefPtr message) override;
+ virtual DECL void OnWebKitInitialized() override;
+ virtual DECL void OnFocusedNodeChanged(CefRefPtr browser, CefRefPtr frame, CefRefPtr node) override;
+ virtual DECL void OnUncaughtException(CefRefPtr browser, CefRefPtr frame, CefRefPtr context, CefRefPtr exception, CefRefPtr stackTrace) override;
+
+ IMPLEMENT_REFCOUNTINGM(CefAppUnmanagedWrapper);
+ };
+ }
}
diff --git a/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h b/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h
index 33b226b74f..934725eaeb 100644
--- a/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h
@@ -11,61 +11,51 @@
#include "Stdafx.h"
#include "JavascriptRootObjectWrapper.h"
-using namespace CefSharp::Internals::Async;
+using namespace CefSharp::BrowserSubprocess::Async;
+#ifndef NETCOREAPP
using namespace System::ServiceModel;
+#endif
using namespace System::Threading;
using namespace System::Threading::Tasks;
namespace CefSharp
{
- // "Master class" for wrapping everything that the Cef Subprocess needs
- // for ONE CefBrowser.
- public ref class CefBrowserWrapper
+ namespace BrowserSubprocess
{
- private:
- MCefRefPtr _cefBrowser;
-
- internal:
- //Frame Identifier is used as Key
- property ConcurrentDictionary^ JavascriptRootObjectWrappers;
-
- public:
- CefBrowserWrapper(CefRefPtr cefBrowser)
- {
- _cefBrowser = cefBrowser;
- BrowserId = cefBrowser->GetIdentifier();
- IsPopup = cefBrowser->IsPopup();
-
- JavascriptRootObjectWrappers = gcnew ConcurrentDictionary();
- }
-
- !CefBrowserWrapper()
- {
- _cefBrowser = nullptr;
- }
-
- ~CefBrowserWrapper()
+ // "Master class" for wrapping everything that the Cef Subprocess needs
+ // for ONE CefBrowser.
+ public ref class CefBrowserWrapper
{
- this->!CefBrowserWrapper();
+ private:
+ MCefRefPtr _cefBrowser;
- if (JavascriptRootObjectWrappers != nullptr)
+ public:
+ CefBrowserWrapper(const CefRefPtr &cefBrowser)
{
- for each(KeyValuePair entry in JavascriptRootObjectWrappers)
- {
- delete entry.Value;
- }
-
- JavascriptRootObjectWrappers = nullptr;
+ _cefBrowser = cefBrowser.get();
+ BrowserId = cefBrowser->GetIdentifier();
+ IsPopup = cefBrowser->IsPopup();
}
- }
- property int BrowserId;
- property bool IsPopup;
+ !CefBrowserWrapper()
+ {
+ _cefBrowser = nullptr;
+ }
- // This allows us to create the WCF proxies back to our parent process.
- property ChannelFactory^ ChannelFactory;
+ ~CefBrowserWrapper()
+ {
+ this->!CefBrowserWrapper();
+ }
- // The WCF proxy to the parent process.
- property IBrowserProcess^ BrowserProcess;
- };
+ property int BrowserId;
+ property bool IsPopup;
+
+#ifndef NETCOREAPP
+ // This allows us to create the WCF proxies back to our parent process.
+ property ChannelFactory^ ChannelFactory;
+ // The WCF proxy to the parent process.
+ property IBrowserProcess^ BrowserProcess;
+#endif
+ };
+ }
}
diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.netcore.filters b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.netcore.filters
new file mode 100644
index 0000000000..adeeecfd00
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.netcore.filters
@@ -0,0 +1,200 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.netcore.vcxproj b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.netcore.vcxproj
new file mode 100644
index 0000000000..78021a1d08
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.netcore.vcxproj
@@ -0,0 +1,351 @@
+
+
+
+
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Debug
+ arm64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+ Release
+ arm64
+
+
+
+ 16.0
+ {6C4BB501-2F8E-48AC-9AB5-8CFB2D74185C}
+ CefSharp.BrowserSubprocess.Core
+ CefSharpBrowserSubprocessCore
+ NetCoreCProj
+ net6.0
+ 10.0
+ 10.0.10240.0
+
+
+
+
+ DynamicLibrary
+ true
+ NetCore
+ Unicode
+
+
+ DynamicLibrary
+ true
+ NetCore
+ Unicode
+
+
+ DynamicLibrary
+ true
+ NetCore
+ Unicode
+
+
+ DynamicLibrary
+ false
+ NetCore
+ Unicode
+
+
+ DynamicLibrary
+ false
+ NetCore
+ Unicode
+
+
+ DynamicLibrary
+ false
+ NetCore
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ ..\CefSharp.snk
+ true
+ bin.netcore\$(Platform)\$(Configuration)\
+ obj.netcore\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
+
+
+ true
+ ..\CefSharp.snk
+ true
+ bin.netcore\$(Platform)\$(Configuration)\
+ obj.netcore\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
+
+
+ true
+ ..\CefSharp.snk
+ true
+ bin.netcore\$(Platform)\$(Configuration)\
+ obj.netcore\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
+
+
+ false
+ ..\CefSharp.snk
+ bin.netcore\$(Platform)\$(Configuration)\
+ obj.netcore\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
+
+
+ false
+ ..\CefSharp.snk
+ bin.netcore\$(Platform)\$(Configuration)\
+ obj.netcore\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
+
+
+ false
+ ..\CefSharp.snk
+ bin.netcore\$(Platform)\$(Configuration)\
+ obj.netcore\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
+
+
+
+ Level3
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;%(AdditionalIncludeDirectories);$(ProjectDir)
+ Disabled
+ _DEBUG;EXPORT;NETCOREAPP;%(PreprocessorDefinitions)
+ Use
+ true
+ true
+ stdcpp20
+ CompileAsCpp
+
+
+ true
+ libcef.lib;libcef_dll_wrapper.lib;User32.lib
+ $(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration);$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration)\VS$(VisualStudioProductVersion);
+ /ignore:4099 %(AdditionalOptions)
+
+
+ Assembly.manifest
+
+
+
+
+ Level3
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;%(AdditionalIncludeDirectories);$(ProjectDir)
+ Disabled
+ _DEBUG;EXPORT;NETCOREAPP;%(PreprocessorDefinitions)
+ Use
+ true
+ stdcpp20
+ CompileAsCpp
+
+
+ true
+ libcef.lib;libcef_dll_wrapper.lib;User32.lib
+ $(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration);$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration)\VS$(VisualStudioProductVersion);
+ /ignore:4099 %(AdditionalOptions)
+
+
+ Assembly.manifest
+
+
+
+
+ Level3
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;%(AdditionalIncludeDirectories);$(ProjectDir)
+ Disabled
+ _DEBUG;EXPORT;NETCOREAPP;%(PreprocessorDefinitions)
+ Use
+ true
+ stdcpp20
+ CompileAsCpp
+
+
+ true
+ libcef.lib;libcef_dll_wrapper.lib;User32.lib
+ $(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration);$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration)\VS$(VisualStudioProductVersion);
+ /ignore:4099 %(AdditionalOptions)
+
+
+ Assembly.manifest
+
+
+
+
+ Level3
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;%(AdditionalIncludeDirectories);$(ProjectDir)
+ NDEBUG;EXPORT;NETCOREAPP;%(PreprocessorDefinitions)
+ Use
+ true
+ true
+ stdcpp20
+ CompileAsCpp
+
+
+ true
+ libcef.lib;libcef_dll_wrapper.lib
+ $(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration);$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration)\VS$(VisualStudioProductVersion)
+
+
+ Assembly.manifest
+
+
+
+
+ Level3
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;%(AdditionalIncludeDirectories);$(ProjectDir)
+ NDEBUG;EXPORT;NETCOREAPP;%(PreprocessorDefinitions)
+ Use
+ true
+ stdcpp20
+ CompileAsCpp
+
+
+ true
+ libcef.lib;libcef_dll_wrapper.lib
+ $(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration);$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration)\VS$(VisualStudioProductVersion)
+
+
+ Assembly.manifest
+
+
+
+
+ Level3
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;%(AdditionalIncludeDirectories);$(ProjectDir)
+ NDEBUG;EXPORT;NETCOREAPP;%(PreprocessorDefinitions)
+ Use
+ true
+ stdcpp20
+ CompileAsCpp
+
+
+ true
+ libcef.lib;libcef_dll_wrapper.lib
+ $(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration);$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration)\VS$(VisualStudioProductVersion)
+
+
+ Assembly.manifest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+ {39E385AD-DC5C-451E-B061-09AF3EE038EB}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj
index 63585f5d91..547f08538d 100644
--- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj
+++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj
@@ -1,6 +1,9 @@
-
+
+
+
+
Debug
@@ -23,10 +26,11 @@
{6C4BB501-2F8E-48AC-9AB5-8CFB2D74185C}
ManagedCProj
CefSharpBrowserSubprocessCore
- v4.5.2
+ v4.6.2
+ 10.0
-
+
DynamicLibrary
true
@@ -106,10 +110,12 @@
Use
true
true
+ stdcpp20
+ CompileAsCpp
true
- libcef.lib;libcef_dll_wrapper.lib
+ libcef.lib;libcef_dll_wrapper.lib;User32.lib
$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration);$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration)\VS$(VisualStudioProductVersion);
/ignore:4099 %(AdditionalOptions)
@@ -122,10 +128,12 @@
WIN32;_DEBUG;EXPORT;%(PreprocessorDefinitions)
Use
true
+ stdcpp20
+ CompileAsCpp
true
- libcef.lib;libcef_dll_wrapper.lib
+ libcef.lib;libcef_dll_wrapper.lib;User32.lib
$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration);$(SolutionDir)packages\$(CefSdkVer)\CEF\$(Platform)\$(Configuration)\VS$(VisualStudioProductVersion);
/ignore:4099 %(AdditionalOptions)
@@ -138,6 +146,8 @@
Use
true
true
+ stdcpp20
+ CompileAsCpp
true
@@ -152,6 +162,8 @@
WIN32;NDEBUG;EXPORT;%(PreprocessorDefinitions)
Use
true
+ stdcpp20
+ CompileAsCpp
true
@@ -167,13 +179,19 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -206,8 +224,8 @@
-
-
+
+
@@ -242,8 +260,12 @@
-
+
-
+
+
+
+
+
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters
index d8aee10e1e..8b695aad3e 100644
--- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters
+++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters
@@ -32,10 +32,10 @@
Header Files
-
+
Header Files
-
+
Header Files
@@ -56,10 +56,7 @@
Header Files
-
- Header Files
-
-
+
Header Files
@@ -77,7 +74,7 @@
Header Files
-
+
Header Files
@@ -116,6 +113,21 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
@@ -148,7 +160,7 @@
Source Files
-
+
Source Files
@@ -166,7 +178,7 @@
Source Files
-
+
Source Files
@@ -187,11 +199,14 @@
Header Files
+
+ Source Files
+
-
+
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptBindingSettings.h b/CefSharp.BrowserSubprocess.Core/JavascriptBindingSettings.h
new file mode 100644
index 0000000000..a30dd30de0
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptBindingSettings.h
@@ -0,0 +1,55 @@
+// Copyright © 2013 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 "include/cef_v8.h"
+
+#include "Stdafx.h"
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ private ref class JavascriptBindingSettings
+ {
+ private:
+ MCefRefPtr _javascriptBindingApiAllowOrigins;
+
+ public:
+ JavascriptBindingSettings()
+ {
+ LegacyBindingEnabled = false;
+ JavascriptBindingApiEnabled = true;
+ JavascriptBindingPropertyName = "CefSharp";
+ JavascriptBindingPropertyNameCamelCase = "cefSharp";
+ JavascriptBindingApiHasAllowOrigins = false;
+ JavascriptBindingApiAllowOrigins = nullptr;
+ }
+
+ !JavascriptBindingSettings()
+ {
+ _javascriptBindingApiAllowOrigins = nullptr;
+ }
+
+ ~JavascriptBindingSettings()
+ {
+ this->!JavascriptBindingSettings();
+ }
+
+ property bool LegacyBindingEnabled;
+ property bool JavascriptBindingApiEnabled;
+
+ property String^ JavascriptBindingPropertyName;
+ property String^ JavascriptBindingPropertyNameCamelCase;
+
+ property bool JavascriptBindingApiHasAllowOrigins;
+ property CefRefPtr JavascriptBindingApiAllowOrigins
+ {
+ CefRefPtr get() { return _javascriptBindingApiAllowOrigins.get(); }
+ void set(CefRefPtr value) { _javascriptBindingApiAllowOrigins = value.get(); }
+ }
+ };
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.cpp b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.cpp
index e8fa646943..a9389a9ca9 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.cpp
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.cpp
@@ -6,10 +6,11 @@
#include "JavascriptCallbackRegistry.h"
using namespace System::Threading;
+using namespace CefSharp::BrowserSubprocess;
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
JavascriptCallback^ JavascriptCallbackRegistry::Register(const CefRefPtr& context, const CefRefPtr& value)
{
@@ -17,14 +18,15 @@ namespace CefSharp
JavascriptCallbackWrapper^ wrapper = gcnew JavascriptCallbackWrapper(value, context);
_callbacks->TryAdd(newId, wrapper);
+
auto result = gcnew JavascriptCallback();
result->Id = newId;
- result->BrowserId = _browserId;
- result->FrameId = context->GetFrame()->GetIdentifier();
+ result->BrowserId = context->GetBrowser()->GetIdentifier();
+ result->FrameId = StringUtils::ToClr(context->GetFrame()->GetIdentifier());
return result;
}
- JavascriptCallbackWrapper^ JavascriptCallbackRegistry::FindWrapper(int64 id)
+ JavascriptCallbackWrapper^ JavascriptCallbackRegistry::FindWrapper(int64_t id)
{
JavascriptCallbackWrapper^ callback;
_callbacks->TryGetValue(id, callback);
@@ -41,4 +43,4 @@ namespace CefSharp
}
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.h b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.h
index 6d31c82251..b2872055a9 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.h
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.h
@@ -7,10 +7,11 @@
#include "JavascriptCallbackWrapper.h"
using namespace System::Collections::Concurrent;
+using namespace CefSharp::BrowserSubprocess;
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
private ref class JavascriptCallbackRegistry
{
@@ -19,14 +20,13 @@ namespace CefSharp
//Is static so ids are unique to this process, which is required until #1984 is implemented
//and callbacks are disposed of properly between contexts
static Int64 _lastId;
- int _browserId;
ConcurrentDictionary^ _callbacks;
internal:
- JavascriptCallbackWrapper^ FindWrapper(int64 id);
+ JavascriptCallbackWrapper^ FindWrapper(int64_t id);
public:
- JavascriptCallbackRegistry(int browserId) : _browserId(browserId)
+ JavascriptCallbackRegistry()
{
_callbacks = gcnew ConcurrentDictionary();
}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.h b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.h
index 7c50966214..ac2072825f 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.h
@@ -8,7 +8,7 @@
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
private ref class JavascriptCallbackWrapper
{
@@ -45,4 +45,4 @@ namespace CefSharp
}
};
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.cpp b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.cpp
index b63627aac6..24267876dd 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.cpp
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.cpp
@@ -8,69 +8,73 @@
namespace CefSharp
{
- bool JavascriptMethodHandler::Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception)
+ namespace BrowserSubprocess
{
- auto parameter = gcnew array(arguments.size());
-
- for (std::vector>::size_type i = 0; i != arguments.size(); i++)
- {
- parameter[i] = TypeUtils::ConvertFromCef(arguments[i], _callbackRegistry);
- }
-
- try
+ bool JavascriptMethodHandler::Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception)
{
- auto response = _method->Invoke(parameter);
+ auto size = static_cast(arguments.size());
+ auto parameter = gcnew array(size);
- retval = ConvertToCefObject(response->Result);
- if (!response->Success)
+ for (int i = 0; i < size; i++)
{
- exception = StringUtils::ToNative(response->Message);
+ parameter[i] = TypeUtils::ConvertFromCef(arguments[i], _callbackRegistry);
}
- }
- catch (Exception^ ex)
- {
- exception = StringUtils::ToNative(ex->ToString());
- }
- //NOTE: Return true otherwise exception is ignored
- return true;
- }
+ try
+ {
+ auto response = _method->Invoke(parameter);
- CefRefPtr JavascriptMethodHandler::ConvertToCefObject(Object^ obj)
- {
- if (obj == nullptr)
- {
- return CefV8Value::CreateNull();
- }
+ retval = ConvertToCefObject(response->Result);
+ if (!response->Success)
+ {
+ exception = StringUtils::ToNative(response->Message);
+ }
+ }
+ catch (Exception^ ex)
+ {
+ exception = StringUtils::ToNative(ex->ToString());
+ }
- auto type = obj->GetType();
+ //NOTE: Return true otherwise exception is ignored
+ return true;
+ }
- if (type == JavascriptObject::typeid)
+ CefRefPtr JavascriptMethodHandler::ConvertToCefObject(Object^ obj)
{
- JavascriptObject^ javascriptObject = (JavascriptObject^)obj;
- CefRefPtr cefObject = CefV8Value::CreateObject(NULL, NULL);
+ if (obj == nullptr)
+ {
+ return CefV8Value::CreateNull();
+ }
- for (int i = 0; i < javascriptObject->Properties->Count; i++)
+ auto type = obj->GetType();
+
+ if (type == JavascriptObject::typeid)
{
- auto prop = javascriptObject->Properties[i];
+ JavascriptObject^ javascriptObject = (JavascriptObject^)obj;
+ CefRefPtr cefObject = CefV8Value::CreateObject(nullptr, nullptr);
- if (prop->IsComplexType)
+ for (int i = 0; i < javascriptObject->Properties->Count; i++)
{
- auto v8Value = ConvertToCefObject(prop->JsObject);
+ auto prop = javascriptObject->Properties[i];
- cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
- }
- else
- {
- auto v8Value = TypeUtils::ConvertToCef(prop->PropertyValue, nullptr);
+ if (prop->IsComplexType)
+ {
+ auto v8Value = ConvertToCefObject(prop->JsObject);
- cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
+ cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
+ }
+ else
+ {
+ auto v8Value = TypeUtils::ConvertToCef(prop->PropertyValue, nullptr);
+
+ cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
+ }
}
+
+ return cefObject;
}
- return cefObject;
+ return TypeUtils::ConvertToCef(obj, nullptr);
}
-
- return TypeUtils::ConvertToCef(obj, nullptr);
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h
index c7202c4a4e..36ee2c31e8 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h
@@ -7,33 +7,38 @@
#include "include/cef_v8.h"
#include "JavascriptCallbackRegistry.h"
+using namespace CefSharp::Internals::Wcf;
+
namespace CefSharp
{
- private class JavascriptMethodHandler : public CefV8Handler
+ namespace BrowserSubprocess
{
- private:
- gcroot^, BrowserProcessResponse^>^> _method;
- gcroot _callbackRegistry;
-
- public:
- JavascriptMethodHandler(Func^, BrowserProcessResponse^>^ method, JavascriptCallbackRegistry^ callbackRegistry)
- {
- _method = method;
- _callbackRegistry = callbackRegistry;
- }
-
- ~JavascriptMethodHandler()
+ private class JavascriptMethodHandler : public CefV8Handler
{
- delete _method;
- // The callback registry is a shared instance among all method handlers (async & sync).
- // It's lifecycle is managed in the JavascriptRootObjectWrapper.
- _callbackRegistry = nullptr;
- }
-
- virtual bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) OVERRIDE;
-
- CefRefPtr ConvertToCefObject(Object^ obj);
-
- IMPLEMENT_REFCOUNTING(JavascriptMethodHandler);
- };
+ private:
+ gcroot^, BrowserProcessResponse^>^> _method;
+ gcroot _callbackRegistry;
+
+ public:
+ JavascriptMethodHandler(Func^, BrowserProcessResponse^>^ method, JavascriptCallbackRegistry^ callbackRegistry)
+ {
+ _method = method;
+ _callbackRegistry = callbackRegistry;
+ }
+
+ ~JavascriptMethodHandler()
+ {
+ delete _method;
+ // The callback registry is a shared instance among all method handlers (async & sync).
+ // It's lifecycle is managed in the JavascriptRootObjectWrapper.
+ _callbackRegistry = nullptr;
+ }
+
+ virtual bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) override;
+
+ CefRefPtr ConvertToCefObject(Object^ obj);
+
+ IMPLEMENT_REFCOUNTINGM(JavascriptMethodHandler);
+ };
+ }
}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptMethodWrapper.cpp b/CefSharp.BrowserSubprocess.Core/JavascriptMethodWrapper.cpp
index 19041027e7..ab8feed45d 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptMethodWrapper.cpp
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptMethodWrapper.cpp
@@ -10,17 +10,20 @@
namespace CefSharp
{
- void JavascriptMethodWrapper::Bind(JavascriptMethod^ javascriptMethod, const CefRefPtr& v8Value)
+ namespace BrowserSubprocess
{
- _javascriptMethodName = javascriptMethod->JavascriptName;
- auto methodName = StringUtils::ToNative(javascriptMethod->JavascriptName);
- auto v8Function = CefV8Value::CreateFunction(methodName, _javascriptMethodHandler.get());
+ void JavascriptMethodWrapper::Bind(JavascriptMethod^ javascriptMethod, const CefRefPtr& v8Value)
+ {
+ _javascriptMethodName = javascriptMethod->JavascriptName;
+ auto methodName = StringUtils::ToNative(javascriptMethod->JavascriptName);
+ auto v8Function = CefV8Value::CreateFunction(methodName, _javascriptMethodHandler.get());
- v8Value->SetValue(methodName, v8Function, V8_PROPERTY_ATTRIBUTE_NONE);
- };
+ v8Value->SetValue(methodName, v8Function, V8_PROPERTY_ATTRIBUTE_NONE);
+ };
- BrowserProcessResponse^ JavascriptMethodWrapper::Execute(array^ parameters)
- {
- return _browserProcess->CallMethod(_ownerId, _javascriptMethodName, parameters);
+ BrowserProcessResponse^ JavascriptMethodWrapper::Execute(array^ parameters)
+ {
+ return _browserProcess->CallMethod(_ownerId, _javascriptMethodName, parameters);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptMethodWrapper.h b/CefSharp.BrowserSubprocess.Core/JavascriptMethodWrapper.h
index 296e493481..ebf980b8cc 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptMethodWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptMethodWrapper.h
@@ -10,38 +10,42 @@
#include "JavascriptMethodHandler.h"
using namespace System::Runtime::Serialization;
+using namespace CefSharp::Internals::Wcf;
namespace CefSharp
{
- private ref class JavascriptMethodWrapper
+ namespace BrowserSubprocess
{
- private:
- MCefRefPtr _javascriptMethodHandler;
- int64 _ownerId;
- String^ _javascriptMethodName;
- IBrowserProcess^ _browserProcess;
-
- public:
- JavascriptMethodWrapper(int64 ownerId, IBrowserProcess^ browserProcess, JavascriptCallbackRegistry^ callbackRegistry)
+ private ref class JavascriptMethodWrapper
{
- _ownerId = ownerId;
- _browserProcess = browserProcess;
- _javascriptMethodHandler = new JavascriptMethodHandler(gcnew Func^, BrowserProcessResponse^>(this, &JavascriptMethodWrapper::Execute), callbackRegistry);
- }
-
- !JavascriptMethodWrapper()
- {
- _javascriptMethodHandler = nullptr;
- }
-
- ~JavascriptMethodWrapper()
- {
- this->!JavascriptMethodWrapper();
-
- _browserProcess = nullptr;
- }
-
- void Bind(JavascriptMethod^ javascriptMethod, const CefRefPtr& v8Value);
- BrowserProcessResponse^ Execute(array^ parameters);
- };
-}
\ No newline at end of file
+ private:
+ MCefRefPtr _javascriptMethodHandler;
+ int64_t _ownerId;
+ String^ _javascriptMethodName;
+ IBrowserProcess^ _browserProcess;
+
+ public:
+ JavascriptMethodWrapper(int64_t ownerId, IBrowserProcess^ browserProcess, JavascriptCallbackRegistry^ callbackRegistry)
+ {
+ _ownerId = ownerId;
+ _browserProcess = browserProcess;
+ _javascriptMethodHandler = new JavascriptMethodHandler(gcnew Func^, BrowserProcessResponse^>(this, &JavascriptMethodWrapper::Execute), callbackRegistry);
+ }
+
+ !JavascriptMethodWrapper()
+ {
+ _javascriptMethodHandler = nullptr;
+ }
+
+ ~JavascriptMethodWrapper()
+ {
+ this->!JavascriptMethodWrapper();
+
+ _browserProcess = nullptr;
+ }
+
+ void Bind(JavascriptMethod^ javascriptMethod, const CefRefPtr& v8Value);
+ BrowserProcessResponse^ Execute(array^ parameters);
+ };
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptObjectWrapper.cpp b/CefSharp.BrowserSubprocess.Core/JavascriptObjectWrapper.cpp
index 46bbbb9b22..afb2926dd8 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptObjectWrapper.cpp
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptObjectWrapper.cpp
@@ -10,45 +10,48 @@
namespace CefSharp
{
- void JavascriptObjectWrapper::Bind(JavascriptObject^ object, const CefRefPtr& v8Value, JavascriptCallbackRegistry^ callbackRegistry)
+ namespace BrowserSubprocess
{
- _objectId = object->Id;
-
- //Create property handler for get and set of Properties of this object
- _jsPropertyHandler = new JavascriptPropertyHandler(
- gcnew Func(this, &JavascriptObjectWrapper::GetProperty),
- gcnew Func(this, &JavascriptObjectWrapper::SetProperty)
- );
-
- //V8Value that represents this javascript object - only one per complex type
- auto javascriptObject = CefV8Value::CreateObject(_jsPropertyHandler.get(), NULL);
- auto objectName = StringUtils::ToNative(object->JavascriptName);
- v8Value->SetValue(objectName, javascriptObject, V8_PROPERTY_ATTRIBUTE_NONE);
-
- for each (JavascriptMethod^ method in Enumerable::OfType(object->Methods))
+ void JavascriptObjectWrapper::Bind(JavascriptObject^ object, const CefRefPtr& v8Value, JavascriptCallbackRegistry^ callbackRegistry)
{
- auto wrappedMethod = gcnew JavascriptMethodWrapper(object->Id, _browserProcess, callbackRegistry);
- wrappedMethod->Bind(method, javascriptObject);
-
- _wrappedMethods->Add(wrappedMethod);
+ _objectId = object->Id;
+
+ //Create property handler for get and set of Properties of this object
+ _jsPropertyHandler = new JavascriptPropertyHandler(
+ gcnew Func(this, &JavascriptObjectWrapper::GetProperty),
+ gcnew Func(this, &JavascriptObjectWrapper::SetProperty)
+ );
+
+ //V8Value that represents this javascript object - only one per complex type
+ auto javascriptObject = CefV8Value::CreateObject(_jsPropertyHandler.get(), nullptr);
+ auto objectName = StringUtils::ToNative(object->JavascriptName);
+ v8Value->SetValue(objectName, javascriptObject, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ for each (JavascriptMethod ^ method in Enumerable::OfType(object->Methods))
+ {
+ auto wrappedMethod = gcnew JavascriptMethodWrapper(object->Id, _browserProcess, callbackRegistry);
+ wrappedMethod->Bind(method, javascriptObject);
+
+ _wrappedMethods->Add(wrappedMethod);
+ }
+
+ for each (JavascriptProperty ^ prop in Enumerable::OfType(object->Properties))
+ {
+ auto wrappedproperty = gcnew JavascriptPropertyWrapper(object->Id, _browserProcess);
+ wrappedproperty->Bind(prop, javascriptObject, callbackRegistry);
+
+ _wrappedProperties->Add(wrappedproperty);
+ }
}
- for each (JavascriptProperty^ prop in Enumerable::OfType(object->Properties))
+ BrowserProcessResponse^ JavascriptObjectWrapper::GetProperty(String^ memberName)
{
- auto wrappedproperty = gcnew JavascriptPropertyWrapper(object->Id, _browserProcess);
- wrappedproperty->Bind(prop, javascriptObject, callbackRegistry);
+ return _browserProcess->GetProperty(_objectId, memberName);
+ };
- _wrappedProperties->Add(wrappedproperty);
- }
+ BrowserProcessResponse^ JavascriptObjectWrapper::SetProperty(String^ memberName, Object^ value)
+ {
+ return _browserProcess->SetProperty(_objectId, memberName, value);
+ };
}
-
- BrowserProcessResponse^ JavascriptObjectWrapper::GetProperty(String^ memberName)
- {
- return _browserProcess->GetProperty(_objectId, memberName);
- };
-
- BrowserProcessResponse^ JavascriptObjectWrapper::SetProperty(String^ memberName, Object^ value)
- {
- return _browserProcess->SetProperty(_objectId, memberName, value);
- };
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptObjectWrapper.h b/CefSharp.BrowserSubprocess.Core/JavascriptObjectWrapper.h
index 9a5bb763ca..28eebd3b55 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptObjectWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptObjectWrapper.h
@@ -17,45 +17,48 @@ using namespace System::Collections::Generic;
namespace CefSharp
{
- private ref class JavascriptObjectWrapper
+ namespace BrowserSubprocess
{
- private:
- List