Add project

This commit is contained in:
Diamond Creeper 2023-02-20 23:24:10 +13:00
commit 7fcb279842
961 changed files with 370491 additions and 0 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- For older nuget versions that don't support buildTransitive save duplication -->
<Import Project="$(MSBuildThisFileDirectory)..\buildTransitive\CefSharp.Common.props"/>
</Project>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- For older nuget versions that don't support buildTransitive save duplication -->
<Import Project="$(MSBuildThisFileDirectory)..\buildTransitive\CefSharp.Common.targets"/>
</Project>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1">
<!-- Add the runtime section if missing. -->
<runtime xdt:Transform="InsertIfMissing"/>
<runtime>
<!-- Add the assemblyBinding section if missing. -->
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" xdt:Transform="InsertIfMissing"/>
</runtime>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- Add the dependentAssembly section for CefSharp.Core.Runtime if missing. -->
<dependentAssembly xdt:Transform="InsertIfMissing" xdt:Locator="Condition(asmv1:assemblyIdentity/@processorArchitecture='amd64' and asmv1:assemblyIdentity/@name='CefSharp.Core.Runtime')">
<assemblyIdentity name="CefSharp.Core.Runtime" processorArchitecture="amd64" publicKeyToken="40c4b6fc221f4138" culture="neutral"/>
</dependentAssembly>
<!-- Add or update the codeBase information for CefSharp.Core.Runtime -->
<dependentAssembly xdt:Locator="Condition(asmv1:assemblyIdentity/@processorArchitecture='amd64' and asmv1:assemblyIdentity/@name='CefSharp.Core.Runtime')">
<!-- Add the codebase section if missing. -->
<codeBase xdt:Transform="InsertIfMissing"/>
<!-- Ensure the codeBase version and href are set to the correct values. -->
<codeBase version="87.1.132.0" href="x64/CefSharp.Core.Runtime.dll" xdt:Transform="Replace"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1">
<!-- Add the runtime section if missing. -->
<runtime xdt:Transform="InsertIfMissing"/>
<runtime>
<!-- Add the assemblyBinding section if missing. -->
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" xdt:Transform="InsertIfMissing"/>
</runtime>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- Add the dependentAssembly section for CefSharp.Core.Runtime if missing. -->
<dependentAssembly xdt:Transform="InsertIfMissing" xdt:Locator="Condition(asmv1:assemblyIdentity/@processorArchitecture='x86' and asmv1:assemblyIdentity/@name='CefSharp.Core.Runtime')">
<assemblyIdentity name="CefSharp.Core.Runtime" processorArchitecture="x86" publicKeyToken="40c4b6fc221f4138" culture="neutral"/>
</dependentAssembly>
<!-- Add or update the codeBase information for CefSharp.Core.Runtime -->
<dependentAssembly xdt:Locator="Condition(asmv1:assemblyIdentity/@processorArchitecture='x86' and asmv1:assemblyIdentity/@name='CefSharp.Core.Runtime')">
<!-- Add the codebase section if missing. -->
<codeBase xdt:Transform="InsertIfMissing"/>
<!-- Ensure the codeBase version and href are set to the correct values. -->
<codeBase version="87.1.132.0" href="x86/CefSharp.Core.Runtime.dll" xdt:Transform="Replace"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<CefSharpCommonBinaries32 Include="$(MSBuildThisFileDirectory)..\CefSharp\x86\*.*" />
<CefSharpCommonBinaries64 Include="$(MSBuildThisFileDirectory)..\CefSharp\x64\*.*" />
<CefSharpCommonBinariesAnyCPU Include="$(MSBuildThisFileDirectory)..\CefSharp\**\*.*" />
<CefSharpCommonManagedDlls Include="$(MSBuildThisFileDirectory)..\lib\net452\**\*.*" />
<CefSharpCommonTransform32 Include="$(MSBuildThisFileDirectory)..\build\app.config.x86.transform"/>
<CefSharpCommonTransform64 Include="$(MSBuildThisFileDirectory)..\build\app.config.x64.transform"/>
<CefSharpBrowserProcessCore32 Include="$(MSBuildThisFileDirectory)..\CefSharp\x86\CefSharp.BrowserSubprocess.Core.dll" />
<CefSharpBrowserProcessCore64 Include="$(MSBuildThisFileDirectory)..\CefSharp\x64\CefSharp.BrowserSubprocess.Core.dll" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,312 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" TreatAsLocalProperty="CefSharpTransformXmlDllPath">
<!-- MSBuild is finding the dll within the package and copying it which is a problem for AnyCPU -->
<Target Name="CefSharpDeleteCoreRuntimeAfterBuild" AfterTargets="AfterBuild" Condition="'$(PlatformTarget)' == 'AnyCPU' AND $(TargetFramework.StartsWith('net4'))">
<Delete Files="$(OutDir)CefSharp.Core.Runtime.dll" />
<Delete Files="$(OutDir)CefSharp.Core.Runtime.pdb" />
<Delete Files="$(OutDir)CefSharp.Core.Runtime.xml" />
</Target>
<!--
Add to project file for debuggint purposes
<Target Name="CefSharpAfterBuildDebug" AfterTargets="AfterBuild">
<CallTarget Targets="CefSharpAfterBuildDiagnostic"/>
</Target>
-->
<Target Name="CefSharpAfterBuildDiagnostic">
<Message Importance="high" Text="CefSharp After Build Diagnostic" />
<Message Importance="high" Text="CefSharpBuildAction = $(CefSharpBuildAction)" />
<Message Importance="high" Text="CefSharpTargetDir = $(CefSharpTargetDir)" />
<Message Importance="high" Text="CefSharpTargetDirAnyCpu32 = $(CefSharpTargetDirAnyCpu32)" />
<Message Importance="high" Text="CefSharpTargetDirAnyCpu64 = $(CefSharpTargetDirAnyCpu64)" />
<Message Importance="high" Text="RuntimeIdentifier = $(RuntimeIdentifier)" />
<Message Importance="high" Text="TargetFramework = $(PlatformTarget)" />
<Message Importance="high" Text="libcef.dll exists = $(OutDir)$(CefSharpTargetDir)libcef.dll" Condition="Exists('$(OutDir)$(CefSharpTargetDir)libcef.dll')" />
<Message Importance="high" Text="libcef.dll exists AnyCPU(x86) = $(OutDir)$(CefSharpTargetDirAnyCpu32)libcef.dll" Condition="Exists('$(OutDir)$(CefSharpTargetDirAnyCpu32)libcef.dll')" />
<Message Importance="high" Text="libcef.dll exists AnyCPU(x64) = $(OutDir)$(CefSharpTargetDirAnyCpu64)libcef.dll" Condition="Exists('$(OutDir)$(CefSharpTargetDirAnyCpu64)libcef.dll')" />
<Message Importance="high" Text="CefSharpTransformXmlDllPath = $(CefSharpTransformXmlDllPath)" />
<Message Importance="high" Text="NuGetProjectStyle = $(NuGetProjectStyle)" />
<Message Importance="high" Text="OutDir = $(OutDir)" />
</Target>
<PropertyGroup>
<!--
Used for AnyCPU transforming of app.config
If https://www.nuget.org/packages/MSBuild.Microsoft.VisualStudio.Web.targets/ package is installed
we'll attempt to use the task from there, otherwise see if it's installed as part of Visual Studio
If not installed then we'll fallback to the old behaviour (user has to manage AnyCPU themselves)
-->
<CefSharpTransformXmlDllPath Condition="$(VSToolsPath) == ''">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll</CefSharpTransformXmlDllPath>
<CefSharpTransformXmlDllPath Condition="$(VSToolsPath) != ''" >$(VSToolsPath)\Web\Microsoft.Web.Publishing.Tasks.dll</CefSharpTransformXmlDllPath>
</PropertyGroup>
<PropertyGroup>
<!--
Allowable options are None, Content, NoAction.
None is the default (same as selecting the None Build Action in Visual Studio) for Non-SdkStyle (packages.config)
Content is the default (same as selecting the None Build Action in Visual Studio) for SdkStyle projects (PackageReference)
-->
<CefSharpBuildAction Condition="'$(CefSharpBuildAction)' == '' AND '$(UsingMicrosoftNETSdk)' != 'true'">None</CefSharpBuildAction>
<CefSharpBuildAction Condition="'$(CefSharpBuildAction)' == '' AND '$(UsingMicrosoftNETSdk)' == 'true'">Content</CefSharpBuildAction>
<CefSharpTargetDir Condition="'$(CefSharpTargetDir)' == ''"></CefSharpTargetDir>
<!-- Ideally we could use EnsureTrailingSlash, was only added on 2016 so unlikely supported in older version of VS -->
<CefSharpTargetDir Condition="'$(CefSharpTargetDir)' != '' AND !HasTrailingSlash('$(CefSharpTargetDir)')">$(CefSharpTargetDir)\</CefSharpTargetDir>
<CefSharpTargetDirAnyCpu32>$(CefSharpTargetDir)x86\</CefSharpTargetDirAnyCpu32>
<CefSharpTargetDirAnyCpu64>$(CefSharpTargetDir)x64\</CefSharpTargetDirAnyCpu64>
</PropertyGroup>
<Choose>
<!--
For .Net Core/Net5 when there's no runtime identifier specified then our lib files will be in the runtimes folders
we copy our unmanaged resources into the sub folder when required
-->
<When Condition="'$(RuntimeIdentifier)' == '' AND ($(TargetFramework.StartsWith('netcoreapp3')) OR $(TargetFramework.StartsWith('net5')))">
<Choose>
<When Condition="'$(PlatformTarget)' == 'x64'">
<PropertyGroup>
<CefSharpTargetDir>runtimes\win-x64\lib\netcoreapp3.0\</CefSharpTargetDir>
</PropertyGroup>
</When>
<When Condition="'$(PlatformTarget)' == 'x86'">
<PropertyGroup>
<CefSharpTargetDir>runtimes\win-x86\lib\netcoreapp3.0\</CefSharpTargetDir>
</PropertyGroup>
</When>
<When Condition="'$(PlatformTarget)' == 'AnyCPU'">
<PropertyGroup>
<CefSharpTargetDirAnyCpu32>runtimes\win-x86\lib\netcoreapp3.0\</CefSharpTargetDirAnyCpu32>
<CefSharpTargetDirAnyCpu64>runtimes\win-x64\lib\netcoreapp3.0\</CefSharpTargetDirAnyCpu64>
</PropertyGroup>
</When>
</Choose>
</When>
<!--
When CefSharpTargetDir is specified for x86/x64 platforms the files are included in a sub directory,
The CefSharp.dll file required by the BrowserSubProcess isn't copied by default and won't start, so we include an extra
copy.
-->
<When Condition="'$(CefSharpTargetDir)' != '' AND $(TargetFramework.StartsWith('net4')) AND '$(PlatformTarget)' != 'AnyCPU'">
<Choose>
<When Condition="'$(CefSharpBuildAction)' == 'None'">
<ItemGroup>
<None Include="@(CefSharpCommonManagedDlls)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
</ItemGroup>
</When>
<When Condition="'$(CefSharpBuildAction)' == 'Content'">
<ItemGroup>
<Content Include="@(CefSharpCommonManagedDlls)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
</ItemGroup>
</When>
</Choose>
</When>
</Choose>
<Choose>
<When Condition="'$(CefSharpBuildAction)' == 'None'">
<Choose>
<When Condition="'$(PlatformTarget)' == 'x64'">
<ItemGroup>
<None Include="@(CefRedist64)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
<None Include="@(CefSharpCommonBinaries64)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
</ItemGroup>
</When>
<When Condition="'$(PlatformTarget)' == 'AnyCPU'">
<ItemGroup>
<None Include="@(CefRedist32)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
<None Include="@(CefRedist64)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
<None Include="@(CefSharpCommonBinaries32)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
<None Include="@(CefSharpCommonBinaries64)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
<!--
Include CefSharp.dll and CefSharp.Core.dll (we only need CefSharp.dll but it's easier to include both)
in the arch specific folders as required by the BrowserSubProcess.
-->
<None Include="@(CefSharpCommonManagedDlls)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
<None Include="@(CefSharpCommonManagedDlls)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
</ItemGroup>
</When>
<!-- x86 and Win32-->
<Otherwise>
<ItemGroup>
<None Include="@(CefRedist32)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
<None Include="@(CefSharpCommonBinaries32)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
</ItemGroup>
</Otherwise>
</Choose>
</When>
<When Condition="'$(CefSharpBuildAction)' == 'Content'">
<Choose>
<When Condition="'$(PlatformTarget)' == 'x64'">
<ItemGroup>
<Content Include="@(CefRedist64)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
<Content Include="@(CefSharpCommonBinaries64)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
</ItemGroup>
</When>
<When Condition="'$(PlatformTarget)' == 'AnyCPU'">
<ItemGroup>
<Content Include="@(CefRedist32)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
<Content Include="@(CefRedist64)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
<Content Include="@(CefSharpCommonBinaries32)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
<Content Include="@(CefSharpCommonBinaries64)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
<!--
Include CefSharp.dll and CefSharp.Core.dll (we only need CefSharp.dll but it's easier to include both)
in the arch specific folders as required by the BrowserSubProcess.
-->
<Content Include="@(CefSharpCommonManagedDlls)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
<Content Include="@(CefSharpCommonManagedDlls)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
</ItemGroup>
</When>
<!-- x86 and Win32-->
<Otherwise>
<ItemGroup>
<Content Include="@(CefRedist32)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
<Content Include="@(CefSharpCommonBinaries32)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</Content>
</ItemGroup>
</Otherwise>
</Choose>
</When>
</Choose>
<!--
For AnyCPU we use a Transform to add entries to app.config if possible
Otherwise throw error to alert user they need to perform additional action
-->
<UsingTask TaskName="TransformXml" AssemblyFile="$(CefSharpTransformXmlDllPath)" Condition="Exists('$(CefSharpTransformXmlDllPath)') AND '$(PlatformTarget)' == 'AnyCPU' AND '$(CefSharpAnyCpuSupport)' == ''" />
<Target Name="CefSharpCommonAnyCPUConfigTransform" AfterTargets="_CopyAppConfigFile" Condition="Exists('$(CefSharpTransformXmlDllPath)') AND '$(PlatformTarget)' == 'AnyCPU' AND '$(CefSharpAnyCpuSupport)' == ''">
<TransformXml Source="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')" Transform="$(MSBuildThisFileDirectory)..\build\app.config.x86.transform" Destination="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')"/>
<TransformXml Source="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')" Transform="$(MSBuildThisFileDirectory)..\build\app.config.x64.transform" Destination="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')"/>
</Target>
<Target Name="CefSharpPlatformCheck" BeforeTargets="ResolveAssemblyReferences" Condition="!Exists('$(CefSharpTransformXmlDllPath)') AND '$(PlatformTarget)' == 'AnyCPU' AND '$(CefSharpAnyCpuSupport)' != 'true'">
<Error Text="$(MSBuildThisFileName) is unable to proceeed as your current PlatformTarget is '$(PlatformTarget)'. To target AnyCPU please read https://github.com/cefsharp/CefSharp/issues/1714. Alternatively change your PlatformTarget to x86 or x64 and the relevant files will be copied automatically." HelpKeyword="CefSharpSolutionPlatformCheck" />
</Target>
<!--
Issue https://github.com/dotnet/project-system/issues/4158
The None/Content entries aren't picked up as the .targets file doesn't exist before the Nuget restore (only when using packages.config)
So in that scenario we display a mssage to the user. Close/reopen the project and the None/Content entries will work as above.
I have attempted to copy the files via a Copy Task, unfortunately the .props entries aren't accessible either so that's not feasible.
-->
<Target Name="CefSharpCopyFilesAfterNugetRestore32" AfterTargets="Build" Condition="'$(UsingMicrosoftNETSdk)' != 'true' AND !Exists('$(OutDir)$(CefSharpTargetDir)libcef.dll') AND '$(CefSharpBuildAction)' != 'NoAction' AND '$(PlatformTarget)' == 'x86'">
<Message Importance="high" Text="CefSharp - Files were not copied by MSBuild after Nuget install/restore! Please close and re-open $(MSBuildProjectFile)." />
</Target>
<Target Name="CefSharpCopyFilesAfterNugetRestore64" AfterTargets="Build" Condition="'$(UsingMicrosoftNETSdk)' != 'true' AND !Exists('$(OutDir)$(CefSharpTargetDir)libcef.dll') AND '$(CefSharpBuildAction)' != 'NoAction' AND '$(PlatformTarget)' == 'x64'">
<Message Importance="high" Text="CefSharp - Files were not copied by MSBuild after Nuget install/restore! Please close and re-open $(MSBuildProjectFile)." />
</Target>
<Target Name="CefSharpCopyFilesAfterNugetRestoreAnyCPU" AfterTargets="Build" Condition="'$(UsingMicrosoftNETSdk)' != 'true' AND !Exists('$(OutDir)$(CefSharpTargetDirAnyCpu32)libcef.dll') AND '$(CefSharpBuildAction)' != 'NoAction' AND '$(PlatformTarget)' == 'AnyCPU'">
<Message Importance="high" Text="CefSharp - Files were not copied by MSBuild after Nuget install/restore! Please close and re-open $(MSBuildProjectFile)." />
</Target>
</Project>

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
#include "Stdafx.h"
using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::CompilerServices;
using namespace System::Runtime::InteropServices;
using namespace System::Security::Permissions;
using namespace CefSharp;
//[assembly:AssemblyTitle("CefSharpBrowserSubprocess.Core")];
//[assembly:AssemblyCompany(AssemblyInfo::AssemblyCompany)];
//[assembly:AssemblyProduct(AssemblyInfo::AssemblyProduct)];
//[assembly:AssemblyCopyright(AssemblyInfo::AssemblyCopyright)];
[assembly:AssemblyVersion(AssemblyInfo::AssemblyVersion)];
[assembly:ComVisible(AssemblyInfo::ComVisible)];
[assembly:CLSCompliant(AssemblyInfo::ClsCompliant)];
[assembly:AssemblyDescription("")];
[assembly:AssemblyConfiguration("")];
[assembly:AssemblyTrademark("")];
[assembly:AssemblyCulture("")];
[assembly:InternalsVisibleTo(AssemblyInfo::CefSharpBrowserSubprocessProject)];

View file

@ -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 Internals
{
namespace Async
{
void JavascriptAsyncMethodCallback::Success(const CefRefPtr<CefV8Value>& 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();
}
}
}
}
}
}

