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.

Closing application correctly

andreykrasnodar
Posts: 112
Joined: Wed Jul 01, 2020 10:22 am

Closing application correctly

Post by andreykrasnodar »

I watch the demos and found out this things made for closing browser correctly:
varables

Code: Select all

protected
    FCanClose        : boolean;
    FClosing         : boolean;
Procedure on create form

Code: Select all

procedure TForm1.FormCreate(Sender: TObject);
begin
  FCanClose       := False;
  FClosing        := False;
end;
After Chromium created

Code: Select all

procedure TForm1.chrmosrAfterCreated(Sender: TObject; const browser: ICefBrowser);
begin
  PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
end;
On close query procedure

Code: Select all

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := FCanClose;
  if not(FClosing) then
    begin
      FClosing := True;
      Visible  := False;
      chrmosr.CloseBrowser(True);
    end;
end;
Before Closing TChromium

Code: Select all

procedure TForm1.chrmosrBeforeClose(Sender: TObject; const browser: ICefBrowser);
begin
  FCanClose := True;
  PostMessage(Handle, WM_CLOSE, 0, 0);
end;
Anything else? Can anybody shortly describe each procedure? Mostly what does PostMessage(Handle, CEF_AFTERCREATED, 0, 0) and PostMessage(Handle, WM_CLOSE, 0, 0) procedures mean and why do they used here?
andreykrasnodar
Posts: 112
Joined: Wed Jul 01, 2020 10:22 am

Re: Closing application correctly

Post by andreykrasnodar »

P.S. What should I do to close application if I have 2 TChromium components on my form?
Sometimes application cases an error "access violation" when I close it on windows xp.
User avatar
salvadordf
Posts: 4052
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Closing application correctly

Post by salvadordf »

There are code comments giving the details of the "destruction sequence" in every demo.

In the case of the SimpleOSRBrowser demo inside the OldCEF4Delphi project the code comments are here :
https://github.com/salvadordf/OldCEF4De ... r.pas#L155

Code: Select all

// This is the destruction sequence in OSR mode :
// 1- FormCloseQuery sets CanClose to the initial FCanClose value (False) and calls chrmosr.CloseBrowser(True).
// 2- chrmosr.CloseBrowser(True) will trigger chrmosr.OnClose and we have to
//    set "Result" to false and CEF3 will destroy the internal browser immediately.
// 3- chrmosr.OnBeforeClose is triggered because the internal browser was destroyed.
//    Now we set FCanClose to True and send WM_CLOSE to the form.
CEF needs to follow some steps when you close a browser and the detailed instructions are in the C source code.
Basically, you need to :
  • 1- Call TChromium.CloseBrowser.
  • 2- Wait for the TChromium.OnClose event.
  • 3- Wait for the TChromium.OnBeforeClose event.
The OSR browsers have a slightly different sequence than the normal browsers but the basic steps are the same.

In your case, the OSR browser needs to set the "Result" parameter to FALSE in the TChromium.OnClose event in order to destroy the internal browser. When the internal browser is destroyed you will get the TChromium.OnBeforeClose event.

At that point the browser is fully closed and you can close the application if that was the last browser.

If you have more than one browser then you need to close each browser and wait until all of them complete the previous steps before closing the application. For example, the MDIBrowser and ToolBoxBrowser demos wait until all child forms with the browsers are closed before closing the main form.
andreykrasnodar
Posts: 112
Joined: Wed Jul 01, 2020 10:22 am

Re: Closing application correctly

Post by andreykrasnodar »

I have made like this

Code: Select all

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := FCanClose1 and FCanClose2;
  if not(FClosing) then
    begin
      FClosing := True;
      Visible  := False;
      Chromium1.CloseBrowser(True);
      Chromium2.CloseBrowser(True);
    end;
end;

Code: Select all

procedure TForm1.Chromium1BeforeClose(Sender: TObject;
  const browser: ICefBrowser);
begin
  FCanClose1 := True;
  if FCanClose1 and FCanClose2 then PostMessage(Handle, WM_CLOSE, 0, 0);
end;

Code: Select all

procedure TForm1.Chromium2BeforeClose(Sender: TObject;
  const browser: ICefBrowser);
begin
  FCanClose2 := True;
  if FCanClose1 and FCanClose2 then PostMessage(Handle, WM_CLOSE, 0, 0);
end;
And it did not help me with 2 "TChromium" components
andreykrasnodar
Posts: 112
Joined: Wed Jul 01, 2020 10:22 am

Re: Closing application correctly

Post by andreykrasnodar »

Nothing changed.
Access violation at address 006B0754 in module 'browser.exe'. Read of address 00000000.
User avatar
salvadordf
Posts: 4052
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Closing application correctly

Post by salvadordf »

That means that you're missing some step in the destruction and the application is closed before all the browsers are fully closed.
Please check that the application receives the TChromium.OnBeforeClose event for all the browsers before closing the form.
andreykrasnodar
Posts: 112
Joined: Wed Jul 01, 2020 10:22 am

Re: Closing application correctly

Post by andreykrasnodar »

How many times should I send
PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
if I have 2 TChromium components?
andreykrasnodar
Posts: 112
Joined: Wed Jul 01, 2020 10:22 am

Re: Closing application correctly

Post by andreykrasnodar »

