Hello,
trying to migrate a Delphi project (Delphi Tokyo 10.2) from CEF3 to CEF4Delphi was not successful, because we only run one instance of the application and we do avoid a second instance using CreateMutex. Using CEF4Delphi we run into the problem "Application already running"
A simple project to demonstrate the issue:
dpr:
program CEFTest;
uses
Vcl.Forms,
Vcl.Dialogs,
Winapi.Windows,
uCEFApplication,
UCEF1 in 'UCEF1.pas' {Form1};
{$R *.res}
var
mHandle : THandle;
MutexErr: Integer = 0;
Window: HWND;
begin
GlobalCEFApp := TCefApplication.Create;
GlobalCEFApp.SingleProcess := False;
GlobalCEFApp.Cache := 'cache';
GlobalCEFApp.Locale := 'de';
// try to create a mutex
mHandle := CreateMutex(nil, True, SWindowClassName);
// check to see if it was successful
MutexErr := GetLastError;
if MutexErr <> ERROR_SUCCESS then
begin
ShowMessage(SWindowClassName + ' already running!');
mHandle := FindWindow('TApplication',SWindowClassName);
ShowWindow(mHandle, SW_RESTORE);
SetForegroundWindow(Window);
end
else
begin
Application.Initialize;
if GlobalCEFApp.StartMainProcess then
begin
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
end;
GlobalCEFApp.Free;
end.
MainForm:
unit UCEF1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, uCEFChromium, Vcl.ExtCtrls,
uCEFWindowParent, uCEFChromiumWindow, uCEFRequest, uCEFPostData, uCEFPostDataElement,
uCEFMiscFunctions, uCEFInterfaces, uCEFConstants, uCEFTypes;
type
TForm1 = class(TForm)
Panel1: TPanel;
ChromiumWindow1: TChromiumWindow;
crm: TChromium;
Button1: TButton;
Timer1: TTimer;
procedure FormShow(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure crmAfterCreated(Sender: TObject; const browser: ICefBrowser);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
const
SWindowClassName = 'CEF4App';
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
crm.LoadURL('www.google.de');
end;
procedure TForm1.crmAfterCreated(Sender: TObject; const browser: ICefBrowser);
begin
PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
end;
procedure TForm1.FormShow(Sender: TObject);
begin
if not(crm.CreateBrowser(ChromiumWindow1, '')) then
Timer1.Enabled := True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
if not (crm.CreateBrowser(ChromiumWindow1, '')) and not (crm.Initialized) then
Timer1.Enabled := True;
end;
end.
Now just starting the programm results in the message, that the application is already running, without trying to load a URL
An idea how to solve this problem?
Best regards,
Christoph
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.
CEF4Delphi and CreateMutex in .dpr file
- salvadordf
- Posts: 4564
- Joined: Thu Feb 02, 2017 12:24 pm
- Location: Spain
- Contact:
Re: CEF4Delphi and CreateMutex in .dpr file
Use a different EXE for the subprocesses.
Take a look at the SubProcess or JSWindowBindingSubProcess demos to know how.
Take a look at the SubProcess or JSWindowBindingSubProcess demos to know how.
Re: CEF4Delphi and CreateMutex in .dpr file
Hello,
thank you very much, it is now working on our side!!
Best regards,
Christoph
thank you very much, it is now working on our side!!
Best regards,
Christoph
- salvadordf
- Posts: 4564
- Joined: Thu Feb 02, 2017 12:24 pm
- Location: Spain
- Contact:
Re: CEF4Delphi and CreateMutex in .dpr file
Please, use the SingleProcess mode only for debugging purposes.
The single process mode is not supported by CEF3 and it's a known cause for errors and access violations.
The single process mode is not supported by CEF3 and it's a known cause for errors and access violations.
Re: CEF4Delphi and CreateMutex in .dpr file
I also have a CEF4Delphi App and I want only a single instance to execute. I think you are need to call GlobalCEFApp.Free and Exit when you already have the app running and you do not want to run a second instance. This works. Here is what I have in the DPR file:
...
if GlobalCEFApp.StartMainProcess then
begin
{Allow Only Once Instance...}
if CreateMutex(nil, True, 'MUTEX-NAME') = 0 then
RaiseLastOSError;
if GetLastError = ERROR_ALREADY_EXISTS then
begin
MessageDlg('My App'#13#10#13#10'MyApp is already running. Only one instance can run per session.', mtInformation, [mbOK], 0);
GlobalCEFApp.Free;
Exit;
end;
Application.Initialize;
Application.ShowMainForm := False;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TLogWindowForm, LogWindowForm);
Application.CreateForm(TDM, DM);
Application.CreateForm(TSplitViewForm, SplitViewForm);
Application.Run;
end;
GlobalCEFApp.Free;
end.
...
if GlobalCEFApp.StartMainProcess then
begin
{Allow Only Once Instance...}
if CreateMutex(nil, True, 'MUTEX-NAME') = 0 then
RaiseLastOSError;
if GetLastError = ERROR_ALREADY_EXISTS then
begin
MessageDlg('My App'#13#10#13#10'MyApp is already running. Only one instance can run per session.', mtInformation, [mbOK], 0);
GlobalCEFApp.Free;
Exit;
end;
Application.Initialize;
Application.ShowMainForm := False;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TLogWindowForm, LogWindowForm);
Application.CreateForm(TDM, DM);
Application.CreateForm(TSplitViewForm, SplitViewForm);
Application.Run;
end;
GlobalCEFApp.Free;
end.