Article View: borland.public.cppbuilder.deployment
Article #12Re: Run Only Ones ???
From: Danila Vershinin
Date: Mon, 28 Mar 2005 22:47
Date: Mon, 28 Mar 2005 22:47
204 lines
8807 bytes
8807 bytes
There are a couple of different ways to create a program that prevents
multiple instances from running. One simple technique is to use the
FindWindow API function. A more robust technique is to use mutexes or
semaphores. This FAQ demonstrates several ways to ensure that only once
instance of the program runs at a time. All of the methods share a common
premise: detect another instances of the program from the WinMain function,
and if you find one, return from WinMain without calling the Run method of
TApplication.
--------------------------------------------------------------------------------
Using FindWindow: The API FindWindow function searches for a window handle
based on a caption string or a registered WndClass. To prevent multiple
instances from running, call FindWindow from the WinMain function to search
for another program with the same window caption. If you find one, abort the
program
This example assumes that you have set the application's title to "single"
from the project options dialog.
--------------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
// Search for a previous instances using the caption of the
// the hidden application window. In order to do this, we
// must temporarily change our caption so that FindWindow
// doesn't find us (the hidden application window has
// already been created before WinMain runs)
Application->Title = "";
HWND hPrevApp = ::FindWindow(NULL, "single");
// FindWindow returns a non-zero HWND if it finds the window
// If the window was found, restore it and return without running
if(hPrevApp)
{
PostMessage(hPrevApp, WM_SYSCOMMAND, SC_RESTORE, 0);
return 0;
}
// else: other instance not found, restore the title and continue
else
Application->Title = "single";
try
{
Application->Initialize();
Application->Title = "single";
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}
--------------------------------------------------------------------------------
Using CreateMutex: The FindWindow approach is nice because it is simple and
easy to understand. Unfortunately, it has some drawbacks. For starters, it
assumes that the caption of the application never changes. Secondly, if the
user clicks an icon several times to start your app, the first app could be
pre-empted by the second app just after the FindWindow call executes, and
both programs might sneak through the if test.
CreateMutex provides a more robust way of testing to see if a previous
instance of a program has been created. Mutexes are system wide objects that
multiple processes can see. If program A creates a mutex, program B can see
that mutex. Mutex'es have names, and only one mutex of a given name can
exist on a machine at a time. If I create a mutex called "Bob's Special
Mutex", no other program can create a mutex with that name.
To use CreateMutex to prevent mutliple instances, you attempt to create a
mutex when WinMain starts. If the mutex cannot be created, then you know
another instance of the program must already be running because somebody had
to create the mutex. Here is sample code that demonstrates how to use
CreateMutex to prevent multiple instances.
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
// Attempt to create a mutex. If the mutex already existed,
// GetLastError will return ERROR_ALREADY_EXISTS
HANDLE hInstanceMutex = ::CreateMutex(NULL,TRUE, "PROJECT1");
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
if(hInstanceMutex)
CloseHandle(hInstanceMutex);
return 0;
}
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
ReleaseMutex(hInstanceMutex);
CloseHandle(hInstanceMutex);
return 0;
}
The OS serializes calls made to CreateMutex, so two instances of a program
can't sneak through the CreateMutex function the same way they sneak past
the FindWindow code. The OS also takes care of releasing the mutex if your
application crashes.
There are times when you may want to restore the original instance of a
program when the user launches a second instance. The following code
demonstrates how you can do that using CreateMutex and FindWindow.
CreateMutex handles the task of blocking mutliple instances of a program
from running, while FindWindow gives us a window handle that we can send the
restore message to.
This example assumes that you have set the application's title to "single"
from the project options dialog.
--------------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
HANDLE hInstanceMutex = ::CreateMutex(NULL,TRUE, "SINGLE.MUTEX");
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
if(hInstanceMutex)
CloseHandle(hInstanceMutex);
// Find the HWND of the hidden application window of the previous
// instance. Note that we are not looking for the HWND of the main
// form. This code fails miserably if you pass it the main form
// HWND instead of the Application's HWND
Application->Title = "";
HWND hPrevApp = ::FindWindow(NULL, "single");
if(hPrevApp)
PostMessage(hPrevApp, WM_SYSCOMMAND, SC_RESTORE, 0);
return 0;
}
try
{
Application->Initialize();
Application->Title = "single";
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
ReleaseMutex(hInstanceMutex);
CloseHandle(hInstanceMutex);
return 0;
}
--------------------------------------------------------------------------------
Using CreateSemaphore: The code example below demonstrates how you can use
semaphores to limit the number of instances of a program that can run at any
one time. This code puts the limit at 5. You can run 5 instances of the
program, but you will not be allowed to execute a sixth instance.
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
// Try to create a semaphore object. If the object already existed, the
// OS will return the previous semaphore without creating a new one
// Note: The semaphore count will decrease each time WaitForSingeObject
// is called. The third argument to CreateSemaphore determines
// the max number of instances. The second argument is the
// initial semaphore count.
HANDLE hSemaphore = ::CreateSemaphore(NULL,5,5, "SINGLE.SEMAPHORE");
// When WaitForSingleObject returns WAIT_OBJECT_O, the semaphore
// count has ran out.
if(hSemaphore && WaitForSingleObject(hSemaphore, 0) != WAIT_OBJECT_0)
{
CloseHandle(hSemaphore);
ShowMessage("Boss says we can only run 5 instances at a time");
return 0;
}
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
ReleaseSemaphore(hSemaphore,1,NULL);
CloseHandle(hSemaphore);
return 0;
}
Technical Details
Message-ID:
<42488a01@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!newshub.sdsu.edu!border1.nntp.dca.giganews.com!nntp.giganews.com!news.moat.net!news-out.newsfeeds.com!propagator3-LAX.newsfeeds.com!news-in.usenet.com!newsfeeds.ihug.co.nz!ihug.co.nz!newsgroups.borland.com!not-for-mailReferences:
<4188b413@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Thread: f8e54,6344dc180b40a147 X-Google-Attributes: gidf8e54,public X-Google-Language: ENGLISH,ASCII-7-bit From: "Danila Vershinin" <danprep@yahoo.com> Newsgroups: borland.public.cppbuilder.deployment References: <4188b413@newsgroups.borland.com> Subject: Re: Run Only Ones ??? Date: Tue, 29 Mar 2005 02:47:20 +0400 Lines: 206 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2900.2527 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2527 X-RFC2646: Format=Flowed; Original NNTP-Posting-Host: 80.95.45.243 Message-ID: <42488a01@newsgroups.borland.com> X-Trace: newsgroups.borland.com 1112050177 80.95.45.243 (28 Mar 2005 14:49:37 -0800) Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!newshub.sdsu.edu!border1.nntp.dca.giganews.com!nntp.giganews.com!news.moat.net!news-out.newsfeeds.com!propagator3-LAX.newsfeeds.com!news-in.usenet.com!newsfeeds.ihug.co.nz!ihug.co.nz!newsgroups.borland.com!not-for-mail