Jump to content

Prevent Multiple Instance of a Program (using Mutex)

- - - - -

  • Please log in to reply
3 replies to this topic

#1
LuthfiHakim

LuthfiHakim

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 765 posts
There are often times we want to make sure that at any given time there is only one instance of our program running. Many solutions available for this problem. Some of them:

  • Find process in process list
  • Find window name
  • Checking existence and status (locked or free) of a file
  • Using OS flags

My favorite is using OS flags, since in my opinion it's the simplest from all the methods. And from several OS flags (or several features that can be used as a flag) provided by Windows, Mutex is my favorite one. You can read more details abut mutex here.

Mutex: The Basics

Quoted from msdn article:

Quote

You can use a mutex object to protect a shared resource from simultaneous access by multiple threads or processes. Each thread must wait for ownership of the mutex before it can execute the code that accesses the shared resource. For example, if several threads share access to a database, the threads can use a mutex object to permit only one thread at a time to write to the database.

From the excerpt above we can deduce that an application can create mutex that unique and detectable from other applications. Therefore we should detect our mutex before move onto the main code of a program. If the mutex exists we should terminate the current process, otherwise we create the mutex ourselves and continue to main code.

The creator of the mutex (i.e. the first instance) must destroy or release the mutex when it is terminated. This is to make sure that the mutex does not exist anymore, so the next first instance of our program can create the mutex successfully. However it's just a good practice. Because Windows actually keeps records of mutex owner. Once the owner got terminated, the mutex will also be destroyed.

Our pseudocode is:

begin

  if MutexIsExists(OurMutexID) then

    Terminate

  else begin

    CreateMutex(OurMutexID);

    Goto MainProgram;

    DestroyMutex;

  end;

end;


Code Implementation

For this tutorial in dealing with mutex we'll be relying on windows api CreateMutex. Official details of CreateMutex is available here.

To check the existence of a mutex we have to call CreateMutex to create a mutex with a specific name, and set us (the caller) as the owner of the mutex. If mutex with the same name already exists, CreateMutex can not set us as the owner and it will raise error with code ERROR_ALREADY_EXISTS (183). If it does not exist, then CreateMutex will succesfully create the mutex and return the handle of the mutex.

In Delphi project, the best place to put the checking code is in .dpr file, immediately after enter the main begin...end block. But this is not mandatory, you can put the checking code in any other place that you want according to specific requirements.

Here is the sample code, in this tutorial we want to show a message before terminating if the same program is already running.


program SingleInstance;


uses

  Windows,

  Forms,

  Dialogs,

  Main_SingleInstance in 'Main_SingleInstance.pas' {Form1};


{$R *.res}


const

  MutexName        = 'CodeCall.Net Mutex';

resourcestring

  DUPLICATE_MSG    = 'Another instance of this program is already running. This one will shutdown';

var

  vMutex: THandle;

begin

  // try to create our mutex

  vMutex := CreateMutex(nil, True, MutexName);


  // check if the previous line caused error and the error is ERROR_ALREADY_EXISTS

  if GetLastError = ERROR_ALREADY_EXISTS then

  begin

    // show the duplication message

    MessageDlg(DUPLICATE_MSG, mtError, [mbOk], 0);

    Exit;  // terminates the program

  end;

  try

    Application.Initialize;

    Application.CreateForm(TForm1, Form1);

    Application.Run;

  finally

    // release the mutex

    CloseHandle(vMutex);

  end;

end.


After compilation, let's try the demo program. First execute will nicely show our main form like this:

[ATTACH]3670[/ATTACH]

Now while the first one is still running, try to execute the same exe once again. This time it will show an error message like shown below. After we close the message, it will immediately terminate.

[ATTACH]3669[/ATTACH]

Full source code of the demo project is attached. Feel free to use or improve.

Attached Files


Edited by LuthfiHakim, 20 March 2011 - 04:17 PM.
fixing code formatting and tag error


#2
Alexander

