Solved

D3: Determining if App is already running (no HPrevInst)

Posted on 1998-03-22
16
958 Views
Last Modified: 2010-08-05
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
0
Comment
Question by:zitt
  • 5
  • 4
  • 4
  • +2
16 Comments
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1360710
Hi

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(TMyMainForm, MyMainForm);
  Result := (FindWindow('TMyMainForm', nil) > 0);
end;

Regards,
JB
0
 
LVL 4

Expert Comment

by:BoRiS
ID: 1360711
I agree with JimBob there....

you can also try this code :

MessageID := RegisterWindowMessage('Check 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(Sender: TObject);
begin
  Application.OnMessage := OnAppMessage;
end;


0
 

Author Comment

by:zitt
ID: 1360712
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
0
 

Author Comment

by:zitt
ID: 1360713
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.
0
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1360714
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(TfrmTest, 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
0
 
LVL 4

Expert Comment

by:BoRiS
ID: 1360715
"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
0
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1360716
Hi zitt

HPrevInst IS defined in D3 (in System.pas) but it may (??) not be used in Win 95...

JB
0
 
LVL 2

Expert Comment

by:Waldek
ID: 1360717
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(TFrmSelProject, 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(TFrmSelProject, 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.Handle) then begin
      Application.MainForm.WindowState := wsNormal;
      ShowWindow(Application.Mainform.Handle, sw_restore);
    end;
    SetForegroundWindow(Application.MainForm.Handle);
  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(Application.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_IGNORECURRENTTASK 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.Handle, SW_ShowNormal);
    Application.ShowMainForm:=True;
    DoFirstInstance;
    result := True;
  end
  else
  begin
    BroadcastFocusMessage;
    result := False;
  end;
end;

initialization

begin
   UniqueAppStr := Application.Exexname;
   MessageID := RegisterWindowMessage(UniqueAppStr);
   ShowWindow(Application.Handle, 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.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 3

Expert Comment

by:williams2
ID: 1360718
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(TForm1, Form1);
    Application.Run;
  End;

begin
  Application.Initialize;
  If LowerCase(ParamStr(1))='/debug' 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_RESTORE);
      // Set Main Form as foreground window
      SetForegroundWindow(Handle1);
    end;
  end;
end.

..Just remember to rename your Form instance to anything but Form1 when using using this.

Regards
Williams
0
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1360719
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
0
 
LVL 3

Expert Comment

by:williams2
ID: 1360720
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
0
 

Author Comment

by:zitt
ID: 1360721
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
0
 
LVL 3

Expert Comment

by:williams2
ID: 1360722
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
0
 
LVL 5

Accepted Solution

by:
JimBob091197 earned 100 total points
ID: 1360723
Hi again

I take it then that you are satisfied with "Result := (FindWindow('TMyMainForm', nil) > 0);"?

BTW, to determine if the Delphi IDE is running, I have the following function.  (Note: it checks for the Delphi main window and the Object Inspector (even if the Obj Inspector is not visible it still works).  You can check for other windows too (e.g. Watch window), but these 2 should be enough.  Also, this function checks if Delphi is running, but not necessarily that your app is the current Delphi project!!)

function DelphiIsRunning: Boolean;
begin
  Result := (FindWindow('TAppBuilder', nil) > 0) and
            (FindWindow('TPropertyInspector', nil) > 0);
end;

Cheers,
JB
0
 
LVL 3

Expert Comment

by:williams2
ID: 1360724
Hi JB

I owe you one. :-)

Regards
Williams
0
 

Author Comment

by:zitt
ID: 1360725
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
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now