Delphi 如何在freepascal/lazarus中在子流程中实现cef3呈现流程处理程序

Delphi 如何在freepascal/lazarus中在子流程中实现cef3呈现流程处理程序,delphi,lazarus,freepascal,chromium-embedded,Delphi,Lazarus,Freepascal,Chromium Embedded,我正在尝试将fpcef3呈现进程处理程序作为子进程实现: Program subprocess; {$mode objfpc}{$H+} Uses {$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} cef3lib, cef3types, cef3api, Handler; Var Args : TCefMainArgs; begin CefLoadLibrary; CefRenderPro

我正在尝试将fpcef3呈现进程处理程序作为子进程实现:

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. 
procedure TForm1.FormCreate(Sender: TObject);
begin
  CefSingleProcess := False;

  //CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
  CefBrowserSubprocessPath := 'C:\Users\aludin\fpCEF3-master\Examples\SubProcess\subprocess64.exe'
end;     
按照fpcef3上提供的示例,我已成功创建了一个渲染进程处理程序子进程:

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. 
procedure TForm1.FormCreate(Sender: TObject);
begin
  CefSingleProcess := False;

  //CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
  CefBrowserSubprocessPath := 'C:\Users\aludin\fpCEF3-master\Examples\SubProcess\subprocess64.exe'
end;     
TCustomRenderProcessHandler
与examples subdir中JavaScript示例提供的处理程序相同:

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.
最后,在主流程的主要形式中,我提供了子流程的路径:

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. 
procedure TForm1.FormCreate(Sender: TObject);
begin
  CefSingleProcess := False;

  //CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
  CefBrowserSubprocessPath := 'C:\Users\aludin\fpCEF3-master\Examples\SubProcess\subprocess64.exe'
end;     
当我启动主应用程序时,chromium浏览器显示正确,但是没有调用处理程序(但是我可以看到子流程已启动)。初始化处理程序时我做错了什么


谢谢你的帮助

好了,我终于明白了,在花了这么多时间之后,我想在这里加上几句诅咒的话

在深入研究了fpcef3源代码并单步执行主进程后,我意识到需要创建一个ICefApp应用程序实例,并将自定义渲染进程处理程序分配给该应用程序。因此,为了简化我的生活并避免实现ICefApp接口,我“劫持”了主进程内部使用的类。更新后的子流程实现现在由以下代码给出:

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.

现在,
ICefApp
实例将使用分配给
CefRenderProcessHandler
的渲染进程处理程序。最后,请注意如何修改
cef\u execute\u process()
,将应用程序作为附加参数

@MartynA所以我检查了两个项目,它们都编译成64位的Windows EXE。我还使用了一个特定的64位CEF3。我还没有检查它是否在32位下工作,但是构建64位EXE应该不是问题(因为主进程成功加载了CEF3并显示了浏览器视图)@Martyna实际上感谢您的建议!我将尝试附加到子进程…但不知何故,我感觉渲染进程处理程序根本没有得到初始化…尝试附加到子进程,正如预期的那样,渲染处理程序的execute方法从未被调用。我怀疑主进程没有“看到”子进程渲染处理程序……因此子进程中出现了某种初始化问题。顺便说一下,我假设您已经跟踪到了cef代码,它应该加载并执行子进程。您已经这样做了,对吗?@MartynAN是的,我在CEF3初始化期间调用的CEFPinitialize函数中设置了一个断点,该函数反过来调用cef_execute_进程函数来启动子进程。这两个函数都没有返回错误。很高兴你找到了答案,+1嗨,我自己也想到了这个问题。你的解决方案似乎很有效。但是你能解释一下我们应该怎么做吗?创建
ICefApp
,分配自定义处理程序等…?@VassilisGr抱歉,我不理解您的问题?你说的另一种方式是什么意思?我的意思是“创建一个ICefApp应用程序实例,并将自定义渲染过程处理程序分配给这个应用程序”,而不使用“劫持”方法。谢谢。@VassilisGr好的,我更明白。在我发表第一篇文章后的一段时间,fpcef3的作者通过电子邮件向我指出,这种方法是正确的,我没有劫持任何东西。换句话说,您可以按原样在自己的代码中使用ICefApp。如果你愿意,我可以再查一下。