Alexander

    It's Science!

  • Moderators
  • 4,124 posts
  • Location:Vancouver, Eh! Cleverness: 200
Very nice tutorial, I am definitely digesting this when I understand a little more about Delphi, I am wishing to learn.
Be sure to read the updated FAQ! || Health is achieved through the same 10,000 steps.
If a suggested code/method fails, informing us is less important than telling us why or what errors occurred.

#3
LuthfiHakim

LuthfiHakim

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 765 posts
Thank you, Alex! Let me know if you need help learning Delphi. You already did help me a lot in learning PHP! :c-thumbup:

#4
rolakyng

rolakyng

    Newbie

  • Members
  • Pip
  • 1 posts

LuthfiHakim said:

There are often times we want to make sure that at any given time there is only one instance of our program running. Many solutions available for this problem. Some of them:

  • Find process in process list
  • Find window name
  • Checking existence and status (locked or free) of a file
  • Using OS flags

My favorite is using OS flags, since in my opinion it's the simplest from all the methods. And from several OS flags (or several features that can be used as a flag) provided by Windows, Mutex is my favorite one. You can read more details abut mutex here.

Mutex: The Basics

Quoted from msdn article:


From the excerpt above we can deduce that an application can create mutex that unique and detectable from other applications. Therefore we should detect our mutex before move onto the main code of a program. If the mutex exists we should terminate the current process, otherwise we create the mutex ourselves and continue to main code.

The creator of the mutex (i.e. the first instance) must destroy or release the mutex when it is terminated. This is to make sure that the mutex does not exist anymore, so the next first instance of our program can create the mutex successfully. However it's just a good practice. Because Windows actually keeps records of mutex owner. Once the owner got terminated, the mutex will also be destroyed.

Our pseudocode is:

begin

  if MutexIsExists(OurMutexID) then

    Terminate

  else begin

    CreateMutex(OurMutexID);

    Goto MainProgram;

    DestroyMutex;

  end;

end;


Code Implementation

For this tutorial in dealing with mutex we'll be relying on windows api CreateMutex. Official details of CreateMutex is available here.

To check the existence of a mutex we have to call CreateMutex to create a mutex with a specific name, and set us (the caller) as the owner of the mutex. If mutex with the same name already exists, CreateMutex can not set us as the owner and it will raise error with code ERROR_ALREADY_EXISTS (183). If it does not exist, then CreateMutex will succesfully create the mutex and return the handle of the mutex.

In Delphi project, the best place to put the checking code is in .dpr file, immediately after enter the main begin...end block. But this is not mandatory, you can put the checking code in any other place that you want according to specific requirements.

Here is the sample code, in this tutorial we want to show a message before terminating if the same program is already running.


program SingleInstance;


uses

  Windows,

  Forms,

  Dialogs,

  Main_SingleInstance in 'Main_SingleInstance.pas' {Form1};


{$R *.res}


const

  MutexName        = 'CodeCall.Net Mutex';

resourcestring

  DUPLICATE_MSG    = 'Another instance of this program is already running. This one will shutdown';

var

  vMutex: THandle;

begin

  // try to create our mutex

  vMutex := CreateMutex(nil, True, MutexName);


  // check if the previous line caused error and the error is ERROR_ALREADY_EXISTS

  if GetLastError = ERROR_ALREADY_EXISTS then

  begin

    // show the duplication message

    MessageDlg(DUPLICATE_MSG, mtError, [mbOk], 0);

    Exit;  // terminates the program

  end;

  try

    Application.Initialize;

    Application.CreateForm(TForm1, Form1);

    Application.Run;

  finally

    // release the mutex

    CloseHandle(vMutex);

  end;

end.


After compilation, let's try the demo program. First execute will nicely show our main form like this:

[ATTACH]3670[/ATTACH]

Now while the first one is still running, try to execute the same exe once again. This time it will show an error message like shown below. After we close the message, it will immediately terminated.

[ATTACH]3669[/ATTACH]

Full source code of the demo project is attached. Feel free to use or improve.

Hey thanks a lot for post.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users