×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!
  • Students Click Here

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Jobs

Single Instance Applications

Single Instance Applications

Single Instance Applications

(OP)
Hi,

I'm using mutex to insure that only one instance of one of my application is running with this code (in Project.dpr):

CODE

var
 hMutex: THandle;
begin
  hMutex := CreateMutex(nil, False, 'termBlaster');
  if WaitForSingleObject (HMutex, 0) = WAIT_TIMEOUT then
  begin
    MessageDlg ('Only one allowed!', mtInformation, [mbOK], 0);
    Application.Terminate;
    exit;
  end;

I've also associated the application to some file extensions.  But if they have the application running, and the user double clicks on an associated file in Windows Explorer all they get is 'Only one allowed!'.  How can I get the current instance to load the file instead of displaying 'Only one allowed!'.

RE: Single Instance Applications

I got 80% of the way through typing an answer before I realised I was on the Delphi forum and not the VB.Net forum.

I can't remember what's available in the various Delphi units, but in .NET I would use System.Diagonostics.Process to locate:

The Process ID of this process and then look for a Process with the same name but a different Process ID.  If found bring the other process to the front and terminate this one.

Hopefully Delphi provides similar functionality, but my code sample would be obviously be useless here.

Hope this helps.

RE: Single Instance Applications

Maybe you could do something like this:

When you detect that there is already an instance open
and the new instances was supposed to load a file you
could have it create a file in for example the
application.exename path.

Now in the old instance you could use a timer to check
wether or not this file exists and when it does read the
file name and path out from that file and load it. Then of course you would have to delete the file that was created
afterwards.

  BobbaFet  

CODE

if not Programming = 'Severe Migraine' then
                       ShowMessage('Eureka!');

RE: Single Instance Applications

He is a better way to use a mutex.

CODE

var
  mAppMutexHnd: cardinal;
const
  APPLICATION_MUTEX_ID = 'AppMutex';
begin
  Application.Initialize;
  // Create mutex to show application is running
  mAppMutexHnd := CreateMutex(nil, BOOL(1), PChar APPLICATION_MUTEX_ID));
  // check if application was already running
  if (mAppMutexHnd = 0) or (GetLastError <> 0) then
  begin
    MessageBox(0, 'An instance of this application is already running.', 'Application already running', MB_ICONHAND);
    EXIT;
  end;
  try
    Application.Run;
  finally
    // release application's mutex that indicates it is running
    CloseHandle(mAppMutexHnd);
  end;
end.

I will look in to your original issue though. :)

-Markus Rissmann
www.tometasoftware.com

RE: Single Instance Applications

I use the following trick :

CODE

begin
 {$IFDEF MSWINDOWS}
 if ParamCount > 0 then                
  begin
  // there are some command line parameters, put them in the registry
   WriteCmdLineToRegistry(CmdLine);
  end;
 {$ENDIF}
 hwnd_first := FindWindow('TFrm_main', STR_APPNAME);
 if hwnd_first <> 0 then                   // app resides already in memory ??
  begin
   PostMessage(hwnd_first, WM_SYSTEM_UPDATED, 0, 0); // inform other program that registry has been updated
  end
 else
  begin
   Application.Initialize;
   Application.CreateForm(TFrm_Main, Frm_Main);
   Application.Run;
  end;
end.

my main form has a public method declared like this

CODE

procedure SystemUpdated(var msg : TMessage); message WM_SYSTEM_UPDATED;

// definition of WM_SYSTEM_UPDATED
{ custom windows messages }
 WM_USER                         = 22000;
 WM_SYSTEM_UPDATED               = WM_USER+1;

so this is what happens:

run the first instance of the application.
run a second instance of the application, this one will detect that there's already on in memory, so it will store it's parameters (like a filename) in a specific registry location and then posts a user defined message to the existing app. the existing app receives the message from the queue and will load the the stored registry data...

Cheers,
Daddy

-----------------------------------------------------
 What You See Is What You Get
