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.
If you find these projects useful please consider becoming a sponsor with Patreon, GitHub or Liberapay.

Avoid this mistake

Post Reply
rgdawson
Posts: 22
Joined: Tue Apr 10, 2018 11:05 pm

Avoid this mistake

Post by rgdawson »

Following the pattern my .dpr code looks like this:

Code: Select all

begin
 CreateGlobalCEFApp;
 if GlobalCEFApp.StartMainProcess then
  begin
    Application.Initialize;
    Application.MainFormOnTaskbar := True;
    Application.Title := 'AppName';
    Application.CreateForm(TMainView, MainView);
    Application.Run;
  end;
  DestroyGlobalCEFApp;
end.
It is easy to forget that whatever code you put in CreateGlobalCEFApp gets executed multiple times from multiple processes and that can cause unanticipated problems. I had code in my CreateGlobalCEFApp that effectively was doing something like this:

Code: Select all

procedure CreateGlobalCEFApp;
var
  RegIniFile: TRegIniFile;
  DoClearCache: Boolean;
begin

  RegIniFile := TRegIniFile.Create('SOFTWARE\AppName');
  try
    DoClearCache := RegIniFile.ReadBool('', 'ClearCache', False);
  finally
    RegIniFile.Free;
  end;

  GlobalCEFApp := TCefApplication.Create;
  with GlobalCEFApp do
  begin
    CheckCEFFiles        := False;
    OnWebKitInitialized  := GlobalCEFApp_OnWebKitInitialized;
    Cache                := CefCacheDir;
    DeleteCache          := DoClearCache;
    DeleteCookies        := False;
    EnableHighDPISupport := True;
  end;
end.
Looks harmless enough. BUT, consider that TRegIniFile.Create will attempt to create the key 'SOFTWARE\Appname' if it does not exist. And since this code will actually get executed multiple times in multiple processes on startup, two processes might be trying to do this at exactly the same time. The registry may be locked and you could get a registry exception on startup 'Unable to create key' because two processes are trying to create a registry key it simultaneously.

I had this code in program for quite a while until one day a user said, by the way I keep getting this error. Thousands of users never saw it or it happened so rarely they didn't bother to report it. But one user got it every time.

I had forgotten the way CEF initialization works and that this code gets executed multiple times near simultaneously. And, I had overlooked the fact that TRegIniFile.Create will create a key if one does not already exist, which is the case on the very first run of my app. Be careful what you put in your TCefApplication initialization code.

I decided to pass this along so you can avoid my mistake.

R Greg Dawson
User avatar
salvadordf
Posts: 4572
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Avoid this mistake

Post by salvadordf »

Thanks for this information! :D

To avoid this issue create GlobalCEFApp and check the GlobalCEFApp.ProcessType before executing the code that needs to be run only once like this :

Code: Select all

GlobalCEFApp := TCefApplication.Create;

if (GlobalCEFApp.ProcessType = ptBrowser) then
  begin
    // Your code here 
  end;
Post Reply