diff --git a/CefSharp.BrowserSubprocess/CefSharp.BrowserSubprocess.csproj b/CefSharp.BrowserSubprocess/CefSharp.BrowserSubprocess.csproj
index feb97392d1..ba872a98f0 100644
--- a/CefSharp.BrowserSubprocess/CefSharp.BrowserSubprocess.csproj
+++ b/CefSharp.BrowserSubprocess/CefSharp.BrowserSubprocess.csproj
@@ -70,6 +70,7 @@
+
@@ -78,6 +79,8 @@
+
+
diff --git a/CefSharp.BrowserSubprocess/JavascriptProxy.cs b/CefSharp.BrowserSubprocess/JavascriptProxy.cs
new file mode 100644
index 0000000000..27f3ab8900
--- /dev/null
+++ b/CefSharp.BrowserSubprocess/JavascriptProxy.cs
@@ -0,0 +1,18 @@
+using CefSharp.Internals.JavascriptBinding;
+using System;
+
+namespace CefSharp.BrowserSubprocess
+{
+ internal class JavascriptProxy : IJavascriptProxy
+ {
+ public const String BaseAddress = "net.pipe://localhost";
+ public const String ServiceName = "JavaScriptProxy";
+ public const String Address = BaseAddress + "/" + ServiceName;
+
+ public object EvaluateScript(int frameId, string script, double timeout)
+ {
+ var cefFrame = SubprocessCefApp.Instance.CefBrowserWrapper.GetFrame(frameId);
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess/JavascriptServiceHost.cs b/CefSharp.BrowserSubprocess/JavascriptServiceHost.cs
new file mode 100644
index 0000000000..8930eca2a6
--- /dev/null
+++ b/CefSharp.BrowserSubprocess/JavascriptServiceHost.cs
@@ -0,0 +1,51 @@
+using CefSharp.Internals.JavascriptBinding;
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Description;
+
+namespace CefSharp.BrowserSubprocess
+{
+ internal class JavascriptServiceHost
+ {
+ public static void Create(int browserId)
+ {
+ var uris = new[]
+ {
+ new Uri(JavascriptProxy.BaseAddress)
+ };
+
+ var host = new ServiceHost(typeof(JavascriptProxy), uris);
+ AddDebugBehavior(host);
+
+ // TODO: Include the name of the "parent process" here also, so you can run more than one CefSharp-based application
+ // TODO: simultaneously. :)
+ var serviceName = JavascriptProxy.ServiceName + "_" + browserId;
+
+ host.AddServiceEndpoint(
+ typeof(IJavascriptProxy),
+ new NetNamedPipeBinding(),
+ serviceName
+ );
+
+ host.Open();
+ }
+
+ private static void AddDebugBehavior(ServiceHostBase host)
+ {
+ var serviceDebugBehavior = host.Description.Behaviors.Find();
+
+ if (serviceDebugBehavior == null)
+ {
+ serviceDebugBehavior = new ServiceDebugBehavior
+ {
+ IncludeExceptionDetailInFaults = true
+ };
+ host.Description.Behaviors.Add(serviceDebugBehavior);
+ }
+ else
+ {
+ serviceDebugBehavior.IncludeExceptionDetailInFaults = true;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/CefSharp.BrowserSubprocess/Program.cs b/CefSharp.BrowserSubprocess/Program.cs
index bac6820ca7..fdcabc3899 100644
--- a/CefSharp.BrowserSubprocess/Program.cs
+++ b/CefSharp.BrowserSubprocess/Program.cs
@@ -15,7 +15,7 @@ static int Main(string[] args)
{
var hInstance = Process.GetCurrentProcess().Handle;
LogCommandLine(args);
- //MessageBox.Show("Please attach debugger now");
+ MessageBox.Show("Please attach debugger now", null, MessageBoxButtons.OK, MessageBoxIcon.Information);
return ExecuteCefRenderProcess(hInstance);
}
@@ -27,7 +27,7 @@ private static void LogCommandLine(string[] args)
private static int ExecuteCefRenderProcess(IntPtr hInstance)
{
- var subprocessCefApp = new SubprocessCefApp();
+ var subprocessCefApp = SubprocessCefApp.Instance;
return GlobalMethods.CefExecuteProcess(hInstance, subprocessCefApp);
}
}
diff --git a/CefSharp.BrowserSubprocess/SubprocessCefApp.cs b/CefSharp.BrowserSubprocess/SubprocessCefApp.cs
index b0031d46c3..9e38238d7b 100644
--- a/CefSharp.BrowserSubprocess/SubprocessCefApp.cs
+++ b/CefSharp.BrowserSubprocess/SubprocessCefApp.cs
@@ -4,5 +4,19 @@ namespace CefSharp.BrowserSubprocess
{
internal class SubprocessCefApp : CefAppWrapper
{
+ private static SubprocessCefApp instance;
+
+ public static SubprocessCefApp Instance
+ {
+ get { return instance ?? (instance = new SubprocessCefApp()); }
+ }
+
+ public CefBrowserWrapper CefBrowserWrapper { get; private set; }
+
+ public override void OnBrowserCreated(CefBrowserWrapper cefBrowserWrapper)
+ {
+ CefBrowserWrapper = cefBrowserWrapper;
+ JavascriptServiceHost.Create(cefBrowserWrapper.BrowserId);
+ }
}
}
\ No newline at end of file
diff --git a/CefSharp/CefSharp.vcxproj b/CefSharp/CefSharp.vcxproj
index 361e48717e..5eb23949bd 100644
--- a/CefSharp/CefSharp.vcxproj
+++ b/CefSharp/CefSharp.vcxproj
@@ -279,6 +279,7 @@
+
diff --git a/CefSharp/CefSharp.vcxproj.filters b/CefSharp/CefSharp.vcxproj.filters
index 27f433f5b8..af6f45dbbf 100644
--- a/CefSharp/CefSharp.vcxproj.filters
+++ b/CefSharp/CefSharp.vcxproj.filters
@@ -208,5 +208,8 @@
Header Files
+
+ Source Files\Wrappers
+
\ No newline at end of file
diff --git a/CefSharp/Wrappers/CefAppWrapper.cpp b/CefSharp/Wrappers/CefAppWrapper.cpp
index f1d989402e..887f7386e4 100644
--- a/CefSharp/Wrappers/CefAppWrapper.cpp
+++ b/CefSharp/Wrappers/CefAppWrapper.cpp
@@ -11,7 +11,7 @@ namespace CefSharp
{
CefAppWrapper::CefAppWrapper()
{
- cefApp = new CefRefPtr(new CefAppUnmanagedWrapper());
+ cefApp = new CefRefPtr(new CefAppUnmanagedWrapper(this));
}
CefAppWrapper::~CefAppWrapper()
diff --git a/CefSharp/Wrappers/CefAppWrapper.h b/CefSharp/Wrappers/CefAppWrapper.h
index 3425021f97..e65c4a01b7 100644
--- a/CefSharp/Wrappers/CefAppWrapper.h
+++ b/CefSharp/Wrappers/CefAppWrapper.h
@@ -3,16 +3,14 @@
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#include "Stdafx.h"
+#include "CefBrowserWrapper.h"
#include "include/cef_app.h"
namespace CefSharp
{
namespace Wrappers
{
- private class CefAppUnmanagedWrapper : CefApp
- {
- IMPLEMENT_REFCOUNTING(CefAppUnmanagedWrapper);
- };
+ class CefAppUnmanagedWrapper;
// TODO: Support the stuff that CefApp has. One important question is whether we go with the C++ API or make the (seemingly a bit
// strange) move to start using the C API instead. It may actually make it possible to write our code in a cleaner fashion. Worth
@@ -27,9 +25,36 @@ namespace CefSharp
CefAppWrapper();
~CefAppWrapper();
void* GetUnmanaged();
+ virtual void OnBrowserCreated(CefBrowserWrapper^ cefBrowserWrapper) {};
private:
!CefAppWrapper();
};
+
+ private class CefAppUnmanagedWrapper : CefApp, CefRenderProcessHandler
+ {
+ private:
+ gcroot _cefAppWrapper;
+ CefRefPtr _browser;
+
+ public:
+ CefAppUnmanagedWrapper(CefAppWrapper^ cefAppWrapper)
+ {
+ _cefAppWrapper = cefAppWrapper;
+ }
+
+ virtual DECL CefRefPtr GetRenderProcessHandler() OVERRIDE
+ {
+ return this;
+ }
+
+ virtual DECL void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr browser) OVERRIDE
+ {
+ // TODO: Could destroy this CefBrowserWrapper in OnBrowserDestroyed(), but it doesn't seem to be reliably called...
+ _cefAppWrapper->OnBrowserCreated(gcnew CefBrowserWrapper(browser));
+ }
+
+ IMPLEMENT_REFCOUNTING(CefAppUnmanagedWrapper);
+ };
}
}
diff --git a/CefSharp/Wrappers/CefBrowserWrapper.h b/CefSharp/Wrappers/CefBrowserWrapper.h
new file mode 100644
index 0000000000..7f8333f7c0
--- /dev/null
+++ b/CefSharp/Wrappers/CefBrowserWrapper.h
@@ -0,0 +1,75 @@
+// Copyright © 2010-2013 The CefSharp Project. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "include/cef_browser.h"
+#include "include/cef_runnable.h"
+
+using namespace System::Threading;
+
+namespace CefSharp
+{
+ namespace Wrappers
+ {
+ private class CefBrowserUnmanagedWrapper
+ {
+ CefRefPtr _cefBrowser;
+
+ public:
+ CefRefPtr Frame;
+ gcroot WaitHandle;
+
+ CefBrowserUnmanagedWrapper(CefRefPtr cefBrowser)
+ {
+ _cefBrowser = cefBrowser;
+ WaitHandle = gcnew AutoResetEvent(false);
+ }
+
+ void GetFrameCallback(int64 frameId)
+ {
+ Frame = _cefBrowser->GetFrame(frameId);
+ WaitHandle->Set();
+ }
+
+ IMPLEMENT_REFCOUNTING(CefBrowserUnmanagedWrapper);
+ };
+
+ public ref class CefBrowserWrapper
+ {
+ CefRefPtr* _cefBrowser;
+ int _browserId;
+ CefRefPtr* _unmanagedWrapper;
+
+ public:
+ property int BrowserId
+ {
+ int get() { return _browserId; }
+ private: void set(int value) { _browserId = value; }
+ }
+
+ CefBrowserWrapper(CefRefPtr cefBrowser)
+ {
+ _cefBrowser = &cefBrowser;
+ _browserId = cefBrowser->GetIdentifier();
+
+ // TODO: Should be deallocated at some point to avoid leaking memory.
+ _unmanagedWrapper = new CefRefPtr(new CefBrowserUnmanagedWrapper(cefBrowser));
+ }
+
+ System::IntPtr GetFrame(long frameId)
+ {
+ // TODO: Could we do something genericly useful here using C++ lambdas? To avoid having to make a lot of of these...
+ // TODO: DON'T USE AUTORESETEVENT STUPIDITY! Even though the code below compiles & runs correctly, it deadlocks the
+ // thread from which the request came, which is very, very stupid, especially since V8 and Chromium are built
+ // with asynchrony in mind. Instead, we should re-think this API to utilize WCF callbacks instead:
+ // http://idunno.org/archive/2008/05/29/wcf-callbacks-a-beginners-guide.aspx
+ // That feels much more like 2013, and not 1994... :)
+ CefPostTask(CefThreadId::TID_RENDERER, NewCefRunnableMethod(_unmanagedWrapper->get(), &CefBrowserUnmanagedWrapper::GetFrameCallback, frameId));
+ _unmanagedWrapper->get()->WaitHandle->WaitOne();
+
+ // TODO: Wrap in a CefFrameWrapper, obviously...
+ return (System::IntPtr)&_unmanagedWrapper->get()->Frame;
+ }
+ };
+ }
+}