Page 1 of 3
Closing application correctly
Posted: Fri Aug 28, 2020 8:57 am
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?
Re: Closing application correctly
Posted: Fri Aug 28, 2020 12:07 pm
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.
Re: Closing application correctly
Posted: Fri Aug 28, 2020 12:36 pm
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.
Re: Closing application correctly
Posted: Fri Aug 28, 2020 3:14 pm
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
Re: Closing application correctly
Posted: Sat Aug 29, 2020 10:07 am
by andreykrasnodar
Nothing changed.
Access violation at address 006B0754 in module 'browser.exe'. Read of address 00000000.
Re: Closing application correctly
Posted: Sat Aug 29, 2020 10:13 am
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.
Re: Closing application correctly
Posted: Sat Aug 29, 2020 11:40 am
by andreykrasnodar
How many times should I send
PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
if I have 2 TChromium components?
Re: Closing application correctly
Posted: Sat Aug 29, 2020 11:42 am
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?
Re: Closing application correctly
Posted: Sat Aug 29, 2020 12:10 pm
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.
Re: Closing application correctly
Posted: Sun Aug 30, 2020 8:52 am
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