salvadordf wrote: Sat Aug 29, 2020 10:13 am That means that you're missing some step in the destruction and the application is closed before all the browsers are fully closed.
Please check that the application receives the TChromium.OnBeforeClose event for all the browsers before closing the form.
Before closing 1st TChromium:

Code: Select all

  FCanClose1 := True;
  if FCanClose1 and FCanClose2 then PostMessage(Handle, WM_CLOSE, 0, 0);
Before closing 2nd TChromium:

Code: Select all

  FCanClose2 := True;
  if FCanClose1 and FCanClose2 then PostMessage(Handle, WM_CLOSE, 0, 0);
Is that correct?
User avatar
salvadordf
Posts: 4052
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Closing application correctly

Post by salvadordf »

andreykrasnodar wrote: Sat Aug 29, 2020 11:40 am How many times should I send
PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
if I have 2 TChromium components?
That message is used to know when a browser is initialized. TChromium doesn't allow some procedures or functions if it's not initialized and you should send it in case you need to do something else with that browser besides showing the default web page.

If you have more than one browser I would suggest you send some kind of id or a different message to know which browser is initialized.
andreykrasnodar wrote: Sat Aug 29, 2020 11:42 am
salvadordf wrote: Sat Aug 29, 2020 10:13 am That means that you're missing some step in the destruction and the application is closed before all the browsers are fully closed.
Please check that the application receives the TChromium.OnBeforeClose event for all the browsers before closing the form.
Before closing 1st TChromium:

Code: Select all

  FCanClose1 := True;
  if FCanClose1 and FCanClose2 then PostMessage(Handle, WM_CLOSE, 0, 0);
Before closing 2nd TChromium:

Code: Select all

  FCanClose2 := True;
  if FCanClose1 and FCanClose2 then PostMessage(Handle, WM_CLOSE, 0, 0);
Is that correct?
It looks fine but it's complicated to guess what else could be missing.
Please send a complete demo with the minimal code to reproduce that issue.
andreykrasnodar
Posts: 112
Joined: Wed Jul 01, 2020 10:22 am

Re: Closing application correctly

Post by andreykrasnodar »

salvadordf wrote: Sat Aug 29, 2020 12:10 pm Please send a complete demo with the minimal code to reproduce that issue.
The code is

Code: Select all

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, uCEFChromium, Vcl.ExtCtrls, uCEFApplication,
  uCEFTypes, uCEFInterfaces, uCEFConstants, uBufferPanel,
  uCEFWindowParent, uCefRequest, uCEFStringMultimap,uCEFPostData, uCEFMiscFunctions;

type
  TForm1 = class(TForm)
    Chromium1: TChromium;
    Chromium2: TChromium;
    Timer1: TTimer;
    Timer2: TTimer;
    Timer3: TTimer;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormCreate(Sender: TObject);
    procedure Chromium1AfterCreated(Sender: TObject;
      const browser: ICefBrowser);
    procedure Chromium2AfterCreated(Sender: TObject;
      const browser: ICefBrowser);
    procedure Chromium2BeforeClose(Sender: TObject; const browser: ICefBrowser);
    procedure Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
    procedure Timer1Timer(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
    procedure Timer3Timer(Sender: TObject);
  private
    { Private declarations }
  public
    cr1, cr2, FCanClose1, FCanClose2, FClosing : boolean;
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Chromium1AfterCreated(Sender: TObject;
  const browser: ICefBrowser);
begin
  CR1:=true;
  if CR1 and CR2 then
  begin
    CR1:=False;
    CR2:=False;
    PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
  end;
end;

procedure TForm1.Chromium1BeforeClose(Sender: TObject;
  const browser: ICefBrowser);
begin
  FCanClose1 := True;
  if FCanClose1 and FCanClose2 then PostMessage(Handle, CEF_DESTROY, 0, 0);
end;

procedure TForm1.Chromium2AfterCreated(Sender: TObject;
  const browser: ICefBrowser);
begin
  CR2:=true;
  if CR1 and CR2 then
  begin
    CR1:=False;
    CR2:=False;
    PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
  end;
end;

procedure TForm1.Chromium2BeforeClose(Sender: TObject;
  const browser: ICefBrowser);
begin
  FCanClose2 := True;
  if FCanClose1 and FCanClose2 then PostMessage(Handle, CEF_DESTROY, 0, 0);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  GlobalCEFApp.Destroy;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := FCanClose1 and FCanClose2;
  if not(FClosing) then
    begin
      FClosing := True;
      Visible  := False;
      Chromium1.CloseBrowser(True);
      Chromium2.CloseBrowser(True);
    end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FCanClose1:= False;
  FCanClose2:= False;
  FClosing := False;
  CR1:=False;
  CR2:=False;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  Chromium1.CreateBrowser(nil, '');
  if not(Chromium1.Initialized) then Timer1.Enabled := True;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
  Timer2.Enabled := False;
  Chromium2.CreateBrowser(nil, '');
  if not(Chromium2.Initialized) then Timer2.Enabled := True;
end;

procedure TForm1.Timer3Timer(Sender: TObject);
begin
  Timer3.Enabled:=false;
  Chromium1.LoadURL('https://google.com');
  Chromium2.LoadURL('https://google.com');

end;

end.
I think I did not mistakes. The same demo with dpr and dfm is near
You do not have the required permissions to view the files attached to this post.
Post Reply