Updated cefsharp and removed flash.
But there is now a bug where the browser crashed when trying to download anything.
This commit is contained in:
Diamond Creeper 2023-05-18 17:03:55 +12:00
parent d685e803b3
commit 81286909c6
776 changed files with 255315 additions and 42 deletions

274
UpgradeLog3.htm Normal file
View file

@ -0,0 +1,274 @@
<!DOCTYPE html>
<!-- saved from url=(0014)about:internet -->
<html xmlns:msxsl="urn:schemas-microsoft-com:xslt"><head><meta content="en-us" http-equiv="Content-Language" /><meta content="text/html; charset=utf-16" http-equiv="Content-Type" /><title _locID="ConversionReport0">
Migration Report
</title><style>
/* Body style, for the entire document */
body
{
background: #F3F3F4;
color: #1E1E1F;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
padding: 0;
margin: 0;
}
/* Header1 style, used for the main title */
h1
{
padding: 10px 0px 10px 10px;
font-size: 21pt;
background-color: #E2E2E2;
border-bottom: 1px #C1C1C2 solid;
color: #201F20;
margin: 0;
font-weight: normal;
}
/* Header2 style, used for "Overview" and other sections */
h2
{
font-size: 18pt;
font-weight: normal;
padding: 15px 0 5px 0;
margin: 0;
}
/* Header3 style, used for sub-sections, such as project name */
h3
{
font-weight: normal;
font-size: 15pt;
margin: 0;
padding: 15px 0 5px 0;
background-color: transparent;
}
/* Color all hyperlinks one color */
a
{
color: #1382CE;
}
/* Table styles */
table
{
border-spacing: 0 0;
border-collapse: collapse;
font-size: 10pt;
}
table th
{
background: #E7E7E8;
text-align: left;
text-decoration: none;
font-weight: normal;
padding: 3px 6px 3px 6px;
}
table td
{
vertical-align: top;
padding: 3px 6px 5px 5px;
margin: 0px;
border: 1px solid #E7E7E8;
background: #F7F7F8;
}
/* Local link is a style for hyperlinks that link to file:/// content, there are lots so color them as 'normal' text until the user mouse overs */
.localLink
{
color: #1E1E1F;
background: #EEEEED;
text-decoration: none;
}
.localLink:hover
{
color: #1382CE;
background: #FFFF99;
text-decoration: none;
}
/* Center text, used in the over views cells that contain message level counts */
.textCentered
{
text-align: center;
}
/* The message cells in message tables should take up all avaliable space */
.messageCell
{
width: 100%;
}
/* Padding around the content after the h1 */
#content
{
padding: 0px 12px 12px 12px;
}
/* The overview table expands to width, with a max width of 97% */
#overview table
{
width: auto;
max-width: 75%;
}
/* The messages tables are always 97% width */
#messages table
{
width: 97%;
}
/* All Icons */
.IconSuccessEncoded, .IconInfoEncoded, .IconWarningEncoded, .IconErrorEncoded
{
min-width:18px;
min-height:18px;
background-repeat:no-repeat;
background-position:center;
}
/* Success icon encoded */
.IconSuccessEncoded
{
/* Note: Do not delete the comment below. It is used to verify the correctness of the encoded image resource below before the product is released */
/* [---XsltValidateInternal-Base64EncodedImage:IconSuccess#Begin#background-image: url(data:image/png;base64,#Separator#);#End#] */
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABcElEQVR4Xq2TsUsCURzHv15g8ZJcBWlyiYYgCIWcb9DFRRwMW5TA2c0/QEFwFkxxUQdxVlBwCYWOi6IhWgQhBLHJUCkhLr/BW8S7gvrAg+N+v8/v+x68Z8MGy+XSCyABQAXgBgHGALoASkIIDWSLeLBetdHryMjd5IxQPWT4rn1c/P7+xxp72Cs9m5SZ0Bq2vPnbPFafK2zDvmNHypdC0BPkLlQhxJsCAhQoZwdZU5mwxh720qGo8MzTxTTKZDPCx2HoVzp6lz0Q9tKhyx0kGs8Ny+TkWRKk8lCROwEduhyg9l/6lunOPSfmH3NUH6uQ0KHLAe7JYvJjevm+DAMGJHToKtigE+vwvIidxLamb8IBY9e+C5LiXREkfho3TSd06HJA13/oh6T51MTsfQbHrsMynQ5dDihFjiK8JJAU9AKIWTp76dCVN7HWHrajmUEGvyF9nkbAE6gLIS7kTUyuf2gscLoJrElZo/Mvj+nPz/kLTmfnEwP3tB0AAAAASUVORK5CYII=);
}
/* Information icon encoded */
.IconInfoEncoded
{
/* Note: Do not delete the comment below. It is used to verify the correctness of the encoded image resource below before the product is released */
/* [---XsltValidateInternal-Base64EncodedImage:IconInformation#Begin#background-image: url(data:image/png;base64,#Separator#);#End#] */
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABHElEQVR4Xs2TsUoDQRRF7wwoziokjZUKadInhdhukR9YP8DMX1hYW+QvdsXa/QHBbcXC7W0CamWTQnclFutceIQJwwaWNLlwm5k5d94M76mmaeCrrmsLYOocY12FcxZFUeozCqKqqgYA8uevv1H6VuPxcwlfk5N92KHBxfFeCSAxxswlYAW/Xr989x/mv9gkhtyMDhcAxgzRsp7flj8B/HF1RsMXq+NZMkopaHe7lbKxQUEIGbKsYNoGn969060hZBkQex/W8oRQwsQaW2o3Ago2SVcJUzAgY3N0lTCZZm+zPS8HB51gMmS1DEYyOz9acKO1D8JWTlafKIMxdhvlfdyT94Vv5h7P8Ky7nQzACmhvKq3zk3PjW9asz9D/1oigecsioooAAAAASUVORK5CYII=);
}
/* Warning icon encoded */
.IconWarningEncoded
{
/* Note: Do not delete the comment below. It is used to verify the correctness of the encoded image resource below before the product is released */
/* [---XsltValidateInternal-Base64EncodedImage:IconWarning#Begin#background-image: url(data:image/png;base64,#Separator#);#End#] */
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAx0lEQVR4XpWSMQ7CMAxFf4xAyBMLCxMrO8dhaBcuwdCJS3RJBw7SA/QGTCxdWJgiQYWKXJWKIXHIlyw5lqr34tQgEOdcBsCOx5yZK3hCCKdYXneQkh4pEfqzLfu+wVDSyyzFoJjfz9NB+pAF+eizx2Vruts0k15mPgvS6GYvpVtQhB61IB/dk6AF6fS4Ben0uIX5odtFe8Q/eW1KvFeH4e8khT6+gm5B+t3juyDt7n0jpe+CANTd+oTUjN/U3yVaABnSUjFz/gFq44JaVSCXeQAAAABJRU5ErkJggg==);
}
/* Error icon encoded */
.IconErrorEncoded
{
/* Note: Do not delete the comment below. It is used to verify the correctness of the encoded image resource below before the product is released */
/* [---XsltValidateInternal-Base64EncodedImage:IconError#Begin#background-image: url(data:image/png;base64,#Separator#);#End#] */
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABQElEQVR4XqWTvUoEQRCE6wYPZUA80AfwAQz23uCMjA7MDRQEIzPBVEyNTQUFIw00vcQTTMzuAh/AxEQQT8HF/3G/oGGnEUGuoNnd6qoZuqltyKEsyzVJq5I6rnUp6SjGeGhESikzzlc1eL7opfuVbrqbU1Zw9NCgtQMaZpY0eNnaaL2fHusvTK5vKu7sjSS1Y4y3QUA6K3e3Mau5UFDyMP7tYF9o8cAHZv68vipoIJg971PZIZ5HiwdvYGGvFVFHmGmZ2MxwmQYPXubPl9Up0tfoMQGetXd6mRbvhBw+boZ6WF7Mbv1+GsHRk0fQmPAH1GfmZirbCfDJ61tw3Px8/8pZsPAG4jlVhcPgZ7adwNWBB68lkRQWFiTgFlbnLY3DGGM7izIJIyT/jjIvEJw6fdJTc6krDzh6aMwMP9bvDH4ADSsa9uSWVJkAAAAASUVORK5CYII=);
}
</style><script type="text/javascript" language="javascript">
// Startup
// Hook up the the loaded event for the document/window, to linkify the document content
var startupFunction = function() { linkifyElement("messages"); };
if(window.attachEvent)
{
window.attachEvent('onload', startupFunction);
}
else if (window.addEventListener)
{
window.addEventListener('load', startupFunction, false);
}
else
{
document.addEventListener('load', startupFunction, false);
}
// Toggles the visibility of table rows with the specified name
function toggleTableRowsByName(name)
{
var allRows = document.getElementsByTagName('tr');
for (i=0; i < allRows.length; i++)
{
var currentName = allRows[i].getAttribute('name');
if(!!currentName && currentName.indexOf(name) == 0)
{
var isVisible = allRows[i].style.display == '';
isVisible ? allRows[i].style.display = 'none' : allRows[i].style.display = '';
}
}
}
function scrollToFirstVisibleRow(name)
{
var allRows = document.getElementsByTagName('tr');
for (i=0; i < allRows.length; i++)
{
var currentName = allRows[i].getAttribute('name');
var isVisible = allRows[i].style.display == '';
if(!!currentName && currentName.indexOf(name) == 0 && isVisible)
{
allRows[i].scrollIntoView(true);
return true;
}
}
return false;
}
// Linkifies the specified text content, replaces candidate links with html links
function linkify(text)
{
if(!text || 0 === text.length)
{
return text;
}
// Find http, https and ftp links and replace them with hyper links
var urlLink = /(http|https|ftp)\:\/\/[a-zA-Z0-9\-\.]+(:[a-zA-Z0-9]*)?\/?([a-zA-Z0-9\-\._\?\,\/\\\+&%\$#\=~;\{\}])*/gi;
return text.replace(urlLink, '<a href="$&">$&</a>') ;
}
// Linkifies the specified element by ID
function linkifyElement(id)
{
var element = document.getElementById(id);
if(!!element)
{
element.innerHTML = linkify(element.innerHTML);
}
}
function ToggleMessageVisibility(projectName)
{
if(!projectName || 0 === projectName.length)
{
return;
}
toggleTableRowsByName("MessageRowClass" + projectName);
toggleTableRowsByName('MessageRowHeaderShow' + projectName);
toggleTableRowsByName('MessageRowHeaderHide' + projectName);
}
function ScrollToFirstVisibleMessage(projectName)
{
if(!projectName || 0 === projectName.length)
{
return;
}
// First try the 'Show messages' row
if(!scrollToFirstVisibleRow('MessageRowHeaderShow' + projectName))
{
// Failed to find a visible row for 'Show messages', try an actual message row
scrollToFirstVisibleRow('MessageRowClass' + projectName);
}
}
</script></head><body><h1 _locID="ConversionReport">
Migration Report - </h1><div id="content"><h2 _locID="OverviewTitle">Overview</h2><div id="overview"><table><tr><th></th><th _locID="ProjectTableHeader">Project</th><th _locID="PathTableHeader">Path</th><th _locID="ErrorsTableHeader">Errors</th><th _locID="WarningsTableHeader">Warnings</th><th _locID="MessagesTableHeader">Messages</th></tr><tr><td class="IconErrorEncoded" /><td><strong><a href="#Xero Browser Setup">Xero Browser Setup</a></strong></td><td>Xero Browser Setup\Xero Browser Setup.vdproj</td><td class="textCentered"><a href="#Xero Browser SetupError">1</a></td><td class="textCentered"><a>0</a></td><td class="textCentered"><a href="#">0</a></td></tr><tr><td class="IconSuccessEncoded" /><td><strong><a href="#Solution Items">Solution Items</a></strong></td><td>Solution Items</td><td class="textCentered"><a>0</a></td><td class="textCentered"><a>0</a></td><td class="textCentered"><a href="#">0</a></td></tr><tr><td class="IconSuccessEncoded" /><td><strong><a href="#Solution"><span _locID="OverviewSolutionSpan">Solution</span></a></strong></td><td>XeroBrowser.sln</td><td class="textCentered"><a>0</a></td><td class="textCentered"><a>0</a></td><td class="textCentered"><a href="#" onclick="ScrollToFirstVisibleMessage('Solution'); return false;">1</a></td></tr></table></div><h2 _locID="SolutionAndProjectsTitle">Solution and projects</h2><div id="messages"><a name="Xero Browser Setup" /><h3>Xero Browser Setup</h3><table><tr id="Xero Browser SetupHeaderRow"><th></th><th class="messageCell" _locID="MessageTableHeader">Message</th></tr><tr name="ErrorRowClassXero Browser Setup"><td class="IconErrorEncoded"><a name="Xero Browser SetupError" /></td><td class="messageCell"><strong>Xero Browser Setup\Xero Browser Setup.vdproj:
</strong><span>The application which this project type is based on was not found. Please try this link for further information: 54435603-dbb4-11d2-8724-00a0c9a8b90c</span></td></tr></table><a name="Solution Items" /><h3>Solution Items</h3><table><tr id="Solution ItemsHeaderRow"><th></th><th class="messageCell" _locID="MessageTableHeader">Message</th></tr><tr><td class="IconInfoEncoded" /><td class="messageCell" _locID="NoMessagesRow">Solution Items logged no messages.
</td></tr></table><a name="Solution" /><h3 _locID="ProjectDisplayNameHeader">Solution</h3><table><tr id="SolutionHeaderRow"><th></th><th class="messageCell" _locID="MessageTableHeader">Message</th></tr><tr name="MessageRowHeaderShowSolution"><td class="IconInfoEncoded" /><td class="messageCell"><a _locID="ShowAdditionalMessages" href="#" name="SolutionMessage" onclick="ToggleMessageVisibility('Solution'); return false;">
Show 1 additional messages
</a></td></tr><tr name="MessageRowClassSolution" style="display: none"><td class="IconInfoEncoded"><a name="SolutionMessage" /></td><td class="messageCell"><strong>XeroBrowser.sln:
</strong><span>The solution file does not require migration.</span></td></tr><tr style="display: none" name="MessageRowHeaderHideSolution"><td class="IconInfoEncoded" /><td class="messageCell"><a _locID="HideAdditionalMessages" href="#" name="SolutionMessage" onclick="ToggleMessageVisibility('Solution'); return false;">
Hide 1 additional messages
</a></td></tr></table></div></div></body></html>

View file

@ -1,29 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Bunifu.UI.WinForms.BunifuScrollBar" publicKeyToken="e8e24ccd28363fe9" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.3.0.0" newVersion="5.3.0.0"/>
<assemblyIdentity name="Bunifu.UI.WinForms.BunifuScrollBar" publicKeyToken="e8e24ccd28363fe9" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.3.0.0" newVersion="5.3.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Bunifu.UI.WinForms.BunifuFormDock" publicKeyToken="e8e24ccd28363fe9" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.3.0.0" newVersion="5.3.0.0"/>
<assemblyIdentity name="Bunifu.UI.WinForms.BunifuFormDock" publicKeyToken="e8e24ccd28363fe9" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.3.0.0" newVersion="5.3.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Svg" publicKeyToken="12a0bac221edeae2" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.4.0.0" newVersion="3.4.0.0"/>
<assemblyIdentity name="Svg" publicKeyToken="12a0bac221edeae2" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.4.0.0" newVersion="3.4.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Fizzler" publicKeyToken="4ebff4844e382110" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0"/>
<assemblyIdentity name="Fizzler" publicKeyToken="4ebff4844e382110" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="ExCSS" publicKeyToken="bdbe16be9b936b9a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

View file

@ -88,5 +88,10 @@ namespace XeroBrowser
}
catch (InvalidOperationException){}
}
public bool CanDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, string url, string requestMethod)
{
throw new NotImplementedException();
}
}
}

View file

