Page 1 of 1

Eval

Posted: Mon Jul 24, 2017 8:25 pm
by xpert13
Hello. guys.

Help me please to understand how can I use Eval method of V8Context.

First of all I need to get V8Context. When I try go use next code in main process it throw error:

Code: Select all

TCefv8ContextRef.Current.Eval(sScript, '', 1, TempValue, TempException);
The process need to be PID_BROWSER (I am right?). But how can I send message to this process and read this message?

Re: Eval

Posted: Tue Jul 25, 2017 12:08 pm
by salvadordf
Hi,

The V8 engine runs in a separate process and you would need to send and receive messages between processes to use eval.

It's much easier to use TChromium.ExecuteJavaScript to execute a JS script.

The MiniBrowser demo has all the code necessary to execute and get the results from the scripts in the Delphi form.

Re: Eval

Posted: Tue Jul 25, 2017 7:07 pm
by xpert13
It's much easier to use TChromium.ExecuteJavaScript to execute a JS script.
I know, but I need eval.
The MiniBrowser demo has all the code necessary to execute and get the results from the scripts in the Delphi form.
The MiniBrowser has too much functions and I don't understand which of them useful for me and which is not

Re: Eval

Posted: Tue Jul 25, 2017 8:57 pm
by salvadordf
Hi,

I uploaded a separate demo called JSExtension only with the JavaScript extension code.

You should be able to call TCefv8ContextRef.Current.Eval inside the extension in uTestExtension.pas and get the results in the
TJSExtensionFrm.Chromium1ProcessMessageReceived event.

The code comments explain all the steps.

Re: Eval

Posted: Thu Jul 27, 2017 6:00 pm
by xpert13
I don't need extensions but your demo code was helpful for me. The right solution in my case was:

1. Create TCefCustomRenderProcessHandler, fill MessageName and OnCustomMessage properties

Code: Select all

  FProcessHandler := TCefCustomRenderProcessHandler.Create;
  FProcessHandler.MessageName := EVAL_JS;
  FProcessHandler.OnCustomMessage := RenderProcessHandler_OnCustomMessage;
  GlobalCEFApp.RenderProcessHandler := FProcessHandler as ICefRenderProcessHandler;
2. Send to render process message with code for eval

Code: Select all

var
  msg: ICefProcessMessage;
begin
  msg := TCefProcessMessageRef.New(EVAL_JS);
  msg.ArgumentList.SetString(0, sScript);
  FChromium.SendProcessMessage(PID_RENDERER, msg);
3. Catch this message in render proccess

Code: Select all

procedure TChromiumClient.RenderProcessHandler_OnCustomMessage(const pBrowser: ICefBrowser; 
  uSourceProcess: TCefProcessId; const pMessage: ICefProcessMessage);
var
  pV8Context : ICefv8Context;
  pReturnValue : ICefv8Value;
  pException : ICefV8Exception;
begin
  if (pMessage = nil) or (pMessage.ArgumentList = nil) then exit;

  if pMessage.Name = EVAL_JS then
  begin
    pV8Context := pBrowser.MainFrame.GetV8Context;
    if pV8Context.Enter then
    begin
      pV8Context.Eval(pMessage.ArgumentList.GetString(0), '', 1, pReturnValue, pException);
      ParseEvalJsAnswer(pMessage, pBrowser, pReturnValue, pException);
      pV8Context.Exit;
    end;
  end;
end;
4. Parse the results and send message back to browser process

Code: Select all

procedure TChromiumClient.ParseEvalJsAnswer(const pMessage: ICefProcessMessage; pBrowser: ICefBrowser;
  pReturnValue : ICefv8Value; pException : ICefV8Exception);
var
  pAnswer: ICefProcessMessage;
  strResult : String;
  bGoodDataType : Boolean;
begin
  pAnswer := TCefProcessMessageRef.New(EVAL_JS);

  if (pReturnValue = nil) or (not pReturnValue.IsValid) then
  begin
    pAnswer.ArgumentList.SetBool(0, false);
    pAnswer.ArgumentList.SetString(1, pException.Message);
  end else
  begin
    bGoodDataType := True;
    if pReturnValue.IsString then strResult := pReturnValue.GetStringValue
    else if pReturnValue.IsBool   then strResult := BooleanToStr(pReturnValue.GetBoolValue)
    else if pReturnValue.IsInt    then strResult := IntToStr(pReturnValue.GetIntValue)
    else if pReturnValue.IsUInt   then strResult := IntToStr(pReturnValue.GetUIntValue)
    else if pReturnValue.IsDouble then strResult := FloatToStr(pReturnValue.GetDoubleValue)
    else bGoodDataType := False;

    if bGoodDataType then
    begin
      pAnswer.ArgumentList.SetBool(0, true);
      pAnswer.ArgumentList.SetString(1, strResult);
    end else
    begin
      pAnswer.ArgumentList.SetBool(0, false);
      pAnswer.ArgumentList.SetString(1, 'Result data type need to be string, int, uint or double!');
    end;
  end;

  pBrowser.SendProcessMessage(PID_BROWSER, pAnswer);
end;
5. And catch result message in OnProcessMessageReceived of browser process

P.S. Thank you, salvadordf, for your work and help.