zitt
asked on
D3: Determining if App is already running (no HPrevInst)
I have a D1 app that I'm migrating to Win32 via Delphi 3. In this app, I used the HPrevInst property of TApplication to detect that I already have the application running. When I moved the code to Delphi 3, I've found that HPrevInst nolonger exists?!??!
So, the question is this:
How to I determine that my D3 app is already running?
Note: I want to know if my program is running, not just any application.
Note#2: Simple is better. I'm looking to write a function to replace the HPrevInst property so I don't have to patch a lot of code.
(sometimes I just wanna slap Borland for this kinda crap)
John
So, the question is this:
How to I determine that my D3 app is already running?
Note: I want to know if my program is running, not just any application.
Note#2: Simple is better. I'm looking to write a function to replace the HPrevInst property so I don't have to patch a lot of code.
(sometimes I just wanna slap Borland for this kinda crap)
John
I agree with JimBob there....
you can also try this code :
MessageID := RegisterWindowMessage('Che ck if already running');
if hPrevInst <> 0 then
begin
PostMessage(hwnd_Broadcast ,MessageId ,0,0);
end
else
begin
normal startup code.
....
end;
Then you can restore the original instance by adding this code.
create this procedure ...
procedure TYourForm.OnAppMessage(var Msg : TMsg;var Handled : Boolean);
begin
if Msg.Message = MessageId then
begin
Application.Restore;
TYourForm.SetFocus;
end;{if Msg.Message = MessageId then}
end;
Then add this to the onFormCreate...
procedure TYourForm.FormCreate(Sende r: TObject);
begin
Application.OnMessage := OnAppMessage;
end;
you can also try this code :
MessageID := RegisterWindowMessage('Che
if hPrevInst <> 0 then
begin
PostMessage(hwnd_Broadcast
end
else
begin
normal startup code.
....
end;
Then you can restore the original instance by adding this code.
create this procedure ...
procedure TYourForm.OnAppMessage(var
begin
if Msg.Message = MessageId then
begin
Application.Restore;
TYourForm.SetFocus;
end;{if Msg.Message = MessageId then}
end;
Then add this to the onFormCreate...
procedure TYourForm.FormCreate(Sende
begin
Application.OnMessage := OnAppMessage;
end;
ASKER
I don't understand how
if hPrevInst <> 0 then
Can work in a Delphi3.0 app, when hPrevInst is not defined in Delphi3.
Are you attempting to combine your answer with JimBob's comment?
Also, BoRiS's answer is more complicated than I'd like. The impact to my D1 code should be minimal.
Does anyone know how D1 implemented the hPrevInst property?
John
if hPrevInst <> 0 then
Can work in a Delphi3.0 app, when hPrevInst is not defined in Delphi3.
Are you attempting to combine your answer with JimBob's comment?
Also, BoRiS's answer is more complicated than I'd like. The impact to my D1 code should be minimal.
Does anyone know how D1 implemented the hPrevInst property?
John
ASKER
I tired Jim's comments and I can't get
FindWindow('TMyMainForm', nil)
to return zero when there my app isn't running.
The end result here folks is that, I want to determine my if my program is already running... do some "checks" to determine if I should halt this new instance of my program.
FindWindow('TMyMainForm', nil)
to return zero when there my app isn't running.
The end result here folks is that, I want to determine my if my program is already running... do some "checks" to determine if I should halt this new instance of my program.
Hi zitt
The following code is from a test program I've just written. This works fine in Delphi 3. The 1st program runs. When you try to run a 2nd instance, it pops up a msg and then closes.
// --- Start of Project code ---
program Project1;
uses
Forms, Windows, Dialogs,
Unit1 in 'Unit1.pas' {frmTest};
{$R *.RES}
begin
if (FindWindow('TfrmTest', nil) > 0) then
ShowMessage('Already running...')
else begin
Application.Initialize;
Application.CreateForm(Tfr mTest, frmTest);
Application.Run;
end;
end.
// --- End of Project code ---
Unit1.pas has a form called frmTest (class is thus TfrmTest).
Your FindWindow may have returned non-zero if there was already an existing window in the system with the same class name. (E.g. TForm1) Try giving your main form a name (TfrmThisIsUnique) to test this method...
Regards,
JB
The following code is from a test program I've just written. This works fine in Delphi 3. The 1st program runs. When you try to run a 2nd instance, it pops up a msg and then closes.
// --- Start of Project code ---
program Project1;
uses
Forms, Windows, Dialogs,
Unit1 in 'Unit1.pas' {frmTest};
{$R *.RES}
begin
if (FindWindow('TfrmTest', nil) > 0) then
ShowMessage('Already running...')
else begin
Application.Initialize;
Application.CreateForm(Tfr
Application.Run;
end;
end.
// --- End of Project code ---
Unit1.pas has a form called frmTest (class is thus TfrmTest).
Your FindWindow may have returned non-zero if there was already an existing window in the system with the same class name. (E.g. TForm1) Try giving your main form a name (TfrmThisIsUnique) to test this method...
Regards,
JB
"I don't understand how"
if hPrevInst <> 0 then
Answer:
If it is 0 then there is no previous instance otherwise your app is already running somewhere.
Yes I'm was trying to elaborate on JimBob's comment
if hPrevInst <> 0 then
Answer:
If it is 0 then there is no previous instance otherwise your app is already running somewhere.
Yes I'm was trying to elaborate on JimBob's comment
Hi zitt
HPrevInst IS defined in D3 (in System.pas) but it may (??) not be used in Win 95...
JB
HPrevInst IS defined in D3 (in System.pas) but it may (??) not be used in Win 95...
JB
From: "The Graphical Gnome" <rdb@ktibv.nl>
Taken from Delphi 2 Developers Guide by Pacheco and Teixeira with heavy modifications.
Usage: In the Project source change to the following
-------------------------- ---------- ---------- ---------- ---------- ------
if InitInstance then
begin
Application.Initialize;
Application.CreateForm(TFr mSelProjec t, FrmSelProject);
Application.Run;
end;
unit multinst;
{
Taken from Delphi 2 Developers Guide by Pacheco and Teixeira
With heavy Modifications.
Usage:
In the Project source change to the following
if InitInstance then
begin
Application.Initialize;
Application.CreateForm(TFr mSelProjec t, FrmSelProject);
Application.Run;
end;
That's all folks ( I hope ;()
}
interface
uses Forms, Windows, Dialogs, SysUtils;
const
MI_NO_ERROR = 0;
MI_FAIL_SUBCLASS = 1;
MI_FAIL_CREATE_MUTEX = 2;
{ Query this function to determine if error occurred in startup. }
{ Value will be one or more of the MI_* error flags. }
function GetMIError: Integer;
Function InitInstance : Boolean;
implementation
const
UniqueAppStr : PChar; {Change for every Application}
var
MessageId: Integer;
WProc: TFNWndProc = Nil;
MutHandle: THandle = 0;
MIError: Integer = 0;
function GetMIError: Integer;
begin
Result := MIError;
end;
function NewWndProc(Handle: HWND; Msg: Integer; wParam,
lParam: Longint): Longint; StdCall;
begin
{ If this is the registered message... }
if Msg = MessageID then begin
{ if main form is minimized, normalize it }
{ set focus to application }
if IsIconic(Application.Handl e) then begin
Application.MainForm.Windo wState := wsNormal;
ShowWindow(Application.Mai nform.Hand le, sw_restore);
end;
SetForegroundWindow(Applic ation.Main Form.Handl e);
end
{ Otherwise, pass message on to old window proc }
else
Result := CallWindowProc(WProc, Handle, Msg, wParam, lParam);
end;
procedure SubClassApplication;
begin
{ We subclass Application window procedure so that }
{ Application.OnMessage remains available for user. }
WProc := TFNWndProc(SetWindowLong(A pplication .Handle, GWL_WNDPROC,
Longint(@NewWndProc)));
{ Set appropriate error flag if error condition occurred }
if WProc = Nil then
MIError := MIError or MI_FAIL_SUBCLASS;
end;
procedure DoFirstInstance;
begin
SubClassApplication;
MutHandle := CreateMutex(Nil, False, UniqueAppStr);
if MutHandle = 0 then
MIError := MIError or MI_FAIL_CREATE_MUTEX;
end;
procedure BroadcastFocusMessage;
{ This is called when there is already an instance running. }
var
BSMRecipients: DWORD;
begin
{ Don't flash main form }
Application.ShowMainForm := False;
{ Post message and inform other instance to focus itself }
BSMRecipients := BSM_APPLICATIONS;
BroadCastSystemMessage(BSF _IGNORECUR RENTTASK or BSF_POSTMESSAGE,
@BSMRecipients, MessageID, 0, 0);
end;
Function InitInstance : Boolean;
begin
MutHandle := OpenMutex(MUTEX_ALL_ACCESS , False, UniqueAppStr);
if MutHandle = 0 then
begin
{ Mutex object has not yet been created, meaning that no previous }
{ instance has been created. }
ShowWindow(Application.Han dle, SW_ShowNormal);
Application.ShowMainForm:= True;
DoFirstInstance;
result := True;
end
else
begin
BroadcastFocusMessage;
result := False;
end;
end;
initialization
begin
UniqueAppStr := Application.Exexname;
MessageID := RegisterWindowMessage(Uniq ueAppStr);
ShowWindow(Application.Han dle, SW_Hide);
Application.ShowMainForm:= FALSE;
end;
finalization
begin
if WProc <> Nil then
{ Restore old window procedure }
SetWindowLong(Application. Handle, GWL_WNDPROC, LongInt(WProc));
end;
end.
Taken from Delphi 2 Developers Guide by Pacheco and Teixeira with heavy modifications.
Usage: In the Project source change to the following
--------------------------
if InitInstance then
begin
Application.Initialize;
Application.CreateForm(TFr
Application.Run;
end;
unit multinst;
{
Taken from Delphi 2 Developers Guide by Pacheco and Teixeira
With heavy Modifications.
Usage:
In the Project source change to the following
if InitInstance then
begin
Application.Initialize;
Application.CreateForm(TFr
Application.Run;
end;
That's all folks ( I hope ;()
}
interface
uses Forms, Windows, Dialogs, SysUtils;
const
MI_NO_ERROR = 0;
MI_FAIL_SUBCLASS = 1;
MI_FAIL_CREATE_MUTEX = 2;
{ Query this function to determine if error occurred in startup. }
{ Value will be one or more of the MI_* error flags. }
function GetMIError: Integer;
Function InitInstance : Boolean;
implementation
const
UniqueAppStr : PChar; {Change for every Application}
var
MessageId: Integer;
WProc: TFNWndProc = Nil;
MutHandle: THandle = 0;
MIError: Integer = 0;
function GetMIError: Integer;
begin
Result := MIError;
end;
function NewWndProc(Handle: HWND; Msg: Integer; wParam,
lParam: Longint): Longint; StdCall;
begin
{ If this is the registered message... }
if Msg = MessageID then begin
{ if main form is minimized, normalize it }
{ set focus to application }
if IsIconic(Application.Handl
Application.MainForm.Windo
ShowWindow(Application.Mai
end;
SetForegroundWindow(Applic
end
{ Otherwise, pass message on to old window proc }
else
Result := CallWindowProc(WProc, Handle, Msg, wParam, lParam);
end;
procedure SubClassApplication;
begin
{ We subclass Application window procedure so that }
{ Application.OnMessage remains available for user. }
WProc := TFNWndProc(SetWindowLong(A
Longint(@NewWndProc)));
{ Set appropriate error flag if error condition occurred }
if WProc = Nil then
MIError := MIError or MI_FAIL_SUBCLASS;
end;
procedure DoFirstInstance;
begin
SubClassApplication;
MutHandle := CreateMutex(Nil, False, UniqueAppStr);
if MutHandle = 0 then
MIError := MIError or MI_FAIL_CREATE_MUTEX;
end;
procedure BroadcastFocusMessage;
{ This is called when there is already an instance running. }
var
BSMRecipients: DWORD;
begin
{ Don't flash main form }
Application.ShowMainForm := False;
{ Post message and inform other instance to focus itself }
BSMRecipients := BSM_APPLICATIONS;
BroadCastSystemMessage(BSF
@BSMRecipients, MessageID, 0, 0);
end;
Function InitInstance : Boolean;
begin
MutHandle := OpenMutex(MUTEX_ALL_ACCESS
if MutHandle = 0 then
begin
{ Mutex object has not yet been created, meaning that no previous }
{ instance has been created. }
ShowWindow(Application.Han
Application.ShowMainForm:=
DoFirstInstance;
result := True;
end
else
begin
BroadcastFocusMessage;
result := False;
end;
end;
initialization
begin
UniqueAppStr := Application.Exexname;
MessageID := RegisterWindowMessage(Uniq
ShowWindow(Application.Han
Application.ShowMainForm:=
end;
finalization
begin
if WProc <> Nil then
{ Restore old window procedure }
SetWindowLong(Application.
end;
end.
Why so much code? It seems a bit like shooting canaries with dumdum bullets. I simply did like this:
program SingleInst;
uses
Forms,
Windows,
Messages,
MainUnit in 'MainUnit.pas' {Form1};
var
Handle1 : LongInt;
Handle2 : LongInt;
{$R *.RES}
Procedure Run;
Begin
Application.CreateForm(TFo rm1, Form1);
Application.Run;
End;
begin
Application.Initialize;
If LowerCase(ParamStr(1))='/d ebug' then Run // See not to interfear with Dephi projects at designtime
else
Begin
Handle1 := FindWindow('TForm1',nil);
if handle1 = 0 then Run else
begin
// Obtain handle to owner of Main Form. This is the application window
Handle2 := GetWindow(Handle1,GW_OWNER );
// Hide application window to avoid zoom effect
ShowWindow(Handle2,SW_HIDE );
// Restore application window
ShowWindow(Handle2,SW_REST ORE);
// Set Main Form as foreground window
SetForegroundWindow(Handle 1);
end;
end;
end.
..Just remember to rename your Form instance to anything but Form1 when using using this.
Regards
Williams
program SingleInst;
uses
Forms,
Windows,
Messages,
MainUnit in 'MainUnit.pas' {Form1};
var
Handle1 : LongInt;
Handle2 : LongInt;
{$R *.RES}
Procedure Run;
Begin
Application.CreateForm(TFo
Application.Run;
End;
begin
Application.Initialize;
If LowerCase(ParamStr(1))='/d
else
Begin
Handle1 := FindWindow('TForm1',nil);
if handle1 = 0 then Run else
begin
// Obtain handle to owner of Main Form. This is the application window
Handle2 := GetWindow(Handle1,GW_OWNER
// Hide application window to avoid zoom effect
ShowWindow(Handle2,SW_HIDE
// Restore application window
ShowWindow(Handle2,SW_REST
// Set Main Form as foreground window
SetForegroundWindow(Handle
end;
end;
end.
..Just remember to rename your Form instance to anything but Form1 when using using this.
Regards
Williams
williams2: Your comment is almost identical to my own!! (See my 1st & 2nd comments...) All you've done is to add code to restore the prev app and bring it to foreground, but zitt is having trouble even getting FindWindow to work!
JB
JB
Hi JimBob
Sorry, I missed your comment, hehe. I just saw Waldeks answer and felt like doing some Cut'n'paste job. But you're absolutely right. :-)
Regards
Williams
Sorry, I missed your comment, hehe. I just saw Waldeks answer and felt like doing some Cut'n'paste job. But you're absolutely right. :-)
Regards
Williams
ASKER
Waldek and others,
I appreciate your comments and proposed answer(s). I'm "rejecting" Waldek's answer not for his effort or solution, but because his solution is too complicated to implement without a complex "patch".
JimBob,
Yours was the most elegant, I want to give you the points. Please respond to the question with an answer so I can award points.
Technical:
The problem with my FindWindow was that under the Delphi3 IDE, the code:
if (FindWindow('TfrmTest', nil) > 0) then
ShowMessage('Already running...')
was detecting the "open" project in Delphi 3 and returning that my app was already running. I figured this out by closing Delphi and running the standalone EXE.
Now the question is:
Without a lot of code (or a command-line parameter), how does one detect he's trying to run under the IDE?
Thanks for all the responses!
John
I appreciate your comments and proposed answer(s). I'm "rejecting" Waldek's answer not for his effort or solution, but because his solution is too complicated to implement without a complex "patch".
JimBob,
Yours was the most elegant, I want to give you the points. Please respond to the question with an answer so I can award points.
Technical:
The problem with my FindWindow was that under the Delphi3 IDE, the code:
if (FindWindow('TfrmTest', nil) > 0) then
ShowMessage('Already running...')
was detecting the "open" project in Delphi 3 and returning that my app was already running. I figured this out by closing Delphi and running the standalone EXE.
Now the question is:
Without a lot of code (or a command-line parameter), how does one detect he's trying to run under the IDE?
Thanks for all the responses!
John
Yup! That's nice! The most simple thing is to add a "/debug" parameter in the Delphi project paramters menu.
I've tried to prevent this otherwise, but it's not trivial. I tried locating the application objects ComponentState property, and see to it to be different than csDesigning. That didn't seem to work, so I tried using messagehandling instead. That did work fine, but it's a bit complex. (Though that might be because of my incomplete knowledge to messagehandling).
Another approach could be to use DDE instead, and that's a typical MS solution, but it suck's a bit in my opninion.
All in all I ended up using a /debug parameter, since it doesn't need much attention compared to other approaches, but if you come up with other ideas, I'm very interested.
Regards
Williams
I've tried to prevent this otherwise, but it's not trivial. I tried locating the application objects ComponentState property, and see to it to be different than csDesigning. That didn't seem to work, so I tried using messagehandling instead. That did work fine, but it's a bit complex. (Though that might be because of my incomplete knowledge to messagehandling).
Another approach could be to use DDE instead, and that's a typical MS solution, but it suck's a bit in my opninion.
All in all I ended up using a /debug parameter, since it doesn't need much attention compared to other approaches, but if you come up with other ideas, I'm very interested.
Regards
Williams
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Hi JB
I owe you one. :-)
Regards
Williams
I owe you one. :-)
Regards
Williams
ASKER
JimBob,
I'm very pleased with all your answers. Everything has worked as expected.
Again, The key to getting FindWindow to work was realizing that it will return non-zero if your project is open in Delphi3.
John
I'm very pleased with all your answers. Everything has worked as expected.
Again, The key to getting FindWindow to work was realizing that it will return non-zero if your project is open in Delphi3.
John
You can try checking if your main form's window already exists.
In your project code, before "Application.Initialize;" add the following:
if (ProgramIsRunning) then
{ Exit the program or show some message... };
Implement ProgramIsRunning as follows (maybe you want to call it HPrevInst??):
function ProgramIsRunning: Boolean;
begin
// TMyMainForm is your apps main form.
// I.e. it is the form class called in the project code by:
// Application.CreateForm(TMy
Result := (FindWindow('TMyMainForm',
end;
Regards,
JB