View file

@ -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 Internals
{
namespace Async
{
private ref class JavascriptAsyncMethodCallback
{
private:
MCefRefPtr<CefV8Context> _context;
MCefRefPtr<CefV8Value> _resolve;
MCefRefPtr<CefV8Value> _reject;
public:
JavascriptAsyncMethodCallback(CefRefPtr<CefV8Context> context, CefRefPtr<CefV8Value> resolve, CefRefPtr<CefV8Value> reject)
:_context(context), _resolve(resolve.get()), _reject(reject.get())
{
}
!JavascriptAsyncMethodCallback()
{
_resolve = nullptr;
_reject = nullptr;
_context = nullptr;
}
~JavascriptAsyncMethodCallback()
{
this->!JavascriptAsyncMethodCallback();
}
void Success(const CefRefPtr<CefV8Value>& result);
void Fail(const CefString& exception);
};
}
}
}

View file

@ -0,0 +1,73 @@
// 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;
namespace CefSharp
{
namespace Internals
{
namespace Async
{
bool JavascriptAsyncMethodHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
{
auto context = CefV8Context::GetCurrentContext();
auto frame = context->GetFrame();
CefRefPtr<CefV8Value> promiseData;
CefRefPtr<CefV8Exception> 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 == NULL)
{
LOG(WARNING) << "JavascriptAsyncMethodHandler::Execute promiseData returned NULL";
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;
}
}
}
}

View file

@ -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 Internals
{
namespace Async
{
private class JavascriptAsyncMethodHandler : public virtual CefV8Handler
{
private:
gcroot<JavascriptCallbackRegistry^> _callbackRegistry;
gcroot<Func<JavascriptAsyncMethodCallback^, int64>^> _methodCallbackSave;
int64 _objectId;
public:
JavascriptAsyncMethodHandler(int64 objectId, JavascriptCallbackRegistry^ callbackRegistry, Func<JavascriptAsyncMethodCallback^, int64>^ methodCallbackSave)
:_callbackRegistry(callbackRegistry), _objectId(objectId), _methodCallbackSave(methodCallbackSave)
{
}
virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& 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_REFCOUNTING(JavascriptAsyncMethodHandler);
};
}
}
}

View file

@ -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 Internals
{
namespace Async
{
void JavascriptAsyncMethodWrapper::Bind(JavascriptMethod^ method, const CefRefPtr<CefV8Value>& value)
{
auto methodName = StringUtils::ToNative(method->JavascriptName);
auto v8Function = CefV8Value::CreateFunction(methodName, _javascriptMethodHandler.get());
value->SetValue(methodName, v8Function, V8_PROPERTY_ATTRIBUTE_NONE);
}
}
}
}

View file

@ -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 Internals
{
namespace Async
{
private ref class JavascriptAsyncMethodWrapper
{
private:
MCefRefPtr<JavascriptAsyncMethodHandler> _javascriptMethodHandler;
public:
JavascriptAsyncMethodWrapper(int64 ownerId, JavascriptCallbackRegistry^ callbackRegistry, Func<JavascriptAsyncMethodCallback^, int64>^ methodCallbackSave)
: _javascriptMethodHandler(new JavascriptAsyncMethodHandler(ownerId, callbackRegistry, methodCallbackSave))
{
}
void Bind(JavascriptMethod^ method, const CefRefPtr<CefV8Value>& value);
};
}
}
}

View file

@ -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 Internals
{
namespace Async
{
void JavascriptAsyncObjectWrapper::Bind(JavascriptObject^ object, const CefRefPtr<CefV8Value> &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<JavascriptMethod^>(object->Methods))
{
auto wrappedMethod = gcnew JavascriptAsyncMethodWrapper(object->Id, _callbackRegistry, _methodCallbackSave);
wrappedMethod->Bind(method, javascriptObject);
_wrappedMethods->Add(wrappedMethod);
}
}
}
}
}

View file

@ -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 Internals
{
namespace Async
{
private ref class JavascriptAsyncObjectWrapper
{
private:
initonly List<JavascriptAsyncMethodWrapper^>^ _wrappedMethods;
Func<JavascriptAsyncMethodCallback^, int64>^ _methodCallbackSave;
JavascriptCallbackRegistry^ _callbackRegistry;
public:
JavascriptAsyncObjectWrapper(JavascriptCallbackRegistry^ callbackRegistry, Func<JavascriptAsyncMethodCallback^, int64>^ saveMethod)
: _wrappedMethods(gcnew List<JavascriptAsyncMethodWrapper^>()), _methodCallbackSave(saveMethod), _callbackRegistry(callbackRegistry)
{
}
~JavascriptAsyncObjectWrapper()
{
_callbackRegistry = nullptr;
_methodCallbackSave = nullptr;
for each (JavascriptAsyncMethodWrapper^ var in _wrappedMethods)
{
delete var;
}
}
void Bind(JavascriptObject^ object, const CefRefPtr<CefV8Value> &value);
};
}
}
}

View file

@ -0,0 +1,322 @@
// 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;
namespace CefSharp
{
const CefString kBindObjectAsync = CefString("BindObjectAsync");
const CefString kBindObjectAsyncCamelCase = CefString("bindObjectAsync");
private class BindObjectAsyncHandler : public CefV8Handler
{
private:
gcroot<RegisterBoundObjectRegistry^> _callbackRegistry;
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
gcroot<CefBrowserWrapper^> _browserWrapper;
public:
BindObjectAsyncHandler(RegisterBoundObjectRegistry^ callbackRegistery, Dictionary<String^, JavascriptObject^>^ javascriptObjects, CefBrowserWrapper^ browserWrapper)
{
_callbackRegistry = callbackRegistery;
_javascriptObjects = javascriptObjects;
_browserWrapper = browserWrapper;
}
~BindObjectAsyncHandler()
{
_callbackRegistry = nullptr;
_javascriptObjects = nullptr;
_browserWrapper = nullptr;
}
bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& 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<JavascriptObject^>();
//TODO: Create object to represent this information
auto objectNamesWithBoundStatus = gcnew List<Tuple<String^, bool, bool>^>();
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 (cachedObjects->Count == objectCount && ignoreCache == false)
{
if (Object::ReferenceEquals(_browserWrapper, nullptr))
{
exception = "BindObjectAsyncHandler::Execute - Browser wrapper null, unable to bind objects";
return true;
}
auto browser = context->GetBrowser();
auto rootObjectWrappers = _browserWrapper->JavascriptRootObjectWrappers;
JavascriptRootObjectWrapper^ rootObject;
if (!rootObjectWrappers->TryGetValue(frame->GetIdentifier(), rootObject))
{
#ifdef NETCOREAPP
rootObject = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier());
#else
rootObject = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier(), _browserWrapper->BrowserProcess);
#endif
rootObjectWrappers->TryAdd(frame->GetIdentifier(), rootObject);
}
//Cached objects only contains a list of objects not already bound
rootObject->Bind(cachedObjects, context->GetGlobal());
//Objects already bound or ignore cache
CefRefPtr<CefV8Value> promiseResolve;
CefRefPtr<CefV8Exception> 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<CefV8Value> promiseData;
CefRefPtr<CefV8Exception> 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 == NULL)
{
LOG(WARNING) << "BindObjectAsyncHandler::Execute promiseData returned NULL";
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<CefV8Value> promiseResolve;
CefRefPtr<CefV8Exception> 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<CefFrame> frame, List<Tuple<String^, bool, bool>^>^ 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<CefV8Value> 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_REFCOUNTING(BindObjectAsyncHandler);
};
}

View file

@ -0,0 +1,157 @@
// 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
{
/// <summary>
/// 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).
/// </summary>
public ref class BrowserSubprocessExecutable
{
public:
BrowserSubprocessExecutable()
{
}
/// <summary>
/// This function should be called from the application entry point function (typically Program.Main)
/// to execute a secondary process e.g. gpu, plugin, renderer, utility
/// 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
/// - Calls CefEnableHighDPISupport before any other processing
/// </summary>
/// <returns>
/// 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.
/// </returns
static int MainSelfHost(array<String^>^ args)
{
auto subProcess = gcnew BrowserSubprocessExecutable();
return subProcess->Main(args, nullptr);
}
/// <summary>
/// This function should be called from the application entry point function (typically Program.Main)
/// to execute a secondary process e.g. gpu, plugin, renderer, utility
/// 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
/// - Calls CefEnableHighDPISupport before any other processing
/// </summary>
/// <returns>
/// 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.
/// </returns
static int MainNetCore(IntPtr arg, int argLength)
{
SubProcess::EnableHighDPISupport();
auto args = Environment::GetCommandLineArgs();
auto subProcess = gcnew BrowserSubprocessExecutable();
return subProcess->Main(args, nullptr);
}
/// <summary>
/// This function should be called from the application entry point function (typically Program.Main)
/// to execute a secondary process e.g. gpu, plugin, renderer, utility
/// 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.
/// </summary>
/// <param name="args">command line args</param>
/// <returns>
/// 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.
/// </returns
int Main(IEnumerable<String^>^ args)
{
return Main(args, nullptr);
}
/// <summary>
/// This function should be called from the application entry point function (typically Program.Main)
/// to execute a secondary process e.g. gpu, plugin, renderer, utility
/// 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.
/// </summary>
/// <param name="args">command line args</param>
/// <param name="handler">An option IRenderProcessHandler implementation, use null if no handler is required</param>
/// <returns>
/// 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.
/// </returns>
int Main(IEnumerable<String^>^ 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")
{
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<String^>^ args, int parentProcessId, IRenderProcessHandler^ handler)
{
return gcnew SubProcess(handler, args);
}
};
}
}

View file

@ -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
{
/// <summary>
/// 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.
/// </summary>
public ref class Cef sealed
{
public:
/// <summary>
/// Register a new V8 extension with the specified JavaScript extension code.
/// </summary>
/// <param name="name">name</param>
/// <param name="javascriptCode">JavaScript code</param>
static void RegisterExtension(String^ name, String^ javascriptCode)
{
CefRegisterExtension(StringUtils::ToNative(name), StringUtils::ToNative(javascriptCode), nullptr);
}
};
}
}

View file