Never underestimate tha powah of tha google!

RE: Single Instance Applications

(OP)
Thanks for your comments.

TometaSoftware: It looks good, but how is it better?  It seems  to accomplish the same thing.. I'm fairly new to mutex.  I'll be looking into mutexes.

whosrdaddy: I'm trying to make your code with mutex, because I will need to use them anyways.

Thanks!

RE: Single Instance Applications

Omnicog,

mutex is indeed a solution here, but don't forget you need to find the Handle of the running app's window to do the post message trick...

-----------------------------------------------------
 What You See Is What You Get
Never underestimate tha powah of tha google!

RE: Single Instance Applications

My post was to help you do the mutex correctly. My way is one of the safest ways that I have found to make sure that the mutex is never left behind.

I am still researching your original question:

"How can I get the current instance to load the file instead of displaying 'Only one allowed!'."

It would be nice to know.

RE: Single Instance Applications

I did post one solution for that, I'll be the first to admit that it's not a very nifty way of doing it, but it'll
work.

  BobbaFet  

CODE

if not Programming = 'Severe Migraine' then
                       ShowMessage('Eureka!');

RE: Single Instance Applications

(OP)
I'm sorry, BobbaFet didn't mean to leave you out :D

I like your solution, but it could probably be done with a registry entry.  I do appreciate your help though, thanks.

RE: Single Instance Applications

(OP)
Alright, I got something working that using mutex and postmessage (no extra registry entries or files).  It does not handle multiple command line arguments.

In case someone else is, in the App unit (Credit go to TometaSoftware, whosrdaddy for the hard parts, and random google results for the whole atom tables thing):

CODE

var
 hMutex: THandle;
 hwndFirst: HWND;
 lParam: Word;
 commandArg: AnsiString;
const
  APPLICATION_MUTEX_ID = 'AppMutex';
begin
  Application.Initialize;

  {See TometaSoftware's post for a better example}
  hMutex := CreateMutex(nil, True, PChar (APPLICATION_MUTEX_ID));

  if (hMutex = 0) or (GetLastError <> 0) then
  begin
    {See whosrdaddy's post for a better example}
    hwndFirst := FindWindow ('TfrmMain', nil);
    if ParamStr(1) <> ' then
    begin
      // Get the first command line argument
      commandArg := ParamStr(1);
      // Add to global atom table and get it's id
      lParam := GlobalAddAtom(PAnsiChar(commandArg));
      // Pass length of the string and the id
      PostMessage (hwndFirst, WM_SYSTEM_UPDATED, Length(commandArg), lParam)
    end
    exit;
  end;

Reciever:

CODE

const
  WM_SYSTEM_UPDATED = WM_USER + 1;
...
procedure SystemUpdateMessage(var Msg: TMessage); message WM_SYSTEM_UPDATED;
...

procedure TfrmMain.SystemUpdateMessage(var Msg: TMessage);
var
  FileName: String;
  Buffer: PChar;
begin
  // Get FileName from the global atom table
  Buffer := StrAlloc(Msg.wParam + 1);
  GlobalGetAtomName(Msg.lParam, Buffer, Msg.wParam + 1);
  GlobalDeleteAtom(Msg.lParam);
  FileName := StrPas(Buffer);
  // Do something with the FileName
  DoSomethingWithIt(FileName);
end;

If anyone is interested, I found this AFTER already putting most of the pieces together sadeyes that does exactly the same thing, but is a bit complex and probably does it better.  It allows for more than one argument.

http://www.swissdelphicenter.ch/torry/showcode.php?id=2126

RE: Single Instance Applications

Omnicog, be aware that the line

CODE

 hwndFirst := FindWindow ('TfrmMain', nil);
is not 100% foulproof, suppose you have a second app (something totally different) with the same formclass name (TfrmMain). So you'll need to find a way to make SURE you have the right Hwnd...

-----------------------------------------------------
 What You See Is What You Get
Never underestimate tha powah of tha google!

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close