I am trying to implement a fpcef3 render process handler as a subprocess:
following the examples provided on the fpcef3 github repo, I have managed to create a render process handler subprocess:
Program subprocess;
{$mode objfpc}{$H+}
Uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
cef3lib, cef3types, cef3api, Handler;
Var
Args : TCefMainArgs;
begin
CefLoadLibrary;
CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
{$IFDEF WINDOWS}
Args.instance := HINSTANCE();
Halt(cef_execute_process(@Args, nil, nil));
{$ELSE}
Args.argc := argc;
Args.argv := argv;
Halt(cef_execute_process(@Args, nil, nil));
{$ENDIF}
end.
The TCustomRenderProcessHandler is identical to the handler provided with the JavaScript example in examples subdir:
Unit Handler;
{$MODE objfpc}{$H+}
(*
* Everything in here is called from a render process, so there is no access to GUI and all the
* data of the main process.
*)
Interface
Uses
Classes, SysUtils,
cef3types, cef3intf, cef3ref, cef3own, cef3lib;
Type
{ Custom handler for the render process }
TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn)
protected
// Test Window Bindings
procedure OnContextCreated(const browser: ICefBrowser; const frame: ICefFrame; const context: ICefv8Context); override;
// Test Extension
procedure OnWebKitInitialized; override;
end;
TMyHandler = class(TCefv8HandlerOwn)
protected
function Execute(const name: ustring; const obj: ICefv8Value;
const arguments: ICefv8ValueArray; var retval: ICefv8Value;
var exception: ustring): Boolean; override;
end;
Implementation
Var
mystr : String;
{ TMyHandler }
function TMyHandler.Execute(const name : ustring; const obj : ICefv8Value;
const arguments : ICefv8ValueArray; var retval : ICefv8Value;
var exception : ustring) : Boolean;
begin
// return a value
//retval := TCefv8ValueRef.NewString('TMyHandler');
retval := TCefv8ValueRef.NewDate(Now);
Result := True;
end;
{ TCustomRenderProcessHandler }
procedure TCustomRenderProcessHandler.OnContextCreated(const browser : ICefBrowser;
const frame : ICefFrame; const context : ICefv8Context);
Var
myWin : ICefv8Value;
args : ICefv8ValueArray;
begin
myWin := context.GetGlobal;
mystr := 'a test string';
SetLength(args, 1);
args[0] := TCefv8ValueRef.NewString(mystr);
myWin.SetValueByKey('myval', args[0], []);
end;
procedure TCustomRenderProcessHandler.OnWebKitInitialized;
Var
Code: ustring;
begin
Code :=
'var cef;'+
'if (!cef)'+
' cef = {};'+
'if (!cef.test)'+
' cef.test = {};'+
'(function() {'+
' cef.test.__defineGetter__(''test_param'', function() {'+
' native function GetTestParam();'+
' return GetTestParam();'+
' });'+
' cef.test.__defineSetter__(''test_param'', function(b) {'+
' native function SetTestParam();'+
' if(b) SetTestParam(b);'+
' });'+
' cef.test.test_object = function() {'+
' native function GetTestObject();'+
' return GetTestObject();'+
' };'+
'})();';
CefRegisterExtension('example/v8', Code, TMyHandler.Create as ICefv8Handler);
end;
end.
And finally in the main form of my master process, I am providing the path to the subprocess:
procedure TForm1.FormCreate(Sender: TObject);
begin
CefSingleProcess := False;
//CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
CefBrowserSubprocessPath := 'C:\Users\aludin\fpCEF3-master\Examples\SubProcess\subprocess64.exe'
end;
When I launch the main app, the chromium browser is displayed correctly, however the handler does not get called (I can see however that the subprocess is launched). What am I doing wrong when initializing the handler?
Thanks for your help!
OK finally figured it out and I feel like adding a couple of curse-words here after having spent so much time on this.
After having diggged a bit in the fpcef3 sources and single-stepping the main process, I realized that you need to create an ICefApp app instance and assign the custom render process handler to this app. So to simplify my life and avoid implementing the ICefApp interface, I "hijacked" the class used internally in the main process. The updated subprocess implementation is now given by the following code:
Program subprocess;
{$mode objfpc}{$H+}
Uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
cef3lib, cef3types, cef3api, cef3own, cef3intf, Handler;
Var
Args : TCefMainArgs;
app : ICefApp;
begin
CefLoadLibrary;
CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
app := TInternalApp.Create;
{$IFDEF WINDOWS}
Args.instance := HINSTANCE();
Halt(cef_execute_process(@Args, CefGetData(app), nil));
{$ELSE}
Args.argc := argc;
Args.argv := argv;
Halt(cef_execute_process(@Args, CefGetData(app), nil));
{$ENDIF}
end.
Now the ICefApp instance will use the render process handler assigned to CefRenderProcessHandler. Finally note how cef_execute_process() has been modified to take the app as an additional parameter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With