@ -0,0 +1,726 @@
// 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 "Async\JavascriptAsyncMethodCallback.h"
#include "Serialization\V8Serialization.h"
#include "Serialization\JsObjectsSerialization.h"
#include "Wrapper\V8Context.h"
#include "Wrapper\Frame.h"
#include "Wrapper\Browser.h"
#include "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
using namespace System;
using namespace System::Diagnostics;
using namespace System::Collections::Generic;
using namespace CefSharp::BrowserSubprocess;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
const CefString CefAppUnmanagedWrapper::kPromiseCreatorScript = ""
"(function()"
"{"
" var result = {};"
" var promise = new Promise(function(resolve, reject) {"
" result.res = resolve; result.rej = reject;"
" });"
" result.p = promise;"
" return result;"
"})();";
const CefString kRenderProcessId = CefString("RenderProcessId");
const CefString kRenderProcessIdCamelCase = CefString("renderProcessId");
CefRefPtr<CefRenderProcessHandler> CefAppUnmanagedWrapper::GetRenderProcessHandler()
{
return this;
};
// CefRenderProcessHandler
void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extraInfo)
{
auto wrapper = gcnew CefBrowserWrapper(browser);
_onBrowserCreated->Invoke(wrapper);
//Multiple CefBrowserWrappers created when opening popups
_browserWrappers->TryAdd(browser->GetIdentifier(), wrapper);
//For the main browser only we check LegacyBindingEnabled and
//load the objects. Popups don't send this information and checking
//will override the _legacyBindingEnabled field
if (!browser->IsPopup())
{
_legacyBindingEnabled = extraInfo->GetBool("LegacyBindingEnabled");
if (_legacyBindingEnabled)
{
auto objects = extraInfo->GetList("LegacyBindingObjects");
if (objects.get() && objects->IsValid())
{
auto javascriptObjects = DeserializeJsObjects(objects, 0);
for each (JavascriptObject^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
{
//Using LegacyBinding with multiple ChromiumWebBrowser instances that share the same
//render process and using LegacyBinding will cause problems for the limited caching implementation
//that exists at the moment, for now we'll remove an object if already exists, same behaviour
//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("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
{
//TODO: Create constant for these and legacy binding strings above
_jsBindingPropertyName = extraInfo->GetString("JsBindingPropertyName");
_jsBindingPropertyNameCamelCase = extraInfo->GetString("JsBindingPropertyNameCamelCase");
}
else
{
_jsBindingPropertyName = "CefSharp";
_jsBindingPropertyNameCamelCase = "cefSharp";
}
}
void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
{
CefBrowserWrapper^ wrapper;
if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
{
_onBrowserDestroyed->Invoke(wrapper);
delete wrapper;
}
};
void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
if (!Object::ReferenceEquals(_handler, nullptr))
{
Browser browserWrapper(browser);
Frame frameWrapper(frame);
V8Context contextWrapper(context);
_handler->OnContextCreated(%browserWrapper, %frameWrapper, %contextWrapper);
}
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
if (_legacyBindingEnabled)
{
if (_javascriptObjects->Count > 0 && rootObject != nullptr)
{
rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
}
}
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
auto global = context->GetGlobal();
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
auto 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, browserWrapper));
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
//By default We'll support both CefSharp and cefSharp, for those who prefer the JS style
auto createCefSharpObj = !_jsBindingPropertyName.empty();
auto createCefSharpObjCamelCase = !_jsBindingPropertyNameCamelCase.empty();
if (createCefSharpObj)
{
auto cefSharpObj = CefV8Value::CreateObject(NULL, NULL);
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
}
if (createCefSharpObjCamelCase)
{
auto cefSharpObjCamelCase = CefV8Value::CreateObject(NULL, NULL);
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kRemoveObjectFromCacheCamelCase, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kIsObjectCachedCamelCase, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kPostMessageCamelCase, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kSendEvalScriptResponseCamelCase, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kRenderProcessIdCamelCase, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
}
//Send a message to the browser processing signaling that OnContextCreated has been called
//only param is the FrameId. Previous sent only for main frame, now sent for all frames
//Message sent after legacy objects have been bound and the CefSharp bind async helper methods
//have been created
auto contextCreatedMessage = CefProcessMessage::Create(kOnContextCreatedRequest);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextCreatedMessage);
};
void CefAppUnmanagedWrapper::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
if (!Object::ReferenceEquals(_handler, nullptr))
{
Browser browserWrapper(browser);
Frame frameWrapper(frame);
V8Context contextWrapper(context);
_handler->OnContextReleased(%browserWrapper, %frameWrapper, %contextWrapper);
}
auto contextReleasedMessage = CefProcessMessage::Create(kOnContextReleasedRequest);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextReleasedMessage);
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
//If we no longer have a browser wrapper reference then there's nothing we can do
if (browserWrapper == nullptr)
{
return;
}
auto rootObjectWrappers = browserWrapper->JavascriptRootObjectWrappers;
JavascriptRootObjectWrapper^ wrapper;
if (rootObjectWrappers->TryRemove(frame->GetIdentifier(), wrapper))
{
delete wrapper;
}
};
void CefAppUnmanagedWrapper::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefDOMNode> node)
{
if (!_focusedNodeChangedEnabled)
{
return;
}
auto focusedNodeChangedMessage = CefProcessMessage::Create(kOnFocusedNodeChanged);
auto list = focusedNodeChangedMessage->GetArgumentList();
// The node will be empty if an element loses focus but another one
// doesn't gain focus. Only transfer information if the node is an
// element.
if (node != nullptr && node->IsElement())
{
// True when a node exists, false if it doesn't.
list->SetBool(0, true);
// Store the tag name.
list->SetString(1, node->GetElementTagName());
// Transfer the attributes in a Dictionary.
auto attributes = CefDictionaryValue::Create();
CefDOMNode::AttributeMap attributeMap;
node->GetElementAttributes(attributeMap);
for (auto iter : attributeMap)
{
attributes->SetString(iter.first, iter.second);
}
list->SetDictionary(2, attributes);
}
else
{
list->SetBool(0, false);
}
frame->SendProcessMessage(CefProcessId::PID_BROWSER, focusedNodeChangedMessage);
}
void CefAppUnmanagedWrapper::OnUncaughtException(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context, CefRefPtr<CefV8Exception> exception, CefRefPtr<CefV8StackTrace> stackTrace)
{
auto uncaughtExceptionMessage = CefProcessMessage::Create(kOnUncaughtException);
auto list = uncaughtExceptionMessage->GetArgumentList();
list->SetString(0, exception->GetMessage());
auto frames = CefListValue::Create();
for (auto i = 0; i < stackTrace->GetFrameCount(); i++)
{
auto stackTraceFrame = CefListValue::Create();
auto frameArg = stackTrace->GetFrame(i);
stackTraceFrame->SetString(0, frameArg->GetFunctionName());
stackTraceFrame->SetInt(1, frameArg->GetLineNumber());
stackTraceFrame->SetInt(2, frameArg->GetColumn());
stackTraceFrame->SetString(3, frameArg->GetScriptNameOrSourceURL());
frames->SetList(i, stackTraceFrame);
}
list->SetList(1, frames);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, uncaughtExceptionMessage);
}
JavascriptRootObjectWrapper^ CefAppUnmanagedWrapper::GetJsRootObjectWrapper(int browserId, int64 frameId)
{
auto browserWrapper = FindBrowserWrapper(browserId);
if (browserWrapper == nullptr)
{
return nullptr;
}
auto rootObjectWrappers = browserWrapper->JavascriptRootObjectWrappers;
JavascriptRootObjectWrapper^ rootObject;
if (!rootObjectWrappers->TryGetValue(frameId, rootObject))
{
#ifdef NETCOREAPP
rootObject = gcnew JavascriptRootObjectWrapper(browserId);
#else
rootObject = gcnew JavascriptRootObjectWrapper(browserId, browserWrapper->BrowserProcess);
#endif
rootObjectWrappers->TryAdd(frameId, rootObject);
}
return rootObject;
}
CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId)
{
CefBrowserWrapper^ wrapper = nullptr;
_browserWrappers->TryGetValue(browserId, wrapper);
if (wrapper == nullptr)
{
//TODO: Find the syntax for delcaring the native string directly
LOG(ERROR) << StringUtils::ToNative("Failed to identify BrowserWrapper in OnContextCreated BrowserId:" + browserId).ToString();
}
return wrapper;
}
bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId sourceProcessId, CefRefPtr<CefProcessMessage> message)
{
auto handled = false;
auto name = message->GetName();
auto argList = message->GetArgumentList();
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
//Error handling for missing/closed browser
if (browserWrapper == nullptr)
{
if (name == kJavascriptCallbackDestroyRequest ||
name == kJavascriptRootObjectResponse ||
name == kJavascriptAsyncMethodCallResponse)
{
//If we can't find the browser wrapper then we'll just
//ignore this as it's likely already been disposed of
return true;
}
CefString responseName;
if (name == kEvaluateJavascriptRequest)
{
responseName = kEvaluateJavascriptResponse;
}
else if (name == kJavascriptCallbackRequest)
{
responseName = kJavascriptCallbackResponse;
}
else
{
//TODO: Should be throw an exception here? It's likely that only a CefSharp developer would see this
// when they added a new message and haven't yet implemented the render process functionality.
throw gcnew Exception("Unsupported message type");
}
auto callbackId = GetInt64(argList, 0);
auto response = CefProcessMessage::Create(responseName);
auto responseArgList = response->GetArgumentList();
auto errorMessage = String::Format("Request BrowserId : {0} not found it's likely the browser is already closed", browser->GetIdentifier());
//success: false
responseArgList->SetBool(0, false);
SetInt64(responseArgList, 1, callbackId);
responseArgList->SetString(2, StringUtils::ToNative(errorMessage));
frame->SendProcessMessage(sourceProcessId, response);
return true;
}
//these messages are roughly handled the same way
if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest)
{
bool sendResponse = true;
bool success = false;
CefRefPtr<CefV8Value> result;
CefString errorMessage;
CefRefPtr<CefProcessMessage> response;
if (name == kEvaluateJavascriptRequest)
{
response = CefProcessMessage::Create(kEvaluateJavascriptResponse);
}
else
{
response = CefProcessMessage::Create(kJavascriptCallbackResponse);
}
//both messages have callbackId stored at index 0
auto frameId = frame->GetIdentifier();
int64 callbackId = GetInt64(argList, 0);
if (name == kEvaluateJavascriptRequest)
{
JavascriptRootObjectWrapper^ rootObjectWrapper;
browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
//NOTE: In the rare case when when OnContextCreated hasn't been called we need to manually create the rootObjectWrapper
//It appears that OnContextCreated is only called for pages that have javascript on them, which makes sense
//as without javascript there is no need for a context.
if (rootObjectWrapper == nullptr)
{
#ifdef NETCOREAPP
rootObjectWrapper = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier());
#else
rootObjectWrapper = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier(), browserWrapper->BrowserProcess);
#endif
browserWrapper->JavascriptRootObjectWrappers->TryAdd(frameId, rootObjectWrapper);
}
auto callbackRegistry = rootObjectWrapper->CallbackRegistry;
auto script = argList->GetString(1);
auto scriptUrl = argList->GetString(2);
auto startLine = argList->GetInt(3);
if (frame.get() && frame->IsValid())
{
auto context = frame->GetV8Context();
if (context.get() && context->Enter())
{
try
{
CefRefPtr<CefV8Exception> exception;
success = context->Eval(script, scriptUrl, startLine, result, exception);
//we need to do this here to be able to store the v8context
if (success)
{
//If the response is a string of CefSharpDefEvalScriptRes then
//we don't send the response, we'll let that happen when the promise has completed.
if (result->IsString() && result->GetStringValue() == "CefSharpDefEvalScriptRes")
{
sendResponse = false;
}
else
{
auto responseArgList = response->GetArgumentList();
SerializeV8Object(result, responseArgList, 2, callbackRegistry);
}
}
else
{
errorMessage = StringUtils::CreateExceptionString(exception);
}
}
finally
{
context->Exit();
}
}
else
{
errorMessage = "Unable to Enter Context";
}
}
else
{
errorMessage = StringUtils::ToNative("Frame " + frameId + " is no longer available, most likely the Frame has been Disposed or Removed.");
}
}
else
{
JavascriptRootObjectWrapper^ rootObjectWrapper;
browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
if (callbackRegistry == nullptr)
{
errorMessage = StringUtils::ToNative("The callback registry for Frame " + frameId + " is no longer available, most likely the Frame has been Disposed.");
}
else
{
auto jsCallbackId = GetInt64(argList, 1);
auto callbackWrapper = callbackRegistry->FindWrapper(jsCallbackId);
if (callbackWrapper == nullptr)
{
errorMessage = StringUtils::ToNative("Unable to find JavascriptCallback with Id " + jsCallbackId + " for Frame " + frameId);
}
else
{
auto context = callbackWrapper->GetContext();
auto value = callbackWrapper->GetValue();
if (context.get() && context->Enter())
{
try
{
auto parameterList = argList->GetList(2);
CefV8ValueList params;
//Needs to be called within the context as for Dictionary (mapped to struct)
//a V8Object will be created
for (CefV8ValueList::size_type i = 0; i < parameterList->GetSize(); i++)
{
params.push_back(DeserializeV8Object(parameterList, static_cast<int>(i)));
}
result = value->ExecuteFunction(nullptr, params);
success = result.get() != nullptr;
//we need to do this here to be able to store the v8context
if (success)
{
auto responseArgList = response->GetArgumentList();
SerializeV8Object(result, responseArgList, 2, callbackRegistry);
}
else
{
auto exception = value->GetException();
errorMessage = StringUtils::CreateExceptionString(exception);
}
}
finally
{
context->Exit();
}
}
else
{
errorMessage = "Unable to Enter Context";
}
}
}
}
if (sendResponse)
{
auto responseArgList = response->GetArgumentList();
responseArgList->SetBool(0, success);
SetInt64(responseArgList, 1, callbackId);
if (!success)
{
responseArgList->SetString(2, errorMessage);
}
frame->SendProcessMessage(sourceProcessId, response);
}
handled = true;
}
else if (name == kJavascriptCallbackDestroyRequest)
{
if (frame.get() && frame->IsValid())
{
auto jsCallbackId = GetInt64(argList, 0);
JavascriptRootObjectWrapper^ rootObjectWrapper;
browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frame->GetIdentifier(), rootObjectWrapper);
if (rootObjectWrapper != nullptr && rootObjectWrapper->CallbackRegistry != nullptr)
{
rootObjectWrapper->CallbackRegistry->Deregister(jsCallbackId);
}
}
handled = true;
}
else if (name == kJavascriptRootObjectResponse)
{
if (browser.get() && frame.get() && frame->IsValid())
{
auto callbackId = GetInt64(argList, 0);
auto javascriptObjects = DeserializeJsObjects(argList, 1);
//Caching of JavascriptObjects
//TODO: JSB Should caching be configurable? On a per object basis?
for each (JavascriptObject^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
{
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
{
_javascriptObjects->Remove(obj->JavascriptName);
}
_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
{
rootObject->Bind(javascriptObjects, context->GetGlobal());
if (_registerBoundObjectRegistry->TryGetAndRemoveMethodCallback(callbackId, callback))
{
//Response object has no Accessor or Interceptor
auto response = CefV8Value::CreateObject(NULL, NULL);
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();
for (auto i = 0; i < javascriptObjects->Count; i++)
{
auto dict = CefDictionaryValue::Create();
auto objectName = javascriptObjects[i]->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();
delete callback;
}
}
}
else
{
LOG(INFO) << "CefAppUnmanagedWrapper Frame Invalid";
}
handled = true;
}
else if (name == kJavascriptAsyncMethodCallResponse)
{
if (frame.get() && frame->IsValid())
{
auto frameId = frame->GetIdentifier();
auto callbackId = GetInt64(argList, 0);
JavascriptRootObjectWrapper^ rootObjectWrapper;
browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper);
if (rootObjectWrapper != nullptr)
{
JavascriptAsyncMethodCallback^ callback;
if (rootObjectWrapper->TryGetAndRemoveMethodCallback(callbackId, callback))
{
try
{
auto context = frame->GetV8Context();
if (context.get() && context->Enter())
{
try
{
auto success = argList->GetBool(1);
if (success)
{
callback->Success(DeserializeV8Object(argList, 2));
}
else
{
callback->Fail(argList->GetString(2));
}
}
finally
{
context->Exit();
}
}
else
{
callback->Fail("Unable to Enter Context");
}
}
finally
{
//dispose
delete callback;
}
}
}
}
handled = true;
}
return handled;
};
void CefAppUnmanagedWrapper::OnWebKitInitialized()
{
if (!Object::ReferenceEquals(_handler, nullptr))
{
_handler->OnWebKitInitialized();
}
}
}

View file

