thefunkyjoint wrote: Wed Nov 29, 2017 12:02 pm
I don't know why, but in my case even following the destruction steps, i still get a crash (or a freezing on 100% CPU) on exit my app.
As far as i understand, when i call CloseBrowser(true) , it will send a WM_CLOSE message to the app , right ?
So in my case i have 4 TChromium, it will send 4 WM_CLOSE messages, so FormCloseQuery will be called 4 times, am i right ? Maybe is this the problem ?
Let's say your application has only one TForm called
MainForm with 4 TChromium called
Chromium1,
Chromium2,
Chromium3 and
Chromium4.
Each TChromium uses one TCEFWindowParent, so you will have 4 TCEFWindowParent called
WindowParent1,
WindowParent2,
WindowParent3 and
WindowParent4.
- Chromium1 uses WindowParent1.
- Chromium2 uses WindowParent2.
- Chromium3 uses WindowParent3.
- Chromium4 uses WindowParent4.
You will need to use these events :
- MainForm.FormCloseQuery
- Chromium1.OnClose
- Chromium2.OnClose
- Chromium3.OnClose
- Chromium4.OnClose
- Chromium1.OnBeforeClose
- Chromium2.OnBeforeClose
- Chromium3.OnBeforeClose
- Chromium4.OnBeforeClose
- Chromium1.OnAfterCreated
- Chromium2.OnAfterCreated
- Chromium3.OnAfterCreated
- Chromium4.OnAfterCreated
Some of those events are called from a thread where you can't destroy VCL components so you will also need to declare some messages :
Code: Select all
const
CEFBROWSER_DESTROYPARENT1 = WM_APP + $100;
CEFBROWSER_DESTROYPARENT2 = WM_APP + $101;
CEFBROWSER_DESTROYPARENT3 = WM_APP + $102;
CEFBROWSER_DESTROYPARENT4 = WM_APP + $103;
You will also have to use several procedures to handle all those messages :
- The procedure DestroyParent1Msg will handle CEFBROWSER_DESTROYPARENT1
- The procedure DestroyParent2Msg will handle CEFBROWSER_DESTROYPARENT2
- The procedure DestroyParent3Msg will handle CEFBROWSER_DESTROYPARENT3
- The procedure DestroyParent4Msg will handle CEFBROWSER_DESTROYPARENT4
You will also need to know which browsers are initialized so you will declare 4 boolean variables called :
Browser1Initialized,
Browser2Initialized,
Browser3Initialized and
Browser4Initialized.
You will set each of them to True in the TChromium.OnAfterCreated event like this :
- Chromium1.OnAfterCreated sets Browser1Initialized to True
- Chromium2.OnAfterCreated sets Browser2Initialized to True
- Chromium3.OnAfterCreated sets Browser3Initialized to True
- Chromium4.OnAfterCreated sets Browser4Initialized to True
You will also need 4 more boolean variables to know which browser is in the process of destruction. Let's call them
Browser1Closing,
Browser2Closing,
Browser3Closing and
Browser4Closing. Set all of them to False when your app is created.
The destruction sequence is this :
- A user decides to close your app and clicks on the X of your MainForm which will trigger the MainForm.FormCloseQuery event. In this event you will check Browser1Initialized, Browser2Initialized, Browser3Initialized and Browser4Initialized. If all of them are False then you can set CanClose to True.
However, if any of them are True you will set CanClose to False and you will have to call the CloseBrowser function for each initialized browser like this :
Code: Select all
if Browser1Initialized and not(Browser1Closing) then
begin
Browser1Closing := True;
Chromium1.CloseBrowser(True);
end;
if Browser2Initialized and not(Browser2Closing) then
begin
Browser2Closing := True;
Chromium2.CloseBrowser(True);
end;
if Browser3Initialized and not(Browser3Closing) then
begin
Browser3Closing := True;
Chromium3.CloseBrowser(True);
end;
if Browser4Initialized and not(Browser4Closing) then
begin
Browser4Closing := True;
Chromium4.CloseBrowser(True);
end;
- Each TChrromium.CloseBrowser will trigger a TChrromium.OnClose but you can't destroy VCL components in this event so you will need to send a message to your MainForm like this :
- Chromium1.OnClose will do a PostMessage(MainForm.Handle, CEFBROWSER_DESTROYPARENT1, 0, 0);
- Chromium2.OnClose will do a PostMessage(MainForm.Handle, CEFBROWSER_DESTROYPARENT2, 0, 0);
- Chromium3.OnClose will do a PostMessage(MainForm.Handle, CEFBROWSER_DESTROYPARENT3, 0, 0);
- Chromium4.OnClose will do a PostMessage(MainForm.Handle, CEFBROWSER_DESTROYPARENT4, 0, 0);
- You have 4 procedures to handle those messages called : DestroyParent1Msg, DestroyParent2Msg, DestroyParent3Msg and DestroyParent4Msg. Each of those procedures will destroy one TCEFWindowParent like this
- DestroyParent1Msg will call WindowParent1.Free
- DestroyParent2Msg will call WindowParent2.Free
- DestroyParent3Msg will call WindowParent3.Free
- DestroyParent4Msg will call WindowParent4.Free
- Each destroyed TCEFWindowParent will trigger a TChromium.OnBeforeClose event and you will set Browser1Initialized, Browser2Initialized, Browser3Initialized and Browser4Initialized to False in each of them like this :
- Chromium1.OnBeforeClose will set Browser1Initialized to False and send WM_CLOSE to the MainForm.
- Chromium2.OnBeforeClose will set Browser2Initialized to False and send WM_CLOSE to the MainForm.
- Chromium3.OnBeforeClose will set Browser3Initialized to False and send WM_CLOSE to the MainForm.
- Chromium4.OnBeforeClose will set Browser4Initialized to False and send WM_CLOSE to the MainForm.
- After the last TChromium.OnBeforeClose event, all Browser*Initialized variables are False and the MainForm.FormCloseQuery will set CanClose to True to close your app safely.
Edit : You should modify all boolean variables inside a
CRITICAL SECTION.