Skip to content

Commit

Permalink
BrowserSubprocess - Refactor to support .Net Core
Browse files Browse the repository at this point in the history
- Added BrowserSubprocessExecutable for use with .Net Core (no WCF)
- Added WcfBrowserSubprocessExecutable for use with the existing CefSharp.BrowserSubprocess.exe which supports WCF (conditionally)
  • Loading branch information
amaitland committed Sep 6, 2019
1 parent 2d20309 commit d58b192
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 54 deletions.
79 changes: 79 additions & 0 deletions CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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"

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()
{

}

int Main(IEnumerable<String^>^ args, IRenderProcessHandler^ handler)
{
int result;
auto type = CommandLineArgsParser::GetArgumentValue(args, CefSharpArguments::SubProcessTypeArgument);

auto parentProcessId = -1;

// The Crashpad Handler doesn't have any HostProcessIdArgument, so we must not try to
// parse it lest we want an ArgumentNullException.
if (type != "crashpad-handler")
{
parentProcessId = int::Parse(CommandLineArgsParser::GetArgumentValue(args, CefSharpArguments::HostProcessIdArgument));
if (CommandLineArgsParser::HasArgument(args, CefSharpArguments::ExitIfParentProcessClosed))
{
ParentProcessMonitor::StartMonitorTask(parentProcessId);
}
}

// Use our custom subProcess provides features like EvaluateJavascript
if (type == "renderer")
{
auto subProcess = GetSubprocess(args, parentProcessId, handler);

try
{
result = subProcess->Run();
}
finally
{
delete subProcess;
}
}
else
{
result = SubProcess::ExecuteProcess(args);
}

return result;
}

protected:
virtual SubProcess^ GetSubprocess(IEnumerable<String^>^ args, int parentProcessId, IRenderProcessHandler^ handler)
{
return gcnew SubProcess(handler, args);
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,15 @@
<ClInclude Include="..\CefSharp.Core\Internals\Serialization\Primitives.h" />
<ClInclude Include="..\CefSharp.Core\Internals\StringUtils.h" />
<ClInclude Include="BindObjectAsyncHandler.h" />
<ClCompile Include="BrowserSubprocessExecutable.h" />
<ClInclude Include="SubProcessApp.h" />
<ClInclude Include="Async\JavascriptAsyncMethodCallback.h" />
<ClInclude Include="Async\JavascriptAsyncMethodHandler.h" />
<ClInclude Include="Async\JavascriptAsyncMethodWrapper.h" />
<ClInclude Include="Async\JavascriptAsyncObjectWrapper.h" />
<ClInclude Include="CefAppUnmanagedWrapper.h" />
<ClInclude Include="JavascriptPostMessageHandler.h" />
<ClCompile Include="WcfBrowserSubprocessExecutable.h" />
<ClInclude Include="Wrapper\Frame.h" />
<ClInclude Include="Wrapper\Browser.h" />
<ClInclude Include="Wrapper\V8Context.h" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@
<ClCompile Include="Wrapper\Browser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WcfBrowserSubprocessExecutable.h">
<Filter>Header Files</Filter>
</ClCompile>
<ClCompile Include="BrowserSubprocessExecutable.h">
<Filter>Header Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Resource.rc" />
Expand Down
39 changes: 39 additions & 0 deletions CefSharp.BrowserSubprocess.Core/WcfBrowserSubprocessExecutable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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
{
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);
}
};
}
}
58 changes: 4 additions & 54 deletions CefSharp.BrowserSubprocess/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using CefSharp.Internals;
using CefSharp.RenderProcess;

namespace CefSharp.BrowserSubprocess
Expand All @@ -23,63 +21,15 @@ public static int Main(string[] args)

SubProcess.EnableHighDPISupport();

int result;
var type = args.GetArgumentValue(CefSharpArguments.SubProcessTypeArgument);
//Add your own custom implementation of IRenderProcessHandler here
IRenderProcessHandler handler = null;

var parentProcessId = -1;

// The Crashpad Handler doesn't have any HostProcessIdArgument, so we must not try to
// parse it lest we want an ArgumentNullException.
if (type != "crashpad-handler")
{
parentProcessId = int.Parse(args.GetArgumentValue(CefSharpArguments.HostProcessIdArgument));
if (args.HasArgument(CefSharpArguments.ExitIfParentProcessClosed))
{
Task.Factory.StartNew(() => AwaitParentProcessExit(parentProcessId), TaskCreationOptions.LongRunning);
}
}

// Use our custom subProcess provides features like EvaluateJavascript
if (type == "renderer")
{
//Add your own custom implementation of IRenderProcessHandler here
IRenderProcessHandler handler = null;
var wcfEnabled = args.HasArgument(CefSharpArguments.WcfEnabledArgument);
var subProcess = wcfEnabled ? new WcfEnabledSubProcess(parentProcessId, handler, args) : new SubProcess(handler, args);

using (subProcess)
{
result = subProcess.Run();
}
}
else
{
result = SubProcess.ExecuteProcess(args);
}
var browserProcessExe = new WcfBrowserSubprocessExecutable();
var result = browserProcessExe.Main(args, handler);

Debug.WriteLine("BrowserSubprocess shutting down.");

return result;
}

private static async void AwaitParentProcessExit(int parentProcessId)
{
try
{
var parentProcess = Process.GetProcessById(parentProcessId);
parentProcess.WaitForExit();
}
catch (Exception e)
{
//main process probably died already
Debug.WriteLine(e);
}

await Task.Delay(1000); //wait a bit before exiting

Debug.WriteLine("BrowserSubprocess shutting down forcibly.");

Process.GetCurrentProcess().Kill();
}
}
}
1 change: 1 addition & 0 deletions CefSharp/CefSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
<Compile Include="DefaultApp.cs" />
<Compile Include="Enums\SchemeOptions.cs" />
<Compile Include="Internals\CommandLineArgDictionary.cs" />
<Compile Include="Internals\ParentProcessMonitor.cs" />
<Compile Include="Internals\ReadOnlyNameValueCollection.cs" />
<Compile Include="Internals\TaskScheduler\LimitedConcurrencyLevelTaskScheduler.cs" />
<Compile Include="ResourceRequestHandlerFactory.cs" />
Expand Down
49 changes: 49 additions & 0 deletions CefSharp/Internals/ParentProcessMonitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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.

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace CefSharp.Internals
{
/// <summary>
/// Monitor the parent process and exit if the parent process closes
/// before the subprocess. This class is used by the CefSharp.BrowserSubprocess to
/// self terminate if the parent dies without notifying it to exit.
/// See https://github.com/cefsharp/CefSharp/issues/2359 for more information.
/// </summary>
public static class ParentProcessMonitor
{
/// <summary>
/// Starts a long running task (spawns new thread) used to monitor the parent process
/// and calls <see cref="Process.Kill"/> if the parent exits unexpectedly (usually result of a crash).
/// </summary>
/// <param name="parentProcessId">process Id of the parent application</param>
public static void StartMonitorTask(int parentProcessId)
{
Task.Factory.StartNew(() => AwaitParentProcessExit(parentProcessId), TaskCreationOptions.LongRunning);
}

private static async void AwaitParentProcessExit(int parentProcessId)
{
try
{
var parentProcess = Process.GetProcessById(parentProcessId);
parentProcess.WaitForExit();
}
catch (Exception e)
{
//main process probably died already
Debug.WriteLine(e);
}

await Task.Delay(1000); //wait a bit before exiting

Debug.WriteLine("BrowserSubprocess shutting down forcibly.");

Process.GetCurrentProcess().Kill();
}
}
}

0 comments on commit d58b192

Please sign in to comment.