2

I'm quite new in programming multi-threading and I could not understand from the xelium example how I could execute a javascript and get the return value. I have tested:

browser.GetMainFrame().ExecuteJavaScript("SetContent('my Text.')", null, 0);

the javascript is executed, but I this function don’t allow me to get the return value. I should execute the following function to get all the text the user have written in the box..

browser.GetMainFrame().ExecuteJavaScript("getContent('')", null, 0);

the function TryEval should do this…

browser.GetMainFrame().V8Context.TryEval("GetDirtyFlag", out returninformation , out exx);

But this function can’t be called from the browser, I think it must be called from the renderer? How can I do so?

I couldn’t understand the explanations about CefRenderProcessHandler and OnProcessMessageReceived.. How to register a Scriptable Object and set my javascript & parameters?

Thx for any suggestions how I could solve this!

NREZ
  • 942
  • 9
  • 13
Roland
  • 113
  • 2
  • 11
  • Take a look at my solution. It does work, I tried it, and seems more natural and structured than using a ExecuteJavaScrit and XHR combination.. – Moonwalker Aug 13 '14 at 13:38

3 Answers3

4

I have been struggling with this as well. I do not think there is a way to do this synchronously...or easily :)

Perhaps what can be done is this:

  1. From browser do sendProcessMessage with all JS information to renderer process. You can pass all kinds of parameters to this call in a structured way so encapsulating the JS method name and params in order should not be difficult to do.
  2. In renderer process (RenderProcessHandler onProcessMessageReceived method) do TryEval on the V8Context and get the return value via out parameters and sendProcessMessage back to the browser process with the JS return value (Note that this supports ordinary return semantics from your JS method).You get the browser instance reference in the onProcessMessageReceived so it is as easy as this (mixed pseudo code)

    browser.GetMainFrame().CefV8Context.tryEval(js-code,out retValue, out exception);

    process retValue;

    browser.sendProcessMessage(...);

Browser will get a callback in the WebClient in onProcessMessageReceived.

There is nothing special here in terms of setting up JS. I have for example a loaded html page with a js function in it. It takes a param as input and returns a string. in js-code parameter to TryEval I simply provide this value:

"myJSFunctionName('here I am - input param')"

It is slightly convoluted but seems like a neat workable approach - better than doing ExecuteJavaScript and posting results via XHR on custom handler in my view.

I tried this and it does work quite well indeed....and is not bad as it is all non-blocking. The wiring in the browser process needs to be done to process the response properly.

This can be extended and built into a set of classes to abstract this out for all kinds of calls..

Take a look at the Xilium demo app. Most of the necessary wiring is already there for onProcessMessage - do a global search. Look for

  1. DemoRendererProcessHandler.cs - renderer side this is where you will invoke tryEval
  2. DemoApp.cs - this is browser side, look for sendProcessMessage - this will initiate your JS invocation process.
  3. WebClient.cs - this is browser side. Here you receive messages from renderer with return value from your JS

Cheers.

Moonwalker
  • 3,462
  • 4
  • 25
  • 31
  • So basically the right order for the last three digit bullet points is 2, 1, 3 - right (then, we should correct that ;-)? – Phil Rykoff Nov 29 '14 at 09:07
  • Phil hi - I don't think it is in any particular sequential order...it simply highlights 3 areas where you could touch the code to make it work. – Moonwalker Dec 03 '14 at 09:29
1

I resolved this problem by returning the result value from my JavaScript function back to Xilium host application via an ajax call to a custom scheme handler. According to Xilium's author fddima it is the easiest way to do IPC.

You can find an example of how to implement a scheme handler in the Xilium's demo app.

Community
  • 1
  • 1
Stanislav
  • 4,389
  • 2
  • 33
  • 35
  • 1
    Personally I do not like this approach. I posted an alternative solution which is much more natural and structured in my view. – Moonwalker Aug 13 '14 at 21:08
-4

Check out this post: https://groups.google.com/forum/#!topic/cefglue/CziVAo8Ojg4

using System;
using System.Windows.Forms;
using Xilium.CefGlue;
using Xilium.CefGlue.WindowsForms;

namespace CefGlue3
{
  public partial class Form1 : Form
  {
    private CefWebBrowser browser;

    public Form1()
    {
      InitializeCef();
      InitializeComponent();
    }

    private static void InitializeCef()
    {
      CefRuntime.Load();
      CefMainArgs cefArgs = new CefMainArgs(new[] {"--force-renderer-accessibility"});
      CefApplication cefApp = new CefApplication();
      CefRuntime.ExecuteProcess(cefArgs, cefApp);
      CefSettings cefSettings = new CefSettings
      {
        SingleProcess = false, 
        MultiThreadedMessageLoop = true, 
        LogSeverity = CefLogSeverity.ErrorReport, 
        LogFile = "CefGlue.log",
      };
      CefRuntime.Initialize(cefArgs, cefSettings, cefApp);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      browser = new CefWebBrowser
      {
        Visible = true,
        //StartUrl = "http://www.google.com",
        Dock = DockStyle.Fill,
        Parent = this
      };
      Controls.Add(browser);
      browser.BrowserCreated += BrowserOnBrowserCreated;
    }

    private void BrowserOnBrowserCreated(object sender, EventArgs eventArgs)
    {
      browser.Browser.GetMainFrame().LoadUrl("http://www.google.com");
    }
  }
}

using Xilium.CefGlue;

namespace CefGlue3
{
  internal sealed class CefApplication : CefApp
  {
    protected override CefRenderProcessHandler GetRenderProcessHandler()
    {
      return new RenderProcessHandler();
    }
  }

  internal sealed class RenderProcessHandler : CefRenderProcessHandler
  {
    protected override void OnWebKitInitialized()
    {
      CefRuntime.RegisterExtension("testExtension", "var test;if (!test)test = {};(function() {test.myval = 'My Value!';})();", null);
      base.OnWebKitInitialized();
    }
  }
}