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.

Debugging Problems and strange behavior

User avatar
Minz3
Posts: 17
Joined: Tue Nov 12, 2019 12:55 pm

Re: Debugging Problems and strange behavior

Post by Minz3 »

Good news, it shows google now! Finally! :D
Thank you for that special Demo. The actual problem (the white window) was here:

(debug_log)
[1119/135829.008:VERBOSE1:script_context.cc(117)] Created context:
extension id: (none)
frame: 395A1A38
URL:
context_type: WEB_PAGE
effective extension id: (none)
effective context type: WEB_PAGE

The URL was empty, and that was because I forgot to set the Default_URL... I don't know why the BrowserCreatedMsg procedure is still not executed but with the default URL it finally shows something.

But there is still a last problem left. The behavior, that the child form wont close. And the fact, that I now have to transform the toolbox into the embedded form (into the PWA Form, who is calling the child at the moment). But I think that seems to be possible.
User avatar
Minz3
Posts: 17
Joined: Tue Nov 12, 2019 12:55 pm

Re: Debugging Problems and strange behavior

Post by Minz3 »

Hey it's me again,

I have made a few changes and noticed some interesting things.

First: I've changed the Popup Window to an implemented version like this:
Image

The Taskmanager meanwhile looks this:
Image

So far so good. But if I now switch to another module I get an access violation:
Image
The same happens, if I shut down the main app.

Switching a module in that case means, that the main form still exists but the module itself gets closed and the new one will be opened.
I changed the destruction from the toolbox/subprocess demo to the simple browser destruction method. It looks now like this:

Code: Select all

procedure TPWAModuleForm.CEFSentinel1Close(Sender: TObject);
begin
  FCanClose := True;
  PostMessage(Handle, WM_CLOSE, 0, 0);
end;

Code: Select all

function TPWAModuleForm.CloseQuery: Boolean;
begin
  if FClosing {or ChildClosing} then
    Result := FCanClose
   else
   begin
     FClosing := True;
     CloseModule;
   end;
end;

Code: Select all

procedure TPWAModuleForm.Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
begin
  //FCanClose := True;
  //PostMessage(Handle, WM_CLOSE, 0, 0);
  CEFSentinel1.Start;
end;

Code: Select all

procedure TPWAModuleForm.Chromium1Close(Sender: TObject;
                                        const browser: ICefBrowser;
                                        var aAction : TCefCloseBrowserAction);
begin
  PostMessage(Handle, CEFBROWSER_DESTROY, 0, 0);
  aAction := cbaDelay;
  CEFSentinel1.Start;
end;

Code: Select all

procedure TPWAModuleForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := FCanClose;

  if not(FClosing) then
    begin
      FClosing := True;
      Visible  := False;
      Chromium1.CloseBrowser(True);
    end;

  if FActivated then
    Self.SetFocus;
end;

Code: Select all

procedure TPWAModuleForm.FormDestroy(Sender: TObject);
begin
  // Tell the main form that a child has been destroyed.
  // The main form will check if this was the last child to close itself
  PostMessage(PWAModuleForm.Handle, CEFBROWSER_CHILDDESTROYED, 0, 0);

  if FClosing {and (ChildFormCount = 0)} then CEFSentinel1.Start;
end;
The following procedures are commented out:

Code: Select all

private
//    procedure CreateToolboxChild(const ChildCaption, URL: string);
//    procedure CloseAllChildForms;
//    function  GetChildClosing : boolean;
//    function  GetChildFormCount : integer;

public
//    property ChildClosing : boolean read GetChildClosing;
//    property ChildFormCount : integer read GetChildFormCount;
I haven't dived deeper into the sentinel functions but could it be, that it will destroy the main form?
Because after I clicked the AV messages away I can notice this at the Taskmanager:
Image
As you can see, the main application has gone and the subprocesses too. The only thing that remains is the PWA module. But I can navigate inside the rest of the app, exept of the PWA module. If I wanted to switch back to the PWA form, the whole application will shut down without any warnings.

I hope you are not tired of my problem and again I will thank you for your excellent help before and your patience with me and my problem. :)

PS: I added the debug log this time, maybe it will help you.

greetings
You do not have the required permissions to view the files attached to this post.
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Debugging Problems and strange behavior

Post by salvadordf »

If you use a couple of TChromium and TCEFWindowParent components in every child form then you have to destroy each of them following these steps :
  • Use the TForm.OnCloseQuery event on each child form to set CanClose to FALSE and call TChromium.CloseBrowser, which will trigger the TChromium.OnClose event.
  • In the TChromium.OnClose event you have to send a CEFBROWSER_DESTROY message to the child form in order to destroy the TCEFWindowParent component in the main thread, which will trigger the TChromium.OnBeforeClose event.
  • The TChromium.OnBeforeClose event sets FCanClose to TRUE and sends WM_CLOSE to the child form.
  • The TForm.OnCloseQuery event will be executed again but this time set CanClose to TRUE because the browser is now properly destroyed.
  • The TForm.OnDestroy event sends a CEFBROWSER_CHILDDESTROYED message to the main form to inform that one of the child forms was destroyed.