@ -0,0 +1,84 @@
// 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_base.h"
#include "SubProcessApp.h"
#include "CefBrowserWrapper.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 : SubProcessApp, CefRenderProcessHandler
{
private:
gcroot<IRenderProcessHandler^> _handler;
gcroot<Action<CefBrowserWrapper^>^> _onBrowserCreated;
gcroot<Action<CefBrowserWrapper^>^> _onBrowserDestroyed;
gcroot<ConcurrentDictionary<int, CefBrowserWrapper^>^> _browserWrappers;
bool _focusedNodeChangedEnabled;
bool _legacyBindingEnabled;
// The property names used to call bound objects
CefString _jsBindingPropertyName;
CefString _jsBindingPropertyNameCamelCase;
// The serialized registered object data waiting to be used.
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
gcroot<RegisterBoundObjectRegistry^> _registerBoundObjectRegistry;
public:
static const CefString kPromiseCreatorScript;
CefAppUnmanagedWrapper(IRenderProcessHandler^ handler, List<CefCustomScheme^>^ schemes, bool enableFocusedNodeChanged, Action<CefBrowserWrapper^>^ onBrowserCreated, Action<CefBrowserWrapper^>^ onBrowserDestroyed) : SubProcessApp(schemes)
{
_handler = handler;
_onBrowserCreated = onBrowserCreated;
_onBrowserDestroyed = onBrowserDestroyed;
_browserWrappers = gcnew ConcurrentDictionary<int, CefBrowserWrapper^>();
_focusedNodeChangedEnabled = enableFocusedNodeChanged;
_javascriptObjects = gcnew Dictionary<String^, JavascriptObject^>();
_registerBoundObjectRegistry = gcnew RegisterBoundObjectRegistry();
_legacyBindingEnabled = false;
}
~CefAppUnmanagedWrapper()
{
if (!Object::ReferenceEquals(_browserWrappers, nullptr))
{
for each(CefBrowserWrapper^ browser in Enumerable::OfType<CefBrowserWrapper^>(_browserWrappers))
{
delete browser;
}
_browserWrappers = nullptr;
}
delete _onBrowserCreated;
delete _onBrowserDestroyed;
}
CefBrowserWrapper^ FindBrowserWrapper(int browserId);
JavascriptRootObjectWrapper^ GetJsRootObjectWrapper(int browserId, int64 frameId);
virtual DECL CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE;
virtual DECL void OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extraInfo) OVERRIDE;
virtual DECL void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual DECL void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE;
virtual DECL void OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE;
virtual DECL bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId sourceProcessId, CefRefPtr<CefProcessMessage> message) OVERRIDE;
virtual DECL void OnWebKitInitialized() OVERRIDE;
virtual DECL void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefDOMNode> node) OVERRIDE;
virtual DECL void OnUncaughtException(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context, CefRefPtr<CefV8Exception> exception, CefRefPtr<CefV8StackTrace> stackTrace) OVERRIDE;
IMPLEMENT_REFCOUNTING(CefAppUnmanagedWrapper);
};
}

View file

@ -0,0 +1,74 @@
// 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_v8.h"
#include "TypeUtils.h"
#include "Stdafx.h"
#include "JavascriptRootObjectWrapper.h"
using namespace CefSharp::Internals::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
{
private:
MCefRefPtr<CefBrowser> _cefBrowser;
internal:
//Frame Identifier is used as Key
property ConcurrentDictionary<int64, JavascriptRootObjectWrapper^>^ JavascriptRootObjectWrappers;
public:
CefBrowserWrapper(CefRefPtr<CefBrowser> cefBrowser)
{
_cefBrowser = cefBrowser;
BrowserId = cefBrowser->GetIdentifier();
IsPopup = cefBrowser->IsPopup();
JavascriptRootObjectWrappers = gcnew ConcurrentDictionary<int64, JavascriptRootObjectWrapper^>();
}
!CefBrowserWrapper()
{
_cefBrowser = nullptr;
}
~CefBrowserWrapper()
{
this->!CefBrowserWrapper();
if (JavascriptRootObjectWrappers != nullptr)
{
for each(KeyValuePair<int64, JavascriptRootObjectWrapper^> entry in JavascriptRootObjectWrappers)
{
delete entry.Value;
}
JavascriptRootObjectWrappers = nullptr;
}
}
property int BrowserId;
property bool IsPopup;
#ifndef NETCOREAPP
// This allows us to create the WCF proxies back to our parent process.
property ChannelFactory<IBrowserProcess^>^ ChannelFactory;
// The WCF proxy to the parent process.
property IBrowserProcess^ BrowserProcess;
#endif
};
}

View file

@ -0,0 +1,44 @@
// 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"
using namespace System::Threading;
namespace CefSharp
{
namespace Internals
{
JavascriptCallback^ JavascriptCallbackRegistry::Register(const CefRefPtr<CefV8Context>& context, const CefRefPtr<CefV8Value>& 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->FrameId = context->GetFrame()->GetIdentifier();
return result;
}
JavascriptCallbackWrapper^ JavascriptCallbackRegistry::FindWrapper(int64 id)
{
JavascriptCallbackWrapper^ callback;
_callbacks->TryGetValue(id, callback);
return callback;
}
void JavascriptCallbackRegistry::Deregister(Int64 id)
{
JavascriptCallbackWrapper^ callback;
if (_callbacks->TryRemove(id, callback))
{
delete callback;
}
}
}
}

View file

@ -0,0 +1,53 @@
// 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 "JavascriptCallbackWrapper.h"
using namespace System::Collections::Concurrent;
namespace CefSharp
{
namespace Internals
{
private ref class JavascriptCallbackRegistry
{
private:
//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;
int _browserId;
ConcurrentDictionary<Int64, JavascriptCallbackWrapper^>^ _callbacks;
internal:
JavascriptCallbackWrapper^ FindWrapper(int64 id);
public:
JavascriptCallbackRegistry(int browserId) : _browserId(browserId)
{
_callbacks = gcnew ConcurrentDictionary<Int64, JavascriptCallbackWrapper^>();
}
~JavascriptCallbackRegistry()
{
if (_callbacks != nullptr)
{
for each (JavascriptCallbackWrapper^ callback in _callbacks->Values)
{
delete callback;
}
_callbacks->Clear();
_callbacks = nullptr;
}
}
JavascriptCallback^ Register(const CefRefPtr<CefV8Context>& context, const CefRefPtr<CefV8Value>& value);
void Deregister(Int64 id);
};
}
}

View file

@ -0,0 +1,48 @@
// 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 Internals
{
private ref class JavascriptCallbackWrapper
{
private:
MCefRefPtr<CefV8Value> _value;
MCefRefPtr<CefV8Context> _context;
internal:
CefRefPtr<CefV8Value> GetValue()
{
return _value.get();
}
CefRefPtr<CefV8Context> GetContext()
{
return _context.get();
}
public:
JavascriptCallbackWrapper(CefRefPtr<CefV8Value> value, CefRefPtr<CefV8Context> context)
: _value(value), _context(context)
{
}
!JavascriptCallbackWrapper()
{
_value = nullptr;
_context = nullptr;
}
~JavascriptCallbackWrapper()
{
this->!JavascriptCallbackWrapper();
}
};
}
}

View file

@ -0,0 +1,76 @@
// 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 "TypeUtils.h"
#include "JavascriptMethodHandler.h"
namespace CefSharp
{
bool JavascriptMethodHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
{
auto parameter = gcnew array<Object^>(arguments.size());
for (std::vector<CefRefPtr<CefV8Value>>::size_type i = 0; i != arguments.size(); i++)
{
parameter[i] = TypeUtils::ConvertFromCef(arguments[i], _callbackRegistry);
}
try
{
auto response = _method->Invoke(parameter);
retval = ConvertToCefObject(response->Result);
if (!response->Success)
{
exception = StringUtils::ToNative(response->Message);
}
}
catch (Exception^ ex)
{
exception = StringUtils::ToNative(ex->ToString());
}
//NOTE: Return true otherwise exception is ignored
return true;
}
CefRefPtr<CefV8Value> JavascriptMethodHandler::ConvertToCefObject(Object^ obj)
{
if (obj == nullptr)
{
return CefV8Value::CreateNull();
}
auto type = obj->GetType();
if (type == JavascriptObject::typeid)
{
JavascriptObject^ javascriptObject = (JavascriptObject^)obj;
CefRefPtr<CefV8Value> cefObject = CefV8Value::CreateObject(NULL, NULL);
for (int i = 0; i < javascriptObject->Properties->Count; i++)
{
auto prop = javascriptObject->Properties[i];
if (prop->IsComplexType)
{
auto v8Value = ConvertToCefObject(prop->JsObject);
cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
}
else
{
auto v8Value = TypeUtils::ConvertToCef(prop->PropertyValue, nullptr);
cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
}
}
return cefObject;
}
return TypeUtils::ConvertToCef(obj, nullptr);
}
}

View file

@ -0,0 +1,41 @@
// 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 "include/cef_v8.h"
#include "JavascriptCallbackRegistry.h"
using namespace CefSharp::Internals::Wcf;
namespace CefSharp
{
private class JavascriptMethodHandler : public CefV8Handler
{
private:
gcroot<Func<array<Object^>^, BrowserProcessResponse^>^> _method;
gcroot<JavascriptCallbackRegistry^> _callbackRegistry;
public:
JavascriptMethodHandler(Func<array<Object^>^, BrowserProcessResponse^>^ method, JavascriptCallbackRegistry^ callbackRegistry)
{
_method = method;
_callbackRegistry = callbackRegistry;
}
~JavascriptMethodHandler()
{
delete _method;
// The callback registry is a shared instance among all method handlers (async & sync).
// It's lifecycle is managed in the JavascriptRootObjectWrapper.
_callbackRegistry = nullptr;
}
virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE;
CefRefPtr<CefV8Value> ConvertToCefObject(Object^ obj);
IMPLEMENT_REFCOUNTING(JavascriptMethodHandler);
};
}

View file

@ -0,0 +1,26 @@
// 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 "JavascriptMethodWrapper.h"
namespace CefSharp
{
void JavascriptMethodWrapper::Bind(JavascriptMethod^ javascriptMethod, const CefRefPtr<CefV8Value>& v8Value)
{
_javascriptMethodName = javascriptMethod->JavascriptName;
auto methodName = StringUtils::ToNative(javascriptMethod->JavascriptName);
auto v8Function = CefV8Value::CreateFunction(methodName, _javascriptMethodHandler.get());
v8Value->SetValue(methodName, v8Function, V8_PROPERTY_ATTRIBUTE_NONE);
};
BrowserProcessResponse^ JavascriptMethodWrapper::Execute(array<Object^>^ parameters)
{
return _browserProcess->CallMethod(_ownerId, _javascriptMethodName, parameters);
}
}

View file

@ -0,0 +1,48 @@
// 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_v8.h"
#include "JavascriptMethodHandler.h"
using namespace System::Runtime::Serialization;
using namespace CefSharp::Internals::Wcf;
namespace CefSharp
{
private ref class JavascriptMethodWrapper
{
private:
MCefRefPtr<JavascriptMethodHandler> _javascriptMethodHandler;
int64 _ownerId;
String^ _javascriptMethodName;
IBrowserProcess^ _browserProcess;
public:
JavascriptMethodWrapper(int64 ownerId, IBrowserProcess^ browserProcess, JavascriptCallbackRegistry^ callbackRegistry)
{
_ownerId = ownerId;
_browserProcess = browserProcess;
_javascriptMethodHandler = new JavascriptMethodHandler(gcnew Func<array<Object^>^, BrowserProcessResponse^>(this, &JavascriptMethodWrapper::Execute), callbackRegistry);
}
!JavascriptMethodWrapper()
{
_javascriptMethodHandler = nullptr;
}
~JavascriptMethodWrapper()
{
this->!JavascriptMethodWrapper();
_browserProcess = nullptr;
}
void Bind(JavascriptMethod^ javascriptMethod, const CefRefPtr<CefV8Value>& v8Value);
BrowserProcessResponse^ Execute(array<Object^>^ parameters);
};
}

View file

@ -0,0 +1,54 @@
// 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 "JavascriptObjectWrapper.h"
namespace CefSharp
{
void JavascriptObjectWrapper::Bind(JavascriptObject^ object, const CefRefPtr<CefV8Value>& v8Value, JavascriptCallbackRegistry^ callbackRegistry)
{
_objectId = object->Id;
//Create property handler for get and set of Properties of this object
_jsPropertyHandler = new JavascriptPropertyHandler(
gcnew Func<String^, BrowserProcessResponse^>(this, &JavascriptObjectWrapper::GetProperty),
gcnew Func<String^, Object^, BrowserProcessResponse^>(this, &JavascriptObjectWrapper::SetProperty)
);
//V8Value that represents this javascript object - only one per complex type
auto javascriptObject = CefV8Value::CreateObject(_jsPropertyHandler.get(), NULL);
auto objectName = StringUtils::ToNative(object->JavascriptName);
v8Value->SetValue(objectName, javascriptObject, V8_PROPERTY_ATTRIBUTE_NONE);
for each (JavascriptMethod^ method in Enumerable::OfType<JavascriptMethod^>(object->Methods))
{
auto wrappedMethod = gcnew JavascriptMethodWrapper(object->Id, _browserProcess, callbackRegistry);
wrappedMethod->Bind(method, javascriptObject);
_wrappedMethods->Add(wrappedMethod);
}
for each (JavascriptProperty^ prop in Enumerable::OfType<JavascriptProperty^>(object->Properties))
{
auto wrappedproperty = gcnew JavascriptPropertyWrapper(object->Id, _browserProcess);
wrappedproperty->Bind(prop, javascriptObject, callbackRegistry);
_wrappedProperties->Add(wrappedproperty);
}
}
BrowserProcessResponse^ JavascriptObjectWrapper::GetProperty(String^ memberName)
{
return _browserProcess->GetProperty(_objectId, memberName);
};
BrowserProcessResponse^ JavascriptObjectWrapper::SetProperty(String^ memberName, Object^ value)
{
return _browserProcess->SetProperty(_objectId, memberName, value);
};
}

View file

@ -0,0 +1,61 @@
// 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_v8.h"
#include "JavascriptMethodWrapper.h"
#include "JavascriptPropertyWrapper.h"
#include "JavascriptPropertyHandler.h"
using namespace System::Runtime::Serialization;
using namespace System::Linq;
using namespace System::Collections::Generic;
namespace CefSharp
{
private ref class JavascriptObjectWrapper
{
private:
List<JavascriptMethodWrapper^>^ _wrappedMethods;
List<JavascriptPropertyWrapper^>^ _wrappedProperties;
IBrowserProcess^ _browserProcess;
MCefRefPtr<JavascriptPropertyHandler> _jsPropertyHandler;
int64 _objectId;
public:
JavascriptObjectWrapper(IBrowserProcess^ browserProcess)
{
_browserProcess = browserProcess;
_wrappedMethods = gcnew List<JavascriptMethodWrapper^>();
_wrappedProperties = gcnew List<JavascriptPropertyWrapper^>();
}
!JavascriptObjectWrapper()
{
_jsPropertyHandler = nullptr;
}
~JavascriptObjectWrapper()
{
this->!JavascriptObjectWrapper();
for each (JavascriptMethodWrapper^ var in _wrappedMethods)
{
delete var;
}
for each (JavascriptPropertyWrapper^ var in _wrappedProperties)
{
delete var;
}
}
void Bind(JavascriptObject^ object, const CefRefPtr<CefV8Value>& v8Value, JavascriptCallbackRegistry^ callbackRegistry);
BrowserProcessResponse^ GetProperty(String^ memberName);
BrowserProcessResponse^ SetProperty(String^ memberName, Object^ value);
};
}

View file

@ -0,0 +1,92 @@
// 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 "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
#include "Serialization\V8Serialization.h"
using namespace System;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
const CefString kPostMessage = CefString("PostMessage");
const CefString kPostMessageCamelCase = CefString("postMessage");
private class JavascriptPostMessageHandler : public CefV8Handler
{
private:
gcroot<JavascriptCallbackRegistry^> _javascriptCallbackRegistry;
public:
JavascriptPostMessageHandler(JavascriptCallbackRegistry^ javascriptCallbackRegistry)
{
_javascriptCallbackRegistry = javascriptCallbackRegistry;
}
bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE
{
if (arguments.size() == 0 || arguments.size() > 1)
{
//TODO: Improve error message
exception = "Only a single param is accepted";
return true;
}
auto context = CefV8Context::GetCurrentContext();
if (context.get())
{
auto frame = context->GetFrame();
if (frame.get() && frame->IsValid() && context->Enter())
{
try
{
auto global = context->GetGlobal();
auto request = CefProcessMessage::Create(kJavascriptMessageReceived);
auto argList = request->GetArgumentList();
auto params = CefListValue::Create();
SerializeV8Object(arguments[0], params, 0, _javascriptCallbackRegistry);
//We're only interested in the first param
if (params->GetSize() > 0)
{
argList->SetValue(0, params->GetValue(0));
}
frame->SendProcessMessage(CefProcessId::PID_BROWSER, request);
retval = CefV8Value::CreateNull();
}
finally
{
context->Exit();
}
}
else
{
exception = "Unable to Enter Context";
}
}
else
{
exception = "Unable to get current context";
}
return true;
}
IMPLEMENT_REFCOUNTING(JavascriptPostMessageHandler);
};
}

