diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..92683c27e2
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,160 @@
+# editorconfig.org
+# Mostly based on https://github.com/dotnet/corefx/blob/master/.editorconfig
+# References
+# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2017
+# https://kent-boogaart.com/blog/editorconfig-reference-for-c-developers
+
+# top-most EditorConfig file
+root = true
+
+# Default settings:
+# A newline ending every file
+# Use 4 spaces as indentation
+[*]
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+charset = utf-8
+end_of_line = crlf
+trim_trailing_whitespace = true
+
+# Powershell files (build.ps1)
+[*.ps1]
+charset = utf-8-bom
+
+# Xml config files
+[*.{props,targets,config,nuspec,manifest}]
+indent_size = 2
+
+# Javascript Files
+[*.js]
+curly_bracket_next_line = true
+indent_brace_style = Allman
+
+# C++ Files
+[*.{cpp,h,in}]
+curly_bracket_next_line = true
+indent_brace_style = Allman
+
+[*.cs]
+# Capitalization styles
+dotnet_naming_style.constant_field_case_style.capitalization = pascal_case
+dotnet_naming_style.property_case_style.capitalization = pascal_case
+dotnet_naming_style.static_field_case_style.capitalization = pascal_case
+dotnet_naming_style.private_internal_field_case_style.capitalization = camel_case
+
+# New line preferences
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = false
+csharp_indent_switch_labels = true
+csharp_indent_labels = one_less_than_current
+
+# this.
+dotnet_style_qualification_for_field = false : suggestion
+dotnet_style_qualification_for_property = false : suggestion
+dotnet_style_qualification_for_method = false : suggestion
+dotnet_style_qualification_for_event = false : suggestion
+
+# Prefer using var
+csharp_style_var_for_built_in_types = true : none
+csharp_style_var_when_type_is_apparent = true : suggestion
+csharp_style_var_elsewhere = true : suggestion
+
+# use language keywords instead of BCL types
+dotnet_style_predefined_type_for_locals_parameters_members = true : suggestion
+dotnet_style_predefined_type_for_member_access = true : suggestion
+
+# Constant fields
+dotnet_naming_rule.constant_field_style.severity = error
+dotnet_naming_rule.constant_field_style.symbols = constant_field_target
+dotnet_naming_rule.constant_field_style.style = constant_field_case_style
+
+dotnet_naming_symbols.constant_field_target.applicable_kinds = field
+dotnet_naming_symbols.constant_field_target.required_modifiers = const
+
+# Properties
+dotnet_naming_rule.property_style.severity = error
+dotnet_naming_rule.property_style.symbols = property_target
+dotnet_naming_rule.property_style.style = property_case_style
+
+dotnet_naming_symbols.property_target.applicable_kinds = property
+dotnet_naming_symbols.property_target.required_modifiers = *
+
+# Static fields
+dotnet_naming_rule.static_field_style.severity = error
+dotnet_naming_rule.static_field_style.symbols = static_field_target
+dotnet_naming_rule.static_field_style.style = static_field_case_style
+
+dotnet_naming_symbols.static_field_target.applicable_kinds = field
+dotnet_naming_symbols.static_field_target.required_modifiers = static
+
+# Private and internal fields
+dotnet_naming_rule.private_internal_field_style.severity = error
+dotnet_naming_rule.private_internal_field_style.symbols = private_internal_field_target
+dotnet_naming_rule.private_internal_field_style.style = private_internal_field_case_style
+
+dotnet_naming_symbols.private_internal_field_target.applicable_kinds = field
+dotnet_naming_symbols.private_internal_field_target.applicable_accessibilities = private, internal
+
+# Code style defaults
+dotnet_sort_system_directives_first = true
+csharp_preserve_single_line_blocks = true
+csharp_prefer_braces = true
+csharp_preserve_single_line_statements = false
+dotnet_style_prefer_auto_properties = true : suggestion
+
+# Expression-level preferences
+dotnet_style_object_initializer = true : suggestion
+dotnet_style_collection_initializer = true : suggestion
+dotnet_style_explicit_tuple_names = false : suggestion
+dotnet_style_coalesce_expression = false : suggestion
+dotnet_style_null_propagation = false : suggestion
+
+# Expression-bodied members
+csharp_style_expression_bodied_methods = false : none
+csharp_style_expression_bodied_constructors = false : none
+csharp_style_expression_bodied_operators = false : none
+csharp_style_expression_bodied_properties = false : none
+csharp_style_expression_bodied_indexers = false : none
+csharp_style_expression_bodied_accessors = false : none
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = do_not_ignore
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# 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
new file mode 100644
index 0000000000..b55aeeadbe
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,13 @@
+# These are supported funding model platforms
+
+#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+#patreon: # Replace with a single Patreon username
+#open_collective: # Replace with a single Open Collective username
+#ko_fi: # Replace with a single Ko-fi username
+#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+#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
+custom: https://paypal.me/AlexMaitland
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
new file mode 100644
index 0000000000..9910de4839
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,31 @@
+---
+name: Feature request
+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: ''
+
+---
+
+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://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 its own `Feature Request Forum` at https://magpcss.org/ceforum/viewforum.php?f=7
+
+---
+
+**Describe the solution you'd like**
+A clear and concise description of the feature you are proposing
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+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.
diff --git a/.github/config.yml b/.github/config.yml
new file mode 100644
index 0000000000..9dab6a46eb
--- /dev/null
+++ b/.github/config.yml
@@ -0,0 +1,16 @@
+# Comment to be posted to on first time issues
+newIssueWelcomeComment: >
+ Welcome! We prefer to keep this issue track just for bug reports. If you have a question or need help with something I'd ask that you self close this issue and have a read over https://github.com/cefsharp/CefSharp/blob/master/ISSUE_TEMPLATE.md it contains
+ background information, details on where to ask your questions [Gitter](https://gitter.im/cefsharp/CefSharp) or [StackOverflow](https://stackoverflow.com/questions/tagged/cefsharp)) should be used.
+
+
+ If you're reporting a bug, you **must** complete the bug report template see https://github.com/cefsharp/CefSharp/blob/master/ISSUE_TEMPLATE.md#bug-report.
+ Please make sure you provide enough detail that **someone else** can reproduce the issue you are experiencing.
+
+
+ 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
+
+
+
+
diff --git a/.github/no-response.yml b/.github/no-response.yml
new file mode 100644
index 0000000000..cd5f107372
--- /dev/null
+++ b/.github/no-response.yml
@@ -0,0 +1,15 @@
+# Configuration for probot-no-response - https://github.com/probot/no-response
+
+# Number of days of inactivity before an Issue is closed for lack of response
+daysUntilClose: 14
+
+# Label requiring a response
+responseRequiredLabel: more-details-needed-from-op
+
+# Comment to post when closing an Issue for lack of response. Set to `false` to disable
+closeComment: >
+ This issue has been automatically closed because there has been no response
+ to our request for more information from the original author. With only the
+ information that is currently in the issue, we don't have enough information
+ to take action. Please reach out if you have or find the answers we need so
+ that we can investigate further.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000..c2d7925c5e
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,32 @@
+**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 Binding Implementation
+ - Added support for Async binding to return Task
+ - Added new QUnit Test cases
+
+**How Has This Been Tested?**
+
+
+
+
+**Screenshots (if appropriate):**
+
+**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)
+- [ ] New files have a license disclaimer
+- [ ] The formatting is consistent with the project (project supports .editorconfig)
diff --git a/.github/support.yml b/.github/support.yml
new file mode 100644
index 0000000000..0ee8bc127f
--- /dev/null
+++ b/.github/support.yml
@@ -0,0 +1,27 @@
+# Configuration for Support Requests - https://github.com/dessant/support-requests
+
+# Label used to mark issues as support requests
+supportLabel: support
+
+# Comment to post on issues marked as support requests, `{issue-author}` is an
+# optional placeholder. Set to `false` to disable
+supportComment: >
+ :wave: @{issue-author}, we use the issue tracker exclusively for bug reports
+ and feature requests. However, this issue appears to be a support request.
+ Please use our support channels to get help with the project.
+
+ If you have a question, ask it on [StackOverflow](http://stackoverflow.com/questions/tagged/cefsharp) or use [ceforum](http://magpcss.org/ceforum/) (for questions specific to `CEF`).
+
+ If you are new to `CefSharp` then we suggest you read https://github.com/cefsharp/CefSharp/wiki/General-Usage
+
+ If you feel this was closed in error then you **must** edit your original issue and complete the [Bug Report Template](https://github.com/cefsharp/CefSharp/blob/master/.github/ISSUE_TEMPLATE/bug_report.md#bug-report)
+ then post a comment asking for a review.
+
+# Close issues marked as support requests
+close: true
+
+# Lock issues marked as support requests
+lock: false
+
+# Assign `off-topic` as the reason for locking. Set to `false` to disable
+setLockReason: false
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 445e78f6b7..e92d3bb6b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,10 +16,14 @@
*.swp
*.user
*.xml
+*.VC.opendb
+*.VC.db
_ReSharper*
bin/
+bin.netcore/
obj/
+obj.netcore/
packages/
Debug/
Release/
@@ -35,4 +39,6 @@ CefSharp.BrowserSubprocess.lib
Win32/Release
x64/Release
Win32/Release
-.vs/
\ No newline at end of file
+.vs/
+/Help
+/tools
diff --git a/.vsconfig b/.vsconfig
new file mode 100644
index 0000000000..9c22b175de
--- /dev/null
+++ b/.vsconfig
@@ -0,0 +1,33 @@
+{
+ "version": "1.0",
+ "components": [
+ "Microsoft.VisualStudio.Component.CoreEditor",
+ "Microsoft.VisualStudio.Workload.CoreEditor",
+ "Microsoft.VisualStudio.Component.NuGet",
+ "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.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.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 0eefda7fac..281ae9dda1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,44 +1,42 @@
-##CefSharp Project Contribution Guide
+## CefSharp Project Contribution Guide
Thanks for your interest in contributing to the project! Please follow these simple guidelines:
### General
-- **Please read the full contents of [the FAQ](https://github.com/cefsharp/CefSharp/wiki/Frequently-asked-questions) before submitting an issue, or posting to the Google Group. It's quite likely your question has already been answered before.** If something is unclear in the FAQ, of course feel free to ask; the idea is just to reduce the level of "noise" we have to go through, reading the same questions over and over again.
-- Please make sure to **test out the current version** of CefSharp to see whether the problem you are encountering still exists.
-- If you are unsure if something is a "bug" or a "feature", discuss it with the Google Group first. Don't cross-post: if you create an issue, and all the information is contained there, that's perfectly enough. There's no reason to also post it to the group; it just creates "line noise". The project maintainers are very busy people like you and me, and things will sometimes take a few weeks (or in worst case, more) to answer. If you are in a rush - do your very best to investigate the problem thoroughly; if possible, fix the bug yourself and submit a pull request.
+- Please use [](https://gitter.im/cefsharp/CefSharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) as your first point of call for basic/simple questions.
+- When creating an issue please use the issue template provided.
+- **Please read the full contents of [the FAQ](https://github.com/cefsharp/CefSharp/wiki/Frequently-asked-questions) before submitting an issue**. Also searching the `GitHub` project is a **must**. It's quite likely your question has already been answered before. If something is unclear in the FAQ, of course feel free to ask; the idea is just to reduce the level of "noise" we have to go through, reading the same questions over and over again.
+- Please make sure to **test out the current version** of `CefSharp` to see whether the problem you are encountering still exists.
+- Don't cross-post: if you create an issue, and all the information is contained there, that's enough. There's no reason to also post it to Stackoverflow; it just creates "line noise". The project maintainers are very busy people like you and me, and things will sometimes take a few weeks (or in worst case, more) to answer. If you are in a rush - do your very best to investigate the problem thoroughly; if possible, fix the bug yourself and submit a pull request.
- Before creating a GitHub issue or pull request, try looking through the list & issue archives to make sure the issue at hand hasn't been raised before. [Google](http://www.google.com) can also be helpful: just typing "cefsharp appdomain" for example (when trying to see whether AppDomain support has been discussed before) will often give you helpful results.
-- We do appreciate cultural/languages differences, that being said **never** demand that someone help you, this is not a commercial application with paid support!
+- We do appreciate cultural/languages differences, that being said **never** demand that someone help you, this is not a commercial application with paid support! Please and thank you go a long way.
- This is a volunteer project, we give of our time freely and we ask for you to do the same. Contributions can be simple like updating/adding new entries in the [FAQ](https://github.com/cefsharp/CefSharp/wiki/Frequently-asked-questions), creating new pages in the [WIKI](https://github.com/cefsharp/CefSharp/wiki), updating the examples. (Anyone with a `GitHub` account can edit the `WIKI`)
-- We have **very** limited active contributors so please spend as much time looking into your own problem as possible, the more you help yourself, the quicker things will get fixed.
-- Asking the same questions over and over again is **Wasting our time**, search open/closed issues to see if your issue has already been addressed.
-- Having to constantly query users to gather information is **very frustrating**!
-- Please don't hijack issues, if your problem is distinct then please create a unique issue (after searching previous issues).
-### `CefSharp` vs `CEF`
+### `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 **Test App** from http://cefbuilds.com
-- To compare with WPF run `cefclient --multi-threaded-message-loop --off-screen-rendering-enabled`
-- 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.2062.1898`, in this case `2062` represents the branch which corresponds to http://cefbuilds.com/#branch_2062
+ - 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`?
-A bug is a _demonstrable problem_ that is caused by the code in the repository. Ideally each issue is a useful resource for references purposes (Don't take offence if someone edits your description).
+When creating an issue please use the provided by report template (the field will be pre-populated).
-1. Good bug reports are extremely helpful. The more information you provide, the more likely your issue will be resolved.
-2. Good bug reports shouldn't leave others needing to chase you up for more information. Be sure to include the
-details of your environment.
-3. 'Ask Don't Tell' : Ask how to achieve something, **don't say it's broken** just because you haven't got it working yet!
-4. **Isolate the problem** — ideally create a reproducible example.
-5. **Include a screencast if relevant** - Is your issue about a design or front end feature or bug? The most helpful thing in the world is if we can *see* what you're talking about. Use [LICEcap](http://www.cockos.com/licecap/) to quickly and easily record a short screencast (24fps) and save it as an animated gif! Embed it directly into your GitHub issue.
-6. **Include as much info as possible!** Use the **Bug Report template** below or [click this link](https://github.com/CefSharp/CefSharp/issues/new?title=Bug%3A&body=%23%23%23%23+Issue+Summary%0D%0AWhat+is+the+expected+output%3F+What+do+you+see+instead%3F%0D%0A%0D%0A%23%23%23%23+Steps+to+Reproduce%0D%0A1.+This+is+the+first+step%0D%0A%0D%0AThis+is+a+bug+because...%0D%0ACode+sample+if+relevant%0D%0ADoes+this+problem+also+occur+in+the+%60Cef%60+TestApp+from+http%3A%2F%2Fcefbuilds.com%3F%0D%0A%0D%0A%23%23%23%23+Technical+details%0D%0A%2A+CefSharp+Version%3A+nuget+-+master+-+latest+commit%3A++INSERT+COMMIT+REF%0D%0A%2A+Operating+System%3A+%0D%0A%2A+x86%2Fx64%3A+%0D%0A%2A+WinForms%2FWPF%2FOffScreen%3A+) to start creating a bug report with the template automatically.
-7. When including code limit to small chunks, large blocks post as gist or similar
-8. Please no links to binaries, e.g. zip files, either contribute your example as a github project, a gist or another public code sharing service.
+A bug is a _demonstrable problem_ that is caused by the code in the repository. Ideally each issue is a useful resource for references purposes (Don't take offence if someone edits your description).
Your bug report should **always follow this template**:
@@ -47,36 +45,56 @@ 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, 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` TestApp from http://cefbuilds.com?**
+- **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**.
**BE AWARE THAT BUG REPORTS MUST PROVIDE ALL OF THE INFORMATION STATED ABOVE!**
+#### Help us help you
+
+1. Asking the same questions over and over again is **Wasting our time**, search open/closed issues to see if your issue has already been addressed.
+2. Having to constantly query users to gather information is **very frustrating**! Use the bug template provided above.
+3. We have **very** limited active contributors so please spend as much time looking into your own problem as possible, the more you help yourself, the quicker things will get fixed.
+4. Please don't hijack issues, if your problem is distinct then please create a unique issue (after searching previous issues).
+5. Good bug reports are extremely helpful. The more information you provide, the more likely your issue will be resolved.
+6. Good bug reports shouldn't leave others needing to chase you up for more information. Be sure to include the
+details of your environment.
+7. 'Ask Don't Tell' : Ask how to achieve something, **don't say it's broken** just because you haven't got it working yet!
+8. **Isolate the problem** — ideally create a reproducible example.
+9. **Include a screencast if relevant** - Is your issue about a design or front end feature or bug? The most helpful thing in the world is if we can *see* what you're talking about. Use [LICEcap](http://www.cockos.com/licecap/) to quickly and easily record a short screencast (24fps) and save it as an animated gif! Embed it directly into your GitHub issue.
+10. When including code limit to small chunks, large blocks post as a [Gist](http://gist.github.com/) or similar
+11. Please no links to binaries, e.g. zip files, either contribute your example as a github project, a gist or another public code sharing service.
+
### Change Requests
Change requests cover both architectural and functional changes to how `CefSharp` works. If you have an idea for a refactor, or an improvement to a feature, etc - please be sure to:
1. **Use the GitHub search** and check someone else didn't get there first
2. Take a moment to think about the best way to make a case for, and explain what you're thinking as it's up to you to convince the project's leaders the change is worthwhile. Some questions to consider are:
- - Is it really one idea or is it many?
- - What problem are you solving?
- - Why is what you are suggesting better than what's already there?
+ - Is it really one idea or is it many?
+ - What problem are you solving?
+ - Why is what you are suggesting better than what's already there?
### Pull Requests/Feature Branches
-Pull requests are **awesome**. If you're looking to raise a PR for something which doesn't have an open issue, please think carefully about raising an issue which your PR can close, especially if you're fixing a bug. This makes it more likely that there will be enough information available for your PR to be properly tested and merged.
+Pull requests are **awesome**. If you're looking to raise a `PR` for something which doesn't have an open issue, please think carefully about raising an issue which your PR can close, especially if you're fixing a bug. This makes it more likely that there will be enough information available for your PR to be properly tested and merged.
- Please limit your changes to a logical grouping, keeping changesets small increases the likelihood they will be merged
- If you then want to make subsequent changes, it's actually best to not do them before the feature is merged. Please wait for feedback/review before progressing. This greatly improves our ability to review your changes and dramatically increases the likelihood they will be merged in a timely fashion.
- If you wish to keep progressing on your work, please maintain a feature branch independent of the branch referenced by your pull request. From your WIP branch you can selectively merge in changes to the PR branch as required.
- In general, it's much better to be "too granular" with PR's that contain "change-the-world"-kind of changes, which usually tend to lag behind a lot longer before getting merged (if they ever will...).
- Small (really, minimalistic) commits. Each individual commit only adds one specific thing. The basic approach to achieving this is to read your commit message. Do you feel the need to add multiple lines? Then you're doing too much at the same time.
+- Keep the first line of commit message short (max 50 characters), then a blank line, then a full description if needed. Good example:
+
+ > Run tests in the default appdomain
+ >
+ > Due to limitations of VC++ we must run our tests in the default appdomain, it's possible to use xunit for testing. Re-add CefSharp.Test.csproj to solution Add some very basic unit tests using xunit, DisableTestParallelization, Set xunit.appDomain to denied in app.config to disable using appdomains (https://xunit.github.io/docs/configuring-with-xml.html) Add xunit vs test running packages, using 2.2.0 version as 2.3.0 was throwing an exception similar to https://github.com/xunit/xunit/issues/1514 TODO: Take a look at https://github.com/NuGet/NuGetGallery/tree/master/tests/NuGetGallery.Facts for some ideas on structuring xunit tests (look at implementing Theory)
### Coding Style
- **Please** follow existing coding style when submitting pull requests.
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
new file mode 100644
index 0000000000..b7c6b55967
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp
@@ -0,0 +1,49 @@
+// Copyright © 2015 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.
+
+#include "stdafx.h"
+#include "JavascriptAsyncMethodCallback.h"
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ namespace Async
+ {
+ void JavascriptAsyncMethodCallback::Success(const CefRefPtr& result)
+ {
+ if (_resolve.get() && _context.get() && _context->Enter())
+ {
+ try
+ {
+ CefV8ValueList args;
+ args.push_back(result);
+ _resolve->ExecuteFunction(nullptr, args);
+ }
+ finally
+ {
+ _context->Exit();
+ }
+ }
+ }
+
+ void JavascriptAsyncMethodCallback::Fail(const CefString& exception)
+ {
+ if (_reject.get() && _context.get() && _context->Enter())
+ {
+ try
+ {
+ CefV8ValueList args;
+ args.push_back(CefV8Value::CreateString(exception));
+ _reject->ExecuteFunction(nullptr, args);
+ }
+ finally
+ {
+ _context->Exit();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h
new file mode 100644
index 0000000000..27411d722b
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h
@@ -0,0 +1,47 @@
+// Copyright © 2015 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"
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ namespace Async
+ {
+ private ref class JavascriptAsyncMethodCallback
+ {
+ private:
+ MCefRefPtr _context;
+ MCefRefPtr _resolve;
+ MCefRefPtr _reject;
+
+ public:
+ JavascriptAsyncMethodCallback(CefRefPtr context, CefRefPtr resolve, CefRefPtr reject)
+ :_context(context), _resolve(resolve.get()), _reject(reject.get())
+ {
+
+ }
+
+ !JavascriptAsyncMethodCallback()
+ {
+ _resolve = nullptr;
+ _reject = nullptr;
+ _context = nullptr;
+ }
+
+ ~JavascriptAsyncMethodCallback()
+ {
+ this->!JavascriptAsyncMethodCallback();
+ }
+
+ void Success(const CefRefPtr& result);
+
+ void Fail(const CefString& exception);
+ };
+ }
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp
new file mode 100644
index 0000000000..71628d738f
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp
@@ -0,0 +1,74 @@
+// Copyright © 2015 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.
+
+#include "stdafx.h"
+#include "JavascriptAsyncMethodHandler.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 BrowserSubprocess
+ {
+ namespace Async
+ {
+ bool JavascriptAsyncMethodHandler::Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception)
+ {
+ auto context = CefV8Context::GetCurrentContext();
+ auto frame = context->GetFrame();
+
+ 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))
+ {
+ LOG(WARNING) << "JavascriptAsyncMethodHandler::Execute promiseData returned exception: " + promiseException->GetMessage().ToString();
+
+ exception = promiseException->GetMessage();
+
+ 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 == nullptr)
+ {
+ LOG(WARNING) << "JavascriptAsyncMethodHandler::Execute promiseData returned nullptr";
+
+ return true;
+ }
+
+ retval = promiseData->GetValue("p");
+
+ auto resolve = promiseData->GetValue("res");
+ auto reject = promiseData->GetValue("rej");
+ auto callback = gcnew JavascriptAsyncMethodCallback(context, resolve, reject);
+ auto callbackId = _methodCallbackSave->Invoke(callback);
+
+ auto request = CefProcessMessage::Create(kJavascriptAsyncMethodCallRequest);
+ auto argList = request->GetArgumentList();
+ auto params = CefListValue::Create();
+ for (size_t i = 0; i < arguments.size(); i++)
+ {
+ SerializeV8Object(arguments[i], params, i, _callbackRegistry);
+ }
+
+ SetInt64(argList, 0, _objectId);
+ SetInt64(argList, 1, callbackId);
+ argList->SetString(2, name);
+ argList->SetList(3, params);
+
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, request);
+
+ return true;
+ }
+ }
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.h
new file mode 100644
index 0000000000..aa315f69c9
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.h
@@ -0,0 +1,45 @@
+// Copyright © 2015 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 "JavascriptCallbackRegistry.h"
+#include "JavascriptAsyncMethodCallback.h"
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ namespace Async
+ {
+ private class JavascriptAsyncMethodHandler : public virtual CefV8Handler
+ {
+ private:
+ gcroot _callbackRegistry;
+ gcroot^> _methodCallbackSave;
+ int64_t _objectId;
+
+ public:
+ JavascriptAsyncMethodHandler(int64_t objectId, JavascriptCallbackRegistry^ callbackRegistry, Func^ methodCallbackSave)
+ :_callbackRegistry(callbackRegistry), _objectId(objectId), _methodCallbackSave(methodCallbackSave)
+ {
+
+ }
+
+ virtual bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception);
+
+ ~JavascriptAsyncMethodHandler()
+ {
+ // The callback registry is a shared instance among all method handlers (async & sync).
+ // It's lifecycle is managed in the JavascriptRootObjectWrapper.
+ _callbackRegistry = nullptr;
+ _methodCallbackSave = nullptr;
+ }
+
+ IMPLEMENT_REFCOUNTINGM(JavascriptAsyncMethodHandler);
+ };
+ }
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.cpp
new file mode 100644
index 0000000000..9d60fc2cfd
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.cpp
@@ -0,0 +1,24 @@
+// Copyright © 2015 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.
+
+#include "stdafx.h"
+#include "JavascriptCallbackRegistry.h"
+#include "JavascriptAsyncMethodWrapper.h"
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ namespace Async
+ {
+ void JavascriptAsyncMethodWrapper::Bind(JavascriptMethod^ method, const CefRefPtr& value)
+ {
+ auto methodName = StringUtils::ToNative(method->JavascriptName);
+ auto v8Function = CefV8Value::CreateFunction(methodName, _javascriptMethodHandler.get());
+
+ value->SetValue(methodName, v8Function, V8_PROPERTY_ATTRIBUTE_NONE);
+ }
+ }
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.h
new file mode 100644
index 0000000000..876aa52026
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodWrapper.h
@@ -0,0 +1,32 @@
+// Copyright © 2015 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 "JavascriptAsyncMethodHandler.h"
+#include "JavascriptCallbackRegistry.h"
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ namespace Async
+ {
+ private ref class JavascriptAsyncMethodWrapper
+ {
+ private:
+ MCefRefPtr _javascriptMethodHandler;
+
+ public:
+ JavascriptAsyncMethodWrapper(int64_t ownerId, JavascriptCallbackRegistry^ callbackRegistry, Func^ methodCallbackSave)
+ : _javascriptMethodHandler(new JavascriptAsyncMethodHandler(ownerId, callbackRegistry, methodCallbackSave))
+ {
+
+ }
+
+ void Bind(JavascriptMethod^ method, const CefRefPtr& value);
+ };
+ }
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.cpp
new file mode 100644
index 0000000000..401b85a643
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.cpp
@@ -0,0 +1,35 @@
+// Copyright © 2015 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.
+
+#include "stdafx.h"
+#include "JavascriptCallbackRegistry.h"
+#include "JavascriptAsyncObjectWrapper.h"
+#include "JavascriptAsyncMethodWrapper.h"
+
+using namespace System::Linq;
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ namespace Async
+ {
+ void JavascriptAsyncObjectWrapper::Bind(JavascriptObject^ object, const CefRefPtr &value)
+ {
+ //V8Value that represents this javascript object - only one per complex type, no accessor
+ auto javascriptObject = CefV8Value::CreateObject(nullptr, nullptr);
+ auto objectName = StringUtils::ToNative(object->JavascriptName);
+ value->SetValue(objectName, javascriptObject, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ for each (JavascriptMethod^ method in Enumerable::OfType(object->Methods))
+ {
+ auto wrappedMethod = gcnew JavascriptAsyncMethodWrapper(object->Id, _callbackRegistry, _methodCallbackSave);
+ wrappedMethod->Bind(method, javascriptObject);
+
+ _wrappedMethods->Add(wrappedMethod);
+ }
+ }
+ }
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.h
new file mode 100644
index 0000000000..f42ac60e42
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncObjectWrapper.h
@@ -0,0 +1,45 @@
+// Copyright © 2015 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 "JavascriptAsyncMethodCallback.h"
+#include "JavascriptCallbackRegistry.h"
+#include "JavascriptAsyncMethodWrapper.h"
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ namespace Async
+ {
+ private ref class JavascriptAsyncObjectWrapper
+ {
+ private:
+ initonly List^ _wrappedMethods;
+ Func^ _methodCallbackSave;
+ JavascriptCallbackRegistry^ _callbackRegistry;
+
+ public:
+ JavascriptAsyncObjectWrapper(JavascriptCallbackRegistry^ callbackRegistry, Func^ saveMethod)
+ : _wrappedMethods(gcnew List()), _methodCallbackSave(saveMethod), _callbackRegistry(callbackRegistry)
+ {
+
+ }
+
+ ~JavascriptAsyncObjectWrapper()
+ {
+ _callbackRegistry = nullptr;
+ _methodCallbackSave = nullptr;
+ for each (JavascriptAsyncMethodWrapper^ var in _wrappedMethods)
+ {
+ delete var;
+ }
+ }
+
+ void Bind(JavascriptObject^ object, const CefRefPtr &value);
+ };
+ }
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h b/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h
new file mode 100644
index 0000000000..1a99952071
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h
@@ -0,0 +1,317 @@
+// Copyright © 2019 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 "RegisterBoundObjectRegistry.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
+{
+ namespace BrowserSubprocess
+ {
+ const CefString kBindObjectAsync = CefString("BindObjectAsync");
+ const CefString kBindObjectAsyncCamelCase = CefString("bindObjectAsync");
+
+ private class BindObjectAsyncHandler : public CefV8Handler
+ {
+ private:
+ gcroot _callbackRegistry;
+ gcroot^> _javascriptObjects;
+ gcroot _javascriptRootObjectWrapper;
+
+ public:
+ BindObjectAsyncHandler(RegisterBoundObjectRegistry^ callbackRegistery, Dictionary^ javascriptObjects, JavascriptRootObjectWrapper^ javascriptRootObjectWrapper)
+ {
+ _callbackRegistry = callbackRegistery;
+ _javascriptObjects = javascriptObjects;
+ _javascriptRootObjectWrapper = javascriptRootObjectWrapper;
+ }
+
+ ~BindObjectAsyncHandler()
+ {
+ _callbackRegistry = nullptr;
+ _javascriptObjects = nullptr;
+ _javascriptRootObjectWrapper = nullptr;
+ }
+
+ bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) override
+ {
+ auto context = CefV8Context::GetCurrentContext();
+
+ if (context.get() && context->Enter())
+ {
+ try
+ {
+ 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)
+ {
+ objectCount = (int)arguments.size();
+
+ //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();
+
+ //Loop through all arguments and ignore anything that's not a string
+ for (size_t i = 0; i < arguments.size(); i++)
+ {
+ //Validate arg as being a string
+ if (arguments[i]->IsString())
+ {
+ 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)
+ {
+ cached = _javascriptObjects->ContainsKey(managedObjectName);
+ }
+ else
+ {
+ //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;
+ }
+ }
+
+ objectNamesWithBoundStatus->Add(Tuple::Create(managedObjectName, alreadyBound, cached));
+ }
+ }
+ }
+ else
+ {
+ //No objects names were specified so we default to makeing the request
+ boundObjectRequired = true;
+ }
+
+ auto frame = context->GetFrame();
+
+ if (frame.get() && frame->IsValid())
+ {
+ if (boundObjectRequired || ignoreCache)
+ {
+ //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)
+ {
+ if (Object::ReferenceEquals(_javascriptRootObjectWrapper, nullptr))
+ {
+ exception = "BindObjectAsyncHandler::Execute - _javascriptRootObjectWrapper null, unable to bind objects";
+
+ return true;
+ }
+
+ auto browser = context->GetBrowser();
+
+ JavascriptRootObjectWrapper^ rootObject = _javascriptRootObjectWrapper;
+
+ //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;
+
+ 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();
+
+ return true;
+ }
+
+ 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))
+ {
+ exception = promiseException->GetMessage();
+
+ 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 == nullptr)
+ {
+ LOG(WARNING) << "BindObjectAsyncHandler::Execute promiseData returned nullptr";
+
+ return true;
+ }
+
+ //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");
+
+ auto callback = gcnew JavascriptAsyncMethodCallback(context, resolve, reject);
+
+ auto request = CefProcessMessage::Create(kJavascriptRootObjectRequest);
+ auto argList = request->GetArgumentList();
+
+ //Obtain a callbackId then send off the Request for objects
+ auto callbackId = _callbackRegistry->SaveMethodCallback(callback);
+
+ SetInt64(argList, 0, callbackId);
+ argList->SetList(1, params);
+
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, request);
+ }
+ }
+ 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'});");
+
+ if (context->Eval(promiseResolveScript, CefString(), 0, promiseResolve, promiseException))
+ {
+ retval = promiseResolve;
+
+ if (notifyIfAlreadyBound)
+ {
+ NotifyObjectBound(frame, objectNamesWithBoundStatus);
+ }
+ }
+ else
+ {
+ exception = promiseException->GetMessage();
+ }
+ }
+ }
+ else
+ {
+ exception = "BindObjectAsyncHandler::Execute - Frame is invalid.";
+ }
+ }
+ finally
+ {
+ context->Exit();
+ }
+ }
+ else
+ {
+ exception = "BindObjectAsyncHandler::Execute - Unable to Get or Enter Context";
+ }
+
+
+ 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();
+
+ auto boundObjects = CefListValue::Create();
+ auto index = 0;
+
+ 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);
+
+ boundObjects->SetDictionary(index++, dict);
+ }
+
+ args->SetList(0, boundObjects);
+
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, msg);
+ }
+
+ bool GetV8BoolValue(const CefRefPtr val, const CefString key, const CefString camelCaseKey)
+ {
+ if (val->HasValue(key))
+ {
+ auto obj = val->GetValue(key);
+ if (obj->IsBool())
+ {
+ return obj->GetBoolValue();
+ }
+ }
+
+ if (val->HasValue(camelCaseKey))
+ {
+ auto obj = val->GetValue(camelCaseKey);
+ if (obj->IsBool())
+ {
+ return obj->GetBoolValue();
+ }
+ }
+
+ return false;
+ }
+
+ IMPLEMENT_REFCOUNTINGM(BindObjectAsyncHandler);
+ };
+ }
+}
+
diff --git a/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h b/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h
new file mode 100644
index 0000000000..f4f9ca45be
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h
@@ -0,0 +1,165 @@
+// Copyright © 2019 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 "SubProcess.h"
+
+using namespace System;
+using namespace CefSharp::Internals;
+
+namespace CefSharp
+{
+ namespace BrowserSubprocess
+ {
+ ///
+ /// BrowserSubprocessExecutable provides the fundimental browser process handling for
+ /// CefSharp.BrowserSubprocess.exe and can be used to self host the BrowserSubProcess in your
+ /// existing application (preferred approach for .Net Core).
+ ///
+ public ref class BrowserSubprocessExecutable
+ {
+ public:
+ BrowserSubprocessExecutable()
+ {
+
+ }
+
+#ifdef NETCOREAPP
+ ///
+ /// 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.
+ ///
+ ///
+ /// 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
+ /// supplied, see https://github.com/cefsharp/CefSharp/wiki/General-Usage#processes for more details.
+ ///
+ /// command line args
+ ///
+ /// 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)
+ {
+ return 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
+ /// supplied, see https://github.com/cefsharp/CefSharp/wiki/General-Usage#processes for more details.
+ ///
+ /// command line args
+ /// An option IRenderProcessHandler implementation, use null if no handler is required
+ ///
+ /// 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.
+ ///
+ int Main(IEnumerable^ args, IRenderProcessHandler^ handler)
+ {
+ 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")
+ {
+ //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))
+ {
+ ParentProcessMonitor::StartMonitorTask(parentProcessId);
+ }
+ }
+
+ // Use our custom subProcess provides features like EvaluateJavascript
+ if (type == "renderer")
+ {
+ auto subProcess = GetSubprocess(args, parentProcessId, handler);
+
+ try
+ {
+ return subProcess->Run();
+ }
+ finally
+ {
+ delete subProcess;
+ }
+ }
+
+ return SubProcess::ExecuteProcess(args);
+ }
+
+ protected:
+ virtual SubProcess^ GetSubprocess(IEnumerable^ args, int parentProcessId, IRenderProcessHandler^ handler)
+ {
+ return gcnew SubProcess(handler, args);
+ }
+ };
+ }
+}
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 d6590048d2..05ec2fbefc 100644
--- a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp
+++ b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp
@@ -1,267 +1,827 @@
-// Copyright © 2010-2015 The CefSharp Project. All rights reserved.
+// Copyright © 2014 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
#pragma once
#include "Stdafx.h"
#include "CefBrowserWrapper.h"
#include "CefAppUnmanagedWrapper.h"
+#include "RegisterBoundObjectHandler.h"
+#include "BindObjectAsyncHandler.h"
+#include "JavascriptPostMessageHandler.h"
#include "JavascriptRootObjectWrapper.h"
+#include "JavascriptPromiseHandler.h"
+#include "JavascriptPromiseResolverCatch.h"
+#include "JavascriptPromiseResolverThen.h"
+#include "Async\JavascriptAsyncMethodCallback.h"
#include "Serialization\V8Serialization.h"
-#include "..\CefSharp.Core\Internals\Messaging\Messages.h"
-#include "..\CefSharp.Core\Internals\Serialization\Primitives.h"
+#include "Serialization\JsObjectsSerialization.h"
+#include "Wrapper\V8Context.h"
+#include "Wrapper\Frame.h"
+#include "Wrapper\Browser.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::Serialization;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
- 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)
- {
- 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->Add(browser->GetIdentifier(), wrapper);
- }
+ //Multiple CefBrowserWrappers created when opening popups
+ auto browserId = browser->GetIdentifier();
+ _browserWrappers->TryAdd(browserId, wrapper);
- void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr browser)
- {
- auto wrapper = FindBrowserWrapper(browser->GetIdentifier(), false);
+ static gcroot^> factory =
+ gcnew Func(CefAppUnmanagedWrapper::JavascriptBindingSettingsFactory);
- if (wrapper != nullptr)
- {
- _browserWrappers->Remove(wrapper->BrowserId);
- _onBrowserDestroyed->Invoke(wrapper);
- delete wrapper;
+ auto javascriptBindingSettings = _browserJavascriptBindingSettings->GetOrAdd(browserId, factory);
+
+ if (!extraInfo.get())
+ {
+ return;
+ }
+
+ //For the main browser only we check LegacyBindingEnabled and
+ //load the objects. Popups don't send this information and checking
+ //will override the _legacyBindingEnabled field
+ if (!browser->IsPopup())
+ {
+ javascriptBindingSettings->LegacyBindingEnabled = extraInfo->GetBool("LegacyBindingEnabled");
+
+ if (javascriptBindingSettings->LegacyBindingEnabled)
+ {
+ auto objects = extraInfo->GetList("LegacyBindingObjects");
+ if (objects.get() && objects->IsValid())
+ {
+ auto javascriptObjects = DeserializeJsObjects(objects, 0);
+
+ for each (JavascriptObject ^ obj in Enumerable::OfType(javascriptObjects))
+ {
+ //Using LegacyBinding with multiple ChromiumWebBrowser instances that share the same
+ //render process and using LegacyBinding will cause problems for the limited caching implementation
+ //that exists at the moment, for now we'll remove an object if already exists, same behaviour
+ //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);
+ }
+ }
+ }
+ }
+
+ if (extraInfo->HasKey("JavascriptBindingApiEnabled"))
+ {
+ javascriptBindingSettings->JavascriptBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
+ }
+
+ if (extraInfo->HasKey("JavascriptBindingApiHasAllowOrigins"))
+ {
+ javascriptBindingSettings->JavascriptBindingApiHasAllowOrigins = extraInfo->GetBool("JavascriptBindingApiHasAllowOrigins");
+
+ if (javascriptBindingSettings->JavascriptBindingApiHasAllowOrigins)
+ {
+ auto allowOrigins = extraInfo->GetList("JavascriptBindingApiAllowOrigins");
+ if (allowOrigins.get() && allowOrigins->IsValid())
+ {
+ javascriptBindingSettings->JavascriptBindingApiAllowOrigins = allowOrigins->Copy();
+ }
+ }
+ }
+
+ 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"));
+ }
}
- };
- void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context)
- {
- auto wrapper = FindBrowserWrapper(browser->GetIdentifier(), true);
+ void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr browser)
+ {
+ CefBrowserWrapper^ wrapper;
+ if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
+ {
+ _onBrowserDestroyed->Invoke(wrapper);
+ delete wrapper;
+ }
+
+ // Don't remove javascript settings because cef is unreliable in calling OnBrowserCreated/OnBrowserDestroyed consistently:
+ // https://github.com/cefsharp/CefSharp/issues/5228
+ };
- if (wrapper->JavascriptRootObject != nullptr)
+ void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context)
{
- auto window = context->GetGlobal();
+ if (!Object::ReferenceEquals(_handler, nullptr))
+ {
+ Browser browserWrapper(browser);
+ Frame frameWrapper(frame);
+ V8Context contextWrapper(context);
- wrapper->JavascriptRootObjectWrapper = gcnew JavascriptRootObjectWrapper(wrapper->JavascriptRootObject, wrapper->BrowserProcess);
+ _handler->OnContextCreated(% browserWrapper, % frameWrapper, % contextWrapper);
+ }
- wrapper->JavascriptRootObjectWrapper->V8Value = window;
- wrapper->JavascriptRootObjectWrapper->Bind();
- }
- };
+ //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;
+
+ JavascriptBindingSettings^ javascriptBindingSettings = nullptr;
+ _browserJavascriptBindingSettings->TryGetValue(browser->GetIdentifier(), javascriptBindingSettings);
+
+ if (!Object::ReferenceEquals(javascriptBindingSettings, nullptr))
+ {
+ auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
+
+ if (javascriptBindingSettings->LegacyBindingEnabled)
+ {
+ if (_javascriptObjects->Count > 0 && rootObject != nullptr)
+ {
+ rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
+ }
+ }
+
+ 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);
+ }
- void CefAppUnmanagedWrapper::OnContextReleased(CefRefPtr browser, CefRefPtr frame, CefRefPtr context)
- {
- auto wrapper = FindBrowserWrapper(browser->GetIdentifier(), true);
+ 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);
+ }
+ }
+ }
- if (wrapper->JavascriptRootObjectWrapper != nullptr)
+ //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)
{
- delete wrapper->JavascriptRootObjectWrapper;
- wrapper->JavascriptRootObjectWrapper = nullptr;
- }
- };
+ if (!Object::ReferenceEquals(_handler, nullptr))
+ {
+ Browser browserWrapper(browser);
+ Frame frameWrapper(frame);
+ V8Context contextWrapper(context);
- CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId, bool mustExist)
- {
- CefBrowserWrapper^ wrapper = nullptr;
+ _handler->OnContextReleased(% browserWrapper, % frameWrapper, % contextWrapper);
+ }
+
+ auto contextReleasedMessage = CefProcessMessage::Create(kOnContextReleasedRequest);
+
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextReleasedMessage);
- _browserWrappers->TryGetValue(browserId, wrapper);
+ auto rootObjectWrappers = _jsRootObjectWrappersByFrameId;
+
+ //If we no longer have a _jsRootObjectWrappersByFrameId reference then there's nothing we can do
+ if (Object::ReferenceEquals(rootObjectWrappers, nullptr))
+ {
+ return;
+ }
- if (mustExist && wrapper == nullptr)
+ JavascriptRootObjectWrapper^ wrapper;
+ if (rootObjectWrappers->TryRemove(StringUtils::ToClr(frame->GetIdentifier()), wrapper))
+ {
+ delete wrapper;
+ }
+ };
+
+ void CefAppUnmanagedWrapper::OnFocusedNodeChanged(CefRefPtr browser, CefRefPtr frame, CefRefPtr node)
{
- throw gcnew InvalidOperationException(String::Format("Failed to identify BrowserWrapper in OnContextCreated. : {0}", browserId));
+ if (!_focusedNodeChangedEnabled)
+ {
+ return;
+ }
+
+ auto focusedNodeChangedMessage = CefProcessMessage::Create(kOnFocusedNodeChanged);
+ auto list = focusedNodeChangedMessage->GetArgumentList();
+
+ // The node will be empty if an element loses focus but another one
+ // doesn't gain focus. Only transfer information if the node is an
+ // element.
+ if (node != nullptr && node->IsElement())
+ {
+ // True when a node exists, false if it doesn't.
+ list->SetBool(0, true);
+
+ // Store the tag name.
+ list->SetString(1, node->GetElementTagName());
+
+ // Transfer the attributes in a Dictionary.
+ auto attributes = CefDictionaryValue::Create();
+ CefDOMNode::AttributeMap attributeMap;
+ node->GetElementAttributes(attributeMap);
+ for (auto iter : attributeMap)
+ {
+ attributes->SetString(iter.first, iter.second);
+ }
+
+ list->SetDictionary(2, attributes);
+ }
+ else
+ {
+ list->SetBool(0, false);
+ }
+
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, focusedNodeChangedMessage);
}
- return wrapper;
- }
+ void CefAppUnmanagedWrapper::OnUncaughtException(CefRefPtr browser, CefRefPtr frame, CefRefPtr context, CefRefPtr exception, CefRefPtr stackTrace)
+ {
+ auto uncaughtExceptionMessage = CefProcessMessage::Create(kOnUncaughtException);
+ auto list = uncaughtExceptionMessage->GetArgumentList();
- bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr browser, CefProcessId sourceProcessId, CefRefPtr message)
- {
- auto handled = false;
- auto name = message->GetName();
- auto argList = message->GetArgumentList();
+ list->SetString(0, exception->GetMessage());
- auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier(), false);
+ auto frames = CefListValue::Create();
+ for (auto i = 0; i < stackTrace->GetFrameCount(); i++)
+ {
+ auto stackTraceFrame = CefListValue::Create();
+ auto frameArg = stackTrace->GetFrame(i);
+
+ stackTraceFrame->SetString(0, frameArg->GetFunctionName());
+ stackTraceFrame->SetInt(1, frameArg->GetLineNumber());
+ stackTraceFrame->SetInt(2, frameArg->GetColumn());
+ stackTraceFrame->SetString(3, frameArg->GetScriptNameOrSourceURL());
+
+ frames->SetList(i, stackTraceFrame);
+ }
+
+ list->SetList(1, frames);
+
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, uncaughtExceptionMessage);
+ }
- //Error handling for missing/closed browser
- if (browserWrapper == nullptr)
+ JavascriptRootObjectWrapper^ CefAppUnmanagedWrapper::GetJsRootObjectWrapper(int browserId, const CefString& frameId)
{
- if (name == kJavascriptCallbackDestroyRequest)
+ auto rootObjectWrappers = _jsRootObjectWrappersByFrameId;
+
+ if (Object::ReferenceEquals(rootObjectWrappers, 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 nullptr;
}
- CefString responseName;
- if (name == kEvaluateJavascriptRequest)
+ auto frameIdClr = StringUtils::ToClr(frameId);
+
+ JavascriptRootObjectWrapper^ rootObject;
+ if (!rootObjectWrappers->TryGetValue(frameIdClr, rootObject))
{
- responseName = kEvaluateJavascriptResponse;
+#ifdef NETCOREAPP
+ rootObject = gcnew JavascriptRootObjectWrapper();
+#else
+ auto browserWrapper = FindBrowserWrapper(browserId);
+
+ rootObject = gcnew JavascriptRootObjectWrapper(browserWrapper == nullptr ? nullptr : browserWrapper->BrowserProcess);
+#endif
+ rootObjectWrappers->TryAdd(frameIdClr, rootObject);
}
- else if (name == kJavascriptCallbackRequest)
+
+ return rootObject;
+ }
+
+ bool CefAppUnmanagedWrapper::IsJavascriptBindingApiAllowed(JavascriptBindingSettings^ javascriptBindingSettings, CefRefPtr frame)
+ {
+ if (javascriptBindingSettings == nullptr)
{
- responseName = kJavascriptCallbackResponse;
+ return false;
}
- else
+
+ if (!javascriptBindingSettings->JavascriptBindingApiEnabled)
{
- //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 havn't yet implemented the render process functionality.
- throw gcnew Exception("Unsupported message type");
+ return false;
}
- auto callbackId = GetInt64(argList, 1);
- 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());
+ if (!javascriptBindingSettings->JavascriptBindingApiHasAllowOrigins)
+ {
+ return true;
+ }
- //success: false
- responseArgList->SetBool(0, false);
- SetInt64(callbackId, responseArgList, 1);
- responseArgList->SetString(2, StringUtils::ToNative(errorMessage));
- browser->SendProcessMessage(sourceProcessId, response);
+ auto allowOrigins = javascriptBindingSettings->JavascriptBindingApiAllowOrigins;
+ if (!allowOrigins.get())
+ {
+ return false;
+ }
- return true;
+ auto frameUrl = frame->GetURL();
+
+ CefURLParts frameUrlParts;
+
+ if (CefParseURL(frameUrl, frameUrlParts))
+ {
+ auto originStr = frameUrlParts.origin.str;
+ auto originLen = frameUrlParts.origin.length;
+
+ if (originLen > 0 && originStr[originLen - 1] == L'/')
+ {
+ originLen--;
+ }
+
+ auto frameUrlOrigin = CefString(originStr, originLen);
+
+ auto size = static_cast(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;
- CefRefPtr result;
- CefString errorMessage;
- CefRefPtr response;
- //both messages have the callbackid stored at index 1
- int64 callbackId = GetInt64(argList, 1);
-
- if (name == kEvaluateJavascriptRequest)
+ CefBrowserWrapper^ wrapper = nullptr;
+
+ _browserWrappers->TryGetValue(browserId, wrapper);
+
+ if (wrapper == nullptr)
{
- auto frameId = GetInt64(argList, 0);
- auto script = argList->GetString(2);
+ //TODO: Find the syntax for delcaring the native string directly
+ LOG(ERROR) << StringUtils::ToNative("Failed to identify BrowserWrapper in OnContextCreated BrowserId:" + browserId).ToString();
+ }
+
+ return wrapper;
+ }
- response = CefProcessMessage::Create(kEvaluateJavascriptResponse);
+ bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId sourceProcessId, CefRefPtr message)
+ {
+ auto handled = false;
+ auto name = message->GetName();
+ auto argList = message->GetArgumentList();
+
+ //these messages are roughly handled the same way
+ if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest)
+ {
+ bool sendResponse = true;
+ bool success = false;
+ CefRefPtr result;
+ CefString errorMessage;
+ CefRefPtr response;
- auto frame = browser->GetFrame(frameId);
- if (frame.get())
+ if (name == kEvaluateJavascriptRequest)
{
- auto context = frame->GetV8Context();
-
- if (context.get() && context->Enter())
+ response = CefProcessMessage::Create(kEvaluateJavascriptResponse);
+ }
+ else
+ {
+ response = CefProcessMessage::Create(kJavascriptCallbackResponse);
+ }
+
+ //both messages have callbackId stored at index 0
+ auto frameId = StringUtils::ToClr(frame->GetIdentifier());
+ int64_t callbackId = GetInt64(argList, 0);
+
+ //NOTE: In the rare case when when OnContextCreated hasn't been called we need to manually create the rootObjectWrapper
+ //It appears that OnContextCreated is only called for pages that have javascript on them, which makes sense
+ //as without javascript there is no need for a context.
+ JavascriptRootObjectWrapper^ rootObjectWrapper = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
+
+ if (name == kEvaluateJavascriptRequest)
+ {
+ auto script = argList->GetString(1);
+ auto scriptUrl = argList->GetString(2);
+ auto startLine = argList->GetInt(3);
+
+ if (frame.get() && frame->IsValid())
{
- try
+ auto context = frame->GetV8Context();
+
+ if (context.get() && context->Enter())
{
- CefRefPtr exception;
- success = context->Eval(script, result, exception);
-
- //we need to do this here to be able to store the v8context
- if (success)
+ try
{
- auto responseArgList = response->GetArgumentList();
- SerializeV8Object(result, responseArgList, 2, browserWrapper->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 = exception->GetMessage();
+ 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 = "Unable to Get Frame matching Id";
+ auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
+ if (callbackRegistry == nullptr)
+ {
+ errorMessage = StringUtils::ToNative("The callback registry for Frame " + frameId + " is no longer available, most likely the Frame has been Disposed.");
+ }
+ else
+ {
+ auto jsCallbackId = GetInt64(argList, 1);
+
+ auto callbackWrapper = callbackRegistry->FindWrapper(jsCallbackId);
+ if (callbackWrapper == nullptr)
+ {
+ errorMessage = StringUtils::ToNative("Unable to find JavascriptCallback with Id " + jsCallbackId + " for Frame " + frameId);
+ }
+ else
+ {
+ auto context = callbackWrapper->GetContext();
+ auto value = callbackWrapper->GetValue();
+
+ if (context.get() && context->Enter())
+ {
+ try
+ {
+ auto parameterList = argList->GetList(2);
+ CefV8ValueList params;
+
+ //Needs to be called within the context as for Dictionary (mapped to struct)
+ //a V8Object will be created
+ for (CefV8ValueList::size_type i = 0; i < parameterList->GetSize(); i++)
+ {
+ params.push_back(DeserializeV8Object(parameterList, static_cast(i)));
+ }
+
+ result = value->ExecuteFunction(nullptr, params);
+ success = result.get() != nullptr;
+
+ //we need to do this here to be able to store the v8context
+ if (success)
+ {
+ //If the response is a string of CefSharpDefEvalScriptRes then
+ //we don't send the response, we'll let that happen when the promise has completed.
+ if (result->IsString() && result->GetStringValue() == "CefSharpDefEvalScriptRes")
+ {
+ sendResponse = false;
+ }
+ else if (result->IsPromise())
+ {
+ sendResponse = false;
+
+ auto promiseThen = result->GetValue("then");
+ auto promiseCatch = result->GetValue("catch");
+
+ auto promiseThenFunc = CefV8Value::CreateFunction("promiseResolverThen", new JavascriptPromiseResolverThen(callbackId, true));
+ auto promiseCatchFunc = CefV8Value::CreateFunction("promiseResolverCatch", new JavascriptPromiseResolverCatch(callbackId, true));
+
+ CefV8ValueList promiseThenArgs;
+ promiseThenArgs.push_back(promiseThenFunc);
+ promiseThen->ExecuteFunction(result, promiseThenArgs);
+
+ CefV8ValueList promiseCatchArgs;
+ promiseCatchArgs.push_back(promiseCatchFunc);
+ promiseCatch->ExecuteFunction(result, promiseCatchArgs);
+ }
+ else
+ {
+ auto responseArgList = response->GetArgumentList();
+ SerializeV8Object(result, responseArgList, 2, callbackRegistry);
+ }
+ }
+ else
+ {
+ auto exception = value->GetException();
+ errorMessage = StringUtils::CreateExceptionString(exception);
+ }
+ }
+ finally
+ {
+ context->Exit();
+ }
+ }
+ else
+ {
+ errorMessage = "Unable to Enter Context";
+ }
+ }
+ }
+ }
+
+ if (sendResponse)
+ {
+ auto responseArgList = response->GetArgumentList();
+ responseArgList->SetBool(0, success);
+ SetInt64(responseArgList, 1, callbackId);
+ if (!success)
+ {
+ responseArgList->SetString(2, errorMessage);
+ }
+ frame->SendProcessMessage(sourceProcessId, response);
}
+
+ handled = true;
}
- else
+ else if (name == kJavascriptCallbackDestroyRequest)
{
- auto jsCallbackId = GetInt64(argList, 0);
- auto parameterList = argList->GetList(2);
- CefV8ValueList params;
- for (CefV8ValueList::size_type i = 0; i < parameterList->GetSize(); i++)
+ if (frame.get() && frame->IsValid())
{
- params.push_back(DeserializeV8Object(parameterList, static_cast(i)));
+ auto jsCallbackId = GetInt64(argList, 0);
+ JavascriptRootObjectWrapper^ rootObjectWrapper;
+ _jsRootObjectWrappersByFrameId->TryGetValue(StringUtils::ToClr(frame->GetIdentifier()), rootObjectWrapper);
+ if (rootObjectWrapper != nullptr && rootObjectWrapper->CallbackRegistry != nullptr)
+ {
+ rootObjectWrapper->CallbackRegistry->Deregister(jsCallbackId);
+ }
}
- response = CefProcessMessage::Create(kJavascriptCallbackResponse);
-
- auto callbackRegistry = browserWrapper->CallbackRegistry;
- auto callbackWrapper = callbackRegistry->FindWrapper(jsCallbackId);
- auto context = callbackWrapper->GetContext();
- auto value = callbackWrapper->GetValue();
-
- if (context.get() && context->Enter())
+ handled = true;
+ }
+ else if (name == kJavascriptRootObjectResponse)
+ {
+ if (browser.get() && frame.get() && frame->IsValid())
{
- try
+ 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))
{
- 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 (_javascriptObjects->ContainsKey(obj->JavascriptName))
{
- auto responseArgList = response->GetArgumentList();
- SerializeV8Object(result, responseArgList, 2, browserWrapper->CallbackRegistry);
+ _javascriptObjects->Remove(obj->JavascriptName);
}
- else
+ _javascriptObjects->Add(obj->JavascriptName, obj);
+ }
+
+ auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
+
+ if (rootObject == nullptr)
+ {
+ return false;
+ }
+
+ auto context = frame->GetV8Context();
+
+ if (context.get() && context->Enter())
+ {
+ JavascriptAsyncMethodCallback^ callback;
+
+ try
{
- auto exception = value->GetException();
- if(exception.get())
+ rootObject->Bind(javascriptObjects, context->GetGlobal());
+
+ if (_registerBoundObjectRegistry->TryGetAndRemoveMethodCallback(callbackId, callback))
{
- errorMessage = exception->GetMessage();
+ //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);
+
+ if (javascriptObjects->Count > 0)
+ {
+ //TODO: JSB Should we include a list of successfully bound object names?
+ response->SetValue("Success", CefV8Value::CreateBool(true), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
+ response->SetValue("Message", CefV8Value::CreateString("OK"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
+ callback->Success(response);
+ }
+ else
+ {
+ response->SetValue("Success", CefV8Value::CreateBool(false), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
+ response->SetValue("Message", CefV8Value::CreateString("Zero objects bounds"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
+ callback->Success(response);
+ }
+
+ //Send message notifying Browser Process of which objects were bound
+ //We do this after the objects have been created in the V8Context to gurantee
+ //they are accessible.
+ auto msg = CefProcessMessage::Create(kJavascriptObjectsBoundInJavascript);
+ auto args = msg->GetArgumentList();
+
+ auto boundObjects = CefListValue::Create();
+
+ 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);
+
+ frame->SendProcessMessage(CefProcessId::PID_BROWSER, msg);
}
}
- }
- finally
- {
- context->Exit();
+ finally
+ {
+ context->Exit();
+
+ delete callback;
+ }
}
}
else
{
- errorMessage = "Unable to Enter Context";
- }
- }
+ LOG(INFO) << "CefAppUnmanagedWrapper Frame Invalid";
+ }
- if (response.get())
+ handled = true;
+ }
+ else if (name == kJavascriptAsyncMethodCallResponse)
{
- auto responseArgList = response->GetArgumentList();
- responseArgList->SetBool(0, success);
- SetInt64(callbackId, responseArgList, 1);
- if (!success)
+ if (frame.get() && frame->IsValid())
{
- responseArgList->SetString(2, errorMessage);
+ auto frameId = StringUtils::ToClr(frame->GetIdentifier());
+ auto callbackId = GetInt64(argList, 0);
+
+ JavascriptRootObjectWrapper^ rootObjectWrapper;
+ _jsRootObjectWrappersByFrameId->TryGetValue(frameId, rootObjectWrapper);
+
+ if (rootObjectWrapper != nullptr)
+ {
+ JavascriptAsyncMethodCallback^ callback;
+ if (rootObjectWrapper->TryGetAndRemoveMethodCallback(callbackId, callback))
+ {
+ try
+ {
+ auto context = frame->GetV8Context();
+
+ if (context.get() && context->Enter())
+ {
+ try
+ {
+ auto success = argList->GetBool(1);
+ if (success)
+ {
+ callback->Success(DeserializeV8Object(argList, 2));
+ }
+ else
+ {
+ callback->Fail(argList->GetString(2));
+ }
+ }
+ finally
+ {
+ context->Exit();
+ }
+ }
+ else
+ {
+ callback->Fail("Unable to Enter Context");
+ }
+ }
+ finally
+ {
+ //dispose
+ delete callback;
+ }
+ }
+ }
}
- browser->SendProcessMessage(sourceProcessId, response);
+ handled = true;
}
- handled = true;
- }
- else if (name == kJavascriptCallbackDestroyRequest)
- {
- auto jsCallbackId = GetInt64(argList, 0);
- browserWrapper->CallbackRegistry->Deregister(jsCallbackId);
+ return handled;
+ };
- handled = true;
+ void CefAppUnmanagedWrapper::OnWebKitInitialized()
+ {
+ if (!Object::ReferenceEquals(_handler, nullptr))
+ {
+ _handler->OnWebKitInitialized();
+ }
}
-
- return handled;
- };
-}
\ No newline at end of file
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h
index a6755f218d..a6d90755d1 100644
--- a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h
@@ -1,51 +1,114 @@
-// Copyright © 2010-2015 The CefSharp Project. All rights reserved.
+// Copyright © 2014 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#pragma once
-
#include "Stdafx.h"
-#include "include/cef_app.h"
#include "include/cef_base.h"
+#include "SubProcessApp.h"
#include "CefBrowserWrapper.h"
+#include "JavascriptBindingSettings.h"
+#include "RegisterBoundObjectRegistry.h"
using namespace System::Collections::Generic;
+using namespace CefSharp::RenderProcess;
namespace CefSharp
{
- // This class is the native subprocess level CEF object wrapper.
- private class CefAppUnmanagedWrapper : CefApp, CefRenderProcessHandler
+ namespace BrowserSubprocess
{
- private:
- gcroot^> _onBrowserCreated;
- gcroot^> _onBrowserDestroyed;
- gcroot^> _browserWrappers;
- public:
- CefAppUnmanagedWrapper(Action^ onBrowserCreated, Action^ onBrowserDestoryed)
+ // This class is the native subprocess level CEF object wrapper.
+ private class CefAppUnmanagedWrapper : SubProcessApp, CefRenderProcessHandler
{
- _onBrowserCreated = onBrowserCreated;
- _onBrowserDestroyed = onBrowserDestoryed;
- _browserWrappers = gcnew Dictionary();
- }
+ private:
+ gcroot _handler;
+ gcroot^> _onBrowserCreated;
+ gcroot^> _onBrowserDestroyed;
+ gcroot^> _browserWrappers;
+ gcroot^> _browserJavascriptBindingSettings;
+ gcroot^> _jsRootObjectWrappersByFrameId;
+ bool _focusedNodeChangedEnabled;
- ~CefAppUnmanagedWrapper()
- {
- delete _browserWrappers;
- delete _onBrowserCreated;
- delete _onBrowserDestroyed;
- }
-
- CefBrowserWrapper^ FindBrowserWrapper(int browserId, bool mustExist);
-
- virtual DECL CefRefPtr GetRenderProcessHandler() OVERRIDE;
- virtual DECL void OnBrowserCreated(CefRefPtr browser) 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, CefProcessId sourceProcessId, CefRefPtr message) OVERRIDE;
-
- IMPLEMENT_REFCOUNTING(CefAppUnmanagedWrapper);
- };
+ // The serialized registered object data waiting to be used.
+ gcroot^> _javascriptObjects;
+
+ gcroot _registerBoundObjectRegistry;
+
+ static bool IsJavascriptBindingApiAllowed(JavascriptBindingSettings^ javascriptBindingSettings, CefRefPtr frame);
+
+ static JavascriptBindingSettings^ JavascriptBindingSettingsFactory(int _)
+ {
+ 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))
+ {
+ for each (JavascriptBindingSettings ^ javascriptBindingSettings in _browserJavascriptBindingSettings->Values)
+ {
+ delete javascriptBindingSettings;
+ }
+
+ _browserJavascriptBindingSettings = nullptr;
+ }
+
+ if (!Object::ReferenceEquals(_jsRootObjectWrappersByFrameId, nullptr))
+ {
+ for each (JavascriptRootObjectWrapper^ rootObject in _jsRootObjectWrappersByFrameId->Values)
+ {
+ delete rootObject;
+ }
+
+ _jsRootObjectWrappersByFrameId = nullptr;
+ }
+
+ delete _onBrowserCreated;
+ delete _onBrowserDestroyed;
+ }
+
+ 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/CefAppWrapper.cpp b/CefSharp.BrowserSubprocess.Core/CefAppWrapper.cpp
deleted file mode 100644
index d9cdddeaa1..0000000000
--- a/CefSharp.BrowserSubprocess.Core/CefAppWrapper.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright © 2010-2015 The CefSharp Project. 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 "CefAppWrapper.h"
-
-using namespace System;
-using namespace System::Diagnostics;
-using namespace System::Collections::Generic;
-
-namespace CefSharp
-{
- int CefAppWrapper::Run()
- {
- auto hInstance = Process::GetCurrentProcess()->Handle;
-
- CefMainArgs cefMainArgs((HINSTANCE)hInstance.ToPointer());
-
- return CefExecuteProcess(cefMainArgs, (CefApp*)_cefApp.get(), NULL);
- }
-}
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess.Core/CefAppWrapper.h b/CefSharp.BrowserSubprocess.Core/CefAppWrapper.h
deleted file mode 100644
index 15fe97db07..0000000000
--- a/CefSharp.BrowserSubprocess.Core/CefAppWrapper.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright © 2010-2015 The CefSharp Project. 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_app.h"
-#include "include/cef_base.h"
-
-#include "CefBrowserWrapper.h"
-#include "CefAppUnmanagedWrapper.h"
-#include ".\..\CefSharp.Core\Internals\CefTaskScheduler.h"
-
-using namespace System::Collections::Generic;
-
-namespace CefSharp
-{
- // Wrap CefAppUnmangedWrapper in a nice managed wrapper
- public ref class CefAppWrapper abstract : public DisposableResource
- {
- private:
- MCefRefPtr _cefApp;
-
- public:
- CefAppWrapper()
- {
- auto onBrowserCreated = gcnew Action(this, &CefAppWrapper::OnBrowserCreated);
- auto onBrowserDestroyed = gcnew Action(this, &CefAppWrapper::OnBrowserDestroyed);
- _cefApp = new CefAppUnmanagedWrapper(onBrowserCreated, onBrowserDestroyed);
-
- RenderThreadTaskFactory = gcnew TaskFactory(gcnew CefTaskScheduler(TID_RENDERER));
- };
-
- !CefAppWrapper()
- {
- _cefApp = nullptr;
- }
-
- ~CefAppWrapper()
- {
- this->!CefAppWrapper();
- RenderThreadTaskFactory = nullptr;
- }
-
- int Run();
-
- property TaskFactory^ RenderThreadTaskFactory;
-
- virtual void OnBrowserCreated(CefBrowserWrapper^ cefBrowserWrapper) abstract;
- virtual void OnBrowserDestroyed(CefBrowserWrapper^ cefBrowserWrapper) abstract;
- };
-}
diff --git a/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.cpp b/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.cpp
deleted file mode 100644
index 9ad4795c60..0000000000
--- a/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2010-2015 The CefSharp Project. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
-#pragma once
-
-#include "Stdafx.h"
-
-#include "CefBrowserWrapper.h"
-
-namespace CefSharp
-{
- JavascriptRootObjectWrapper^ CefBrowserWrapper::JavascriptRootObjectWrapper::get()
- {
- return _javascriptRootObjectWrapper;
- }
-
- void CefBrowserWrapper::JavascriptRootObjectWrapper::set(CefSharp::JavascriptRootObjectWrapper^ value)
- {
- _javascriptRootObjectWrapper = value;
- if (_javascriptRootObjectWrapper != nullptr)
- {
- _javascriptRootObjectWrapper->CallbackRegistry = _callbackRegistry;
- }
- }
-
- JavascriptCallbackRegistry^ CefBrowserWrapper::CallbackRegistry::get()
- {
- return _callbackRegistry;
- }
-}
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h b/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h
index 085dcfb156..934725eaeb 100644
--- a/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h
@@ -1,80 +1,61 @@
-// Copyright © 2010-2015 The CefSharp Authors. All rights reserved.
+// 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_browser.h"
-#include "include/cef_runnable.h"
#include "include/cef_v8.h"
#include "TypeUtils.h"
#include "Stdafx.h"
#include "JavascriptRootObjectWrapper.h"
-using namespace CefSharp::Internals;
-using namespace System;
+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;
- JavascriptCallbackRegistry^ _callbackRegistry;
- JavascriptRootObjectWrapper^ _javascriptRootObjectWrapper;
-
- internal:
- property JavascriptCallbackRegistry^ CallbackRegistry
- {
- CefSharp::Internals::JavascriptCallbackRegistry^ get();
- }
-
- public:
- CefBrowserWrapper(CefRefPtr cefBrowser)
+ // "Master class" for wrapping everything that the Cef Subprocess needs
+ // for ONE CefBrowser.
+ public ref class CefBrowserWrapper
{
- _cefBrowser = cefBrowser;
- BrowserId = cefBrowser->GetIdentifier();
- IsPopup = cefBrowser->IsPopup();
- _callbackRegistry = gcnew JavascriptCallbackRegistry(BrowserId);
- }
-
- !CefBrowserWrapper()
- {
- _cefBrowser = nullptr;
- }
+ private:
+ MCefRefPtr _cefBrowser;
- ~CefBrowserWrapper()
- {
- this->!CefBrowserWrapper();
- if (_callbackRegistry != nullptr)
+ public:
+ CefBrowserWrapper(const CefRefPtr &cefBrowser)
{
- delete _callbackRegistry;
- _callbackRegistry = 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 serialized registered object data waiting to be used.
- property JavascriptRootObject^ JavascriptRootObject;
+ property int BrowserId;
+ property bool IsPopup;
- property JavascriptRootObjectWrapper^ JavascriptRootObjectWrapper
- {
- CefSharp::JavascriptRootObjectWrapper^ get();
- void set(CefSharp::JavascriptRootObjectWrapper^ value);
+#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
};
-
- // The WCF proxy to the parent process.
- property IBrowserProcess^ BrowserProcess;
- };
+ }
}
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..87f33723fc
--- /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 d90ca20a48..48e8c12730 100644
--- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj
+++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj
@@ -1,6 +1,9 @@
-
-
+
+
+
+
+
Debug
@@ -23,9 +26,11 @@
{6C4BB501-2F8E-48AC-9AB5-8CFB2D74185C}
ManagedCProj
CefSharpBrowserSubprocessCore
+ v4.6.2
+ 10.0
-
+
DynamicLibrary
true
@@ -65,26 +70,36 @@
-
- 6f7de856
-
+
true
..\CefSharp.snk
true
+ bin\$(Platform)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
true
..\CefSharp.snk
true
+ bin\$(Platform)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
false
..\CefSharp.snk
+ bin\$(Platform)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
false
..\CefSharp.snk
+ bin\$(Platform)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+ $(SolutionDir)packages\$(CefSdkVer)\CEF;$(SourcePath)
@@ -94,11 +109,14 @@
WIN32;_DEBUG;EXPORT;%(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);$(SolutionDir)CefSharp.Core\bin
+ 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)
@@ -109,11 +127,14 @@
Disabled
WIN32;_DEBUG;EXPORT;%(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);$(SolutionDir)CefSharp.Core\bin
+ 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)
@@ -124,6 +145,9 @@
WIN32;NDEBUG;EXPORT;%(PreprocessorDefinitions)
Use
true
+ true
+ stdcpp20
+ CompileAsCpp
true
@@ -137,6 +161,9 @@
$(SolutionDir)packages\$(CefSdkVer)\CEF;%(AdditionalIncludeDirectories);$(ProjectDir)
WIN32;NDEBUG;EXPORT;%(PreprocessorDefinitions)
Use
+ true
+ stdcpp20
+ CompileAsCpp
true
@@ -150,18 +177,38 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
-
-
@@ -170,25 +217,31 @@
+
-
-
+
+
+
+
+
+
-
-
+
+
+
-
+
Create
Create
@@ -204,8 +257,15 @@
-
+
+
+
+
-
+
+
+
+
+
\ 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 5c744c4a0f..8b695aad3e 100644
--- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters
+++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters
@@ -14,9 +14,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -35,10 +32,10 @@
Header Files
-
+
Header Files
-
+
Header Files
@@ -50,28 +47,85 @@
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
@@ -82,15 +136,9 @@
Source Files
-
- Source Files
-
Source Files
-
- Source Files
-
Source Files
@@ -103,9 +151,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -115,17 +160,53 @@
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
+
+
+ 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 775a8a9c30..a9389a9ca9 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.cpp
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.cpp
@@ -1,4 +1,4 @@
-// Copyright 2010-2015 The CefSharp Authors. All rights reserved.
+// Copyright © 2015 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.
@@ -6,24 +6,27 @@
#include "JavascriptCallbackRegistry.h"
using namespace System::Threading;
+using namespace CefSharp::BrowserSubprocess;
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
- JavascriptCallback^ JavascriptCallbackRegistry::Register(CefRefPtr context, CefRefPtr value)
+ JavascriptCallback^ JavascriptCallbackRegistry::Register(const CefRefPtr& context, const CefRefPtr& value)
{
Int64 newId = Interlocked::Increment(_lastId);
JavascriptCallbackWrapper^ wrapper = gcnew JavascriptCallbackWrapper(value, context);
_callbacks->TryAdd(newId, wrapper);
+
auto result = gcnew JavascriptCallback();
result->Id = newId;
- result->BrowserId = _browserId;
+ 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);
@@ -33,11 +36,11 @@ namespace CefSharp
void JavascriptCallbackRegistry::Deregister(Int64 id)
{
JavascriptCallbackWrapper^ callback;
- if(_callbacks->TryRemove(id, callback))
+ if (_callbacks->TryRemove(id, callback))
{
delete callback;
}
}
}
-}
\ No newline at end of file
+}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.h b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.h
index fd0d2c1f5f..b2872055a9 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.h
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackRegistry.h
@@ -1,4 +1,4 @@
-// Copyright 2010-2015 The CefSharp Authors. All rights reserved.
+// Copyright © 2015 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.
@@ -7,23 +7,26 @@
#include "JavascriptCallbackWrapper.h"
using namespace System::Collections::Concurrent;
+using namespace CefSharp::BrowserSubprocess;
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
private ref class JavascriptCallbackRegistry
{
private:
- int _browserId;
- Int64 _lastId;
+ //Only access through Interlocked::Increment - used to generate unique callback Id's
+ //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;
ConcurrentDictionary^ _callbacks;
internal:
- JavascriptCallbackWrapper^ FindWrapper(int64 id);
+ JavascriptCallbackWrapper^ FindWrapper(int64_t id);
public:
- JavascriptCallbackRegistry(int browserId) : _browserId(browserId)
+ JavascriptCallbackRegistry()
{
_callbacks = gcnew ConcurrentDictionary();
}
@@ -41,7 +44,7 @@ namespace CefSharp
}
}
- JavascriptCallback^ Register(CefRefPtr context, CefRefPtr value);
+ JavascriptCallback^ Register(const CefRefPtr& context, const CefRefPtr& value);
void Deregister(Int64 id);
};
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.cpp b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.cpp
deleted file mode 100644
index f7b516f222..0000000000
--- a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2010-2015 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.
-
-#include "stdafx.h"
-#include "TypeUtils.h"
-#include "JavascriptCallbackWrapper.h"
-#include "Serialization/V8Serialization.h"
-
-using namespace CefSharp::Internals::Serialization;
-
-namespace CefSharp
-{
- namespace Internals
- {
- CefRefPtr JavascriptCallbackWrapper::GetValue()
- {
- return _value.get();
- }
-
- CefRefPtr JavascriptCallbackWrapper::GetContext()
- {
- return _context.get();
- }
- }
-}
diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.h b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.h
index 0866c9d13b..ac2072825f 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.h
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptCallbackWrapper.h
@@ -1,4 +1,4 @@
-// Copyright 2010-2015 The CefSharp Authors. All rights reserved.
+// Copyright © 2015 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.
@@ -6,11 +6,9 @@
#include "include\cef_v8.h"
-using namespace CefSharp::Internals;
-
namespace CefSharp
{
- namespace Internals
+ namespace BrowserSubprocess
{
private ref class JavascriptCallbackWrapper
{
@@ -19,12 +17,19 @@ namespace CefSharp
MCefRefPtr _context;
internal:
- CefRefPtr GetValue();
- CefRefPtr GetContext();
+ CefRefPtr GetValue()
+ {
+ return _value.get();
+ }
+
+ CefRefPtr GetContext()
+ {
+ return _context.get();
+ }
public:
JavascriptCallbackWrapper(CefRefPtr value, CefRefPtr context)
- : _value(value), _context(context)
+ : _value(value), _context(context)
{
}
@@ -40,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 3c5e8df099..24267876dd 100644
--- a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.cpp
+++ b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.cpp
@@ -1,4 +1,4 @@
-// Copyright 2010-2015 The CefSharp Project. All rights reserved.
+// Copyright © 2015 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.
@@ -6,80 +6,75 @@
#include "TypeUtils.h"
#include "JavascriptMethodHandler.h"
-using namespace CefSharp::Internals;
-
namespace CefSharp
{
- bool JavascriptMethodHandler::Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception)
+ namespace BrowserSubprocess
{
- auto parameter = gcnew array