@ -22,16 +22,9 @@ namespace XeroBrowser
Application.SetCompatibleTextRenderingDefault(false);
Container = new AppContainer();
CefSettings settings = new CefSettings();
if (settings.CefCommandLineArgs.ContainsKey("enable-system-flash"))
settings.CefCommandLineArgs.Remove("enable-system-flash");
settings.CefCommandLineArgs.Add("enable-system-flash", "1");
settings.CefCommandLineArgs.Add("ppapi-flash-path", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "pepflashplayer64_32_0_0_465.dll"));
settings.CefCommandLineArgs.Add("ppapi-flash-version", "32.0.0.465");
settings.CefCommandLineArgs["plugin-policy"] = "allow";
settings.UserAgent = "cpprestsdk/2.9.0 Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 XeroBrowser/1.0.0";
settings.CefCommandLineArgs.Add("enable-media-stream", "1");
Cef.EnableHighDPISupport();
settings.CachePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\CEF";
Cef.Initialize(settings);

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\CefSharp.Common.87.1.132\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.87.1.132\build\CefSharp.Common.props')" />
<Import Project="..\packages\cef.redist.x86.87.1.13\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.87.1.13\build\cef.redist.x86.props')" />
<Import Project="..\packages\cef.redist.x64.87.1.13\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.87.1.13\build\cef.redist.x64.props')" />
<Import Project="..\packages\CefSharp.Common.113.1.40\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.113.1.40\build\CefSharp.Common.props')" />
<Import Project="..\packages\cef.redist.x86.113.1.4\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.113.1.4\build\cef.redist.x86.props')" />
<Import Project="..\packages\cef.redist.x64.113.1.4\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.113.1.4\build\cef.redist.x64.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<NoWarn>0128</NoWarn>
@ -183,18 +183,21 @@
<Reference Include="Bunifu.Utils, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Bunifu.Utils.1.0.6\lib\net\Bunifu.Utils.dll</HintPath>
</Reference>
<Reference Include="CefSharp, Version=87.1.132.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.87.1.132\lib\net452\CefSharp.dll</HintPath>
<Reference Include="CefSharp, Version=113.1.40.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.113.1.40\lib\net452\CefSharp.dll</HintPath>
</Reference>
<Reference Include="CefSharp.Core, Version=87.1.132.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.87.1.132\lib\net452\CefSharp.Core.dll</HintPath>
<Reference Include="CefSharp.Core, Version=113.1.40.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.Common.113.1.40\lib\net452\CefSharp.Core.dll</HintPath>
</Reference>
<Reference Include="CefSharp.WinForms, Version=87.1.132.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.WinForms.87.1.132\lib\net452\CefSharp.WinForms.dll</HintPath>
<Reference Include="CefSharp.WinForms, Version=113.1.40.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
<HintPath>..\packages\CefSharp.WinForms.113.1.40\lib\net462\CefSharp.WinForms.dll</HintPath>
</Reference>
<Reference Include="EasyTabs, Version=2.0.0.39, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\EasyTabs.2.0.0\lib\net40\EasyTabs.dll</HintPath>
</Reference>
<Reference Include="ExCSS, Version=4.2.0.0, Culture=neutral, PublicKeyToken=bdbe16be9b936b9a, processorArchitecture=MSIL">
<HintPath>..\packages\ExCSS.4.2.0\lib\net48\ExCSS.dll</HintPath>
</Reference>
<Reference Include="Fizzler, Version=1.3.0.0, Culture=neutral, PublicKeyToken=4ebff4844e382110, processorArchitecture=MSIL">
<HintPath>..\packages\Fizzler.1.3.0\lib\netstandard2.0\Fizzler.dll</HintPath>
</Reference>
@ -205,7 +208,7 @@
<HintPath>..\packages\EasyTabs.2.0.0\lib\net40\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
</Reference>
<Reference Include="Svg, Version=3.4.0.0, Culture=neutral, PublicKeyToken=12a0bac221edeae2, processorArchitecture=MSIL">
<HintPath>..\packages\Svg.3.4.1\lib\net461\Svg.dll</HintPath>
<HintPath>..\packages\Svg.3.4.4\lib\net462\Svg.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
@ -213,8 +216,8 @@
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
@ -367,10 +370,10 @@
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\cef.redist.x64.87.1.13\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.87.1.13\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('..\packages\cef.redist.x86.87.1.13\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.87.1.13\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.87.1.132\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.87.1.132\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.87.1.132\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.87.1.132\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('..\packages\cef.redist.x64.113.1.4\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.113.1.4\build\cef.redist.x64.props'))" />
<Error Condition="!Exists('..\packages\cef.redist.x86.113.1.4\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.113.1.4\build\cef.redist.x86.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.113.1.40\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.113.1.40\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('..\packages\CefSharp.Common.113.1.40\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.113.1.40\build\CefSharp.Common.targets'))" />
</Target>
<Import Project="..\packages\CefSharp.Common.87.1.132\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.87.1.132\build\CefSharp.Common.targets')" />
<Import Project="..\packages\CefSharp.Common.113.1.40\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.113.1.40\build\CefSharp.Common.targets')" />
</Project>

View file

@ -2,15 +2,16 @@
<packages>
<package id="Bunifu.UI.WinForms" version="5.3.0" targetFramework="net48" />
<package id="Bunifu.Utils" version="1.0.6" targetFramework="net48" />
<package id="cef.redist.x64" version="87.1.13" targetFramework="net48" />
<package id="cef.redist.x86" version="87.1.13" targetFramework="net48" />
<package id="CefSharp.Common" version="87.1.132" targetFramework="net48" />
<package id="CefSharp.WinForms" version="87.1.132" targetFramework="net48" />
<package id="cef.redist.x64" version="113.1.4" targetFramework="net48" />
<package id="cef.redist.x86" version="113.1.4" targetFramework="net48" />
<package id="CefSharp.Common" version="113.1.40" targetFramework="net48" />
<package id="CefSharp.WinForms" version="113.1.40" targetFramework="net48" />
<package id="EasyTabs" version="2.0.0" targetFramework="net48" />
<package id="ExCSS" version="4.2.0" targetFramework="net48" />
<package id="Fizzler" version="1.3.0" targetFramework="net48" />
<package id="Svg" version="3.4.1" targetFramework="net48" />
<package id="Svg" version="3.4.4" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
<package id="System.Memory" version="4.5.5" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
<package id="Win32Interop.Dwmapi" version="1.0.1" targetFramework="net48" />

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="113.1.40.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="113.1.40.0" href="x86/CefSharp.Core.Runtime.dll" xdt:Transform="Replace"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Must be kept in sync with the entries in the .targets files (copy tasks) -->
<ItemGroup>
<CefSharpCommonBinaries32 Include="$(MSBuildThisFileDirectory)..\CefSharp\x86\*.*" />
<CefSharpCommonBinaries64 Include="$(MSBuildThisFileDirectory)..\CefSharp\x64\*.*" />
<CefSharpCommonBinariesAnyCPU Include="$(MSBuildThisFileDirectory)..\CefSharp\**\*.*" />
<CefSharpCommonManagedDlls Include="$(MSBuildThisFileDirectory)..\lib\net452\**\*.*" />
<!-- Just CefSharp.dlll -->
<CefSharpCommonManagedDll Include="$(MSBuildThisFileDirectory)..\lib\net452\CefSharp.dll" />
<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,444 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" TreatAsLocalProperty="CefSharpTransformXmlDllPath">
<!--
MSBuild is finding CefSharp.Core.Runtime.dll from the x86/x64 folders and copying it to the bin folder which is a problem
for targeting AnyCPU and when CefSharpTargetDir is used to move the files into a sub folder.
We manually remove CefSharp.Core.Runtime.dll etc from ReferenceCopyLocalPaths
VS2022 handles file paths differently than VS2019/VS2017 https://github.com/cefsharp/CefSharp/issues/3854
https://thomasfreudenberg.com/archive/2012/11/21/dont-copy-my-referenced-assemblies/
-->
<Target Name="CefSharpExcludeCoreRuntimeAfterResolveAssemblyReferences" AfterTargets="ResolveAssemblyReferences" Condition="('$(CefSharpPlatformTarget)' == 'AnyCPU' OR '$(CefSharpTargetDir)' != '') AND $(TargetFrameworkVersion.StartsWith('v4.'))">
<ItemGroup>
<_CefSharpCoreRuntimeFiltered Include="@(ReferenceCopyLocalPaths)" Condition="'%(Filename)%(Extension)' == 'CefSharp.Core.Runtime.dll'" />
<_CefSharpCoreRuntimeFiltered Include="@(ReferenceCopyLocalPaths)" Condition="'%(Filename)%(Extension)' == 'CefSharp.Core.Runtime.pdb'" />
<_CefSharpCoreRuntimeFiltered Include="@(ReferenceCopyLocalPaths)" Condition="'%(Filename)%(Extension)' == 'CefSharp.Core.Runtime.xml'" />
<ReferenceCopyLocalPaths Remove="@(_CefSharpCoreRuntimeFiltered)" />
</ItemGroup>
</Target>
<!--
For VS2017 when publishing x86/x64 there's CefSharp.Core.Runtime.dll references in both _DeploymentManifestDependencies and _DeploymentManifestFiles
This causes an Error occurred writing to hard disk exception, so we remove one (we leave the dependency and just remove the file reference).
For VS2019 when using PackageReference this target removes CefSharp.Core.Runtime.* from the publish target, $(NuGetProjectStyle) check added.
-->
<Target Name="CefSharpExcludeCoreRuntimeBeforeGenerateApplicationManifest" BeforeTargets="GenerateApplicationManifest" Condition="'$(CefSharpPlatformTarget)' != 'AnyCPU' AND $(TargetFrameworkVersion.StartsWith('v4.')) AND '$(NuGetProjectStyle)' != 'PackageReference'">
<ItemGroup>
<_DeploymentManifestFiles Remove="$(MSBuildThisFileDirectory)..\CefSharp\$(PlatformTarget)\CefSharp.Core.Runtime.dll" />
<_DeploymentManifestFiles Remove="$(MSBuildThisFileDirectory)..\CefSharp\$(PlatformTarget)\CefSharp.Core.Runtime.pdb" />
<_DeploymentManifestFiles Remove="$(MSBuildThisFileDirectory)..\CefSharp\$(PlatformTarget)\CefSharp.Core.Runtime.xml" />
</ItemGroup>
</Target>
<!--
For AnyCPU ClickOnce Publish Remove CefSharp.Core.Runtime.dll for being included in the bin folder
TODO: Publish AnyCPU still not working, requires some tweaking as CefSharp.dll file isn't being copied to the x64 folder.
TODO: Combine CefSharpAnyCPUExcludeCoreRuntimeBeforeGenerateApplicationManifest and CefSharpExcludeCoreRuntimeBeforeGenerateApplicationManifest
use a property instead of two different targets
-->
<Target Name="CefSharpAnyCPUExcludeCoreRuntimeBeforeGenerateApplicationManifest" BeforeTargets="GenerateApplicationManifest" Condition="'$(CefSharpPlatformTarget)' == 'AnyCPU' AND $(TargetFrameworkVersion.StartsWith('v4.'))">
<ItemGroup>
<_CefSharpCoreRuntimeFilteredManifest Include="@(_DeploymentManifestDependencies)" Condition="'%(Filename)%(Extension)' == 'CefSharp.Core.Runtime.dll'" />
<_CefSharpCoreRuntimeFilteredManifest Include="@(_DeploymentManifestDependencies)" Condition="'%(Filename)%(Extension)' == 'CefSharp.Core.Runtime.pdb'" />
<_CefSharpCoreRuntimeFilteredManifest Include="@(_DeploymentManifestDependencies)" Condition="'%(Filename)%(Extension)' == 'CefSharp.Core.Runtime.xml'" />
<_DeploymentManifestDependencies Remove="@(_CefSharpCoreRuntimeFilteredManifest)" />
</ItemGroup>
</Target>
<!--
Add to project file for debugging 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="CefSharpPropertiesLoaded = $(CefSharpPropertiesLoaded)" />
<Message Importance="high" Text="CefSharpTargetDir = $(CefSharpTargetDir)" />
<Message Importance="high" Text="CefSharpTargetDirAnyCpu32 = $(CefSharpTargetDirAnyCpu32)" />
<Message Importance="high" Text="CefSharpTargetDirAnyCpu64 = $(CefSharpTargetDirAnyCpu64)" />
<Message Importance="high" Text="CefSharpAnyCpuSupport = $(CefSharpAnyCpuSupport)" />
<Message Importance="high" Text="RuntimeIdentifier = $(RuntimeIdentifier)" />
<Message Importance="high" Text="EffectivePlatform = $(EffectivePlatform)" />
<Message Importance="high" Text="Platform = $(Platform)" />
<Message Importance="high" Text="PlatformName = $(PlatformName)" />
<Message Importance="high" Text="Platforms = $(Platforms)" />
<Message Importance="high" Text="PlatformTarget = $(PlatformTarget)" />
<Message Importance="high" Text="CefSharpPlatformTarget = $(CefSharpPlatformTarget)" />
<Message Importance="high" Text="PlatformTargetAsMSBuildArchitecture = $(PlatformTargetAsMSBuildArchitecture)" />
<Message Importance="high" Text="TargetFramework = $(TargetFramework)" />
<Message Importance="high" Text="TargetFrameworkVersion = $(TargetFrameworkVersion)" />
<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="NuGetToolVersion = $(NuGetToolVersion)" />
<Message Importance="high" Text="OutputType = $(OutputType)" />
<Message Importance="high" Text="OutDir = $(OutDir)" />
<Message Importance="high" Text="Prefer32Bit = $(Prefer32Bit)" />
</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)
If Microsoft.Web.Publishing.Tasks.dll is in a different location to those below then set
CefSharpTransformXmlDllPathOverride in your project file.
-->
<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>
<CefSharpTransformXmlDllPath Condition="'$(CefSharpTransformXmlDllPathOverride)' != ''">$(CefSharpTransformXmlDllPathOverride)</CefSharpTransformXmlDllPath>
</PropertyGroup>
<PropertyGroup>
<!--
Allowable options are None, Content, NoAction.
None is the default (same as selecting the None Build Action in Visual Studio) for Nuget packages.config
for WinExe/Exe projects (anything that's not Library) see https://github.com/cefsharp/CefSharp/issues/4062
None will copy the dependenceis to a directly referencing project file which is useful for library projects
that target packages.config as buildTransitive is not supported.
Content is the default (same as selecting the Content Build Action in Visual Studio) for Nuget PackageReference
and WinExe/Exe projects (anything that's not Library)
Technically the older Non-SDK Style project can use PackageReference under VS2019 (possibly VS2017 as well),
so we use NuGetProjectStyle which is defined in the .nuget.g.props file for projects using PackageReference.
For class libraries that are often AnyCPU and consuming Exe/WinExe projects that are x64 or x86 the resulting build output
is polluted with extra copies in sub folders. Set CefSharpBuildAction to NoAction to avoid copying the files.
-->
<CefSharpBuildAction Condition="'$(CefSharpBuildAction)' == '' AND ('$(NuGetProjectStyle)' == 'PackageReference' OR '$(OutputType)' != 'Library')">Content</CefSharpBuildAction>
<CefSharpBuildAction Condition="'$(CefSharpBuildAction)' == '' AND '$(NuGetProjectStyle)' != 'PackageReference'">None</CefSharpBuildAction>
<CefSharpTargetDir Condition="'$(CefSharpTargetDir)' == ''"></CefSharpTargetDir>
<!-- Ideally we could use EnsureTrailingSlash, was only added on 2017 so unlikely supported in older version of VS -->
<CefSharpTargetDir Condition="'$(CefSharpTargetDir)' != '' AND !HasTrailingSlash('$(CefSharpTargetDir)')">$(CefSharpTargetDir)\</CefSharpTargetDir>
<CefSharpTargetDirAnyCpu32>$(CefSharpTargetDir)x86\</CefSharpTargetDirAnyCpu32>
<CefSharpTargetDirAnyCpu64>$(CefSharpTargetDir)x64\</CefSharpTargetDirAnyCpu64>
<!--
For Sdk Projects the PlatformTarget is unreliable (https://github.com/dotnet/sdk/issues/1560)
When our targets file is imported $(PlatformTarget) will be x86 when the Platform is infact AnyCPU.
By time the AfterBuilds target runs it's correctly set to AnyCPU as the GetDefaultPlatformTargetForNetFramework
Task correctly sets the build to AnyCPU, unfortunately it's too late. Previous attempt to hack around this failed,
relying on user to manually specify $(PlatformTarget) until the SDK issue is fixed.
When AnyCPU and Prefer32Bit we just set the PlatformTarget to x86 (only when CefSharpAnyCpuSupport is empty)
**This is must be kept in sync with _CefSharpCopyFilesSetProperties**
-->
<CefSharpPlatformTarget>$(PlatformTarget)</CefSharpPlatformTarget>
<CefSharpPlatformTarget Condition="'$(CefSharpPlatformTarget)' == ''">$(Platform)</CefSharpPlatformTarget>
<CefSharpPlatformTarget Condition="'$(CefSharpPlatformTarget)' == 'Win32'">x86</CefSharpPlatformTarget>
<CefSharpPlatformTarget Condition="'$(CefSharpPlatformTarget)' == 'AnyCPU' AND '$(Prefer32Bit)' == 'true' AND '$(CefSharpAnyCpuSupport)' == ''">x86</CefSharpPlatformTarget>
<CefSharpPlatformTarget Condition="'$(CefSharpPlatformTargetOverride)' != ''">$(CefSharpPlatformTargetOverride)</CefSharpPlatformTarget>
<!--
We use this to check if this property group was loaded so we know when to use our copy targets to workaround
https://github.com/dotnet/project-system/issues/4158
-->
<CefSharpPropertiesLoaded>true</CefSharpPropertiesLoaded>
<!--
For PackageReference library projects where buildTransitive is supported we'll default to setting CefSharpAnyCpuSupport to true
This should only require WinExe and Exe projects to specify CefSharpAnyCpuSupport rather than every project in a solution.
Only for PackageReference projects where NuGetToolVersion > 5.0 and OutputType is library.
Defaulting CefSharpAnyCpuSupport to true is simpler than modifying the already complex Condition for the CefSharpPlatformCheck
target below.
https://github.com/cefsharp/CefSharp/issues/3622
-->
<CefSharpAnyCpuSupport Condition="'$(CefSharpAnyCpuSupport)' != 'true' AND '$(NuGetProjectStyle)' == 'PackageReference' AND $(NuGetToolVersion) > '5.0' AND '$(OutputType)' == 'Library'">true</CefSharpAnyCpuSupport>
</PropertyGroup>
<Choose>
<!--
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 $(TargetFrameworkVersion.StartsWith('v4.')) AND '$(CefSharpPlatformTarget)' != 'AnyCPU'">
<Choose>
<When Condition="'$(CefSharpBuildAction)' == 'None'">
<ItemGroup>
<None Include="@(CefSharpCommonManagedDll)">
<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="@(CefSharpCommonManagedDll)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</Content>
</ItemGroup>
</When>
</Choose>
</When>
</Choose>
<Choose>
<When Condition="'$(CefSharpBuildAction)' == 'None'">
<Choose>
<When Condition="'$(CefSharpPlatformTarget)' == '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="'$(CefSharpPlatformTarget)' == '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="@(CefSharpCommonManagedDll)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
</None>
<None Include="@(CefSharpCommonManagedDll)">
<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="'$(CefSharpPlatformTarget)' == 'x64'">
<ItemGroup>
<Content Include="@(CefRedist64)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</Content>
<Content Include="@(CefSharpCommonBinaries64)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</Content>
</ItemGroup>
</When>
<When Condition="'$(CefSharpPlatformTarget)' == 'AnyCPU'">
<ItemGroup>
<Content Include="@(CefRedist32)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</Content>
<Content Include="@(CefRedist64)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</Content>
<Content Include="@(CefSharpCommonBinaries32)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</Content>
<Content Include="@(CefSharpCommonBinaries64)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</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="@(CefSharpCommonManagedDll)">
<Link>$(CefSharpTargetDirAnyCpu32)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</Content>
<Content Include="@(CefSharpCommonManagedDll)">
<Link>$(CefSharpTargetDirAnyCpu64)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</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>
<IncludeInVsix>true</IncludeInVsix>
</Content>
<Content Include="@(CefSharpCommonBinaries32)">
<Link>$(CefSharpTargetDir)%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PublishState>Included</PublishState>
<Visible>false</Visible>
<IncludeInVsix>true</IncludeInVsix>
</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 '$(CefSharpPlatformTarget)' == 'AnyCPU' AND '$(CefSharpAnyCpuSupport)' == '' AND '$(CefSharpBuildAction)' != 'NoAction'" />
<Target Name="CefSharpCommonAnyCPUConfigTransform" AfterTargets="_CopyAppConfigFile" Condition="'@(AppConfigWithTargetPath)' != '' AND Exists('$(CefSharpTransformXmlDllPath)') AND '$(CefSharpPlatformTarget)' == 'AnyCPU' AND '$(CefSharpAnyCpuSupport)' == '' AND '$(CefSharpBuildAction)' != 'NoAction'">
<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="('@(AppConfigWithTargetPath)' == '' OR !Exists('$(CefSharpTransformXmlDllPath)')) AND '$(CefSharpPlatformTarget)' == 'AnyCPU' AND '$(CefSharpAnyCpuSupport)' != 'true' AND '$(CefSharpBuildAction)' != 'NoAction'">
<Error Text="$(MSBuildThisFileName) is unable to proceeed as your current PlatformTarget is '$(CefSharpPlatformTarget)'. 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)
As a workaround we manually copy the files using a series of Targets and private itemgroup/propertygroups.
Accessing the ItemGroups that exist in the .props files isn't possible, the Targets are handled differently by msbuild/VS2017/VS2019 (worked previous in VS2015)
so we duplicate the entries private to these tasks. Must be kept in sync with the .props files.
We cannot use any of the variables defined in this targets file as they won't have been loaded initially.
So we can only use PlatformTarget rather than CefSharpPlatformTarget, leaving the other CefSharp specific variables for now as
they can be user defined so will be loaded.
TODO: Add a cleanup Task to delete the files, will need to update cef.redist packages to add cleanup tasks also
https://stackoverflow.com/questions/38935399/remove-files-and-folders-copied-from-afterbuild-target
-->
<Target Name="CefSharpCopyFilesAfterNugetRestore" AfterTargets="Build" DependsOnTargets="_CefSharpCopyFilesSetProperties" Condition="'$(NuGetProjectStyle)' != 'PackageReference' AND '$(CefSharpBuildAction)' != 'NoAction' AND '$(CefSharpPropertiesLoaded)' == ''">
<CallTarget Targets="CefSharpCopyFilesAfterNugetRestore32" Condition="'$(_CefSharpPlatformTarget)' == 'x86' OR '$(_CefSharpPlatformTarget)' == 'AnyCPU'" />
<CallTarget Targets="CefSharpCopyFilesAfterNugetRestore64" Condition="'$(_CefSharpPlatformTarget)' == 'x64' OR '$(_CefSharpPlatformTarget)' == 'AnyCPU'"/>
</Target>
<Target Name="CefSharpCopyFilesAfterNugetRestore32">
<Message Importance="high" Text="CefSharp - Files were not copied by MSBuild after Nuget install/restore! Manually copying files to $(CefRedist32TargetDir) as workaround. Please close and re-open $(MSBuildProjectFile)." />
<CallTarget Targets="CefRedist32CopyResources"/>
<Message Importance="high" Text="Copying CefSharp Common x86 files from $(MSBuildThisFileDirectory)..\CefSharp\x86 to $(CefRedist32TargetDir)" />
<Copy SourceFiles="@(_CefSharpCommonBinaries32)" DestinationFiles="@(_CefSharpCommonBinaries32->'$(CefRedist32TargetDir)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
<Message Importance="high" Text="Copying CefSharp.dll from $(MSBuildThisFileDirectory)..\lib\net452\CefSharp.dll to $(CefRedist32TargetDir)" />
<Copy SourceFiles="@(_CefSharpCommonManagedDll)" DestinationFiles="@(_CefSharpCommonManagedDll->'$(CefRedist32TargetDir)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
</Target>
<Target Name="CefSharpCopyFilesAfterNugetRestore64">
<Message Importance="high" Text="CefSharp - Files were not copied by MSBuild after Nuget install/restore! Manually copying files to $(CefRedist64TargetDir) as workaround. Please close and re-open $(MSBuildProjectFile)." />
<CallTarget Targets="CefRedist64CopyResources"/>
<Message Importance="high" Text="Copying CefSharp Common x64 files from $(MSBuildThisFileDirectory)..\CefSharp\x64 to $(CefRedist64TargetDir)" />
<Copy SourceFiles="@(_CefSharpCommonBinaries64)" DestinationFiles="@(_CefSharpCommonBinaries64->'$(CefRedist64TargetDir)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
<Message Importance="high" Text="Copying CefSharp.dll from $(MSBuildThisFileDirectory)..\lib\net452\CefSharp.dll to $(CefRedist64TargetDir)" />
<Copy SourceFiles="@(_CefSharpCommonManagedDll)" DestinationFiles="@(_CefSharpCommonManagedDll->'$(CefRedist64TargetDir)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
</Target>
<Target Name="_CefSharpCopyFilesSetProperties">
<PropertyGroup>
<!-- This is must be kept in sync with the main property group above -->
<_CefSharpPlatformTarget>$(PlatformTarget)</_CefSharpPlatformTarget>
<_CefSharpPlatformTarget Condition="'$(_CefSharpPlatformTarget)' == ''">$(Platform)</_CefSharpPlatformTarget>
<_CefSharpPlatformTarget Condition="'$(_CefSharpPlatformTarget)' == 'Win32'">x86</_CefSharpPlatformTarget>
<_CefSharpPlatformTarget Condition="'$(_CefSharpPlatformTarget)' == 'AnyCPU' AND '$(Prefer32Bit)' == 'true' AND '$(CefSharpAnyCpuSupport)' == ''">x86</_CefSharpPlatformTarget>
<_CefSharpPlatformTarget Condition="'$(CefSharpPlatformTargetOverride)' != ''">$(CefSharpPlatformTargetOverride)</_CefSharpPlatformTarget>
<CefRedist32TargetDir Condition="'$(CefRedist32TargetDir)' == ''">$(TargetDir)$(CefSharpTargetDir)</CefRedist32TargetDir>
<CefRedist64TargetDir Condition="'$(CefRedist64TargetDir)' == ''">$(TargetDir)$(CefSharpTargetDir)</CefRedist64TargetDir>
<CefRedist32TargetDir Condition="'$(_CefSharpPlatformTarget)' == 'AnyCPU'">$(CefRedist32TargetDir)x86\</CefRedist32TargetDir>
<CefRedist64TargetDir Condition="'$(_CefSharpPlatformTarget)' == 'AnyCPU'">$(CefRedist64TargetDir)x64\</CefRedist64TargetDir>
</PropertyGroup>
<ItemGroup>
<_CefSharpCommonManagedDll Include="$(MSBuildThisFileDirectory)..\lib\net452\CefSharp.dll" />
<_CefSharpCommonBinaries32 Include="$(MSBuildThisFileDirectory)..\CefSharp\x86\*.*" />
<_CefSharpCommonBinaries64 Include="$(MSBuildThisFileDirectory)..\CefSharp\x64\*.*" />
</ItemGroup>
</Target>
<!--
Sdk Style Projects don't set PlatformTarget correctly issue https://github.com/dotnet/sdk/issues/1560
The PlatformTarget value before build for AnyCPU will end up as x86 and afterbuild the value will
be AnyCPU which means we copied only the x86 libs resulting in an invalid build.
-->
<Target Name="CefSharpPlatformTargetAfterBuildCheck" AfterTargets="Build" Condition="'$(UsingMicrosoftNETSdk)' == 'true' AND '$(CefSharpPlatformTarget)' != '$(PlatformTarget)' AND '$(CefSharpBuildAction)' != 'NoAction' AND '$(CefSharpPlatformTargetOverride)' == ''">
<Error Text="CefSharp copied resources/libs for $(CefSharpPlatformTarget) where the resulting exe was $(PlatformTarget), this is a known issue with SDK Style projects see https://github.com/dotnet/sdk/issues/1560 please explicitly set PlatformTarget in your proj file." />
</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.

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 BrowserSubprocess
{
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 BrowserSubprocess
{
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,74 @@
// Copyright © 2015 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#include "stdafx.h"
#include "JavascriptAsyncMethodHandler.h"
#include "../CefSharp.Core.Runtime/Internals/Messaging/Messages.h"
#include "../CefSharp.Core.Runtime/Internals/Serialization/Primitives.h"
#include "Serialization/V8Serialization.h"
#include "CefAppUnmanagedWrapper.h"
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
using namespace CefSharp::BrowserSubprocess::Serialization;
namespace CefSharp
{
namespace BrowserSubprocess
{
namespace Async
{
bool JavascriptAsyncMethodHandler::Execute(const CefString& name, CefRefPtr<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 == nullptr)
{
LOG(WARNING) << "JavascriptAsyncMethodHandler::Execute promiseData returned nullptr";
return true;
}
retval = promiseData->GetValue("p");
auto resolve = promiseData->GetValue("res");
auto reject = promiseData->GetValue("rej");
auto callback = gcnew JavascriptAsyncMethodCallback(context, resolve, reject);
auto callbackId = _methodCallbackSave->Invoke(callback);
auto request = CefProcessMessage::Create(kJavascriptAsyncMethodCallRequest);
auto argList = request->GetArgumentList();
auto params = CefListValue::Create();
for (size_t i = 0; i < arguments.size(); i++)
{
SerializeV8Object(arguments[i], params, i, _callbackRegistry);
}
SetInt64(argList, 0, _objectId);
SetInt64(argList, 1, callbackId);
argList->SetString(2, name);
argList->SetList(3, params);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, request);
return true;
}
}
}
}

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 BrowserSubprocess
{
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_REFCOUNTINGM(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 BrowserSubprocess
{
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 BrowserSubprocess
{
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 BrowserSubprocess
{
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 BrowserSubprocess
{
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,328 @@
// Copyright © 2019 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#pragma once
#include "include/cef_v8.h"
#include "RegisterBoundObjectRegistry.h"
#include "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
using namespace System;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
using namespace CefSharp::BrowserSubprocess;
namespace CefSharp
{
namespace BrowserSubprocess
{
const CefString kBindObjectAsync = CefString("BindObjectAsync");
const CefString kBindObjectAsyncCamelCase = CefString("bindObjectAsync");
private class BindObjectAsyncHandler : public CefV8Handler
{
private:
gcroot<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 objectCount and cachedObject count are both 0 then we'll
//send the kJavascriptRootObjectRequest message
//https://github.com/cefsharp/CefSharp/issues/3470
if (objectCount > 0 && cachedObjects->Count == objectCount && ignoreCache == false)
{
if (Object::ReferenceEquals(_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 == nullptr)
{
LOG(WARNING) << "BindObjectAsyncHandler::Execute promiseData returned nullptr";
return true;
}
//return the promose
retval = promiseData->GetValue("p");
//References to the promise resolve and reject methods
auto resolve = promiseData->GetValue("res");
auto reject = promiseData->GetValue("rej");
auto callback = gcnew JavascriptAsyncMethodCallback(context, resolve, reject);
auto request = CefProcessMessage::Create(kJavascriptRootObjectRequest);
auto argList = request->GetArgumentList();
//Obtain a callbackId then send off the Request for objects
auto callbackId = _callbackRegistry->SaveMethodCallback(callback);
SetInt64(argList, 0, callbackId);
argList->SetList(1, params);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, request);
}
}
else
{
//Objects already bound or ignore cache
CefRefPtr<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_REFCOUNTINGM(BindObjectAsyncHandler);
};
}
}

View file

@ -0,0 +1,164 @@
// 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, 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
/// </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, 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
/// </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)
{
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, 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, 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")
{
//Lower the shutdown priority so the browser process is shutdown first (Issue #3155)
//The system terminates the process without displaying a retry dialog box for the user.
//Crashpad is lower than other sub processes so it can still monitor process exit crashes.
SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY);
}
else
{
//Lower the shutdown priority so the browser process is shutdown first (Issue #3155)
//The system terminates the process without displaying a retry dialog box for the user.
SetProcessShutdownParameters(0x200, SHUTDOWN_NORETRY);
parentProcessId = int::Parse(CommandLineArgsParser::GetArgumentValue(args, CefSharpArguments::HostProcessIdArgument));
if (CommandLineArgsParser::HasArgument(args, CefSharpArguments::ExitIfParentProcessClosed))
{
ParentProcessMonitor::StartMonitorTask(parentProcessId);
}
}
// Use our custom subProcess provides features like EvaluateJavascript
if (type == "renderer")
{
auto subProcess = GetSubprocess(args, parentProcessId, handler);
try
{
return subProcess->Run();
}
finally
{
delete subProcess;
}
}
return SubProcess::ExecuteProcess(args);
}
protected:
virtual SubProcess^ GetSubprocess(IEnumerable<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,776 @@
// Copyright © 2014 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#pragma once
#include "Stdafx.h"
#include "CefBrowserWrapper.h"
#include "CefAppUnmanagedWrapper.h"
#include "RegisterBoundObjectHandler.h"
#include "BindObjectAsyncHandler.h"
#include "JavascriptPostMessageHandler.h"
#include "JavascriptRootObjectWrapper.h"
#include "JavascriptPromiseHandler.h"
#include "JavascriptPromiseResolverCatch.h"
#include "JavascriptPromiseResolverThen.h"
#include "Async\JavascriptAsyncMethodCallback.h"
#include "Serialization\V8Serialization.h"
#include "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::Serialization;
using namespace CefSharp::Internals::Messaging;
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
namespace BrowserSubprocess
{
const CefString CefAppUnmanagedWrapper::kPromiseCreatorScript = ""
"(function()"
"{"
" var result = {};"
" var promise = new Promise(function(resolve, reject) {"
" result.res = resolve; result.rej = reject;"
" });"
" result.p = promise;"
" return result;"
"})();";
const CefString kRenderProcessId = CefString("RenderProcessId");
const CefString kRenderProcessIdCamelCase = CefString("renderProcessId");
CefRefPtr<CefRenderProcessHandler> CefAppUnmanagedWrapper::GetRenderProcessHandler()
{
return this;
};
// CefRenderProcessHandler
void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extraInfo)
{
auto wrapper = gcnew CefBrowserWrapper(browser);
_onBrowserCreated->Invoke(wrapper);
//Multiple CefBrowserWrappers created when opening popups
_browserWrappers->TryAdd(browser->GetIdentifier(), wrapper);
//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);
}
}
}
_jsBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
if (extraInfo->HasKey("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
{
//TODO: Create constant for these and legacy binding strings above
_jsBindingPropertyName = extraInfo->GetString("JsBindingPropertyName");
_jsBindingPropertyNameCamelCase = extraInfo->GetString("JsBindingPropertyNameCamelCase");
}
}
}
void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
{
CefBrowserWrapper^ wrapper;
if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
{
_onBrowserDestroyed->Invoke(wrapper);
delete wrapper;
}
};
void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
if (!Object::ReferenceEquals(_handler, nullptr))
{
Browser browserWrapper(browser);
Frame frameWrapper(frame);
V8Context contextWrapper(context);
_handler->OnContextCreated(% browserWrapper, % frameWrapper, % contextWrapper);
}
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
if (_legacyBindingEnabled)
{
if (_javascriptObjects->Count > 0 && rootObject != nullptr)
{
rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
}
}
if (_jsBindingApiEnabled)
{
//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(nullptr, nullptr);
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
}
if (createCefSharpObjCamelCase)
{
auto cefSharpObjCamelCase = CefV8Value::CreateObject(nullptr, nullptr);
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kRemoveObjectFromCacheCamelCase, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kIsObjectCachedCamelCase, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kPostMessageCamelCase, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kSendEvalScriptResponseCamelCase, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
cefSharpObjCamelCase->SetValue(kRenderProcessIdCamelCase, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
}
}
//Send a message to the browser processing signaling that OnContextCreated has been called
//only param is the FrameId. Previous sent only for main frame, now sent for all frames
//Message sent after legacy objects have been bound and the CefSharp bind async helper methods
//have been created
auto contextCreatedMessage = CefProcessMessage::Create(kOnContextCreatedRequest);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextCreatedMessage);
};
void CefAppUnmanagedWrapper::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
if (!Object::ReferenceEquals(_handler, nullptr))
{
Browser browserWrapper(browser);
Frame frameWrapper(frame);
V8Context contextWrapper(context);
_handler->OnContextReleased(% browserWrapper, % frameWrapper, % contextWrapper);
}
auto contextReleasedMessage = CefProcessMessage::Create(kOnContextReleasedRequest);
frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextReleasedMessage);
auto 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 if (result->IsPromise())
{
sendResponse = false;
auto promiseThen = result->GetValue("then");
auto promiseCatch = result->GetValue("catch");
auto promiseThenFunc = CefV8Value::CreateFunction("promiseResolverThen", new JavascriptPromiseResolverThen(callbackId, false));
auto promiseCatchFunc = CefV8Value::CreateFunction("promiseResolverCatch", new JavascriptPromiseResolverCatch(callbackId, false));
CefV8ValueList promiseThenArgs;
promiseThenArgs.push_back(promiseThenFunc);
promiseThen->ExecuteFunction(result, promiseThenArgs);
CefV8ValueList promiseCatchArgs;
promiseCatchArgs.push_back(promiseCatchFunc);
promiseCatch->ExecuteFunction(result, promiseCatchArgs);
}
else
{
auto 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)
{
//If the response is a string of CefSharpDefEvalScriptRes then
//we don't send the response, we'll let that happen when the promise has completed.
if (result->IsString() && result->GetStringValue() == "CefSharpDefEvalScriptRes")
{
sendResponse = false;
}
else if (result->IsPromise())
{
sendResponse = false;
auto promiseThen = result->GetValue("then");
auto promiseCatch = result->GetValue("catch");
auto promiseThenFunc = CefV8Value::CreateFunction("promiseResolverThen", new JavascriptPromiseResolverThen(callbackId, true));
auto promiseCatchFunc = CefV8Value::CreateFunction("promiseResolverCatch", new JavascriptPromiseResolverCatch(callbackId, true));
CefV8ValueList promiseThenArgs;
promiseThenArgs.push_back(promiseThenFunc);
promiseThen->ExecuteFunction(result, promiseThenArgs);
CefV8ValueList promiseCatchArgs;
promiseCatchArgs.push_back(promiseCatchFunc);
promiseCatch->ExecuteFunction(result, promiseCatchArgs);
}
else
{
auto responseArgList = response->GetArgumentList();
SerializeV8Object(result, responseArgList, 2, callbackRegistry);
}
}
else
{
auto exception = value->GetException();
errorMessage = StringUtils::CreateExceptionString(exception);
}
}
finally
{
context->Exit();
}
}
else
{
errorMessage = "Unable to Enter Context";
}
}
}
}
if (sendResponse)
{
auto responseArgList = response->GetArgumentList();
responseArgList->SetBool(0, success);
SetInt64(responseArgList, 1, callbackId);
if (!success)
{
responseArgList->SetString(2, errorMessage);
}
frame->SendProcessMessage(sourceProcessId, response);
}
handled = true;
}
else if (name == kJavascriptCallbackDestroyRequest)
{
if (frame.get() && frame->IsValid())
{
auto jsCallbackId = GetInt64(argList, 0);
JavascriptRootObjectWrapper^ rootObjectWrapper;
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(nullptr, nullptr);
response->SetValue("Count", CefV8Value::CreateInt(javascriptObjects->Count), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
if (javascriptObjects->Count > 0)
{
//TODO: JSB Should we include a list of successfully bound object names?
response->SetValue("Success", CefV8Value::CreateBool(true), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
response->SetValue("Message", CefV8Value::CreateString("OK"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
callback->Success(response);
}
else
{
response->SetValue("Success", CefV8Value::CreateBool(false), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
response->SetValue("Message", CefV8Value::CreateString("Zero objects bounds"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
callback->Success(response);
}
//Send message notifying Browser Process of which objects were bound
//We do this after the objects have been created in the V8Context to gurantee
//they are accessible.
auto msg = CefProcessMessage::Create(kJavascriptObjectsBoundInJavascript);
auto args = msg->GetArgumentList();
auto boundObjects = CefListValue::Create();
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,90 @@
// 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
{
namespace BrowserSubprocess
{
// 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;
bool _jsBindingApiEnabled = true;
// 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;
_jsBindingPropertyName = "CefSharp";
_jsBindingPropertyNameCamelCase = "cefSharp";
}
~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_REFCOUNTINGM(CefAppUnmanagedWrapper);
};
}
}

View file

@ -0,0 +1,77 @@
// 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::BrowserSubprocess::Async;
#ifndef NETCOREAPP
using namespace System::ServiceModel;
#endif
using namespace System::Threading;
using namespace System::Threading::Tasks;
namespace CefSharp
{
namespace BrowserSubprocess
{
// "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.get();
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,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.
#include "stdafx.h"
#include "JavascriptCallbackRegistry.h"
using namespace System::Threading;
using namespace CefSharp::BrowserSubprocess;
namespace CefSharp
{
namespace BrowserSubprocess
{
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,54 @@
// 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;
using namespace CefSharp::BrowserSubprocess;
namespace CefSharp
{
namespace BrowserSubprocess
{
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 BrowserSubprocess
{
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,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 "TypeUtils.h"
#include "JavascriptMethodHandler.h"
namespace CefSharp
{
namespace BrowserSubprocess
{
bool JavascriptMethodHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
{
auto size = static_cast<int>(arguments.size());
auto parameter = gcnew array<Object^>(size);
for (int i = 0; i < 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(nullptr, nullptr);
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,44 @@
// 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
{
namespace BrowserSubprocess
{
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_REFCOUNTINGM(JavascriptMethodHandler);
};
}
}

View file

@ -0,0 +1,29 @@
// 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
{
namespace BrowserSubprocess
{
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,51 @@
// 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
{
namespace BrowserSubprocess
{
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,57 @@
// 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
{
namespace BrowserSubprocess
{
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(), nullptr);
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,64 @@
// 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
{
namespace BrowserSubprocess
{
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,94 @@
// 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::BrowserSubprocess::Serialization;
namespace CefSharp
{
namespace BrowserSubprocess
{
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_REFCOUNTINGM(JavascriptPostMessageHandler);
};
}
}

View file

@ -0,0 +1,89 @@
// 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::BrowserSubprocess::Serialization;
namespace CefSharp
{
namespace BrowserSubprocess
{
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 javascriptCallback = arguments.size() < 4 ? false : arguments[3]->GetBoolValue();
auto response = CefProcessMessage::Create(javascriptCallback ? kJavascriptCallbackResponse : 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_REFCOUNTINGM(JavascriptPromiseHandler);
};
}
}

View file

@ -0,0 +1,71 @@
// Copyright © 2022 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"
using namespace System;
namespace CefSharp
{
namespace BrowserSubprocess
{
private class JavascriptPromiseResolverCatch : public CefV8Handler
{
int64 _callbackId;
bool _isJsCallback;
public:
JavascriptPromiseResolverCatch(int64 callbackId, bool isJsCallback) : _callbackId(callbackId), _isJsCallback(isJsCallback)
{
}
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
auto context = CefV8Context::GetCurrentContext();
auto reason = arguments[0];
CefString reasonString;
if (reason->IsString())
{
reasonString = reason->GetStringValue();
}
else
{
//Convert value to String
auto strFunc = context->GetGlobal()->GetValue("String");
CefV8ValueList args;
args.push_back(reason);
auto strVal = strFunc->ExecuteFunction(nullptr, args);
reasonString = strVal->GetStringValue();
}
auto response = CefProcessMessage::Create(_isJsCallback ? kJavascriptCallbackResponse : kEvaluateJavascriptResponse);
auto responseArgList = response->GetArgumentList();
//Success
responseArgList->SetBool(0, false);
//Callback Id
SetInt64(responseArgList, 1, _callbackId);
responseArgList->SetString(2, reasonString);
auto frame = context->GetFrame();
frame->SendProcessMessage(CefProcessId::PID_BROWSER, response);
return true;
}
IMPLEMENT_REFCOUNTINGM(JavascriptPromiseResolverCatch);
};
}
}

View file

@ -0,0 +1,59 @@
// Copyright © 2022 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::BrowserSubprocess::Serialization;
namespace CefSharp
{
namespace BrowserSubprocess
{
private class JavascriptPromiseResolverThen : public CefV8Handler
{
int64 _callbackId;
bool _isJsCallback;
public:
JavascriptPromiseResolverThen(int64 callbackId, bool isJsCallback) : _callbackId(callbackId), _isJsCallback(isJsCallback)
{
}
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
auto response = CefProcessMessage::Create(_isJsCallback ? kJavascriptCallbackResponse : kEvaluateJavascriptResponse);
auto responseArgList = response->GetArgumentList();
//Success
responseArgList->SetBool(0, true);
//Callback Id
SetInt64(responseArgList, 1, _callbackId);
SerializeV8Object(arguments[0], responseArgList, 2, nullptr);
auto context = CefV8Context::GetCurrentContext();
auto frame = context->GetFrame();
frame->SendProcessMessage(CefProcessId::PID_BROWSER, response);
return true;
}
IMPLEMENT_REFCOUNTINGM(JavascriptPromiseResolverThen);
};
}
}

View file

@ -0,0 +1,68 @@
// 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
{
namespace BrowserSubprocess
{
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_REFCOUNTINGM(JavascriptPropertyHandler);
};
}
}

View file

@ -0,0 +1,38 @@
// 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
{
namespace BrowserSubprocess
{
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,45 @@
// 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
{
namespace BrowserSubprocess
{
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,74 @@
// 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
{
namespace BrowserSubprocess
{
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,110 @@
// 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::BrowserSubprocess::Async;
#ifndef NETCOREAPP
using namespace CefSharp::Internals::Wcf;
#endif
namespace CefSharp
{
namespace BrowserSubprocess
{
// 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
{
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,129 @@
// 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
{
namespace BrowserSubprocess
{
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_REFCOUNTINGM(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::BrowserSubprocess::Async;
namespace CefSharp
{
namespace BrowserSubprocess
{
//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,84 @@
// 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"
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
namespace BrowserSubprocess
{
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);
auto size = static_cast<int>(subList->GetSize());
for (int i = 0; i < size; 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 BrowserSubprocess
{
namespace Serialization
{
JavascriptObject^ DeserializeJsObject(const CefRefPtr<CefListValue>& list, int index);
List<JavascriptObject^>^ DeserializeJsObjects(const CefRefPtr<CefListValue>& list, int index);
}
}
}

View file

@ -0,0 +1,203 @@
// 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;
using namespace CefSharp::Internals::Serialization;
namespace CefSharp
{
namespace BrowserSubprocess
{
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())
{
// CEF doesn't differentiate between UINT and INT
// so we have to do some additional bounds checking
// To make sure the correct value is returned
// CEF IPC doesn't support UINT so we can only
// support int and double.
// https://github.com/cefsharp/CefSharp/issues/3858
auto dValue = obj->GetDoubleValue();
if (dValue < INT_MIN || dValue > INT_MAX)
{
list->SetDouble(index, dValue);
}
else
{
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().val);
}
else if (obj->IsArray())
{
int arrLength = obj->GetArrayLength();
auto array = CefListValue::Create();
if (arrLength > 0)
{
for (int i = 0; i < arrLength; i++)
{
SerializeV8Object(obj->GetValue(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))
{
auto time = GetCefTime(list, index);
return CefV8Value::CreateDate(time);
}
if (type == VTYPE_LIST)
{
auto subList = list->GetList(index);
auto size = static_cast<int>(subList->GetSize());
auto result = CefV8Value::CreateArray(size);
for (int 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,30 @@
// 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"
using namespace CefSharp::Internals;
namespace CefSharp
{
namespace BrowserSubprocess
{
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,24 @@
// 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\CefRefCountManaged.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,84 @@
// 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(), nullptr);
}
virtual void OnBrowserCreated(CefBrowserWrapper^ cefBrowserWrapper)
{
}
virtual void OnBrowserDestroyed(CefBrowserWrapper^ cefBrowserWrapper)
{
}
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, nullptr);
}
};
}
}

View file

@ -0,0 +1,50 @@
// 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
{
namespace BrowserSubprocess
{
// 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_REFCOUNTINGM(SubProcessApp);
};
}
}

View file

@ -0,0 +1,260 @@
// 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
{
namespace BrowserSubprocess
{
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)
{
CefBaseTime baseTime;
baseTime.val = CefTimeUtils::FromDateTimeToBaseTime(safe_cast<DateTime>(obj));
return CefV8Value::CreateDate(baseTime);
}
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 CefTimeUtils::FromBaseTimeToDateTime(obj->GetDateValue().val);
}
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.");
}
}
}

View file

@ -0,0 +1,55 @@
// 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
{
namespace BrowserSubprocess
{
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 CefBaseTime (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(CefBaseTime time);
/// <summary>
/// Converts a a (managed) .NET DateTime to Chromium V8 CefBaseTime (Date).
/// </summary>
/// <param name="obj">The DateTime value that should be converted.</param>
/// <returns>A corresponding CefTime (epoch).</returns>
static CefBaseTime 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,226 @@
// 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;
bool Browser::IsValid::get()
{
return _browser->IsValid();
}
///
// 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 static_cast<int>(_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>(static_cast<int>(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,193 @@
// 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:
virtual property bool IsValid
{
bool get();
}
///
// 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 = nullptr;
}
~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 = nullptr;
}
~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,2 @@
#using <mscorlib.dll>
[assembly: System::Runtime::Versioning::TargetFrameworkAttribute(L".NETFramework,Version=v4.5.2", FrameworkDisplayName=L".NET Framework 4.5.2")];

View file

@ -0,0 +1,2 @@
#using <mscorlib.dll>
[assembly: System::Runtime::Versioning::TargetFrameworkAttribute(L".NETFramework,Version=v4.5.2", FrameworkDisplayName=L".NET Framework 4.5.2")];

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

View file

@ -0,0 +1,60 @@
//
// vcclr_local.h - modified version of vcclr.h from c:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\vcclr.h.
// Modifications indicated below.
//
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
#if _MSC_VER > 1000
#pragma once
#endif
#if !defined(_INC_VCCLR)
#define _INC_VCCLR
#ifndef RC_INVOKED
// Deliberately disabled, since this causes mscorlib.dll to be referenced twice from two different locations, breaking
// IntelliSense whenever this header file is included.
//#using <mscorlib.dll>
#include <gcroot.h>
#pragma warning(push)
#pragma warning(disable:4400)
#ifdef __cplusplus_cli
typedef cli::interior_ptr<const System::Char> __const_Char_ptr;
typedef cli::interior_ptr<const System::Byte> __const_Byte_ptr;
typedef cli::interior_ptr<System::Byte> _Byte_ptr;
typedef const System::String^ __const_String_handle;
#define _NULLPTR nullptr
#else
typedef const System::Char* __const_Char_ptr;
typedef const System::Byte* __const_Byte_ptr;
typedef System::Byte* _Byte_ptr;
typedef const System::String* __const_String_handle;
#define _NULLPTR 0
#endif
//
// get an interior gc pointer to the first character contained in a System::String object
//
inline __const_Char_ptr PtrToStringChars(__const_String_handle s)
{
_Byte_ptr bp = const_cast<_Byte_ptr>(reinterpret_cast<__const_Byte_ptr>(s));
if (bp != _NULLPTR)
{
unsigned offset = System::Runtime::CompilerServices::RuntimeHelpers::OffsetToStringData;
bp += offset;
}
return reinterpret_cast<__const_Char_ptr>(bp);
}
#pragma warning(pop)
#undef _NULLPTR
#endif /* RC_INVOKED */
#endif //_INC_VCCLR

View file

@ -0,0 +1,38 @@
// 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.
using System.Diagnostics;
using CefSharp.RenderProcess;
namespace CefSharp.BrowserSubprocess
{
/// <summary>
/// When implementing your own BrowserSubprocess
/// - For Full .Net use <see cref="WcfBrowserSubprocessExecutable"/>
/// - For .Net Core use <see cref="BrowserSubprocessExecutable"/> (No WCF Support)
/// - Include an app.manifest with the dpi/compatability sections, this is required (this project contains the relevant).
/// - If you are targeting x86/Win32 then you should set /LargeAddressAware (https://docs.microsoft.com/en-us/cpp/build/reference/largeaddressaware?view=vs-2017)
/// </summary>
public class Program
{
public static int Main(string[] args)
{
Debug.WriteLine("BrowserSubprocess starting up with command line: " + string.Join("\n", args));
//Add your own custom implementation of IRenderProcessHandler here
IRenderProcessHandler handler = null;
//The WcfBrowserSubprocessExecutable provides BrowserSubProcess functionality
//specific to CefSharp, WCF support (required for Sync JSB) will optionally be
//enabled if the CefSharpArguments.WcfEnabledArgument command line arg is present
//For .Net Core use BrowserSubprocessExecutable as there is no WCF support
var browserProcessExe = new WcfBrowserSubprocessExecutable();
var result = browserProcessExe.Main(args, handler);
Debug.WriteLine("BrowserSubprocess shutting down.");
return result;
}
}
}

View file

@ -0,0 +1,35 @@
// 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.
using System.Diagnostics;
using CefSharp.RenderProcess;
namespace CefSharp.BrowserSubprocess
{
/// <summary>
/// When implementing your own BrowserSubprocess
/// - For .Net Core use <see cref="BrowserSubprocessExecutable"/> (No WCF Support)
/// - Include an app.manifest with the dpi/compatability sections, this is required (this project contains the relevant).
/// - If you are targeting x86/Win32 then you should set /LargeAddressAware (https://docs.microsoft.com/en-us/cpp/build/reference/largeaddressaware?view=vs-2017)
/// </summary>
public class Program
{
public static int Main(string[] args)
{
Debug.WriteLine("BrowserSubprocess starting up with command line: " + string.Join("\n", args));
//Add your own custom implementation of IRenderProcessHandler here
IRenderProcessHandler handler = null;
//The BrowserSubprocessExecutable provides BrowserSubProcess functionality
//specific to CefSharp there is no WCF support used for the sync JSB feature.
var browserProcessExe = new BrowserSubprocessExecutable();
var result = browserProcessExe.Main(args, handler);
Debug.WriteLine("BrowserSubprocess shutting down.");
return result;
}
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using CefSharp;
[assembly: AssemblyTitle("CefSharp.BrowserSubprocess")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyCompany(AssemblyInfo.AssemblyCompany)]
[assembly: AssemblyProduct(AssemblyInfo.AssemblyProduct)]
[assembly: AssemblyCopyright(AssemblyInfo.AssemblyCopyright)]
[assembly: ComVisible(AssemblyInfo.ComVisible)]
[assembly: AssemblyVersion(AssemblyInfo.AssemblyVersion)]
[assembly: AssemblyFileVersion(AssemblyInfo.AssemblyFileVersion)]
[assembly: CLSCompliant(AssemblyInfo.ClsCompliant)]

View file

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5.2", FrameworkDisplayName = ".NET Framework 4.5.2")]

View file

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5.2", FrameworkDisplayName = ".NET Framework 4.5.2")]

View file

@ -0,0 +1,30 @@
// 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.
#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("CefSharp.Core.Runtime")];
[assembly:AssemblyDescription("CefSharp Core Runtime Library (VC++)")];
[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:AssemblyConfiguration("")];
[assembly:AssemblyTrademark("")];
[assembly:AssemblyCulture("")];
[assembly:InternalsVisibleTo(AssemblyInfo::CefSharpBrowserSubprocessCoreProject)];
[assembly:InternalsVisibleTo(AssemblyInfo::CefSharpBrowserSubprocessProject)];
[assembly:InternalsVisibleTo(AssemblyInfo::CefSharpTestProject)];

View file

@ -0,0 +1,366 @@
// 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 "include\internal\cef_types_wrappers.h"
namespace CefSharp
{
namespace Core
{
/// <summary>
/// Browser initialization settings. Specify NULL or 0 to get the recommended
/// default values. The consequences of using custom values may not be well
/// tested. Many of these and other settings can also configured using command-
/// line switches.
/// </summary>
[System::ComponentModel::EditorBrowsableAttribute(System::ComponentModel::EditorBrowsableState::Never)]
public ref class BrowserSettings : IBrowserSettings
{
private:
bool _isDisposed = false;
bool _ownsPointer = false;
bool _autoDispose = false;
internal:
CefBrowserSettings* _browserSettings;
/// <summary>
/// Internal Constructor
/// </summary>
BrowserSettings(CefBrowserSettings* browserSettings)
{
_browserSettings = browserSettings;
}
public:
/// <summary>
/// Default Constructor
/// </summary>
BrowserSettings() : _browserSettings(new CefBrowserSettings())
{
_ownsPointer = true;
}
BrowserSettings(bool autoDispose) : _browserSettings(new CefBrowserSettings())
{
_ownsPointer = true;
_autoDispose = autoDispose;
}
/// <summary>
/// Finalizer.
/// </summary>
!BrowserSettings()
{
if (_ownsPointer)
{
delete _browserSettings;
}
_browserSettings = nullptr;
_isDisposed = true;
}
/// <summary>
/// Destructor.
/// </summary>
~BrowserSettings()
{
this->!BrowserSettings();
}
/// <summary>
/// StandardFontFamily
/// </summary>
virtual property String^ StandardFontFamily
{
String^ get() { return StringUtils::ToClr(_browserSettings->standard_font_family); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_browserSettings->standard_font_family, value); }
}
/// <summary>
/// FixedFontFamily
/// </summary>
virtual property String^ FixedFontFamily
{
String^ get() { return StringUtils::ToClr(_browserSettings->fixed_font_family); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_browserSettings->fixed_font_family, value); }
}
/// <summary>
/// SerifFontFamily
/// </summary>
virtual property String^ SerifFontFamily
{
String^ get() { return StringUtils::ToClr(_browserSettings->serif_font_family); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_browserSettings->serif_font_family, value); }
}
/// <summary>
/// SansSerifFontFamily
/// </summary>
virtual property String^ SansSerifFontFamily
{
String^ get() { return StringUtils::ToClr(_browserSettings->sans_serif_font_family); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_browserSettings->sans_serif_font_family, value); }
}
/// <summary>
/// CursiveFontFamily
/// </summary>
virtual property String^ CursiveFontFamily
{
String^ get() { return StringUtils::ToClr(_browserSettings->cursive_font_family); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_browserSettings->cursive_font_family, value); }
}
/// <summary>
/// FantasyFontFamily
/// </summary>
virtual property String^ FantasyFontFamily
{
String^ get() { return StringUtils::ToClr(_browserSettings->fantasy_font_family); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_browserSettings->fantasy_font_family, value); }
}
/// <summary>
/// DefaultFontSize
/// </summary>
virtual property int DefaultFontSize
{
int get() { return _browserSettings->default_font_size; }
void set(int value) { _browserSettings->default_font_size = value; }
}
/// <summary>
/// DefaultFixedFontSize
/// </summary>
virtual property int DefaultFixedFontSize
{
int get() { return _browserSettings->default_fixed_font_size; }
void set(int value) { _browserSettings->default_fixed_font_size = value; }
}
/// <summary>
/// MinimumFontSize
/// </summary>
virtual property int MinimumFontSize
{
int get() { return _browserSettings->minimum_font_size; }
void set(int value) { _browserSettings->minimum_font_size = value; }
}
/// <summary>
/// MinimumLogicalFontSize
/// </summary>
virtual property int MinimumLogicalFontSize
{
int get() { return _browserSettings->minimum_logical_font_size; }
void set(int value) { _browserSettings->minimum_logical_font_size = value; }
}
/// <summary>
/// Default encoding for Web content. If empty "ISO-8859-1" will be used. Also
/// configurable using the "default-encoding" command-line switch.
/// </summary>
virtual property String^ DefaultEncoding
{
String^ get() { return StringUtils::ToClr(_browserSettings->default_encoding); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_browserSettings->default_encoding, value); }
}
/// <summary>
/// Controls the loading of fonts from remote sources. Also configurable using
/// the "disable-remote-fonts" command-line switch.
/// </summary>
virtual property CefState RemoteFonts
{
CefState get() { return (CefState)_browserSettings->remote_fonts; }
void set(CefState value) { _browserSettings->remote_fonts = (cef_state_t)value; }
}
/// <summary>
/// Controls whether JavaScript can be executed. (Used to Enable/Disable javascript)
/// Also configurable using the "disable-javascript" command-line switch.
/// </summary>
virtual property CefState Javascript
{
CefState get() { return (CefState)_browserSettings->javascript; }
void set(CefState value) { _browserSettings->javascript = (cef_state_t)value; }
}
/// <summary>
/// Controls whether JavaScript can be used to close windows that were not
/// opened via JavaScript. JavaScript can still be used to close windows that
/// were opened via JavaScript. Also configurable using the
/// "disable-javascript-close-windows" command-line switch.
/// </summary>
virtual property CefState JavascriptCloseWindows
{
CefState get() { return (CefState)_browserSettings->javascript_close_windows; }
void set(CefState value) { _browserSettings->javascript_close_windows = (cef_state_t)value; }
}
/// <summary>
/// Controls whether JavaScript can access the clipboard. Also configurable
/// using the "disable-javascript-access-clipboard" command-line switch.
/// </summary>
virtual property CefState JavascriptAccessClipboard
{
CefState get() { return (CefState)_browserSettings->javascript_access_clipboard; }
void set(CefState value) { _browserSettings->javascript_access_clipboard = (cef_state_t)value; }
}
/// <summary>
/// Controls whether DOM pasting is supported in the editor via
/// execCommand("paste"). The |javascript_access_clipboard| setting must also
/// be enabled. Also configurable using the "disable-javascript-dom-paste"
/// command-line switch.
/// </summary>
virtual property CefState JavascriptDomPaste
{
CefState get() { return (CefState)_browserSettings->javascript_dom_paste; }
void set(CefState value) { _browserSettings->javascript_dom_paste = (cef_state_t)value; }
}
/// <summary>
/// Controls whether image URLs will be loaded from the network. A cached image
/// will still be rendered if requested. Also configurable using the
/// "disable-image-loading" command-line switch.
/// </summary>
virtual property CefState ImageLoading
{
CefState get() { return (CefState)_browserSettings->image_loading; }
void set(CefState value) { _browserSettings->image_loading = (cef_state_t)value; }
}
/// <summary>
/// Controls whether standalone images will be shrunk to fit the page. Also
/// configurable using the "image-shrink-standalone-to-fit" command-line
/// switch.
/// </summary>
virtual property CefState ImageShrinkStandaloneToFit
{
CefState get() { return (CefState)_browserSettings->image_shrink_standalone_to_fit; }
void set(CefState value) { _browserSettings->image_shrink_standalone_to_fit = (cef_state_t)value; }
}
/// <summary>
/// Controls whether text areas can be resized. Also configurable using the
/// "disable-text-area-resize" command-line switch.
/// </summary>
virtual property CefState TextAreaResize
{
CefState get() { return (CefState)_browserSettings->text_area_resize; }
void set(CefState value) { _browserSettings->text_area_resize = (cef_state_t)value; }
}
/// <summary>
/// Controls whether the tab key can advance focus to links. Also configurable
/// using the "disable-tab-to-links" command-line switch.
/// </summary>
virtual property CefState TabToLinks
{
CefState get() { return (CefState)_browserSettings->tab_to_links; }
void set(CefState value) { _browserSettings->tab_to_links = (cef_state_t)value; }
}
/// <summary>
/// Controls whether local storage can be used. Also configurable using the
/// "disable-local-storage" command-line switch.
/// </summary>
virtual property CefState LocalStorage
{
CefState get() { return (CefState)_browserSettings->local_storage; }
void set(CefState value) { _browserSettings->local_storage = (cef_state_t)value; }
}
/// <summary>
/// Controls whether databases can be used. Also configurable using the
/// "disable-databases" command-line switch.
/// </summary>
virtual property CefState Databases
{
CefState get() { return (CefState)_browserSettings->databases; }
void set(CefState value) { _browserSettings->databases = (cef_state_t)value; }
}
/// <summary>
/// Controls whether WebGL can be used. Note that WebGL requires hardware
/// support and may not work on all systems even when enabled. Also
/// configurable using the "disable-webgl" command-line switch.
/// </summary>
virtual property CefState WebGl
{
CefState get() { return (CefState)_browserSettings->webgl; }
void set(CefState value) { _browserSettings->webgl = (cef_state_t)value; }
}
/// <summary>
/// Background color used for the browser before a document is loaded and when no document color
/// is specified. The alpha component must be either fully opaque (0xFF) or fully transparent (0x00).
/// If the alpha component is fully opaque then the RGB components will be used as the background
/// color. If the alpha component is fully transparent for a WinForms browser then the
/// CefSettings.BackgroundColor value will be used. If the alpha component is fully transparent
/// for a windowless (WPF/OffScreen) browser then transparent painting will be enabled.
/// </summary>
virtual property uint32 BackgroundColor
{
uint32 get() { return _browserSettings->background_color; }
void set(uint32 value) { _browserSettings->background_color = value; }
}
/// <summary>
/// Comma delimited ordered list of language codes without any whitespace that
/// will be used in the "Accept-Language" HTTP header. May be overridden on a
/// per-browser basis using the CefBrowserSettings.AcceptLanguageList value.
/// If both values are empty then "en-US,en" will be used. Can be overridden
/// for individual RequestContext instances via the
/// RequestContextSettings.AcceptLanguageList value.
/// </summary>
virtual property String^ AcceptLanguageList
{
String^ get() { return StringUtils::ToClr(_browserSettings->accept_language_list); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_browserSettings->accept_language_list, value); }
}
/// <summary>
/// The maximum rate in frames per second (fps) that CefRenderHandler::OnPaint
/// will be called for a windowless browser. The actual fps may be lower if
/// the browser cannot generate frames at the requested rate. The minimum
/// value is 1 and the maximum value is 60 (default 30). This value can also be
/// changed dynamically via IBrowserHost.SetWindowlessFrameRate.
/// </summary>
virtual property int WindowlessFrameRate
{
int get() { return _browserSettings->windowless_frame_rate; }
void set(int value) { _browserSettings->windowless_frame_rate = value; }
}
/// <summary>
/// Gets a value indicating if the browser settings has been disposed.
/// </summary>
virtual property bool IsDisposed
{
bool get() { return _isDisposed; }
}
/// <summary>
/// True if dispose should be called after this object is used
/// </summary>
virtual property bool AutoDispose
{
bool get() { return _autoDispose; }
}
virtual IBrowserSettings^ UnWrap()
{
return this;
}
};
}
}

View file

@ -0,0 +1,909 @@
// 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.
#ifndef CEFSHARP_CORE_CEF_H_
#define CEFSHARP_CORE_CEF_H_
#pragma once
#include "Stdafx.h"
#include <msclr/lock.h>
#include <msclr/marshal.h>
#include <include/cef_version.h>
#include <include/cef_origin_whitelist.h>
#include <include/cef_crash_util.h>
#include <include/cef_parser.h>
#include <include/cef_task.h>
#include <include/internal/cef_types.h>
#include "Internals/CefSharpApp.h"
#include "Internals/CefTaskScheduler.h"
#include "Internals/CefTaskDelegate.h"
#include "CookieManager.h"
#include "CefSettingsBase.h"
#include "RequestContext.h"
using namespace System::Collections::Generic;
using namespace System::Linq;
using namespace System::Reflection;
using namespace msclr::interop;
namespace CefSharp
{
namespace Core
{
/// <summary>
/// Global CEF methods are exposed through this class. e.g. CefInitalize maps to Cef.Initialize
/// CEF API Doc https://magpcss.org/ceforum/apidocs3/projects/(default)/(_globals).html
/// This class cannot be inherited.
/// </summary>
[System::ComponentModel::EditorBrowsableAttribute(System::ComponentModel::EditorBrowsableState::Never)]
public ref class Cef sealed
{
private:
static Object^ _sync;
static bool _initialized = false;
static bool _hasShutdown = false;
static HashSet<IDisposable^>^ _disposables;
static int _initializedThreadId;
static bool _multiThreadedMessageLoop = true;
static bool _waitForBrowsersToCloseEnabled = false;
static Cef()
{
_sync = gcnew Object();
_disposables = gcnew HashSet<IDisposable^>();
}
static bool CurrentOnUiThread()
{
return CefCurrentlyOn(CefThreadId::TID_UI);
}
public:
static property TaskFactory^ UIThreadTaskFactory;
static property TaskFactory^ IOThreadTaskFactory;
static property TaskFactory^ FileThreadTaskFactory;
static void AddDisposable(IDisposable^ item)
{
msclr::lock l(_sync);
_disposables->Add(item);
}
static void RemoveDisposable(IDisposable^ item)
{
msclr::lock l(_sync);
_disposables->Remove(item);
}
/// <summary>Gets a value that indicates whether CefSharp is initialized.</summary>
/// <value>true if CefSharp is initialized; otherwise, false.</value>
static property bool IsInitialized
{
bool get()
{
return _initialized;
}
}
/// <summary>Gets a value that indicates whether CefSharp was shutdown.</summary>
/// <value>true if CefSharp was shutdown; otherwise, false.</value>
static property bool IsShutdown
{
bool get()
{
return _hasShutdown;
}
}
/// <summary>Gets a value that indicates the version of CefSharp currently being used.</summary>
/// <value>The CefSharp version.</value>
static property String^ CefSharpVersion
{
String^ get()
{
Assembly^ assembly = Assembly::GetAssembly(Cef::typeid);
return assembly->GetName()->Version->ToString();
}
}
/// <summary>Gets a value that indicates the CEF version currently being used.</summary>
/// <value>The CEF Version</value>
static property String^ CefVersion
{
String^ get()
{
return String::Format("r{0}", CEF_VERSION);
}
}
/// <summary>Gets a value that indicates the Chromium version currently being used.</summary>
/// <value>The Chromium version.</value>
static property String^ ChromiumVersion
{
String^ get()
{
// Need explicit cast here to avoid C4965 warning when the minor version is zero.
return String::Format("{0}.{1}.{2}.{3}",
CHROME_VERSION_MAJOR, (Object^)CHROME_VERSION_MINOR,
CHROME_VERSION_BUILD, CHROME_VERSION_PATCH);
}
}
/// <summary>
/// Gets a value that indicates the Git Hash for CEF version currently being used.
/// </summary>
/// <value>The Git Commit Hash</value>
static property String^ CefCommitHash
{
String^ get()
{
return CEF_COMMIT_HASH;
}
}
/// <summary>
/// Parse the specified url into its component parts.
/// Uses a GURL to parse the Url. GURL is Google's URL parsing library.
/// </summary>
/// <param name="url">url</param>
/// <returns>Returns null if the URL is empty or invalid.</returns>
static UrlParts^ ParseUrl(String^ url)
{
if (String::IsNullOrEmpty(url))
{
return nullptr;
}
CefURLParts parts;
if (CefParseURL(StringUtils::ToNative(url), parts))
{
auto url = gcnew UrlParts();
url->Fragment = StringUtils::ToClr(parts.fragment);
url->Host = StringUtils::ToClr(parts.host);
url->Origin = StringUtils::ToClr(parts.origin);
url->Password = StringUtils::ToClr(parts.password);
url->Path = StringUtils::ToClr(parts.path);
url->Query = StringUtils::ToClr(parts.query);
url->Scheme = StringUtils::ToClr(parts.scheme);
url->Spec = StringUtils::ToClr(parts.spec);
url->Username = StringUtils::ToClr(parts.username);
auto portString = StringUtils::ToClr(parts.port);
if (!String::IsNullOrEmpty(portString))
{
int port = 0;
if (int::TryParse(portString, port))
{
url->Port = port;
}
}
return url;
}
return nullptr;
}
/// <summary>
/// Initializes CefSharp with user-provided settings.
/// It's important to note that Initialize and Shutdown <strong>MUST</strong> be called on your main
/// application thread (typically the UI thread). If you call them on different
/// threads, your application will hang. See the documentation for Cef.Shutdown() for more details.
/// </summary>
/// <param name="cefSettings">CefSharp configuration settings.</param>
/// <returns>true if successful; otherwise, false.</returns>
static bool Initialize(CefSettingsBase^ cefSettings)
{
auto cefApp = gcnew DefaultApp(nullptr, cefSettings->CefCustomSchemes);
return Initialize(cefSettings, false, cefApp);
}
/// <summary>
/// Initializes CefSharp with user-provided settings.
/// It's important to note that Initialize/Shutdown <strong>MUST</strong> be called on your main
/// application thread (typically the UI thread). If you call them on different
/// threads, your application will hang. See the documentation for Cef.Shutdown() for more details.
/// </summary>
/// <param name="cefSettings">CefSharp configuration settings.</param>
/// <param name="performDependencyCheck">Check that all relevant dependencies avaliable, throws exception if any are missing</param>
/// <returns>true if successful; otherwise, false.</returns>
static bool Initialize(CefSettingsBase^ cefSettings, bool performDependencyCheck)
{
auto cefApp = gcnew DefaultApp(nullptr, cefSettings->CefCustomSchemes);
return Initialize(cefSettings, performDependencyCheck, cefApp);
}
/// <summary>
/// Initializes CefSharp with user-provided settings.
/// It's important to note that Initialize/Shutdown <strong>MUST</strong> be called on your main
/// applicaiton thread (Typically the UI thead). If you call them on different
/// threads, your application will hang. See the documentation for Cef.Shutdown() for more details.
/// </summary>
/// <param name="cefSettings">CefSharp configuration settings.</param>
/// <param name="performDependencyCheck">Check that all relevant dependencies avaliable, throws exception if any are missing</param>
/// <param name="browserProcessHandler">The handler for functionality specific to the browser process. Null if you don't wish to handle these events</param>
/// <returns>true if successful; otherwise, false.</returns>
static bool Initialize(CefSettingsBase^ cefSettings, bool performDependencyCheck, IBrowserProcessHandler^ browserProcessHandler)
{
auto cefApp = gcnew DefaultApp(browserProcessHandler, cefSettings->CefCustomSchemes);
return Initialize(cefSettings, performDependencyCheck, cefApp);
}
/// <summary>
/// Initializes CefSharp with user-provided settings.
/// It's important to note that Initialize/Shutdown <strong>MUST</strong> be called on your main
/// application thread (typically the UI thread). If you call them on different
/// threads, your application will hang. See the documentation for Cef.Shutdown() for more details.
/// </summary>
/// <param name="cefSettings">CefSharp configuration settings.</param>
/// <param name="performDependencyCheck">Check that all relevant dependencies avaliable, throws exception if any are missing</param>
/// <param name="cefApp">Implement this interface to provide handler implementations. Null if you don't wish to handle these events</param>
/// <returns>true if successful; otherwise, false.</returns>
static bool Initialize(CefSettingsBase^ cefSettings, bool performDependencyCheck, IApp^ cefApp)
{
if (_initialized)
{
// NOTE: Can only initialize Cef once, to make this explicitly clear throw exception on subsiquent attempts
throw gcnew Exception("Cef.Initialize can only be called once per process. This is a limitation of the underlying " +
"CEF/Chromium framework. You can change many (not all) settings at runtime through RequestContext.SetPreference. " +
"See https://github.com/cefsharp/CefSharp/wiki/General-Usage#request-context-browser-isolation " +
"Use Cef.IsInitialized to check if Cef.Initialize has already been called to avoid this exception. " +
"If you are seeing this unexpectedly then you are likely " +
"calling Cef.Initialize after you've created an instance of ChromiumWebBrowser, it must be called before the first instance is created.");
}
if (_hasShutdown)
{
// NOTE: CefShutdown has already been called.
throw gcnew Exception("Cef.Shutdown has already been called. Cef.Initialize can only be called once per process. " +
"This is a limitation of the underlying CEF/Chromium framework. Calling Cef.Initialize after Cef.Shutdown is not supported. "
"You can change many (not all) settings at runtime through RequestContext.SetPreference." +
"See https://github.com/cefsharp/CefSharp/wiki/General-Usage#request-context-browser-isolation");
}
//Empty string is acceptable, the main application executable will be used
if (cefSettings->BrowserSubprocessPath == nullptr)
{
throw gcnew Exception("CefSettings BrowserSubprocessPath cannot be null.");
}
PathCheck::AssertAbsolute(cefSettings->RootCachePath, "CefSettings.RootCachePath");
PathCheck::AssertAbsolute(cefSettings->CachePath, "CefSettings.CachePath");
PathCheck::AssertAbsolute(cefSettings->LocalesDirPath, "CefSettings.LocalesDirPath");
PathCheck::AssertAbsolute(cefSettings->BrowserSubprocessPath, "CefSettings.BrowserSubprocessPath");
if (performDependencyCheck)
{
DependencyChecker::AssertAllDependenciesPresent(cefSettings->Locale, cefSettings->LocalesDirPath, cefSettings->ResourcesDirPath, cefSettings->PackLoadingDisabled, cefSettings->BrowserSubprocessPath);
}
else if (!File::Exists(cefSettings->BrowserSubprocessPath))
{
throw gcnew FileNotFoundException("CefSettings.BrowserSubprocessPath not found.", cefSettings->BrowserSubprocessPath);
}
UIThreadTaskFactory = gcnew TaskFactory(gcnew CefTaskScheduler(TID_UI));
IOThreadTaskFactory = gcnew TaskFactory(gcnew CefTaskScheduler(TID_IO));
FileThreadTaskFactory = gcnew TaskFactory(gcnew CefTaskScheduler(TID_FILE_BACKGROUND));
//Allows us to execute Tasks on the CEF UI thread in CefSharp.dll
CefThread::Initialize(UIThreadTaskFactory, gcnew Func<bool>(&CurrentOnUiThread));
//To allow FolderSchemeHandlerFactory to access GetMimeType we pass in a Func
CefSharp::SchemeHandler::FolderSchemeHandlerFactory::GetMimeTypeDelegate = gcnew Func<String^, String^>(&GetMimeType);
CefRefPtr<CefSharpApp> app(new CefSharpApp(cefSettings->ExternalMessagePump,
cefSettings->CommandLineArgsDisabled,
cefSettings->CefCommandLineArgs,
cefSettings->CefCustomSchemes,
cefApp));
CefMainArgs main_args;
CefSettings settings = *(cefSettings->_cefSettings);
auto success = CefInitialize(main_args, settings, app.get(), nullptr);
if (!success)
{
CefSharp::Internals::GlobalContextInitialized::SetResult(false);
}
_initialized = success;
_multiThreadedMessageLoop = cefSettings->MultiThreadedMessageLoop;
_initializedThreadId = Thread::CurrentThread->ManagedThreadId;
//We took a copy of CefSettings earlier, now we set our pointer to nullptr
delete cefSettings;
return success;
}
/// <summary>
/// Run the CEF message loop. Use this function instead of an application-
/// provided message loop to get the best balance between performance and CPU
/// usage. This function should only be called on the main application thread and
/// only if Cef.Initialize() is called with a
/// CefSettings.MultiThreadedMessageLoop value of false. This function will
/// block until a quit message is received by the system.
/// </summary>
static void RunMessageLoop()
{
CefRunMessageLoop();
}
/// <summary>
/// Quit the CEF message loop that was started by calling Cef.RunMessageLoop().
/// This function should only be called on the main application thread and only
/// if Cef.RunMessageLoop() was used.
/// </summary>
static void QuitMessageLoop()
{
CefQuitMessageLoop();
}
/// <summary>
/// Perform a single iteration of CEF message loop processing.This function is
/// provided for cases where the CEF message loop must be integrated into an
/// existing application message loop. Use of this function is not recommended
/// for most users; use CefSettings.MultiThreadedMessageLoop if possible (the default).
/// When using this function care must be taken to balance performance
/// against excessive CPU usage. It is recommended to enable the
/// CefSettings.ExternalMessagePump option when using
/// this function so that IBrowserProcessHandler.OnScheduleMessagePumpWork()
/// callbacks can facilitate the scheduling process. This function should only be
/// called on the main application thread and only if Cef.Initialize() is called
/// with a CefSettings.MultiThreadedMessageLoop value of false. This function
/// will not block.
/// </summary>
static void DoMessageLoopWork()
{
CefDoMessageLoopWork();
}
/// <summary>
/// This function should be called from the application entry point function to execute a secondary process.
/// It can be used to run secondary processes from the browser client executable (default behavior) or
/// from a separate executable specified by the CefSettings.browser_subprocess_path value.
/// 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.
/// The |application| parameter may be empty. The |windows_sandbox_info| parameter is only used on Windows and may be NULL (see cef_sandbox_win.h for details).
/// </summary>
static int ExecuteProcess()
{
auto hInstance = Process::GetCurrentProcess()->Handle;
CefMainArgs cefMainArgs((HINSTANCE)hInstance.ToPointer());
//TODO: Look at ways to expose an instance of CefApp
//CefRefPtr<CefSharpApp> app(new CefSharpApp(nullptr, nullptr));
return CefExecuteProcess(cefMainArgs, nullptr, nullptr);
}
/// <summary>Add an entry to the cross-origin whitelist.</summary>
/// <param name="sourceOrigin">The origin allowed to be accessed by the target protocol/domain.</param>
/// <param name="targetProtocol">The target protocol allowed to access the source origin.</param>
/// <param name="targetDomain">The optional target domain allowed to access the source origin.</param>
/// <param name="allowTargetSubdomains">If set to true would allow a blah.example.com if the
/// <paramref name="targetDomain"/> was set to example.com
/// </param>
/// <returns>Returns false if is invalid or the whitelist cannot be accessed.</returns>
/// <remarks>
/// The same-origin policy restricts how scripts hosted from different origins
/// (scheme + domain + port) can communicate. By default, scripts can only access
/// resources with the same origin. Scripts hosted on the HTTP and HTTPS schemes
/// (but no other schemes) can use the "Access-Control-Allow-Origin" header to
/// allow cross-origin requests. For example, https://source.example.com can make
/// XMLHttpRequest requests on http://target.example.com if the
/// http://target.example.com request returns an "Access-Control-Allow-Origin:
/// https://source.example.com" response header.
//
/// Scripts in separate frames or iframes and hosted from the same protocol and
/// domain suffix can execute cross-origin JavaScript if both pages set the
/// document.domain value to the same domain suffix. For example,
/// scheme://foo.example.com and scheme://bar.example.com can communicate using
/// JavaScript if both domains set document.domain="example.com".
//
/// This method is used to allow access to origins that would otherwise violate
/// the same-origin policy. Scripts hosted underneath the fully qualified
/// <paramref name="sourceOrigin"/> URL (like http://www.example.com) will be allowed access to
/// all resources hosted on the specified <paramref name="targetProtocol"/> and <paramref name="targetDomain"/>.
/// If <paramref name="targetDomain"/> is non-empty and <paramref name="allowTargetSubdomains"/> if false only
/// exact domain matches will be allowed. If <paramref name="targetDomain"/> contains a top-
/// level domain component (like "example.com") and <paramref name="allowTargetSubdomains"/> is
/// true sub-domain matches will be allowed. If <paramref name="targetDomain"/> is empty and
/// <paramref name="allowTargetSubdomains"/> if true all domains and IP addresses will be
/// allowed.
//
/// This method cannot be used to bypass the restrictions on local or display
/// isolated schemes. See the comments on <see cref="CefCustomScheme"/> for more
/// information.
///
/// This function may be called on any thread. Returns false if <paramref name="sourceOrigin"/>
/// is invalid or the whitelist cannot be accessed.
/// </remarks>
static bool AddCrossOriginWhitelistEntry(
String^ sourceOrigin,
String^ targetProtocol,
String^ targetDomain,
bool allowTargetSubdomains)
{
return CefAddCrossOriginWhitelistEntry(
StringUtils::ToNative(sourceOrigin),
StringUtils::ToNative(targetProtocol),
StringUtils::ToNative(targetDomain),
allowTargetSubdomains);
}
/// <summary>Remove entry from cross-origin whitelist</summary>
/// <param name="sourceOrigin">The origin allowed to be accessed by the target protocol/domain.</param>
/// <param name="targetProtocol">The target protocol allowed to access the source origin.</param>
/// <param name="targetDomain">The optional target domain allowed to access the source origin.</param>
/// <param name="allowTargetSubdomains">If set to true would allow a blah.example.com if the
/// <paramref name="targetDomain"/> was set to example.com
/// </param>
/// <remarks>
/// Remove an entry from the cross-origin access whitelist. Returns false if
/// <paramref name="sourceOrigin"/> is invalid or the whitelist cannot be accessed.
/// </remarks>
static bool RemoveCrossOriginWhitelistEntry(String^ sourceOrigin,
String^ targetProtocol,
String^ targetDomain,
bool allowTargetSubdomains)
{
return CefRemoveCrossOriginWhitelistEntry(
StringUtils::ToNative(sourceOrigin),
StringUtils::ToNative(targetProtocol),
StringUtils::ToNative(targetDomain),
allowTargetSubdomains);
}
/// <summary>Remove all entries from the cross-origin access whitelist.</summary>
/// <remarks>
/// Remove all entries from the cross-origin access whitelist. Returns false if
/// the whitelist cannot be accessed.
/// </remarks>
static bool ClearCrossOriginWhitelist()
{
return CefClearCrossOriginWhitelist();
}
/// <summary>
/// Returns the global cookie manager. By default data will be stored at CefSettings.CachePath if specified or in memory otherwise.
/// Using this method is equivalent to calling Cef.GetGlobalRequestContext().GetCookieManager()
/// The cookie managers storage is created in an async fashion, whilst this method may return a cookie manager instance,
/// there may be a short delay before you can Get/Write cookies.
/// To be sure the cookie manager has been initialized use one of the following
/// - Use the GetGlobalCookieManager(ICompletionCallback) overload and access the ICookieManager after
/// ICompletionCallback.OnComplete has been called.
/// - Access the ICookieManager instance in IBrowserProcessHandler.OnContextInitialized.
/// - Use the ChromiumWebBrowser BrowserInitialized (OffScreen) or IsBrowserInitializedChanged (WinForms/WPF) events.
/// </summary>
/// <returns>A the global cookie manager or null if the RequestContext has not yet been initialized.</returns>
static ICookieManager^ GetGlobalCookieManager()
{
return GetGlobalCookieManager(nullptr);
}
/// <summary>
/// Returns the global cookie manager. By default data will be stored at CefSettings.CachePath if specified or in memory otherwise.
/// Using this method is equivalent to calling Cef.GetGlobalRequestContext().GetCookieManager()
/// The cookie managers storage is created in an async fashion, whilst this method may return a cookie manager instance,
/// there may be a short delay before you can Get/Write cookies.
/// To be sure the cookie manager has been initialized use one of the following
/// - Access the ICookieManager after ICompletionCallback.OnComplete has been called
/// - Access the ICookieManager instance in IBrowserProcessHandler.OnContextInitialized.
/// - Use the ChromiumWebBrowser BrowserInitialized (OffScreen) or IsBrowserInitializedChanged (WinForms/WPF) events.
/// </summary>
/// <param name="callback">If non-NULL it will be executed asnychronously on the CEF UI thread after the manager's storage has been initialized.</param>
/// <returns>A the global cookie manager or null if the RequestContext has not yet been initialized.</returns>
static ICookieManager^ GetGlobalCookieManager(ICompletionCallback^ callback)
{
CefRefPtr<CefCompletionCallback> c = callback == nullptr ? nullptr : new CefCompletionCallbackAdapter(callback);
auto cookieManager = CefCookieManager::GetGlobalManager(c);
if (cookieManager.get())
{
return gcnew CookieManager(cookieManager);
}
return nullptr;
}
/// <summary>
/// Called prior to calling Cef.Shutdown, this diposes of any remaning
/// ChromiumWebBrowser instances. In WPF this is used from Dispatcher.ShutdownStarted
/// to release the unmanaged resources held by the ChromiumWebBrowser instances.
/// Generally speaking you don't need to call this yourself.
/// </summary>
static void PreShutdown()
{
msclr::lock l(_sync);
for each(IDisposable^ diposable in Enumerable::ToList(_disposables))
{
delete diposable;
}
_disposables->Clear();
GC::Collect();
GC::WaitForPendingFinalizers();
}
/// <summary>
/// Shuts down CefSharp and the underlying CEF infrastructure. This method is safe to call multiple times; it will only
/// shut down CEF on the first call (all subsequent calls will be ignored).
/// This method should be called on the main application thread to shut down the CEF browser process before the application exits.
/// If you are Using CefSharp.OffScreen then you must call this explicitly before your application exits or it will hang.
/// This method must be called on the same thread as Initialize. If you don't call Shutdown explicitly then CefSharp.Wpf and CefSharp.WinForms
/// versions will do their best to call Shutdown for you, if your application is having trouble closing then call thus explicitly.
/// </summary>
static void Shutdown()
{
if (_initialized)
{
msclr::lock l(_sync);
if (_initialized)
{
if (_initializedThreadId != Thread::CurrentThread->ManagedThreadId)
{
throw gcnew Exception("Cef.Shutdown must be called on the same thread that Cef.Initialize was called - typically your UI thread. " +
"If you called Cef.Initialize on a Thread other than the UI thread then you will need to call Cef.Shutdown on the same thread. " +
"Cef.Initialize was called on ManagedThreadId: " + _initializedThreadId + " where Cef.Shutdown is being called on " +
"ManagedThreadId: " + Thread::CurrentThread->ManagedThreadId);
}
UIThreadTaskFactory = nullptr;
IOThreadTaskFactory = nullptr;
FileThreadTaskFactory = nullptr;
CefThread::Shutdown();
for each(IDisposable^ diposable in Enumerable::ToList(_disposables))
{
delete diposable;
}
GC::Collect();
GC::WaitForPendingFinalizers();
if (!_multiThreadedMessageLoop)
{
// We need to run the message pump until it is idle. However we don't have
// that information here so we run the message loop "for a while".
// See https://github.com/cztomczak/cefpython/issues/245 for an excellent description
for (int i = 0; i < 10; i++)
{
DoMessageLoopWork();
// Sleep to allow the CEF proc to do work.
Sleep(50);
}
}
CefShutdown();
_initialized = false;
_hasShutdown = true;
}
}
}
/// <summary>
/// This method should only be used by advanced users, if you're unsure then use Cef.Shutdown().
/// This function should be called on the main application thread to shut down
/// the CEF browser process before the application exits. This method simply obtains a lock
/// and calls the native CefShutdown method, only IsInitialized is checked. All ChromiumWebBrowser
/// instances MUST be Disposed of before calling this method. If calling this method results in a crash
/// or hangs then you're likely hanging on to some unmanaged resources or haven't closed all of your browser
/// instances
/// </summary>
static void ShutdownWithoutChecks()
{
if (_initialized)
{
msclr::lock l(_sync);
if (_initialized)
{
CefShutdown();
_initialized = false;
_hasShutdown = true;
}
}
}
/// <summary>
/// Clear all scheme handler factories registered with the global request context.
/// Returns false on error. This function may be called on any thread in the browser process.
/// Using this function is equivalent to calling Cef.GetGlobalRequestContext().ClearSchemeHandlerFactories().
/// </summary>
/// <returns>Returns false on error.</returns>
static bool ClearSchemeHandlerFactories()
{
return CefClearSchemeHandlerFactories();
}
/// <summary>
/// Returns true if called on the specified CEF thread.
/// </summary>
/// <returns>Returns true if called on the specified thread.</returns>
static bool CurrentlyOnThread(CefThreadIds threadId)
{
return CefCurrentlyOn((CefThreadId)threadId);
}
/// <summary>
/// Gets the Global Request Context. Make sure to Dispose of this object when finished.
/// The earlier possible place to access the IRequestContext is in IBrowserProcessHandler.OnContextInitialized.
/// Alternative use the ChromiumWebBrowser BrowserInitialized (OffScreen) or IsBrowserInitializedChanged (WinForms/WPF) events.
/// </summary>
/// <returns>Returns the global request context or null if the RequestContext has not been initialized yet.</returns>
static IRequestContext^ GetGlobalRequestContext()
{
auto context = CefRequestContext::GetGlobalContext();
if (context.get())
{
return gcnew RequestContext(context);
}
return nullptr;
}
/// <summary>
/// Helper function (wrapper around the CefColorSetARGB macro) which combines
/// the 4 color components into an uint32 for use with BackgroundColor property
/// </summary>
/// <param name="a">Alpha</param>
/// <param name="r">Red</param>
/// <param name="g">Green</param>
/// <param name="b">Blue</param>
/// <returns>Returns the color.</returns>
static uint32 ColorSetARGB(uint32 a, uint32 r, uint32 g, uint32 b)
{
return CefColorSetARGB(a, r, g, b);
}
/// <summary>
/// Crash reporting is configured using an INI-style config file named
/// crash_reporter.cfg. This file must be placed next to
/// the main application executable. File contents are as follows:
///
/// # Comments start with a hash character and must be on their own line.
///
/// [Config]
/// ProductName=&lt;Value of the &quot;prod&quot; crash key; defaults to &quot;cef&quot;&gt;
/// ProductVersion=&lt;Value of the &quot;ver&quot; crash key; defaults to the CEF version&gt;
/// AppName=&lt;Windows only; App-specific folder name component for storing crash
/// information; default to &quot;CEF&quot;&gt;
/// ExternalHandler=&lt;Windows only; Name of the external handler exe to use
/// instead of re-launching the main exe; default to empty>
/// ServerURL=&lt;crash server URL; default to empty&gt;
/// RateLimitEnabled=&lt;True if uploads should be rate limited; default to true&gt;
/// MaxUploadsPerDay=&lt;Max uploads per 24 hours, used if rate limit is enabled;
/// default to 5&gt;
/// MaxDatabaseSizeInMb=&lt;Total crash report disk usage greater than this value
/// will cause older reports to be deleted; default to 20&gt;
/// MaxDatabaseAgeInDays=&lt;Crash reports older than this value will be deleted;
/// default to 5&gt;
///
/// [CrashKeys]
/// my_key1=&lt;small|medium|large&gt;
/// my_key2=&lt;small|medium|large&gt;
///
/// Config section:
///
/// If &quot;ProductName&quot; and/or &quot;ProductVersion&quot; are set then the specified values
/// will be included in the crash dump metadata.
///
/// If &quot;AppName&quot; is set on Windows then crash report information (metrics,
/// database and dumps) will be stored locally on disk under the
/// &quot;C:\Users\[CurrentUser]\AppData\Local\[AppName]\User Data&quot; folder.
///
/// If &quot;ExternalHandler&quot; is set on Windows then the specified exe will be
/// launched as the crashpad-handler instead of re-launching the main process
/// exe. The value can be an absolute path or a path relative to the main exe
/// directory.
///
/// If &quot;ServerURL&quot; is set then crashes will be uploaded as a multi-part POST
/// request to the specified URL. Otherwise, reports will only be stored locally
/// on disk.
///
/// If &quot;RateLimitEnabled&quot; is set to true then crash report uploads will be rate
/// limited as follows:
/// 1. If &quot;MaxUploadsPerDay&quot; is set to a positive value then at most the
/// specified number of crashes will be uploaded in each 24 hour period.
/// 2. If crash upload fails due to a network or server error then an
/// incremental backoff delay up to a maximum of 24 hours will be applied for
/// retries.
/// 3. If a backoff delay is applied and &quot;MaxUploadsPerDay&quot; is > 1 then the
/// &quot;MaxUploadsPerDay&quot; value will be reduced to 1 until the client is
/// restarted. This helps to avoid an upload flood when the network or
/// server error is resolved.
///
/// If &quot;MaxDatabaseSizeInMb&quot; is set to a positive value then crash report storage
/// on disk will be limited to that size in megabytes. For example, on Windows
/// each dump is about 600KB so a &quot;MaxDatabaseSizeInMb&quot; value of 20 equates to
/// about 34 crash reports stored on disk.
///
/// If &quot;MaxDatabaseAgeInDays&quot; is set to a positive value then crash reports older
/// than the specified age in days will be deleted.
///
/// CrashKeys section:
///
/// Any number of crash keys can be specified for use by the application. Crash
/// key values will be truncated based on the specified size (small = 63 bytes,
/// medium = 252 bytes, large = 1008 bytes). The value of crash keys can be set
/// from any thread or process using the Cef.SetCrashKeyValue function. These
/// key/value pairs will be sent to the crash server along with the crash dump
/// file. Medium and large values will be chunked for submission. For example,
/// if your key is named &quot;mykey&quot; then the value will be broken into ordered
/// chunks and submitted using keys named &quot;mykey-1&quot;, &quot;mykey-2&quot;, etc.
/// </summary>
/// <returns>Returns true if crash reporting is enabled.</returns>
static property bool CrashReportingEnabled
{
bool get()
{
return CefCrashReportingEnabled();
}
}
/// <summary>
/// Sets or clears a specific key-value pair from the crash metadata.
/// </summary>
static void SetCrashKeyValue(String^ key, String^ value)
{
CefSetCrashKeyValue(StringUtils::ToNative(key), StringUtils::ToNative(value));
}
static int GetMinLogLevel()
{
return cef_get_min_log_level();
}
/// <summary>
/// Returns the mime type for the specified file extension or an empty string if unknown.
/// </summary>
/// <param name="extension">file extension</param>
/// <returns>Returns the mime type for the specified file extension or an empty string if unknown.</returns>
static String^ GetMimeType(String^ extension)
{
if (extension == nullptr)
{
throw gcnew ArgumentNullException("extension");
}
if (extension->StartsWith("."))
{
extension = extension->Substring(1, extension->Length - 1);
}
auto mimeType = StringUtils::ToClr(CefGetMimeType(StringUtils::ToNative(extension)));
//Lookup to see if we have a custom mapping
//MimeTypeMapping::GetCustomMapping will Fallback
//to application/octet-stream if no mapping found
if (String::IsNullOrEmpty(mimeType))
{
return MimeTypeMapping::GetCustomMapping(extension);
}
return mimeType;
}
/// <summary>
/// WaitForBrowsersToClose is not enabled by default, call this method
/// before Cef.Initialize to enable. If you aren't calling Cef.Initialize
/// explicitly then this should be called before creating your first
/// ChromiumWebBrowser instance.
/// </summary>
static void EnableWaitForBrowsersToClose()
{
if (_waitForBrowsersToCloseEnabled)
{
return;
}
if (_initialized)
{
throw gcnew Exception("Must be enabled before Cef.Initialize is called. ");
}
_waitForBrowsersToCloseEnabled = true;
BrowserRefCounter::Instance = gcnew BrowserRefCounter();
}
/// <summary>
/// Helper method to ensure all ChromiumWebBrowser instances have been
/// closed/disposed, should be called before Cef.Shutdown.
/// Disposes all remaning ChromiumWebBrowser instances
/// then waits for CEF to release it's remaning CefBrowser instances.
/// Finally a small delay of 50ms to allow for CEF to finish it's cleanup.
/// Should only be called when MultiThreadedMessageLoop = true;
/// (Hasn't been tested when when CEF integrates into main message loop).
/// </summary>
static void WaitForBrowsersToClose()
{
WaitForBrowsersToClose(750);
}
/// <summary>
/// Helper method to ensure all ChromiumWebBrowser instances have been
/// closed/disposed, should be called before Cef.Shutdown.
/// Disposes all remaning ChromiumWebBrowser instances
/// then waits for CEF to release it's remaning CefBrowser instances.
/// Finally a small delay of 50ms to allow for CEF to finish it's cleanup.
/// Should only be called when MultiThreadedMessageLoop = true;
/// (Hasn't been tested when when CEF integrates into main message loop).
/// </summary>
/// <param name="timeoutInMiliseconds">The timeout in miliseconds.</param>
static void WaitForBrowsersToClose(int timeoutInMiliseconds)
{
if (!_waitForBrowsersToCloseEnabled)
{
throw gcnew Exception("This feature is currently disabled. Call Cef.EnableWaitForBrowsersToClose before calling Cef.Initialize to enable.");
}
//Dispose of any remaining browser instances
for each(IDisposable^ diposable in Enumerable::ToList(_disposables))
{
delete diposable;
}
//Clear the list as we've disposed of them all now.
_disposables->Clear();
//Wait for the browsers to close
BrowserRefCounter::Instance->WaitForBrowsersToClose(timeoutInMiliseconds);
//A few extra ms to allow for CEF to finish
Thread::Sleep(50);
}
/// <summary>
/// Post an action for delayed execution on the specified thread.
/// </summary>
/// <param name="threadId">thread id</param>
/// <param name="action">action to execute</param>
/// <param name="delayInMs">delay in ms</param>
/// <returns>bool</returns>
static bool PostDelayedAction(CefThreadIds threadId, Action^ action, int delayInMs)
{
auto task = new CefTaskDelegate(action);
return CefPostDelayedTask((cef_thread_id_t)threadId, task, delayInMs);
}
/// <summary>
/// Post an action for execution on the specified thread.
/// </summary>
/// <param name="threadId">thread id</param>
/// <param name="action">action to execute</param>
/// <returns>bool</returns>
static bool PostAction(CefThreadIds threadId, Action^ action)
{
auto task = new CefTaskDelegate(action);
return CefPostTask((cef_thread_id_t)threadId, task);
}
};
}
}
#endif // CEFSHARP_CORE_CEF_H_

View file

@ -0,0 +1,407 @@
// 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"
using namespace System::Collections::Generic;
using namespace System::IO;
namespace CefSharp
{
namespace Core
{
/// <summary>
/// Initialization settings. Many of these and other settings can also configured using command-line switches.
/// WPF/WinForms/OffScreen each have their own CefSettings implementation that sets
/// relevant settings e.g. OffScreen starts with audio muted.
/// </summary>
[System::ComponentModel::EditorBrowsableAttribute(System::ComponentModel::EditorBrowsableState::Never)]
public ref class CefSettingsBase sealed
{
private:
/// <summary>
/// Command Line Arguments Dictionary.
/// </summary>
CommandLineArgDictionary^ _cefCommandLineArgs;
internal:
/// <summary>
/// CefSettings unmanaged pointer
/// </summary>
::CefSettings* _cefSettings;
/// <summary>
/// CefCustomScheme collection
/// </summary>
List<CefCustomScheme^>^ _cefCustomSchemes;
public:
/// <summary>
/// Default Constructor.
/// </summary>
CefSettingsBase() : _cefSettings(new ::CefSettings())
{
_cefSettings->multi_threaded_message_loop = true;
_cefSettings->no_sandbox = true;
BrowserSubprocessPath = Path::Combine(Path::GetDirectoryName(CefSettingsBase::typeid->Assembly->Location), "CefSharp.BrowserSubprocess.exe");
_cefCustomSchemes = gcnew List<CefCustomScheme^>();
_cefCommandLineArgs = gcnew CommandLineArgDictionary();
}
/// <summary>
/// Finalizer.
/// </summary>
!CefSettingsBase()
{
_cefSettings = nullptr;
}
/// <summary>
/// Destructor.
/// </summary>
~CefSettingsBase()
{
this->!CefSettingsBase();
}
/// <summary>
/// Add Customs schemes to this collection.
/// </summary>
property IEnumerable<CefCustomScheme^>^ CefCustomSchemes
{
IEnumerable<CefCustomScheme^>^ get() { return _cefCustomSchemes; }
}
/// <summary>
/// Add custom command line argumens to this collection, they will be added in OnBeforeCommandLineProcessing. The
/// CefSettings.CommandLineArgsDisabled value can be used to start with an empty command-line object. Any values specified in
/// CefSettings that equate to command-line arguments will be set before this method is called.
/// </summary>
property CommandLineArgDictionary^ CefCommandLineArgs
{
CommandLineArgDictionary^ get() { return _cefCommandLineArgs; }
}
/// <summary>
/// **Experimental**
/// Set to true to enable use of the Chrome runtime in CEF. This feature is
/// considered experimental and is not recommended for most users at this time.
/// See issue https://github.com/chromiumembedded/cef/issues/2969
/// </summary>
property bool ChromeRuntime
{
bool get() { return _cefSettings->chrome_runtime == 1; }
void set(bool value) { _cefSettings->chrome_runtime = value; }
}
/// <summary>
/// Set to true to disable configuration of browser process features using standard CEF and Chromium command-line arguments.
/// Configuration can still be specified using CEF data structures or by adding to CefCommandLineArgs.
/// </summary>
property bool CommandLineArgsDisabled
{
bool get() { return _cefSettings->command_line_args_disabled == 1; }
void set(bool value) { _cefSettings->command_line_args_disabled = value; }
}
/// <summary>
/// Set to true to control browser process main (UI) thread message pump scheduling via the
/// IBrowserProcessHandler.OnScheduleMessagePumpWork callback. This option is recommended for use in combination with the
/// Cef.DoMessageLoopWork() function in cases where the CEF message loop must be integrated into an existing application message
/// loop (see additional comments and warnings on Cef.DoMessageLoopWork). Enabling this option is not recommended for most users;
/// leave this option disabled and use either MultiThreadedMessageLoop (the default) if possible.
/// </summary>
property bool ExternalMessagePump
{
bool get() { return _cefSettings->external_message_pump == 1; }
void set(bool value) { _cefSettings->external_message_pump = value; }
}
/// <summary>
/// Set to true to have the browser process message loop run in a separate thread. If false than the CefDoMessageLoopWork()
/// function must be called from your application message loop. This option is only supported on Windows. The default value is
/// true.
/// </summary>
property bool MultiThreadedMessageLoop
{
bool get() { return _cefSettings->multi_threaded_message_loop == 1; }
void set(bool value) { _cefSettings->multi_threaded_message_loop = value; }
}
/// <summary>
/// The path to a separate executable that will be launched for sub-processes. By default the browser process executable is used.
/// See the comments on Cef.ExecuteProcess() for details. If this value is non-empty then it must be an absolute path.
/// Also configurable using the "browser-subprocess-path" command-line switch.
/// Defaults to using the provided CefSharp.BrowserSubprocess.exe instance
/// </summary>
property String^ BrowserSubprocessPath
{
String^ get() { return StringUtils::ToClr(_cefSettings->browser_subprocess_path); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->browser_subprocess_path, value); }
}
/// <summary>
/// The location where data for the global browser cache will be stored on disk. In this value is non-empty then it must be
/// an absolute path that is must be either equal to or a child directory of CefSettings.RootCachePath (if RootCachePath is
/// empty it will default to this value). If the value is empty then browsers will be created in "incognito mode" where
/// in-memory caches are used for storage and no data is persisted to disk. HTML5 databases such as localStorage will only
/// persist across sessions if a cache path is specified. Can be overridden for individual RequestContext instances via the
/// RequestContextSettings.CachePath value.
/// </summary>
property String^ CachePath
{
String^ get() { return StringUtils::ToClr(_cefSettings->cache_path); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->cache_path, value); }
}
/// <summary>
/// The root directory that all CefSettings.CachePath and RequestContextSettings.CachePath values must have in common. If this
/// value is empty and CefSettings.CachePath is non-empty then it will default to the CefSettings.CachePath value.
/// If this value is non-empty then it must be an absolute path. Failure to set this value correctly may result in the sandbox
/// blocking read/write access to the CachePath directory. NOTE: CefSharp does not implement the CHROMIUM SANDBOX. A non-empty
/// RootCachePath can be used in conjuncation with an empty CefSettings.CachePath in instances where you would like browsers
/// attached to the Global RequestContext (the default) created in "incognito mode" and instances created with a custom
/// RequestContext using a disk based cache.
/// </summary>
property String^ RootCachePath
{
String^ get() { return StringUtils::ToClr(_cefSettings->root_cache_path); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->root_cache_path, value); }
}
/// <summary>
/// The location where user data such as the Widevine CDM module and spell checking dictionary files will be stored on disk.
/// If this value is empty then "Local Settings\Application Data\CEF\User Data" directory under the user profile directory
/// will be used. If this value is non-empty then it must be an absolute path.
/// </summary>
property String^ UserDataPath
{
String^ get() { return StringUtils::ToClr(_cefSettings->user_data_path); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->user_data_path, value); }
}
/// <summary>
/// The locale string that will be passed to WebKit. If empty the default locale of "en-US" will be used. Also configurable using
/// the "lang" command-line switch.
/// </summary>
property String^ Locale
{
String^ get() { return StringUtils::ToClr(_cefSettings->locale); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->locale, value); }
}
/// <summary>
/// The fully qualified path for the locales directory. If this value is empty the locales directory must be located in the
/// module directory. If this value is non-empty then it must be an absolute path. Also configurable using the "locales-dir-path"
/// command-line switch.
/// </summary>
property String^ LocalesDirPath
{
String^ get() { return StringUtils::ToClr(_cefSettings->locales_dir_path); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->locales_dir_path, value); }
}
/// <summary>
/// The fully qualified path for the resources directory. If this value is empty the cef.pak and/or devtools_resources.pak files
/// must be located in the module directory. Also configurable using the "resources-dir-path" command-line switch.
/// </summary>
property String^ ResourcesDirPath
{
String^ get() { return StringUtils::ToClr(_cefSettings->resources_dir_path); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->resources_dir_path, value); }
}
/// <summary>
/// The directory and file name to use for the debug log. If empty a default log file name and location will be used. On Windows
/// a "debug.log" file will be written in the main executable directory. Also configurable using the"log-file" command- line
/// switch.
/// </summary>
property String^ LogFile
{
String^ get() { return StringUtils::ToClr(_cefSettings->log_file); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->log_file, value); }
}
/// <summary>
/// The log severity. Only messages of this severity level or higher will be logged. When set to
/// <see cref="CefSharp::LogSeverity::Disable"/> no messages will be written to the log file, but Fatal messages will still be
/// output to stderr. Also configurable using the "log-severity" command-line switch with a value of "verbose", "info", "warning",
/// "error", "fatal", "error-report" or "disable".
/// </summary>
property CefSharp::LogSeverity LogSeverity
{
CefSharp::LogSeverity get() { return (CefSharp::LogSeverity)_cefSettings->log_severity; }
void set(CefSharp::LogSeverity value) { _cefSettings->log_severity = (cef_log_severity_t)value; }
}
/// <summary>
/// Custom flags that will be used when initializing the V8 JavaScript engine. The consequences of using custom flags may not be
/// well tested. Also configurable using the "js-flags" command-line switch.
/// </summary>
property String^ JavascriptFlags
{
String^ get() { return StringUtils::ToClr(_cefSettings->javascript_flags); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->javascript_flags, value); }
}
/// <summary>
/// Set to true to disable loading of pack files for resources and locales. A resource bundle handler must be provided for the
/// browser and render processes via CefApp::GetResourceBundleHandler() if loading of pack files is disabled. Also configurable
/// using the "disable-pack-loading" command- line switch.
/// </summary>
property bool PackLoadingDisabled
{
bool get() { return _cefSettings->pack_loading_disabled == 1; }
void set(bool value) { _cefSettings->pack_loading_disabled = value; }
}
/// <summary>
/// Value that will be inserted as the product portion of the default User-Agent string. If empty the Chromium product version
/// will be used. If UserAgent is specified this value will be ignored. Also configurable using the "user-agent-product" command-
/// line switch.
/// </summary>
property String^ UserAgentProduct
{
String^ get() { return StringUtils::ToClr(_cefSettings->user_agent_product); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->user_agent_product, value); }
}
/// <summary>
/// Set to a value between 1024 and 65535 to enable remote debugging on the specified port. For example, if 8080 is specified the
/// remote debugging URL will be http://localhost:8080. CEF can be remotely debugged from any CEF or Chrome browser window. Also
/// configurable using the "remote-debugging-port" command-line switch.
/// </summary>
property int RemoteDebuggingPort
{
int get() { return _cefSettings->remote_debugging_port; }
void set(int value) { _cefSettings->remote_debugging_port = value; }
}
/// <summary>
/// The number of stack trace frames to capture for uncaught exceptions. Specify a positive value to enable the
/// CefRenderProcessHandler:: OnUncaughtException() callback. Specify 0 (default value) and OnUncaughtException() will not be
/// called. Also configurable using the "uncaught-exception-stack-size" command-line switch.
/// </summary>
property int UncaughtExceptionStackSize
{
int get() { return _cefSettings->uncaught_exception_stack_size; }
void set(int value) { _cefSettings->uncaught_exception_stack_size = value; }
}
/// <summary>
/// Value that will be returned as the User-Agent HTTP header. If empty the default User-Agent string will be used. Also
/// configurable using the "user-agent" command-line switch.
/// </summary>
property String^ UserAgent
{
String^ get() { return StringUtils::ToClr(_cefSettings->user_agent); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->user_agent, value); }
}
/// <summary>
/// Set to true (1) to enable windowless (off-screen) rendering support. Do not enable this value if the application does not use
/// windowless rendering as it may reduce rendering performance on some systems.
/// </summary>
property bool WindowlessRenderingEnabled
{
bool get() { return _cefSettings->windowless_rendering_enabled == 1; }
void set(bool value) { _cefSettings->windowless_rendering_enabled = value; }
}
/// <summary>
/// To persist session cookies (cookies without an expiry date or validity interval) by default when using the global cookie
/// manager set this value to true. Session cookies are generally intended to be transient and most Web browsers do not persist
/// them. A CachePath value must also be specified to enable this feature. Also configurable using the "persist-session-cookies"
/// command-line switch. Can be overridden for individual RequestContext instances via the
/// RequestContextSettings.PersistSessionCookies value.
/// </summary>
property bool PersistSessionCookies
{
bool get() { return _cefSettings->persist_session_cookies == 1; }
void set(bool value) { _cefSettings->persist_session_cookies = value; }
}
/// <summary>
/// To persist user preferences as a JSON file in the cache path directory set this value to true. A CachePath value must also be
/// specified to enable this feature. Also configurable using the "persist-user-preferences" command-line switch. Can be
/// overridden for individual RequestContext instances via the RequestContextSettings.PersistUserPreferences value.
/// </summary>
property bool PersistUserPreferences
{
bool get() { return _cefSettings->persist_user_preferences == 1; }
void set(bool value) { _cefSettings->persist_user_preferences = value; }
}
/// <summary>
/// Comma delimited ordered list of language codes without any whitespace that will be used in the "Accept-Language" HTTP header.
/// May be set globally using the CefSettings.AcceptLanguageList value. If both values are empty then "en-US,en" will be used.
///
/// </summary>
property String^ AcceptLanguageList
{
String^ get() { return StringUtils::ToClr(_cefSettings->accept_language_list); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->accept_language_list, value); }
}
/// <summary>
/// Background color used for the browser before a document is loaded and when no document color is specified. The alpha
/// component must be either fully opaque (0xFF) or fully transparent (0x00). If the alpha component is fully opaque then the RGB
/// components will be used as the background color. If the alpha component is fully transparent for a WinForms browser then the
/// default value of opaque white be used. If the alpha component is fully transparent for a windowless (WPF/OffScreen) browser
/// then transparent painting will be enabled.
/// </summary>
property uint32 BackgroundColor
{
uint32 get() { return _cefSettings->background_color; }
void set(uint32 value) { _cefSettings->background_color = value; }
}
/// <summary>
/// Comma delimited list of schemes supported by the associated
/// ICookieManager. If CookieableSchemesExcludeDefaults is false the
/// default schemes ("http", "https", "ws" and "wss") will also be supported.
/// Specifying a CookieableSchemesList value and setting
/// CookieableSchemesExcludeDefaults to true will disable all loading
/// and saving of cookies for this manager. Can be overridden
/// for individual RequestContext instances via the
/// RequestContextSettings.CookieableSchemesList and
/// RequestContextSettings.CookieableSchemesExcludeDefaults values.
/// </summary>
property String^ CookieableSchemesList
{
String^ get() { return StringUtils::ToClr(_cefSettings->cookieable_schemes_list); }
void set(String^ value) { StringUtils::AssignNativeFromClr(_cefSettings->cookieable_schemes_list, value); }
}
/// <summary>
/// If CookieableSchemesExcludeDefaults is false the
/// default schemes ("http", "https", "ws" and "wss") will also be supported.
/// Specifying a CookieableSchemesList value and setting
/// CookieableSchemesExcludeDefaults to true will disable all loading
/// and saving of cookies for this manager. Can be overridden
/// for individual RequestContext instances via the
/// RequestContextSettings.CookieableSchemesList and
/// RequestContextSettings.CookieableSchemesExcludeDefaults values.
/// </summary>
property bool CookieableSchemesExcludeDefaults
{
bool get() { return _cefSettings->cookieable_schemes_exclude_defaults == 1; }
void set(bool value) { _cefSettings->cookieable_schemes_exclude_defaults = value; }
}
/// <summary>
/// Registers a custom scheme using the provided settings.
/// </summary>
/// <param name="cefCustomScheme">The CefCustomScheme which provides the details about the scheme.</param>
void RegisterScheme(CefCustomScheme^ cefCustomScheme)
{
//Scheme names are converted to lowercase
cefCustomScheme->SchemeName = cefCustomScheme->SchemeName->ToLower();
_cefCustomSchemes->Add(cefCustomScheme);
}
};
}
}

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