View file

@ -0,0 +1,85 @@
// 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 "include/cef_v8.h"
#include "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
#include "Serialization\V8Serialization.h"
using namespace System;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
const CefString kSendEvalScriptResponse = CefString("SendEvalScriptResponse");
const CefString kSendEvalScriptResponseCamelCase = CefString("sendEvalScriptResponse");
private class JavascriptPromiseHandler : public CefV8Handler
{
public:
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
if (arguments.size() < 2)
{
//TODO: Improve error message
exception = "Must specify a callback Id and then/catch.";
return true;
}
auto callbackId = arguments[0]->GetIntValue();
if (callbackId == 0)
{
exception = "Invalid callback Id";
return true;
}
auto success = arguments[1]->GetBoolValue();
auto response = CefProcessMessage::Create(kEvaluateJavascriptResponse);
auto responseArgList = response->GetArgumentList();
//Success
responseArgList->SetBool(0, success);
//Callback Id
SetInt64(responseArgList, 1, callbackId);
if (exception == "")
{
if (success)
{
SerializeV8Object(arguments[2], responseArgList, 2, nullptr);
}
else
{
auto reason = arguments[2];
responseArgList->SetString(2, reason->GetStringValue());
}
}
else
{
responseArgList->SetString(2, exception);
}
auto context = CefV8Context::GetCurrentContext();
auto frame = context->GetFrame();
frame->SendProcessMessage(CefProcessId::PID_BROWSER, response);
return false;
}
IMPLEMENT_REFCOUNTING(JavascriptPromiseHandler);
};
}

View file

@ -0,0 +1,65 @@
// 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_v8.h"
#include "TypeUtils.h"
namespace CefSharp
{
private class JavascriptPropertyHandler : public CefV8Accessor
{
gcroot<Func<String^, BrowserProcessResponse^>^> _getter;
gcroot<Func<String^, Object^, BrowserProcessResponse^>^> _setter;
public:
JavascriptPropertyHandler(Func<String^, BrowserProcessResponse^>^ getter, Func<String^, Object^, BrowserProcessResponse^>^ setter)
{
_getter = getter;
_setter = setter;
}
~JavascriptPropertyHandler()
{
delete _getter;
delete _setter;
}
virtual bool Get(const CefString& name, const CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value>& retval,
CefString& exception) override
{
//System::Diagnostics::Debugger::Break();
auto propertyName = StringUtils::ToClr(name);
auto response = _getter->Invoke(propertyName);
retval = TypeUtils::ConvertToCef(response->Result, nullptr);
if (!response->Success)
{
exception = StringUtils::ToNative(response->Message);
}
//NOTE: Return true otherwise exception is ignored
return true;
}
virtual bool Set(const CefString& name, const CefRefPtr<CefV8Value> object, const CefRefPtr<CefV8Value> value,
CefString& exception) override
{
//System::Diagnostics::Debugger::Break();
auto propertyName = StringUtils::ToClr(name);
auto managedValue = TypeUtils::ConvertFromCef(value, nullptr);
auto response = _setter->Invoke(propertyName, managedValue);
if (!response->Success)
{
exception = StringUtils::ToNative(response->Message);
}
//NOTE: Return true otherwise exception is ignored
return true;
}
IMPLEMENT_REFCOUNTING(JavascriptPropertyHandler);
};
}

View file

@ -0,0 +1,35 @@
// 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 "JavascriptPropertyWrapper.h"
#include "JavascriptObjectWrapper.h"
using namespace System;
namespace CefSharp
{
void JavascriptPropertyWrapper::Bind(JavascriptProperty^ javascriptProperty, const CefRefPtr<CefV8Value>& v8Value, JavascriptCallbackRegistry^ callbackRegistry)
{
auto propertyName = StringUtils::ToNative(javascriptProperty->JavascriptName);
auto clrPropertyName = javascriptProperty->JavascriptName;
if (javascriptProperty->IsComplexType)
{
auto javascriptObjectWrapper = gcnew JavascriptObjectWrapper(_browserProcess);
javascriptObjectWrapper->Bind(javascriptProperty->JsObject, v8Value, callbackRegistry);
_javascriptObjectWrapper = javascriptObjectWrapper;
}
else
{
auto propertyAttribute = javascriptProperty->IsReadOnly ? V8_PROPERTY_ATTRIBUTE_READONLY : V8_PROPERTY_ATTRIBUTE_NONE;
v8Value->SetValue(propertyName, V8_ACCESS_CONTROL_DEFAULT, propertyAttribute);
}
};
}

View file

@ -0,0 +1,42 @@
// 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_v8.h"
#include "JavascriptCallbackRegistry.h"
using namespace CefSharp::Internals::Wcf;
namespace CefSharp
{
private ref class JavascriptPropertyWrapper
{
private:
int64 _ownerId;
IBrowserProcess^ _browserProcess;
//TODO: Strongly type this variable - currently trying to include JavascriptObjectWrapper.h creates a circular reference, so won't compile
Object^ _javascriptObjectWrapper;
public:
JavascriptPropertyWrapper(int64 ownerId, IBrowserProcess^ browserProcess)
{
_ownerId = ownerId;
_browserProcess = browserProcess;
_javascriptObjectWrapper = nullptr;
}
~JavascriptPropertyWrapper()
{
if (_javascriptObjectWrapper != nullptr)
{
delete _javascriptObjectWrapper;
_javascriptObjectWrapper = nullptr;
}
}
void Bind(JavascriptProperty^ javascriptProperty, const CefRefPtr<CefV8Value>& v8Value, JavascriptCallbackRegistry^ callbackRegistry);
};
}

View file

@ -0,0 +1,71 @@
// 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 "JavascriptRootObjectWrapper.h"
#include "CefAppUnmanagedWrapper.h"
using namespace System::Threading;
namespace CefSharp
{
void JavascriptRootObjectWrapper::Bind(ICollection<JavascriptObject^>^ objects, const CefRefPtr<CefV8Value>& v8Value)
{
if (objects->Count > 0)
{
auto saveMethod = gcnew Func<JavascriptAsyncMethodCallback^, int64>(this, &JavascriptRootObjectWrapper::SaveMethodCallback);
for each (JavascriptObject^ obj in Enumerable::OfType<JavascriptObject^>(objects))
{
if (obj->IsAsync)
{
auto wrapperObject = gcnew JavascriptAsyncObjectWrapper(_callbackRegistry, saveMethod);
wrapperObject->Bind(obj, v8Value);
_wrappedAsyncObjects->Add(wrapperObject);
}
#ifndef NETCOREAPP
else
{
if (_browserProcess == nullptr)
{
LOG(ERROR) << StringUtils::ToNative("IBrowserProcess is null, unable to bind object " + obj->JavascriptName).ToString();
continue;
}
auto wrapperObject = gcnew JavascriptObjectWrapper(_browserProcess);
wrapperObject->Bind(obj, v8Value, _callbackRegistry);
_wrappedObjects->Add(wrapperObject);
}
#endif
}
}
}
JavascriptCallbackRegistry^ JavascriptRootObjectWrapper::CallbackRegistry::get()
{
return _callbackRegistry;
}
int64 JavascriptRootObjectWrapper::SaveMethodCallback(JavascriptAsyncMethodCallback^ callback)
{
auto callbackId = Interlocked::Increment(_lastCallback);
_methodCallbacks->Add(callbackId, callback);
return callbackId;
}
bool JavascriptRootObjectWrapper::TryGetAndRemoveMethodCallback(int64 id, JavascriptAsyncMethodCallback^% callback)
{
bool result = false;
if (result = _methodCallbacks->TryGetValue(id, callback))
{
_methodCallbacks->Remove(id);
}
return result;
}
}

View file

@ -0,0 +1,107 @@
// 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 "include/cef_v8.h"
#include "JavascriptCallbackRegistry.h"
#ifndef NETCOREAPP
#include "JavascriptObjectWrapper.h"
#endif
#include "Async/JavascriptAsyncObjectWrapper.h"
using namespace System::Runtime::Serialization;
using namespace System::Linq;
using namespace System::Collections::Generic;
using namespace CefSharp::Internals::Async;
#ifndef NETCOREAPP
using namespace CefSharp::Internals::Wcf;
#endif
namespace CefSharp
{
// This wraps the transmitted registered objects
// by binding the meta-data to V8 JavaScript objects
// and installing callbacks for changes to those
// objects.
private ref class JavascriptRootObjectWrapper
{
private:
//Only access through Interlocked::Increment - used to generate unique callback Id's
//Is static so ids are unique to this process https://github.com/cefsharp/CefSharp/issues/2792
static int64 _lastCallback;
#ifndef NETCOREAPP
initonly List<JavascriptObjectWrapper^>^ _wrappedObjects;
#endif
initonly List<JavascriptAsyncObjectWrapper^>^ _wrappedAsyncObjects;
initonly Dictionary<int64, JavascriptAsyncMethodCallback^>^ _methodCallbacks;
#ifndef NETCOREAPP
IBrowserProcess^ _browserProcess;
#endif
// The entire set of possible JavaScript functions to
// call directly into.
JavascriptCallbackRegistry^ _callbackRegistry;
int64 SaveMethodCallback(JavascriptAsyncMethodCallback^ callback);
internal:
property JavascriptCallbackRegistry^ CallbackRegistry
{
CefSharp::Internals::JavascriptCallbackRegistry^ get();
}
public:
#ifdef NETCOREAPP
JavascriptRootObjectWrapper(int browserId)
#else
JavascriptRootObjectWrapper(int browserId, IBrowserProcess^ browserProcess)
#endif
{
#ifndef NETCOREAPP
_browserProcess = browserProcess;
_wrappedObjects = gcnew List<JavascriptObjectWrapper^>();
#endif
_wrappedAsyncObjects = gcnew List<JavascriptAsyncObjectWrapper^>();
_callbackRegistry = gcnew JavascriptCallbackRegistry(browserId);
_methodCallbacks = gcnew Dictionary<int64, JavascriptAsyncMethodCallback^>();
}
~JavascriptRootObjectWrapper()
{
if (_callbackRegistry != nullptr)
{
delete _callbackRegistry;
_callbackRegistry = nullptr;
}
#ifndef NETCOREAPP
for each (JavascriptObjectWrapper^ var in _wrappedObjects)
{
delete var;
}
_wrappedObjects->Clear();
#endif
for each (JavascriptAsyncObjectWrapper^ var in _wrappedAsyncObjects)
{
delete var;
}
_wrappedAsyncObjects->Clear();
for each(JavascriptAsyncMethodCallback^ var in _methodCallbacks->Values)
{
delete var;
}
_methodCallbacks->Clear();
}
bool TryGetAndRemoveMethodCallback(int64 id, JavascriptAsyncMethodCallback^% callback);
void Bind(ICollection<JavascriptObject^>^ objects, const CefRefPtr<CefV8Value>& v8Value);
};
}

View file

@ -0,0 +1,126 @@
// Copyright © 2018 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;
namespace CefSharp
{
const CefString kIsObjectCached = CefString("IsObjectCached");
const CefString kIsObjectCachedCamelCase = CefString("isObjectCached");
const CefString kRemoveObjectFromCache = CefString("RemoveObjectFromCache");
const CefString kRemoveObjectFromCacheCamelCase = CefString("removeObjectFromCache");
const CefString kDeleteBoundObject = CefString("DeleteBoundObject");
const CefString kDeleteBoundObjectCamelCase = CefString("deleteBoundObject");
private class RegisterBoundObjectHandler : public CefV8Handler
{
private:
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
public:
RegisterBoundObjectHandler(Dictionary<String^, JavascriptObject^>^ javascriptObjects)
{
_javascriptObjects = javascriptObjects;
}
bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE
{
auto context = CefV8Context::GetCurrentContext();
if (context.get())
{
if (context.get() && context->Enter())
{
try
{
if (name == kIsObjectCached || name == kIsObjectCachedCamelCase)
{
if (arguments.size() == 0 || arguments.size() > 1)
{
//TODO: Improve error message
exception = "Must specify the name of a single bound object to check the cache for";
return true;
}
auto objectName = arguments[0]->GetStringValue();
auto managedObjectName = StringUtils::ToClr(objectName);
//Check to see if the object name is within the cache
retval = CefV8Value::CreateBool(_javascriptObjects->ContainsKey(managedObjectName));
}
else if (name == kRemoveObjectFromCache || name == kRemoveObjectFromCacheCamelCase)
{
if (arguments.size() == 0 || arguments.size() > 1)
{
//TODO: Improve error message
exception = "Must specify the name of a single bound object to remove from cache";
return true;
}
auto objectName = arguments[0]->GetStringValue();
auto managedObjectName = StringUtils::ToClr(objectName);
if (_javascriptObjects->ContainsKey(managedObjectName))
{
//Remove object from cache
retval = CefV8Value::CreateBool(_javascriptObjects->Remove(managedObjectName));
}
else
{
retval = CefV8Value::CreateBool(false);
}
}
//TODO: Better name for this function
else if (name == kDeleteBoundObject || name == kDeleteBoundObjectCamelCase)
{
if (arguments.size() == 0 || arguments.size() > 1)
{
//TODO: Improve error message
exception = "Must specify the name of a bound object to unbind, one object at a time.";
return true;
}
auto objectName = arguments[0]->GetStringValue();
auto global = context->GetGlobal();
auto success = global->DeleteValue(objectName);
retval = CefV8Value::CreateBool(success);
}
}
finally
{
context->Exit();
}
}
else
{
exception = "Unable to Enter Context";
}
}
else
{
exception = "Unable to get current context";
}
return true;
}
IMPLEMENT_REFCOUNTING(RegisterBoundObjectHandler);
};
}

View file

@ -0,0 +1,64 @@
// Copyright © 2018 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 "Async/JavascriptAsyncMethodCallback.h"
using namespace System::Runtime::Serialization;
using namespace System::Linq;
using namespace System::Threading;
using namespace System::Collections::Generic;
using namespace CefSharp::Internals::Async;
namespace CefSharp
{
//TODO: JSB Fix naming of this class, it's pretty horrible currently
private ref class RegisterBoundObjectRegistry
{
private:
//Only access through Interlocked::Increment - used to generate unique callback Id's
//Is static so ids are unique to this process https://github.com/cefsharp/CefSharp/issues/2792
static int64 _lastCallback;
initonly Dictionary<int64, JavascriptAsyncMethodCallback^>^ _methodCallbacks;
public:
RegisterBoundObjectRegistry()
{
_methodCallbacks = gcnew Dictionary<int64, JavascriptAsyncMethodCallback^>();
}
~RegisterBoundObjectRegistry()
{
for each(JavascriptAsyncMethodCallback^ var in _methodCallbacks->Values)
{
delete var;
}
_methodCallbacks->Clear();
}
int64 SaveMethodCallback(JavascriptAsyncMethodCallback^ callback)
{
auto callbackId = Interlocked::Increment(_lastCallback);
_methodCallbacks->Add(callbackId, callback);
return callbackId;
}
bool TryGetAndRemoveMethodCallback(int64 id, JavascriptAsyncMethodCallback^% callback)
{
bool result = false;
if (result = _methodCallbacks->TryGetValue(id, callback))
{
_methodCallbacks->Remove(id);
}
return result;
}
};
}