The main application form must check if all the child forms were properly destroyed before terminating the application.

This is what happens when the user tries to close the main form :
  • The main form overrides TMainForm.CloseQuery and checks if there are any child forms still running. If there are no child forms then sets "Result" to true to continue closing the main form but if there are child forms then it sends a WM_CLOSE to all of them and sets "Result" to FALSE to wait until all of the child forms are properly destroyed.
  • Each child form follows the previous destruction steps and sends a CEFBROWSER_CHILDDESTROYED message to the main form when it's destroyed.
  • The main form receives each CEFBROWSER_CHILDDESTROYED message and checks if there are any child forms still running before terminating the application.
Your application must follow all these steps to avoid destruction crashes.

As you know, the latest version of CEF4Delphi has a shutdown issue since the CEF 77 update :
https://github.com/salvadordf/CEF4Delphi/issues/230

We could avoid this issue in previous releases by disabling the "Network Service" but we can't disable that service in the latest CEF libraries.

For this reason, it's recommended that you use the latest release which uses CEF 75 :
https://github.com/salvadordf/CEF4Delph ... ses/latest

Install the latest CEF4Delphi release and add this code line to disable the Network Service before the GlobalCEFApp.StartMainProcess and GlobalCEFApp.StartSubProcess calls in uCEFLoader.pas and the subprocess DPR file :

Code: Select all

GlobalCEFApp.DisableFeatures := 'NetworkService';
The MiniBrowser demo in that release already has that code line as you can see here :
https://github.com/salvadordf/CEF4Delph ... er.dpr#L68

If you still want to use the latest CEF4Delphi version then you can try the TCEFSentinel component. It seems to avoid some of the crashes but you may still see some of them when the application is closed. We have to wait until this issue is resolved in the CEF project.
User avatar
Minz3
Posts: 17
Joined: Tue Nov 12, 2019 12:55 pm

Re: Debugging Problems and strange behavior

Post by Minz3 »

Hey!

Thanks a lot for your help now it kinda works the most time.

So I've worked a lot with the help of your remarks. I guess I am quite close to the solution now. The only failure I get is, when I switch to another module and then switch back to the PWA module. Then the Error "Could not access libcef.dll" appears. An again a Memory leak, which I guess is caused by this .dll access violation.
The rest seems to work. I hope this is my last problem. ^^

How can I ensure, that the libcef.dll gets closed, when I called the DestroyGlobalCEFApp method?

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

Re: Debugging Problems and strange behavior

Post by salvadordf »

Are you trying to initialize CEF more than one time?

CEF can't be initialized more than once per process. This is a CEF feature and we can't do anything to avoid it.

If you need to create and destroy a browser several times during the lifetime of your application then you need to initialize CEF only one time, then create and destroy all the browsers you need, and finalize CEF when all the browsers are properly closed.
User avatar
Minz3
Posts: 17
Joined: Tue Nov 12, 2019 12:55 pm

Re: Debugging Problems and strange behavior

Post by Minz3 »

Actually yes I do. CEF will be initialized each time the module will be opened by the user. I thought I could destroy the whole CEF components while closing the module and this will also cause to free all libraries.

I thought the simple way and tried to add a flag to controll the initialization process for the first time. Like so:

Code: Select all

procedure CreateGlobalCEFApp;
begin
  if PWAModuleForm.IsAlreadyInitialized then
  begin
  end
  else
  begin
    GlobalCEFApp                      := TCefApplication.Create;
    GlobalCEFApp.OnContextInitialized := GlobalCEFApp_OnContextInitialized;
    TPWAModuleForm.Logging('CreateGlobalCEFApp','CEF App created');
    PWAModuleForm.IsAlreadyInitialized := True;
  end;
end;
But unfortunately this will not do the trick.
User avatar
Minz3
Posts: 17
Joined: Tue Nov 12, 2019 12:55 pm

Re: Debugging Problems and strange behavior

Post by Minz3 »

Update:

Finally I've got a solution. I just needed to talk to some of our old delphi gurus who also developed the ERP system.
The problem was, that the single initialization was kinda hard to realize. The porject works with some initial routines, where I put the initialization of the cef components. And when the application gets closed, the components will be deinitialzied.

At least it was pretty simple... Now it works fine!

Thank you for your excellent help Salvador!

greetz
Post Reply