Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.

Calling cef_shutdown() restarts the application

Post Reply
lasaranza
Posts: 23
Joined: Tue Feb 25, 2020 8:27 am

Calling cef_shutdown() restarts the application

Post by lasaranza »

Hi,

I noticed that when I destroy the GlobalCEFApp using DestroyGlobalCEFApp() procedure, the application restarts itself when cef_shutdown() in TCefApplicationCore.ShutDown is called. When the application restarts the GlobalCEFApp.StartMainProcess() returns false, that made the application to close by itself. I encountered the same behaviour in DCEF3 when using multi-processes. I wanted to confirm is this is a default behaviour or known issue?

Thank you.
User avatar
salvadordf
Posts: 4047
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Calling cef_shutdown() restarts the application

Post by salvadordf »

I've never seen that. This could be an issue in the DPR code.

Please, provide a code sample to reproduce that issue.
lasaranza
Posts: 23
Joined: Tue Feb 25, 2020 8:27 am

Re: Calling cef_shutdown() restarts the application

Post by lasaranza »

Hi Salvador,

This is my DPR code.

Code: Select all

 
 TCEFApplicationHandler2D.StartGlobalCEF();
 try
    if not TCEFApplicationHandler2D.StartMainProcess() then
      EXIT;
    Application.Initialize();
    Application.MainFormOnTaskbar := True;
    Application.CreateForm(TfrmMain, frmMain);
    Application.Run();
  finally
    TCEFApplicationHandler2D.ShutdownGlobalCEF();
  end;
And this is the TCEFApplicationHandler2D:

Code: Select all

  
  TCEFApplicationHandler2D = class(TCEFApplicationHandler_Abstract)
  strict protected
    class constructor ClassCreate();
    class destructor ClassDestroy();
  end;
  
  class constructor TCEFApplicationHandler2D.ClassCreate();
  begin
    FInstance := TCEFApplicationHandler2D.Create();
  end;

  class destructor TCEFApplicationHandler2D.ClassDestroy();
  begin
    FreeAndNil(FInstance);
  end;  
And this is my code for TCEFApplicationHandler_Abstract

Code: Select all

  TCEFApplicationHandler_Abstract = class
  strict private
    class var FInstance: TCEFApplicationHandler_Abstract;
  public
    constructor Create();
    destructor Destroy(); override;
    class function StartMainProcess(): Boolean;
    class procedure StartGlobalCEF();
    class procedure ShutdownGlobalCEF();
  end;
  
constructor TCEFApplicationHandler_Abstract.Create();
begin
   if Assigned(FInstance) then
      raise EPlxCEFApplicationException.CreateFmt('%s is a singleton class and is already instantiated before.', [ClassName]);
   inherited Create();
end;

destructor TCEFApplicationHandler_Abstract.Destroy();
begin
   DestroyGlobalCEFApp();
   inherited Destroy();
end;
  
class procedure TCEFApplicationHandler_Abstract.StartGlobalCEF();
begin
  if not Assigned(FInstance) then
    raise EPlxCEFApplicationException.Create('Cannot start GlobalCEFApp from abstract class!');

  GlobalCEFApp := TCefApplication.Create();
  GlobalCEFApp.FrameworkDirPath := 'dcef';
  GlobalCEFApp.ResourcesDirPath := 'dcef';

  GlobalCEFApp.OnRegCustomSchemes := RegisterSchemes; // code not added here
  GlobalCEFApp.OnBrowserCreated := HandleOnBrowserCreated; // code not added here
  GlobalCEFApp.OnWebKitInitialized := HandleOnWebKitInitialized; // code not added here
end;

class procedure TCEFApplicationHandler_Abstract.ShutdownGlobalCEF();
begin
  DestroyGlobalCEFApp();
end;

class function TCEFApplicationHandler_Abstract.StartMainProcess(): Boolean;
begin
  Result := GlobalCEFApp.StartMainProcess();
end;


User avatar
salvadordf
Posts: 4047
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Calling cef_shutdown() restarts the application

Post by salvadordf »

Sorry for the delay.

I added most of your code to the SimpleBrowser2 demo to make some tests. I added this unit :

Code: Select all

unit uCEFApplicationHandler;

interface

type
 TCEFApplicationHandler_Abstract = class
  protected
    class var FInstance: TCEFApplicationHandler_Abstract;
  public
    constructor Create();
    destructor Destroy(); override;
    class function StartMainProcess(): Boolean;
    class procedure StartGlobalCEF();
    class procedure ShutdownGlobalCEF();
  end;

 TCEFApplicationHandler2D = class(TCEFApplicationHandler_Abstract)
  strict protected
    class constructor ClassCreate();
    class destructor ClassDestroy();
  end;

implementation

uses
  SysUtils,
  uCEFApplication;

constructor TCEFApplicationHandler_Abstract.Create();
begin
   if Assigned(FInstance) then
      raise Exception.Create('TCEFApplicationHandler_Abstract.Create error : assigned FInstance');
   inherited Create();
end;

destructor TCEFApplicationHandler_Abstract.Destroy();
begin
   DestroyGlobalCEFApp();
   inherited Destroy();
end;