View file

@ -0,0 +1,80 @@
// 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 "JsObjectsSerialization.h"
#include "../CefSharp.Core.Runtime/Internals/Serialization/Primitives.h"
#include "../CefSharp.Core.Runtime/Internals/Serialization/ObjectsSerialization.h"
namespace CefSharp
{
namespace Internals
{
namespace Serialization
{
JavascriptObject^ DeserializeJsObject(const CefRefPtr<CefListValue>& rootList, int index)
{
if (rootList->GetType(index) == VTYPE_INVALID ||
rootList->GetType(index) == VTYPE_NULL)
{
return nullptr;
}
auto list = rootList->GetList(index);
auto jsObject = gcnew JavascriptObject();
jsObject->Id = GetInt64(list, 0);
jsObject->Name = StringUtils::ToClr(list->GetString(1));
jsObject->JavascriptName = StringUtils::ToClr(list->GetString(2));
jsObject->IsAsync = list->GetBool(3);
auto methodList = list->GetList(4);
auto methodCount = methodList->GetInt(0);
auto k = 1;
for (auto j = 0; j < methodCount; j++)
{
auto jsMethod = gcnew JavascriptMethod();
jsMethod->Id = GetInt64(methodList, k++);
jsMethod->ManagedName = StringUtils::ToClr(methodList->GetString(k++));
jsMethod->JavascriptName = StringUtils::ToClr(methodList->GetString(k++));
jsMethod->ParameterCount = methodList->GetInt(k++);
jsObject->Methods->Add(jsMethod);
}
auto propertyList = list->GetList(5);
auto propertyCount = propertyList->GetInt(0);
k = 1;
for (auto j = 0; j < propertyCount; j++)
{
auto jsProperty = gcnew JavascriptProperty();
jsProperty->Id = GetInt64(propertyList, k++);
jsProperty->ManagedName = StringUtils::ToClr(propertyList->GetString(k++));
jsProperty->JavascriptName = StringUtils::ToClr(propertyList->GetString(k++));
jsProperty->IsComplexType = propertyList->GetBool(k++);
jsProperty->IsReadOnly = propertyList->GetBool(k++);
jsProperty->JsObject = DeserializeJsObject(propertyList, k++);
jsProperty->PropertyValue = DeserializeObject(propertyList, k++, nullptr);
jsObject->Properties->Add(jsProperty);
}
return jsObject;
}
List<JavascriptObject^>^ DeserializeJsObjects(const CefRefPtr<CefListValue>& list, int index)
{
auto result = gcnew List<JavascriptObject^>();
auto subList = list->GetList(index);
for (size_t i = 0; i < subList->GetSize(); i++)
{
result->Add(DeserializeJsObject(subList, i));
}
return result;
}
}
}
}

View file

@ -0,0 +1,19 @@
// 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_values.h"
namespace CefSharp
{
namespace Internals
{
namespace Serialization
{
JavascriptObject^ DeserializeJsObject(const CefRefPtr<CefListValue>& list, int index);
List<JavascriptObject^>^ DeserializeJsObjects(const CefRefPtr<CefListValue>& list, int index);
}
}
}

View file

@ -0,0 +1,188 @@
// 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 "V8Serialization.h"
#include "JavascriptCallbackRegistry.h"
#include "../CefSharp.Core.Runtime/Internals/Serialization/Primitives.h"
#include <deque>
using namespace std;
namespace CefSharp
{
namespace Internals
{
namespace Serialization
{
typedef deque<CefRefPtr<CefV8Value>> value_deque;
template<typename TList, typename TIndex>
void SerializeV8Object(const CefRefPtr<CefV8Value> &obj, const CefRefPtr<TList>& list, const TIndex& index, JavascriptCallbackRegistry^ callbackRegistry, value_deque &seen)
{
for (value_deque::const_iterator it = seen.begin(); it != seen.end(); ++it)
{
if (obj->IsSame(*it))
{
throw exception("Cycle found");
}
}
seen.push_back(obj);
if (obj->IsNull() || obj->IsUndefined())
{
list->SetNull(index);
}
else if (obj->IsBool())
{
list->SetBool(index, obj->GetBoolValue());
}
else if (obj->IsInt())
{
list->SetInt(index, obj->GetIntValue());
}
else if (obj->IsDouble())
{
list->SetDouble(index, obj->GetDoubleValue());
}
else if (obj->IsString())
{
list->SetString(index, obj->GetStringValue());
}
else if (obj->IsDate())
{
SetCefTime(list, index, obj->GetDateValue());
}
else if (obj->IsArray())
{
int arrLength = obj->GetArrayLength();
std::vector<CefString> keys;
auto array = CefListValue::Create();
if (arrLength > 0 && obj->GetKeys(keys))
{
for (int i = 0; i < arrLength; i++)
{
SerializeV8Object(obj->GetValue(keys[i]), array, i, callbackRegistry, seen);
}
}
list->SetList(index, array);
}
else if (obj->IsFunction())
{
auto context = CefV8Context::GetCurrentContext();
auto jsCallback = callbackRegistry->Register(context, obj);
SetJsCallback(list, index, jsCallback);
}
else if (obj->IsObject())
{
std::vector<CefString> keys;
if (obj->GetKeys(keys) && keys.size() > 0)
{
auto result = CefDictionaryValue::Create();
for (size_t i = 0; i < keys.size(); i++)
{
auto p_keyStr = StringUtils::ToClr(keys[i].ToString());
if ((obj->HasValue(keys[i])) && (!p_keyStr->StartsWith("__")))
{
SerializeV8Object(obj->GetValue(keys[i]), result, keys[i], callbackRegistry, seen);
}
}
list->SetDictionary(index, result);
}
}
else
{
list->SetNull(index);
}
seen.pop_back();
}
template<typename TList, typename TIndex>
void SerializeV8Object(const CefRefPtr<CefV8Value> &obj, const CefRefPtr<TList>& list, const TIndex& index, JavascriptCallbackRegistry^ callbackRegistry)
{
try
{
value_deque seen;
SerializeV8Object(obj, list, index, callbackRegistry, seen);
}
catch (const exception&)
{
list->SetNull(index);
}
}
template<typename TList, typename TIndex>
CefRefPtr<CefV8Value> DeserializeV8Object(const CefRefPtr<TList>& list, const TIndex& index)
{
auto type = list->GetType(index);
if (type == VTYPE_BOOL)
{
return CefV8Value::CreateBool(list->GetBool(index));
}
if (type == VTYPE_INT)
{
return CefV8Value::CreateInt(list->GetInt(index));
}
if (type == VTYPE_DOUBLE)
{
return CefV8Value::CreateDouble(list->GetDouble(index));
}
if (type == VTYPE_STRING)
{
return CefV8Value::CreateString(list->GetString(index));
}
if (IsCefTime(list, index))
{
return CefV8Value::CreateDate(GetCefTime(list, index));
}
if (type == VTYPE_LIST)
{
auto subList = list->GetList(index);
size_t size = subList->GetSize();
auto result = CefV8Value::CreateArray(size);
for (size_t i = 0; i < size; i++)
{
result->SetValue(i, DeserializeV8Object(subList, i));
}
return result;
}
if (type == VTYPE_DICTIONARY)
{
auto subDict = list->GetDictionary(index);
auto size = subDict->GetSize();
std::vector<CefString> keys;
subDict->GetKeys(keys);
auto result = CefV8Value::CreateObject(nullptr, nullptr);
for (size_t i = 0; i < size; i++)
{
result->SetValue(keys[i], DeserializeV8Object(subDict, keys[i]), V8_PROPERTY_ATTRIBUTE_NONE);
}
return result;
}
return CefV8Value::CreateNull();
}
template void SerializeV8Object(const CefRefPtr<CefV8Value> &value, const CefRefPtr<CefListValue>& list, const int& index, JavascriptCallbackRegistry^ callbackRegistry);
template void SerializeV8Object(const CefRefPtr<CefV8Value> &value, const CefRefPtr<CefListValue>& list, const size_t& index, JavascriptCallbackRegistry^ callbackRegistry);
template void SerializeV8Object(const CefRefPtr<CefV8Value> &value, const CefRefPtr<CefDictionaryValue>& list, const CefString& index, JavascriptCallbackRegistry^ callbackRegistry);
template void SerializeV8Object(const CefRefPtr<CefV8Value> &value, const CefRefPtr<CefListValue>& list, const size_t& index, JavascriptCallbackRegistry^ callbackRegistry, value_deque &visited);
template void SerializeV8Object(const CefRefPtr<CefV8Value> &value, const CefRefPtr<CefDictionaryValue>& list, const CefString& index, JavascriptCallbackRegistry^ callbackRegistry, value_deque &visited);
template CefRefPtr<CefV8Value> DeserializeV8Object(const CefRefPtr<CefListValue>& list, const int& index);
template CefRefPtr<CefV8Value> DeserializeV8Object(const CefRefPtr<CefDictionaryValue>& list, const CefString& index);
}
}
}

View file

@ -0,0 +1,29 @@
// 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 Internals
{
ref class JavascriptCallbackRegistry;
namespace Serialization
{
//Functions to serialize/deserialize data sent to/received from the browser process.
//Serializes a V8 structure into a given index of a CefListValue or CefDictionaryValue
//JavascriptCallbackRegistry should be passed to save V8Values with function types
template<typename TList, typename TIndex>
void SerializeV8Object(const CefRefPtr<CefV8Value> &value, const CefRefPtr<TList>& list, const TIndex& index, JavascriptCallbackRegistry^ callbackRegistry);
//Deserializes data from a given index of a CefListValue or a CefDictionaryValue
template<typename TList, typename TIndex>
CefRefPtr<CefV8Value> DeserializeV8Object(const CefRefPtr<TList>& list, const TIndex& index);
}
}
}

View file

@ -0,0 +1,3 @@
#pragma once
#include "Stdafx.h"

View file

@ -0,0 +1,23 @@
// 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
#ifdef EXPORT
#define DECL __declspec(dllexport)
#else
#define DECL __declspec(dllimport)
#endif
#include <vector>
#include <include/cef_base.h>
#include ".\..\CefSharp.Core.Runtime\Internals\MCefRefPtr.h"
#include ".\..\CefSharp.Core.Runtime\Internals\StringUtils.h"
#include "vcclr_local.h"
using namespace System;
using namespace CefSharp;
using namespace CefSharp::Internals;

View file

@ -0,0 +1,89 @@
// Copyright © 2016 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 "SubProcessApp.h"
#include "CefBrowserWrapper.h"
#include "CefAppUnmanagedWrapper.h"
#include "Cef.h"
using namespace System::Collections::Generic;
using namespace System::Linq;
using namespace CefSharp::Internals;
using namespace CefSharp::RenderProcess;
namespace CefSharp
{
namespace BrowserSubprocess
{
// Wrap CefAppUnmangedWrapper in a nice managed wrapper
public ref class SubProcess
{
private:
MCefRefPtr<CefAppUnmanagedWrapper> _cefApp;
public:
SubProcess(IRenderProcessHandler^ handler, IEnumerable<String^>^ args)
{
auto onBrowserCreated = gcnew Action<CefBrowserWrapper^>(this, &SubProcess::OnBrowserCreated);
auto onBrowserDestroyed = gcnew Action<CefBrowserWrapper^>(this, &SubProcess::OnBrowserDestroyed);
auto schemes = CefCustomScheme::ParseCommandLineArguments(args);
auto enableFocusedNodeChanged = CommandLineArgsParser::HasArgument(args, CefSharpArguments::FocusedNodeChangedEnabledArgument);
_cefApp = new CefAppUnmanagedWrapper(handler, schemes, enableFocusedNodeChanged, onBrowserCreated, onBrowserDestroyed);
}
!SubProcess()
{
_cefApp = nullptr;
}
~SubProcess()
{
this->!SubProcess();
}
int Run()
{
auto hInstance = Process::GetCurrentProcess()->Handle;
CefMainArgs cefMainArgs((HINSTANCE)hInstance.ToPointer());
return CefExecuteProcess(cefMainArgs, (CefApp*)_cefApp.get(), NULL);
}
virtual void OnBrowserCreated(CefBrowserWrapper^ cefBrowserWrapper)
{
}
virtual void OnBrowserDestroyed(CefBrowserWrapper^ cefBrowserWrapper)
{
}
static void EnableHighDPISupport()
{
CefEnableHighDPISupport();
}
static int ExecuteProcess(IEnumerable<String^>^ args)
{
auto hInstance = Process::GetCurrentProcess()->Handle;
CefMainArgs cefMainArgs((HINSTANCE)hInstance.ToPointer());
auto schemes = CefCustomScheme::ParseCommandLineArguments(args);
CefRefPtr<CefApp> app = new SubProcessApp(schemes);
return CefExecuteProcess(cefMainArgs, app, NULL);
}
};
}
}

View file

@ -0,0 +1,47 @@
// 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 "include/cef_app.h"
using namespace System::Collections::Generic;
namespace CefSharp
{
// CefApp implementation that's common across all subprocess types
public class SubProcessApp : public CefApp
{
private:
gcroot<List<CefCustomScheme^>^> _schemes;
public:
SubProcessApp(List<CefCustomScheme^>^ schemes)
{
_schemes = schemes;
}
~SubProcessApp()
{
delete _schemes;
_schemes = nullptr;
}
void OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) OVERRIDE
{
for each (CefCustomScheme^ scheme in _schemes->AsReadOnly())
{
auto schemeName = StringUtils::ToNative(scheme->SchemeName);
auto schemeOptions = (int)scheme->Options;
if (!registrar->AddCustomScheme(schemeName, schemeOptions))
{
LOG(ERROR) << "SubProcessApp::OnRegisterCustomSchemes failed for schemeName:" << schemeName;
}
}
}
IMPLEMENT_REFCOUNTING(SubProcessApp);
};
}

View file

