salvadordf / CEF4Delphi

CEF4Delphi is an open source project to embed Chromium-based browsers in applications made with Delphi or Lazarus/FPC for Windows, Linux and MacOS.
https://www.briskbard.com/forum/
Other
1.21k stars 372 forks source link

CEF Initialization & Finalization from a DLL problem #405

Closed hafedh-trimeche closed 2 years ago

hafedh-trimeche commented 2 years ago

Hello, Please note that I would call CEF Initialization/Finalization from DLL instead form DPR to keep Code unchanged.

library CefLoader;
{$I cef.inc}
uses
  Windows,SysUtils,DateUtils,Forms,
  uCEFConstants,uCEFApplication,uCEFChromiumWindow,uCEFChromium;
{$R *.res}
var
  LChromium : TChromium = nil;

function CefInitialize:Boolean;cdecl;
begin
  if Assigned(LChromium) then Exit(True);
  GlobalCEFApp               := TCefApplication.Create;
  GlobalCEFApp.SetCurrentDir := True;
  GlobalCEFApp.SingleProcess := True;
  GlobalCEFApp.LogFile       := 'Cef.log';
  GlobalCEFApp.LogSeverity   := LOGSEVERITY_DEBUG;
  Result                     := GlobalCEFApp.StartMainProcess;
  if Result then
  begin
    try
      LChromium := TChromium.create(nil);
    except
    end;
    Result := Assigned(LChromium);
  end;
  if Result then
  begin
    LChromium.MultiBrowserMode := False;
  end
  else
  begin
    if Assigned(LChromium) then FreeAndNil(LChromium);
    DestroyGlobalCEFApp;
  end;
end;

procedure CefFinalize;cdecl;
begin
  if Assigned(LChromium) then
  begin
    LChromium.CloseAllBrowsers;
    FreeAndNil(LChromium);
  end;
  DestroyGlobalCEFApp;
end;

function CefCreateWindow(ChromiumWindow:TChromiumWindow;SecondsTimeout:Int64=INFINITE):Boolean;cdecl;
var
  TickBegin : TDateTime;
begin
  Result := False;
  if (not Assigned(LChromium)) then Exit;
  if SecondsTimeout<10 then SecondsTimeout := 10;
  Result    := True;
  TickBegin := Now;
  while (not GlobalCEFApp.GlobalContextInitialized) do
  begin
    if SecondsBetween(Now,TickBegin)>SecondsTimeout then Exit(Result);
    Sleep(10);
    Application.ProcessMessages;
  end;
  while (not ChromiumWindow.Initialized) do
  begin
    LChromium.CreateBrowser(ChromiumWindow);
    if SecondsBetween(Now,TickBegin)>SecondsTimeout then Exit(False);
    Sleep(10);
    Application.ProcessMessages;
  end;
end;

exports
  CefInitialize   ,
  CefFinalize     ,
  CefCreateWindow ;
end.

And invoking Window creation from the Min Form:

unit Main;
{$I ReleaseDebug.inc}
interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, cefvcl,
  uCEFChromiumCore, uCEFChromium, uCEFWinControl, uCEFLinkedWinControlBase,
  uCEFTypes,uCEFConstants,uCEFApplication,uCEFChromiumWindow, uCEFWindowParent, Vcl.ExtCtrls;

type
  TCefForm = class(TForm)
    Button1: TButton;
    ChromiumWindow: TChromiumWindow;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    procedure InitializeChromium;
  public
    { Public declarations }
  end;

var
  CefForm: TCefForm;

implementation

{$R *.dfm}

var
  CefInitialize   : function:Boolean;cdecl;
  CefFinalize     : procedure;cdecl;
  CefCreateWindow : function(ChromiumWindow:TChromiumWindow;SecondsTimeout:Int64=INFINITE):Boolean;cdecl;

procedure TCefForm.InitializeChromium;
var
  Lib : THandle;
begin
  Lib              := LoadLibrary('CEFLoader.dll');
  @CefInitialize   := GetProcAddress(Lib,'CefInitialize');
  @CefFinalize     := GetProcAddress(Lib,'CefFinalize');
  @CefCreateWindow := GetProcAddress(Lib,'CefCreateWindow');
  CefInitialize;
end;

procedure TCefForm.Button1Click(Sender: TObject);
begin
  CefCreateWindow(ChromiumWindow,10);
  ChromiumWindow.ChromiumBrowser.LoadURL('file:///S:/Downloads/Resident.html');
  while ChromiumWindow.ChromiumBrowser.IsLoading do
  begin
    Sleep(10);
    Application.ProcessMessages;
  end;
end;

procedure TCefForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ChromiumWindow.DestroyChildWindow;
  CefFinalize;
end;

procedure TCefForm.FormCreate(Sender: TObject);
begin
  InitializeChromium;
end;

end.

But the Chromium Window has never been initialized and the application hangs preventing its close.

Best regards.

salvadordf commented 2 years ago

The DLLBrowser demo has all the code you need to put a CEF browser inside a DLL.

The single process mode is only intended for debugging purposes and it's a known cause of unexpected issues. In this case, you need to use a different EXE for the CEF subprocesses.

Read the code comments in that demo for more information.