diff --git a/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h b/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h
new file mode 100644
index 0000000000..aa98156724
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/BrowserSubprocessExecutable.h
@@ -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
+ {
+ ///
+ /// BrowserSubprocessExecutable provides the fundimental browser process handling for
+ /// CefSharp.BrowserSubprocess.exe and can be used to self host the BrowserSubProcess in your
+ /// existing application (preferred approach for .Net Core).
+ ///
+ public ref class BrowserSubprocessExecutable
+ {
+ public:
+ BrowserSubprocessExecutable()
+ {
+
+ }
+
+ int Main(IEnumerable^ 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^ args, int parentProcessId, IRenderProcessHandler^ handler)
+ {
+ return gcnew SubProcess(handler, args);
+ }
+ };
+ }
+}
diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj
index bd3cc35392..aa36e21395 100644
--- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj
+++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj
@@ -173,6 +173,7 @@
+
@@ -180,6 +181,7 @@
+
diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters
index 4c402a4914..d8aee10e1e 100644
--- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters
+++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj.filters
@@ -181,6 +181,12 @@
Source Files
+
+ Header Files
+
+
+ Header Files
+
diff --git a/CefSharp.BrowserSubprocess.Core/WcfBrowserSubprocessExecutable.h b/CefSharp.BrowserSubprocess.Core/WcfBrowserSubprocessExecutable.h
new file mode 100644
index 0000000000..4fcaf246fb
--- /dev/null
+++ b/CefSharp.BrowserSubprocess.Core/WcfBrowserSubprocessExecutable.h
@@ -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^ 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);
+ }
+ };
+ }
+}
diff --git a/CefSharp.BrowserSubprocess/Program.cs b/CefSharp.BrowserSubprocess/Program.cs
index a8975d3448..30351fbbca 100644
--- a/CefSharp.BrowserSubprocess/Program.cs
+++ b/CefSharp.BrowserSubprocess/Program.cs
@@ -4,8 +4,6 @@
using System;
using System.Diagnostics;
-using System.Threading.Tasks;
-using CefSharp.Internals;
using CefSharp.RenderProcess;
namespace CefSharp.BrowserSubprocess
@@ -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();
- }
}
}
diff --git a/CefSharp/CefSharp.csproj b/CefSharp/CefSharp.csproj
index e3f2b07e73..69ee661fad 100644
--- a/CefSharp/CefSharp.csproj
+++ b/CefSharp/CefSharp.csproj
@@ -103,6 +103,7 @@
+
diff --git a/CefSharp/Internals/ParentProcessMonitor.cs b/CefSharp/Internals/ParentProcessMonitor.cs
new file mode 100644
index 0000000000..61d5def837
--- /dev/null
+++ b/CefSharp/Internals/ParentProcessMonitor.cs
@@ -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
+{
+ ///
+ /// 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.
+ ///
+ public static class ParentProcessMonitor
+ {
+ ///
+ /// Starts a long running task (spawns new thread) used to monitor the parent process
+ /// and calls if the parent exits unexpectedly (usually result of a crash).
+ ///
+ /// process Id of the parent application
+ 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();
+ }
+ }
+}