@ -0,0 +1,271 @@
// Copyright © 2010 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 ".\..\CefSharp.Core.Runtime\Internals\StringUtils.h"
#include "TypeUtils.h"
using namespace System::Collections::Generic;
namespace CefSharp
{
CefRefPtr<CefV8Value> TypeUtils::ConvertToCef(Object^ obj, Type^ type)
{
if (type == Void::typeid)
{
return CefV8Value::CreateUndefined();
}
if (obj == nullptr)
{
return CefV8Value::CreateNull();
}
if (type == nullptr)
{
type = obj->GetType();
}
Type^ underlyingType = Nullable::GetUnderlyingType(type);
if (underlyingType != nullptr) type = underlyingType;
if (type == Boolean::typeid)
{
return CefV8Value::CreateBool(safe_cast<bool>(obj));
}
if (type == Int32::typeid)
{
return CefV8Value::CreateInt(safe_cast<int>(obj));
}
if (type == String::typeid)
{
CefString str = StringUtils::ToNative(safe_cast<String^>(obj));
return CefV8Value::CreateString(str);
}
if (type == Double::typeid)
{
return CefV8Value::CreateDouble(safe_cast<double>(obj));
}
if (type == Decimal::typeid)
{
return CefV8Value::CreateDouble(Convert::ToDouble(obj));
}
if (type == SByte::typeid)
{
return CefV8Value::CreateInt(Convert::ToInt32(obj));
}
if (type == Int16::typeid)
{
return CefV8Value::CreateInt(Convert::ToInt32(obj));
}
if (type == Int64::typeid)
{
return CefV8Value::CreateDouble(Convert::ToDouble(obj));
}
if (type == Byte::typeid)
{
return CefV8Value::CreateInt(Convert::ToInt32(obj));
}
if (type == UInt16::typeid)
{
return CefV8Value::CreateInt(Convert::ToInt32(obj));
}
if (type == UInt32::typeid)
{
return CefV8Value::CreateDouble(Convert::ToDouble(obj));
}
if (type == UInt64::typeid)
{
return CefV8Value::CreateDouble(Convert::ToDouble(obj));
}
if (type == Single::typeid)
{
return CefV8Value::CreateDouble(Convert::ToDouble(obj));
}
if (type == Char::typeid)
{
return CefV8Value::CreateInt(Convert::ToInt32(obj));
}
if (type == DateTime::typeid)
{
return CefV8Value::CreateDate(TypeUtils::ConvertDateTimeToCefTime(safe_cast<DateTime>(obj)));
}
if (type->IsArray)
{
Array^ managedArray = (Array^)obj;
CefRefPtr<CefV8Value> cefArray = CefV8Value::CreateArray(managedArray->Length);
for (int i = 0; i < managedArray->Length; i++)
{
Object^ arrObj;
arrObj = managedArray->GetValue(i);
if (arrObj != nullptr)
{
CefRefPtr<CefV8Value> cefObj = TypeUtils::ConvertToCef(arrObj, arrObj->GetType());
cefArray->SetValue(i, cefObj);
}
else
{
cefArray->SetValue(i, CefV8Value::CreateNull());
}
}
return cefArray;
}
if (type->IsValueType && !type->IsPrimitive && !type->IsEnum)
{
cli::array<System::Reflection::FieldInfo^>^ fields = type->GetFields();
CefRefPtr<CefV8Value> cefArray = CefV8Value::CreateArray(fields->Length);
for (int i = 0; i < fields->Length; i++)
{
String^ fieldName = fields[i]->Name;
CefString strFieldName = StringUtils::ToNative(safe_cast<String^>(fieldName));
Object^ fieldVal = fields[i]->GetValue(obj);
if (fieldVal != nullptr)
{
CefRefPtr<CefV8Value> cefVal = TypeUtils::ConvertToCef(fieldVal, fieldVal->GetType());
cefArray->SetValue(strFieldName, cefVal, V8_PROPERTY_ATTRIBUTE_NONE);
}
else
{
cefArray->SetValue(strFieldName, CefV8Value::CreateNull(), V8_PROPERTY_ATTRIBUTE_NONE);
}
}
return cefArray;
}
//TODO: What exception type?
throw gcnew Exception(String::Format("Cannot convert '{0}' object from CLR to CEF.", type->FullName));
}
Object^ TypeUtils::ConvertFromCef(CefRefPtr<CefV8Value> obj, JavascriptCallbackRegistry^ callbackRegistry)
{
if (obj->IsNull() || obj->IsUndefined())
{
return nullptr;
}
if (obj->IsBool())
{
return gcnew System::Boolean(obj->GetBoolValue());
}
if (obj->IsInt())
{
return gcnew System::Int32(obj->GetIntValue());
}
if (obj->IsDouble())
{
return gcnew System::Double(obj->GetDoubleValue());
}
if (obj->IsString())
{
return StringUtils::ToClr(obj->GetStringValue());
}
if (obj->IsDate())
{
return TypeUtils::ConvertCefTimeToDateTime(obj->GetDateValue());
}
if (obj->IsArray())
{
int arrLength = obj->GetArrayLength();
if (arrLength > 0)
{
std::vector<CefString> keys;
if (obj->GetKeys(keys))
{
auto array = gcnew List<Object^>();
//TODO: This can likely be simplified to just call GetValue(i) rather than accessing the keys
for (int i = 0; i < arrLength; i++)
{
auto data = obj->GetValue(keys[i]);
if (data != nullptr)
{
auto p_data = TypeUtils::ConvertFromCef(data, callbackRegistry);
array->Add(p_data);
}
}
return array->ToArray();
}
}
return nullptr;
}
if (obj->IsFunction())
{
if (callbackRegistry == nullptr)
{
return nullptr;
}
return callbackRegistry->Register(CefV8Context::GetCurrentContext(), obj);
}
if (obj->IsObject())
{
std::vector<CefString> keys;
if (obj->GetKeys(keys))
{
size_t objLength = keys.size();
if (objLength > 0)
{
auto result = gcnew Dictionary<String^, Object^>();
for (size_t i = 0; i < objLength; i++)
{
String^ p_keyStr = StringUtils::ToClr(keys[i].ToString());
if ((obj->HasValue(keys[i])) && (!p_keyStr->StartsWith("__")))
{
CefRefPtr<CefV8Value> data = obj->GetValue(keys[i]);
if (data != nullptr)
{
Object^ p_data = TypeUtils::ConvertFromCef(data, callbackRegistry);
result->Add(p_keyStr, p_data);
}
}
}
return result;
}
}
return nullptr;
}
//TODO: What exception type?
throw gcnew Exception("Cannot convert object from Cef to CLR.");
}
DateTime TypeUtils::ConvertCefTimeToDateTime(CefTime time)
{
return DateTimeUtils::FromCefTime(time.year,
time.month,
time.day_of_month,
time.hour,
time.minute,
time.second,
time.millisecond);
}
CefTime TypeUtils::ConvertDateTimeToCefTime(DateTime dateTime)
{
return CefTime(DateTimeUtils::ToCefTime(dateTime));
}
}

View file

@ -0,0 +1,52 @@
// Copyright © 2012 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"
#include "JavascriptCallbackRegistry.h"
using namespace System;
namespace CefSharp
{
private class TypeUtils
{
public:
/// <summary>
/// Converts a .NET object to an (unmanaged) Chromium V8 object.
/// </summary>
/// <param name="obj">The .NET object that should be converted.</param>
/// <param name="type">The type of the source object. If this parameter is a null reference, the type will be determined
/// automatically.</param>
/// <returns>A corresponding V8 value.</returns>
static CefRefPtr<CefV8Value> ConvertToCef(Object^ obj, Type^ type);
/// <summary>
/// Converts a Chromium V8 value to a (managed) .NET object
/// using a JavascriptCallbackRegistry param to convert any
/// anonymous function to IJavascriptCallback, if callbackRegistry
/// is nullptr will use nullptr to each anonymous function instead.
/// </summary>
/// <param name="obj">The V8 value that should be converted.</param>
/// <param name="callbackRegistry">Instance of JavascriptCallbackRegistry to manage IJavascriptCallback instances.</param>
/// <returns>A corresponding .NET object.</returns>
static Object^ ConvertFromCef(CefRefPtr<CefV8Value> obj, JavascriptCallbackRegistry^ callbackRegistry);
/// <summary>
/// Converts a Chromium V8 CefTime (Date) to a (managed) .NET DateTime.
/// </summary>
/// <param name="obj">The CefTime value that should be converted.</param>
/// <returns>A corresponding .NET DateTime.</returns>
static DateTime ConvertCefTimeToDateTime(CefTime time);
/// <summary>
/// Converts a a (managed) .NET DateTime to Chromium V8 CefTime (Date).
/// </summary>
/// <param name="obj">The DateTime value that should be converted.</param>
/// <returns>A corresponding CefTime (epoch).</returns>
static CefTime ConvertDateTimeToCefTime(DateTime dateTime);
};
}

View file

@ -0,0 +1,46 @@
// 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"
#include "WcfEnabledSubProcess.h"
#include "BrowserSubprocessExecutable.h"
using namespace System;
using namespace CefSharp::Internals;
namespace CefSharp
{
namespace BrowserSubprocess
{
/// <summary>
/// WcfBrowserSubprocessExecutable 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).
/// If the <see cref="CefSharpArguments::WcfEnabledArgument"/> command line argument is
/// present then the WcfEnabledSubProcess implementation is used.
/// </summary>
public ref class WcfBrowserSubprocessExecutable : BrowserSubprocessExecutable
{
public:
WcfBrowserSubprocessExecutable()
{
}
protected:
SubProcess^ GetSubprocess(IEnumerable<String^>^ args, int parentProcessId, IRenderProcessHandler^ handler) override
{
auto wcfEnabled = CommandLineArgsParser::HasArgument(args, CefSharpArguments::WcfEnabledArgument);
if (wcfEnabled)
{
return gcnew WcfEnabledSubProcess(parentProcessId, handler, args);
}
return gcnew SubProcess(handler, args);
}
};
}
}

View file

@ -0,0 +1,103 @@
// Copyright © 2016 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 "WcfEnabledSubProcess.h"
using namespace System::ServiceModel;
namespace CefSharp
{
namespace BrowserSubprocess
{
void WcfEnabledSubProcess::OnBrowserCreated(CefBrowserWrapper^ browser)
{
if (!_parentBrowserId.HasValue)
{
_parentBrowserId = browser->BrowserId;
}
if (!_parentBrowserId.HasValue)
{
return;
}
//TODO: This can likely be simplified as both values are likely equal
auto browserId = browser->IsPopup ? _parentBrowserId.Value : browser->BrowserId;
auto serviceName = RenderprocessClientFactory::GetServiceName(_parentProcessId, browserId);
auto binding = BrowserProcessServiceHost::CreateBinding();
auto channelFactory = gcnew ChannelFactory<IBrowserProcess^>(
binding,
gcnew EndpointAddress(serviceName)
);
channelFactory->Open();
auto browserProcess = channelFactory->CreateChannel();
auto clientChannel = ((IClientChannel^)browserProcess);
try
{
clientChannel->Open();
browser->ChannelFactory = channelFactory;
browser->BrowserProcess = browserProcess;
}
catch (Exception^)
{
}
}
void WcfEnabledSubProcess::OnBrowserDestroyed(CefBrowserWrapper^ browser)
{
auto channelFactory = browser->ChannelFactory;
//Add null check for issue https://github.com/cefsharp/CefSharp/issues/2839
if (channelFactory == nullptr)
{
LOG(ERROR) << "WcfEnabledSubProcess::OnBrowserDestroyed - browser->ChannelFactory was unexpectedly null, see https://github.com/cefsharp/CefSharp/issues/2839 for some debugging tips.";
}
else
{
try
{
if (channelFactory->State == CommunicationState::Opened)
{
channelFactory->Close();
}
}
catch (Exception^)
{
channelFactory->Abort();
}
}
//Add null check for issue https://github.com/cefsharp/CefSharp/issues/2839
if (browser->BrowserProcess != nullptr)
{
auto clientChannel = ((IClientChannel^)browser->BrowserProcess);
try
{
if (clientChannel->State == CommunicationState::Opened)
{
clientChannel->Close();
}
}
catch (Exception^)
{
clientChannel->Abort();
}
}
browser->ChannelFactory = nullptr;
browser->BrowserProcess = nullptr;
}
}
}

View file

@ -0,0 +1,38 @@
// Copyright © 2016 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"
#include "CefBrowserWrapper.h"
using namespace System;
using namespace CefSharp::RenderProcess;
namespace CefSharp
{
namespace BrowserSubprocess
{
public ref class WcfEnabledSubProcess : SubProcess
{
private:
Nullable<int> _parentBrowserId;
/// <summary>
/// The PID for the parent (browser) process
/// </summary>
int _parentProcessId;
public:
WcfEnabledSubProcess(int parentProcessId, IRenderProcessHandler^ handler, IEnumerable<String^>^ args) : SubProcess(handler,args)
{
_parentProcessId = parentProcessId;
}
void OnBrowserCreated(CefBrowserWrapper^ browser) override;
void OnBrowserDestroyed(CefBrowserWrapper^ browser) override;
};
}
}

View file

@ -0,0 +1,221 @@
// 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.
#include "Stdafx.h"
#include "Frame.h"
#include "Browser.h"
using namespace CefSharp::BrowserSubprocess;
///
// Returns the browser host object. This method can only be called in the
// browser process.
///
/*--cef()--*/
IBrowserHost^ Browser::GetHost()
{
throw gcnew NotImplementedException("Browser process only");
}
///
// Returns true if the browser can navigate backwards.
///
/*--cef()--*/
bool Browser::CanGoBack::get()
{
return _browser->CanGoBack();
}
///
// Navigate backwards.
///
/*--cef()--*/
void Browser::GoBack()
{
_browser->GoBack();
}
///
// Returns true if the browser can navigate forwards.
///
/*--cef()--*/
bool Browser::CanGoForward::get()
{
return _browser->CanGoForward();
}
///
// Navigate forwards.
///
/*--cef()--*/
void Browser::GoForward()
{
_browser->GoForward();
}
///
// Returns true if the browser is currently loading.
///
/*--cef()--*/
bool Browser::IsLoading::get()
{
return _browser->IsLoading();
}
void Browser::CloseBrowser(bool forceClose)
{
throw gcnew NotImplementedException("Browser process only");
}
///
// Reload the current page.
///
/*--cef()--*/
void Browser::Reload(bool ignoreCache)
{
if (ignoreCache)
{
_browser->ReloadIgnoreCache();
}
else
{
_browser->Reload();
}
}
///
// Stop loading the page.
///
/*--cef()--*/
void Browser::StopLoad()
{
_browser->StopLoad();
}
///
// Returns the globally unique identifier for this browser.
///
/*--cef()--*/
int Browser::Identifier::get()
{
return _browser->GetIdentifier();
}
///
// Returns true if this object is pointing to the same handle as |that|
// object.
///
/*--cef()--*/
bool Browser::IsSame(IBrowser^ that)
{
return _browser->IsSame(dynamic_cast<Browser^>(that)->_browser.get());
}
///
// Returns true if the window is a popup window.
///
/*--cef()--*/
bool Browser::IsPopup::get()
{
return _browser->IsPopup();
}
///
// Returns true if a document has been loaded in the browser.
///
/*--cef()--*/
bool Browser::HasDocument::get()
{
return _browser->HasDocument();
}
IFrame^ Browser::MainFrame::get()
{
auto frame = _browser->GetMainFrame();
return gcnew Frame(frame);
}
///
// Returns the focused frame for the browser window.
///
/*--cef()--*/
IFrame^ Browser::FocusedFrame::get()
{
return gcnew Frame(_browser->GetFocusedFrame());
}
///
// Returns the frame with the specified identifier, or NULL if not found.
///
/*--cef(capi_name=get_frame_byident)--*/
IFrame^ Browser::GetFrame(Int64 identifier)
{
auto frame = _browser->GetFrame(identifier);
if (frame.get())
{
return gcnew Frame(frame);
}
return nullptr;
}
///
// Returns the frame with the specified name, or NULL if not found.
///
/*--cef(optional_param=name)--*/
IFrame^ Browser::GetFrame(String^ name)
{
auto frame = _browser->GetFrame(StringUtils::ToNative(name));
if (frame.get())
{
return gcnew Frame(frame);
}
return nullptr;
}
///
// Returns the number of frames that currently exist.
///
/*--cef()--*/
int Browser::GetFrameCount()
{
return _browser->GetFrameCount();
}
///
// Returns the identifiers of all existing frames.
///
/*--cef(count_func=identifiers:GetFrameCount)--*/
List<Int64>^ Browser::GetFrameIdentifiers()
{
std::vector<Int64> identifiers;
_browser->GetFrameIdentifiers(identifiers);
List<Int64>^ results = gcnew List<Int64>(identifiers.size());
for (UINT i = 0; i < identifiers.size(); i++)
{
results->Add(identifiers[i]);
}
return results;
}
///
// Returns the names of all existing frames.
///
/*--cef()--*/
List<String^>^ Browser::GetFrameNames()
{
std::vector<CefString> names;
_browser->GetFrameNames(names);
return StringUtils::ToClr(names);
}
bool Browser::IsDisposed::get()
{
return _disposed;
}