class procedure TCEFApplicationHandler_Abstract.StartGlobalCEF();
begin
  if not Assigned(FInstance) then
    raise Exception.Create('TCEFApplicationHandler_Abstract.StartGlobalCEF error : assigned FInstance');

  GlobalCEFApp := TCefApplication.Create();
//  GlobalCEFApp.FrameworkDirPath := 'dcef';
//  GlobalCEFApp.ResourcesDirPath := 'dcef';

//  GlobalCEFApp.OnRegCustomSchemes := RegisterSchemes; // code not added here
//  GlobalCEFApp.OnBrowserCreated := HandleOnBrowserCreated; // code not added here
//  GlobalCEFApp.OnWebKitInitialized := HandleOnWebKitInitialized; // code not added here
end;

class procedure TCEFApplicationHandler_Abstract.ShutdownGlobalCEF();
begin
  DestroyGlobalCEFApp();
end;

class function TCEFApplicationHandler_Abstract.StartMainProcess(): Boolean;
begin
  Result := GlobalCEFApp.StartMainProcess();
end;

class constructor TCEFApplicationHandler2D.ClassCreate();
begin
  FInstance := TCEFApplicationHandler2D.Create();
end;

class destructor TCEFApplicationHandler2D.ClassDestroy();
begin
  FreeAndNil(FInstance);
end;

end.
The DPR looked like this :

Code: Select all

program SimpleBrowser2;

{$I cef.inc}

uses
  Vcl.Forms,
  uSimpleBrowser2 in 'uSimpleBrowser2.pas' {Form1},
  uCEFApplicationHandler in 'uCEFApplicationHandler.pas';

{$R *.res}

begin
  TCEFApplicationHandler2D.StartGlobalCEF();
  try
    if not TCEFApplicationHandler2D.StartMainProcess() then
      EXIT;
    Application.Initialize();
    Application.MainFormOnTaskbar := True;
    Application.CreateForm(TForm1, Form1);
    Application.Run();
  finally
    TCEFApplicationHandler2D.ShutdownGlobalCEF();
  end;
end.
The uSimpleBrowser2 unit wasn't modified.

I run the demo in Delphi 10.3.3 and it worked correctly with the latest CEF4Delphi version.

Seeing your TCEFApplicationHandler2D class makes me think that your application has a complicated initialization. Perhaps this issue could be solved (or at least identified) if you use a different EXE for the CEF subprocesses.

Take a look at the "SubProcess" demo for more details.
lasaranza
Posts: 23
Joined: Tue Feb 25, 2020 8:27 am

Re: Calling cef_shutdown() restarts the application

Post by lasaranza »

Hi,

I did test this in SimpleBrowser2 by using cefdebuglog to check if the application restarts. See the modified dpr code below:

Code: Select all

begin
  GlobalCEFApp := TCefApplication.Create;
  GlobalCEFApp.LogFile := 'debug.log';
  GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO;

  if GlobalCEFApp.StartMainProcess then
  begin
    CefDebugLog('Start main process!');
    Application.Initialize;
    {$IFDEF DELPHI11_UP}
    Application.MainFormOnTaskbar := True;
    {$ENDIF}
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end
  else
  begin
    CefDebugLog('Cannot start main process!');
  end;

  CefDebugLog('Shutting down!');

  GlobalCEFApp.Free;
  GlobalCEFApp := nil;
end.
  
And I did get a log that shows the following:

Code: Select all

[0424/162123.163:ERROR:CEF4Delphi(1)] PID: 12864, TID: 10868, PT: Browser - Start main process!
[0424/162141.471:ERROR:CEF4Delphi(1)] PID: 12864, TID: 10868, PT: Browser - Shutting down!
[0424/162141.490:ERROR:CEF4Delphi(1)] PID: 22172, TID: 30532, PT: Other - Cannot start main process!
[0424/162141.491:ERROR:CEF4Delphi(1)] PID: 22172, TID: 30532, PT: Other - Shutting down!

I am using Delphi 10.3 and Windows 10. I wonder if you could reproduce this issue.
User avatar
salvadordf
Posts: 4047
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Calling cef_shutdown() restarts the application

Post by salvadordf »

Thanks for reporting this! :)

I just added a missing process type to the CefDebugLog procedure and updated CEF4Delphi.

The last process in that log is in fact a "Utility" process also known as a "Network Service" process.

That's a normal Chromium process and as all other subprocesses, it's handled internally in Chromium's code.
lasaranza
Posts: 23
Joined: Tue Feb 25, 2020 8:27 am

Re: Calling cef_shutdown() restarts the application

Post by lasaranza »

Thank you for checking. Kudos for this library!
lasaranza
Posts: 23
Joined: Tue Feb 25, 2020 8:27 am

Re: Calling cef_shutdown() restarts the application

Post by lasaranza »

Hi Salvador,

Just a followup question. What is the quick fix to disable the restart?
User avatar
salvadordf
Posts: 4047
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Calling cef_shutdown() restarts the application

Post by salvadordf »

I would try to use a different EXE for the subprocesses as shown in the SubProcess demo.

It seems that your application has a complex initialization. In those cases it's recommended to use a different EXE to avoid issues like this one.
lasaranza
Posts: 23
Joined: Tue Feb 25, 2020 8:27 am

Re: Calling cef_shutdown() restarts the application

Post by lasaranza »

Ok, thank you again.
Post Reply