View file

@ -0,0 +1,188 @@
// 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 <include/cef_browser.h>
namespace CefSharp
{
namespace BrowserSubprocess
{
private ref class Browser : public IBrowser
{
private:
MCefRefPtr<CefBrowser> _browser;
bool _disposed;
internal:
Browser(CefRefPtr<CefBrowser> &browser)
: _browser(browser)
{
}
!Browser()
{
// Release the reference.
_browser = nullptr;
}
~Browser()
{
this->!Browser();
_disposed = true;
}
public:
///
// Returns the browser host object. This method can only be called in the
// browser process.
///
/*--cef()--*/
virtual IBrowserHost^ GetHost();
///
// Returns true if the browser can navigate backwards.
///
/*--cef()--*/
virtual property bool CanGoBack
{
bool get();
}
///
// Navigate backwards.
///
/*--cef()--*/
virtual void GoBack();
///
// Returns true if the browser can navigate forwards.
///
/*--cef()--*/
virtual property bool CanGoForward
{
bool get();
}
///
// Navigate forwards.
///
/*--cef()--*/
virtual void GoForward();
///
// Returns true if the browser is currently loading.
///
/*--cef()--*/
virtual property bool IsLoading
{
bool get();
}
virtual void CloseBrowser(bool forceClose);
///
// Reload the current page.
///
/*--cef()--*/
virtual void Reload(bool ignoreCache);
///
// Stop loading the page.
///
/*--cef()--*/
virtual void StopLoad();
///
// Returns the globally unique identifier for this browser.
///
/*--cef()--*/
virtual property int Identifier
{
int get();
}
///
// Returns true if this object is pointing to the same handle as |that|
// object.
///
/*--cef()--*/
virtual bool IsSame(IBrowser^ that);
///
// Returns true if the window is a popup window.
///
/*--cef()--*/
virtual property bool IsPopup
{
bool get();
}
///
// Returns true if a document has been loaded in the browser.
///
/*--cef()--*/
virtual property bool HasDocument
{
bool get();
}
///
// Returns the main (top-level) frame for the browser window.
///
/*--cef()--*/
virtual property IFrame^ MainFrame
{
IFrame^ get();
}
///
// Returns the focused frame for the browser window.
///
/*--cef()--*/
virtual property IFrame^ FocusedFrame
{
IFrame^ get();
}
///
// Returns the frame with the specified identifier, or NULL if not found.
///
/*--cef(capi_name=get_frame_byident)--*/
virtual IFrame^ GetFrame(Int64 identifier);
///
// Returns the frame with the specified name, or NULL if not found.
///
/*--cef(optional_param=name)--*/
virtual IFrame^ GetFrame(String^ name);
///
// Returns the number of frames that currently exist.
///
/*--cef()--*/
virtual int GetFrameCount();
///
// Returns the identifiers of all existing frames.
///
/*--cef(count_func=identifiers:GetFrameCount)--*/
virtual List<Int64>^ GetFrameIdentifiers();
///
// Returns the names of all existing frames.
///
/*--cef()--*/
virtual List<String^>^ GetFrameNames();
virtual property bool IsDisposed
{
bool get();
}
};
}
}

View file

@ -0,0 +1,290 @@
// 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.
#include "Stdafx.h"
#include <msclr/lock.h>
#include "Frame.h"
#include "Browser.h"
using namespace CefSharp::BrowserSubprocess;
///
// True if this object is currently attached to a valid frame.
///
/*--cef()--*/
bool Frame::IsValid::get()
{
return _frame->IsValid();
}
///
// Execute undo in this frame.
///
/*--cef()--*/
void Frame::Undo()
{
_frame->Undo();
}
///
// Execute redo in this frame.
///
/*--cef()--*/
void Frame::Redo()
{
_frame->Redo();
}
///
// Execute cut in this frame.
///
/*--cef()--*/
void Frame::Cut()
{
_frame->Cut();
}
///
// Execute copy in this frame.
///
/*--cef()--*/
void Frame::Copy()
{
_frame->Copy();
}
///
// Execute paste in this frame.
///
/*--cef()--*/
void Frame::Paste()
{
_frame->Paste();
}
///
// Execute delete in this frame.
///
/*--cef(capi_name=del)--*/
void Frame::Delete()
{
_frame->Delete();
}
///
// Execute select all in this frame.
///
/*--cef()--*/
void Frame::SelectAll()
{
_frame->SelectAll();
}
///
// Save this frame's HTML source to a temporary file and open it in the
// default text viewing application. This method can only be called from the
// browser process.
///
/*--cef()--*/
void Frame::ViewSource()
{
throw gcnew NotImplementedException("Browser process only");
}
///
// Retrieve this frame's HTML source as a string sent to the specified
// visitor.
///
/*--cef()--*/
Task<String^>^ Frame::GetSourceAsync()
{
throw gcnew NotImplementedException();
}
///
// Retrieve this frame's HTML source as a string sent to the specified
// visitor.
///
/*--cef()--*/
void Frame::GetSource(IStringVisitor^ visitor)
{
throw gcnew NotImplementedException();
}
///
// Retrieve this frame's display text as a string sent to the specified
// visitor.
///
/*--cef()--*/
Task<String^>^ Frame::GetTextAsync()
{
throw gcnew NotImplementedException();
}
///
// Retrieve this frame's display text as a string sent to the specified
// visitor.
///
/*--cef()--*/
void Frame::GetText(IStringVisitor^ visitor)
{
throw gcnew NotImplementedException();
}
///
// Load the request represented by the |request| object.
///
/*--cef()--*/
void Frame::LoadRequest(IRequest^ request)
{
throw gcnew NotImplementedException();
}
///
// Load the specified |url|.
///
/*--cef()--*/
void Frame::LoadUrl(String^ url)
{
_frame->LoadURL(StringUtils::ToNative(url));
}
///
// Execute a string of JavaScript code in this frame. The |script_url|
// parameter is the URL where the script in question can be found, if any.
// The renderer may request this URL to show the developer the source of the
// error. The |start_line| parameter is the base line number to use for error
// reporting.
///
/*--cef(optional_param=script_url)--*/
void Frame::ExecuteJavaScriptAsync(String^ code, String^ scriptUrl, int startLine)
{
_frame->ExecuteJavaScript(StringUtils::ToNative(code), StringUtils::ToNative(scriptUrl), startLine);
}
Task<JavascriptResponse^>^ Frame::EvaluateScriptAsync(String^ script, String^ scriptUrl, int startLine, Nullable<TimeSpan> timeout, bool useImmediatelyInvokedFuncExpression)
{
throw gcnew NotImplementedException();
}
///
// Returns true if this is the main (top-level) frame.
///
/*--cef()--*/
bool Frame::IsMain::get()
{
return _frame->IsMain();
}
///
// Returns true if this is the focused frame.
///
/*--cef()--*/
bool Frame::IsFocused::get()
{
return _frame->IsFocused();
}
///
// Returns the name for this frame. If the frame has an assigned name (for
// example, set via the iframe "name" attribute) then that value will be
// returned. Otherwise a unique name will be constructed based on the frame
// parent hierarchy. The main (top-level) frame will always have an empty name
// value.
///
/*--cef()--*/
String^ Frame::Name::get()
{
return StringUtils::ToClr(_frame->GetName());
}
///
// Returns the globally unique identifier for this frame.
///
/*--cef()--*/
Int64 Frame::Identifier::get()
{
return _frame->GetIdentifier();
}
///
// Returns the parent of this frame or NULL if this is the main (top-level)
// frame.
///
/*--cef()--*/
IFrame^ Frame::Parent::get()
{
if (_parentFrame != nullptr)
{
return _parentFrame;
}
// Be paranoid about creating the cached IFrame.
msclr::lock sync(_syncRoot);
if (_parentFrame != nullptr)
{
return _parentFrame;
}
auto parent = _frame->GetParent();
if (parent == nullptr)
{
return nullptr;
}
_parentFrame = gcnew Frame(parent);
return _parentFrame;
}
///
// Returns the URL currently loaded in this frame.
///
/*--cef()--*/
String^ Frame::Url::get()
{
return StringUtils::ToClr(_frame->GetURL());
}
///
// Returns the browser that this frame belongs to.
///
/*--cef()--*/
IBrowser^ Frame::Browser::get()
{
if (_owningBrowser != nullptr)
{
return _owningBrowser;
}
// Be paranoid about creating the cached IBrowser.
msclr::lock sync(_syncRoot);
if (_owningBrowser != nullptr)
{
return _owningBrowser;
}
_owningBrowser = gcnew CefSharp::BrowserSubprocess::Browser(_frame->GetBrowser());
return _owningBrowser;
}
IRequest^ Frame::CreateRequest(bool initializePostData)
{
throw gcnew NotImplementedException();
}
IUrlRequest^ Frame::CreateUrlRequest(IRequest^ request, IUrlRequestClient^ client)
{
throw gcnew NotImplementedException();
}
bool Frame::IsDisposed::get()
{
return _disposed;
}

View file

@ -0,0 +1,247 @@
// 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 "include\cef_frame.h"
using namespace System::Threading::Tasks;
namespace CefSharp
{
namespace BrowserSubprocess
{
///
// Class used to represent a frame in the browser window. When used in the
// browser process the methods of this class may be called on any thread unless
// otherwise indicated in the comments. When used in the render process the
// methods of this class may only be called on the main thread.
///
/*--cef(source=library)--*/
private ref class Frame : public IFrame
{
private:
MCefRefPtr<CefFrame> _frame;
IFrame^ _parentFrame;
IBrowser^ _owningBrowser;
Object^ _syncRoot;
bool _disposed;
internal:
Frame(CefRefPtr<CefFrame> &frame)
: _frame(frame), _parentFrame(nullptr),
_owningBrowser(nullptr), _syncRoot(gcnew Object())
{
}
!Frame()
{
_frame = NULL;
}
~Frame()
{
this->!Frame();
delete _parentFrame;
delete _owningBrowser;
_parentFrame = nullptr;
_owningBrowser = nullptr;
_syncRoot = nullptr;
_disposed = true;
}
public:
///
// True if this object is currently attached to a valid frame.
///
/*--cef()--*/
virtual property bool IsValid
{
bool get();
}
///
// Execute undo in this frame.
///
/*--cef()--*/
virtual void Undo();
///
// Execute redo in this frame.
///
/*--cef()--*/
virtual void Redo();
///
// Execute cut in this frame.
///
/*--cef()--*/
virtual void Cut();
///
// Execute copy in this frame.
///
/*--cef()--*/
virtual void Copy();
///
// Execute paste in this frame.
///
/*--cef()--*/
virtual void Paste();
///
// Execute delete in this frame.
///
/*--cef(capi_name=del)--*/
virtual void Delete();
///
// Execute select all in this frame.
///
/*--cef()--*/
virtual void SelectAll();
///
// Save this frame's HTML source to a temporary file and open it in the
// default text viewing application. This method can only be called from the
// browser process.
///
/*--cef()--*/
virtual void ViewSource();
///
// Retrieve this frame's HTML source as a string sent to the specified
// visitor.
///
/*--cef()--*/
virtual Task<String^>^ GetSourceAsync();
///
// Retrieve this frame's HTML source as a string sent to the specified
// visitor.
///
/*--cef()--*/
virtual void GetSource(IStringVisitor^ visitor);
///
// Retrieve this frame's display text as a string sent to the specified
// visitor.
///
/*--cef()--*/
virtual Task<String^>^ GetTextAsync();
///
// Retrieve this frame's display text as a string sent to the specified
// visitor.
///
/*--cef()--*/
virtual void GetText(IStringVisitor^ visitor);
///
/// Load the request represented by the |request| object.
///
/*--cef()--*/
virtual void LoadRequest(IRequest^ request);
///
// Load the specified |url|.
///
/*--cef()--*/
virtual void LoadUrl(String^ url);
///
// Execute a string of JavaScript code in this frame. The |script_url|
// parameter is the URL where the script in question can be found, if any.
// The renderer may request this URL to show the developer the source of the
// error. The |start_line| parameter is the base line number to use for error
// reporting.
///
/*--cef(optional_param=script_url)--*/
virtual void ExecuteJavaScriptAsync(String^ code, String^ scriptUrl, int startLine);
virtual Task<JavascriptResponse^>^ EvaluateScriptAsync(String^ script, String^ scriptUrl, int startLine, Nullable<TimeSpan> timeout, bool useImmediatelyInvokedFuncExpression);
///
// Returns true if this is the main (top-level) frame.
///
/*--cef()--*/
virtual property bool IsMain
{
bool get();
}
///
// Returns true if this is the focused frame.
///
/*--cef()--*/
virtual property bool IsFocused
{
bool get();
}
///
// Returns the name for this frame. If the frame has an assigned name (for
// example, set via the iframe "name" attribute) then that value will be
// returned. Otherwise a unique name will be constructed based on the frame
// parent hierarchy. The main (top-level) frame will always have an empty name
// value.
///
/*--cef()--*/
virtual property String^ Name
{
String^ get();
}
///
// Returns the globally unique identifier for this frame.
///
/*--cef()--*/
virtual property Int64 Identifier
{
Int64 get();
}
///
// Returns the parent of this frame or NULL if this is the main (top-level)
// frame.
///
/*--cef()--*/
virtual property IFrame^ Parent
{
IFrame^ get();
}
///
// Returns the URL currently loaded in this frame.
///
/*--cef()--*/
virtual property String^ Url
{
String^ get();
}
///
// Returns the browser that this frame belongs to.
///
/*--cef()--*/
virtual property IBrowser^ Browser
{
IBrowser^ get();
}
virtual IRequest^ CreateRequest(bool initializePostData);
virtual IUrlRequest^ CreateUrlRequest(IRequest^ request, IUrlRequestClient^ client);
virtual property bool IsDisposed
{
bool get();
}
};
}
}

View file

@ -0,0 +1,66 @@
// 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 "include\cef_v8.h"
using namespace System::Runtime::InteropServices;
using namespace CefSharp::RenderProcess;
namespace CefSharp
{
namespace BrowserSubprocess
{
private ref class V8Context : public IV8Context
{
private:
MCefRefPtr<CefV8Context> _context;
public:
V8Context(CefRefPtr<CefV8Context> &context)
: _context(context)
{
}
!V8Context()
{
_context = NULL;
}
~V8Context()
{
this->!V8Context();
}
virtual bool Execute(String^ code, String^ scriptUrl, int startLine, [Out] V8Exception^ %exception)
{
exception = nullptr;
CefRefPtr<CefV8Value> result;
CefRefPtr<CefV8Exception> ex;
if (_context->Eval(StringUtils::ToNative(code), StringUtils::ToNative(scriptUrl), startLine, result, ex))
{
return true;
}
exception = gcnew V8Exception(ex->GetEndColumn(),
ex->GetEndPosition(),
ex->GetLineNumber(),
StringUtils::ToClr(ex->GetMessage()),
StringUtils::ToClr(ex->GetScriptResourceName()),
StringUtils::ToClr(ex->GetSourceLine()),
ex->GetStartColumn(),
ex->GetStartPosition());
return false;
}
};
}
}

View file

@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Resource.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

Some files were not shown because too many files have changed in this diff Show more