BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

How to prevent an application running twice?

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (VCL Components Development)
View previous topic :: View next topic  
Author Message
julius
Guest





PostPosted: Thu Apr 21, 2005 12:21 pm    Post subject: How to prevent an application running twice? Reply with quote



Hello,
How to prevent an application from running twice?

What I mean is :I want to detect if the same program is running.If yes, I
want to terminate this one.

The IDE is C++Builder 6.0.

Because the application contains a server socket. If two instance running
concurrently, problem may happen due to same socket port can not be opened
twice on the same computer.

Thanks


Julius Wang


Back to top
Hans
Guest





PostPosted: Thu Apr 21, 2005 12:48 pm    Post subject: Re: How to prevent an application running twice? Reply with quote




"julius" <juliuswang (AT) sina (DOT) com> wrote

Quote:
Hello,
How to prevent an application from running twice?

What I mean is :I want to detect if the same program is running.If yes, I
want to terminate this one.

The IDE is C++Builder 6.0.

Because the application contains a server socket. If two instance running
concurrently, problem may happen due to same socket port can not be opened
twice on the same computer.


In your project's main cpp file:

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
// only one instance of this program is allowed

// Create a mutex
::CreateMutex(NULL,NULL, "UniqueString"); // Use a unique
string

// If the mutex already existed, i.e. another instance is already
running, the creation failed
if (GetLastError())
{
// So, find the first instance
HWND FirstWnd;
Application->Title = "";
FirstWnd = ::FindWindow("TApplication", "MyApp");

// And make it active
PostMessage(FirstWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
::SetForegroundWindow(FirstWnd);
}
else
{
// Otherwise, them mutex-creation succeeded, act as normal
Application->Initialize();
Application->Title = "MyApp";

Application->CreateForm(__classid(TpoMainForm), &poMainForm);
Application->Run();
}
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}

HTH, Hans



Back to top
Francisco M. Marzoa
Guest





PostPosted: Thu Apr 21, 2005 1:31 pm    Post subject: Re: How to prevent an application running twice? Reply with quote



julius wrote:
Quote:
Hello,
How to prevent an application from running twice?

What I mean is :I want to detect if the same program is running.If yes, I
want to terminate this one.

The IDE is C++Builder 6.0.

Because the application contains a server socket. If two instance running
concurrently, problem may happen due to same socket port can not be opened
twice on the same computer.

If you can open the TCP port your application will not run, no matter if
there's another instance of the same application blocking it or if its
another different application, so you can handle both cases in the same
manner.

BTW. this seems to be an offtopic in VCL components writing list.

Quote:

Thanks


Julius Wang





Back to top
Hans Galema
Guest





PostPosted: Thu Apr 21, 2005 2:07 pm    Post subject: Re: How to prevent an application running twice? Reply with quote

julius wrote:

Quote:
How to prevent an application from running twice?

What I mean is :I want to detect if the same program is running.If yes, I
want to terminate this one.

Which is this >

Quote:
Because the application contains a server socket. If two instance running
concurrently, problem may happen due to same socket port can not be opened
twice on the same computer.

Well then you are done! If your program cannot open its port for listening
then it is not the first instance. So let the application terminate then.

Hans.

Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Thu Apr 21, 2005 4:48 pm    Post subject: Re: How to prevent an application running twice? Reply with quote


"Hans Galema" <notused (AT) notused (DOT) nl> wrote


Quote:
Well then you are done! If your program cannot open its port
for listening then it is not the first instance. So let the application
terminate then.

That is a little misleading. A completely unrelated program may be using
the port. The presense of the port being used does not automatically mean
that his own program is running multiple times.


Gambit



Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Thu Apr 21, 2005 4:50 pm    Post subject: Re: How to prevent an application running twice? Reply with quote


"julius" <juliuswang (AT) sina (DOT) com> wrote


Quote:
How to prevent an application from running twice?

Prevent multiple instances of the same program from running
http://web.archive.org/web/20030626080800/www.bcbdev.com/faqs/faq74.htm


Gambit



Back to top
Hans Galema
Guest





PostPosted: Thu Apr 21, 2005 6:07 pm    Post subject: Re: How to prevent an application running twice? Reply with quote

Remy Lebeau (TeamB) wrote:

Quote:
Well then you are done! If your program cannot open its port
for listening then it is not the first instance. So let the application
terminate then.

That is a little misleading. A completely unrelated program may be using
the port. The presense of the port being used does not automatically mean
that his own program is running multiple times.

Indeed. So I will rephrase:

Well then you are done! If your program cannot open its port
for listening then it is not the first one that listens on that port.
So let the application terminate then.

Hans.

Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Thu Apr 21, 2005 6:18 pm    Post subject: Re: How to prevent an application running twice? Reply with quote


"Hans Galema" <notused (AT) notused (DOT) nl> wrote


Quote:
Well then you are done! If your program cannot open its port
for listening then it is not the first one that listens on that port.
So let the application terminate then.

That may not be desirable either. If the first instance of the program
cannot gain access to the port, that does not mean that the program should
automatically terminate itself. He may want it to do other things, or try
other ports, etc.


Gambit



Back to top
JD
Guest





PostPosted: Fri Apr 22, 2005 9:15 am    Post subject: Re: How to prevent an application running twice? Reply with quote


"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote:
Quote:

"julius" <juliuswang (AT) sina (DOT) com> wrote in message
news:42679a8e (AT) newsgroups (DOT) borland.com...

How to prevent an application from running twice?

Prevent multiple instances of the same program from running
http://web.archive.org/web/20030626080800/www.bcbdev.com/faqs/faq74.htm


None of the samples by H^2 address a known problem with
correctly restoring the first instance.

~ JD


Back to top
gary
Guest





PostPosted: Fri Apr 22, 2005 11:50 am    Post subject: Re: How to prevent an application running twice? Reply with quote

code snippet that should get you on the right track

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
::CreateMutex(NULL,NULL,"DELIVERYPOSMUTEX");
if (GetLastError())
{
Application->Title = "Delivery POS Duplicate";
HWND FirstWnd;
FirstWnd = ::FindWindow("TApplication","Delivery POS");
if (FirstWnd!=NULL)
{
if (::IsIconic(FirstWnd))
{
::ShowWindow(FirstWnd,SW_SHOWDEFAULT);
}
::SetForegroundWindow(FirstWnd);
}
else
Application->MessageBox("Application Already RunningnCheck
Your Task Bar","Application Running",MB_OK+MB_ICONINFORMATION);
}
else
{
Application->Initialize();
Application->Title = "Delivery POS";
Application->CreateForm(__classid(Tpassword), &password);
Application->Run();
}
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}

HTT
Gary


Back to top
Michel Corbin
Guest





PostPosted: Fri Apr 22, 2005 1:26 pm    Post subject: Re: How to prevent an application running twice? Reply with quote

A simple way to achieve that is to give a very special name
to the main form (the Caption property) of your application.
then in the WinMain function (in the CPP file that has the
same name as your project) you add at the beginning :

HWND hWnd=::FindWindow(NULL,"The special Name") ;
// change "The Special Name" to the real Caption
if(hWnd)
{
Application->MessageBox("Already running","Process stopped",
MB_OK) ;
return 0 ;
}

Michel.


julius wrote:
Quote:
Hello,
How to prevent an application from running twice?



Back to top
JD
Guest





PostPosted: Sun Apr 24, 2005 8:24 am    Post subject: Re: How to prevent an application running twice? Reply with quote


"gary" <user (AT) home (DOT) com> wrote:
Quote:

[...]
if (::IsIconic(FirstWnd))

If you test this code, you'll find that IsIconic (and related
functions) will *always* return false, be it minimized or not,
unless you apply WS_EX_APPWINDOW to it's exStyle and if you do
that, you'll get 2 icons on the taskbar.

If you presume that it's minimized and restore it regardless
of it's state, you'll end up disabling the Minimize border
icon.

For your sample to work as expected, you need to use the
win32 API RegisterMessage so that both instance interpret
the message the same and then use the SendMessage API to
send that message to the first instance.

Then you have to override the main form's WndProc method so
that you can recieve notice of the custom message. In
addition, the WndProc needs to monitor the main form's window
state by listening for WM_SYSCOMMAND with a WParam of
SC_MINIMIZE, SC_MAXIMIZE or SC_RESTORE. This way, when the
custom message is recieved, you'll know if you need to restore
the application or simply bring it to front.

One possible final issue (it's been a while so I can't recall)
is if the user uses the system menu to change the window state.
IIRC, that *does not* generate a WM_SYSCOMMAND so you're right
back where you started from.

~ JD


Back to top
JD
Guest





PostPosted: Sun Apr 24, 2005 8:34 am    Post subject: Re: How to prevent an application running twice? Reply with quote


"julius" <juliuswang (AT) sina (DOT) com> wrote:
Quote:

How to prevent an application from running twice?

The following is a fully tested component. To use it, all you
have to do is drop it on the main form and give your main form
a unique class name, something like: CompanyNameApplicationName

//-------------------------------------------------------------
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
//-------------------------------------------------------------
class PACKAGE TSingleInstance : public TComponent
{
private:
bool FHooked;
bool FMinimized;
HANDLE hMutex;
HHOOK WndReturnHook;
unsigned int SI_CUSTOM_MESSAGE;
TForm* FParentForm;
protected:
bool __fastcall AppWndProcHook( TMessage &Message );
static int __stdcall CallWndRetCallBackProc( int Code, WPARAM WParam, LPARAM LParam );
public:
__fastcall TSingleInstance(TComponent* Owner);
__fastcall ~TSingleInstance();
};
//-------------------------------------------------------------
#endif

//-------------------------------------------------------------
#include <vcl.h>
#include <basepch.h>

#pragma hdrstop

#include "SingleInstance.h"
#pragma package(smart_init)
//-------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TSingleInstance *)
{
new TSingleInstance(NULL);
}
//-------------------------------------------------------------

TSingleInstance* ThisSingleInstance = NULL;
HWND hFirstInstance, hSecondInstance;
//-------------------------------------------------------------
BOOL CALLBACK EnumWindowsCallBack( HWND hWnd, LPARAM lParam )
{
char WindowClassName[256] = {0};
if( ::GetClassName(hWnd, WindowClassName, 255) )
{
if( stricmp(WindowClassName, (char*)lParam) == 0)
{
if( hFirstInstance )
{
hSecondInstance = hWnd;
return FALSE;
}
else hFirstInstance = hWnd;
}
}
return TRUE;
}
//-------------------------------------------------------------
__fastcall TSingleInstance::TSingleInstance(TComponent* Owner) : TComponent(Owner)
{
if( ThisSingleInstance ) throw Exception("TSingleInstance : Only one instance of TSingleInstance is allowed per application.");
if( !Owner ) throw Exception("TSingleInstance : You must assign an Owner.");
FParentForm = dynamic_cast<TForm*>(Owner);
if( !FParentForm ) throw Exception("TSingleInstance : The Owner must be a TForm.");
ThisSingleInstance = this;

FHooked = false;
hMutex = NULL;
WndReturnHook = NULL;

if( !ComponentState.Contains(csDesigning) )
{
FMinimized = false;
char ThisClassName[ 256 ] = { 0 };
::GetClassName( FParentForm->Handle, ThisClassName, 255 );
SI_CUSTOM_MESSAGE = ::RegisterWindowMessage( ThisClassName );
hMutex = ::CreateMutex( NULL, TRUE, ThisClassName );
if( GetLastError() == ERROR_ALREADY_EXISTS )
{
Application->ShowMainForm = false;
hFirstInstance = hSecondInstance = NULL;
::EnumWindows( (WNDENUMPROC)EnumWindowsCallBack, (LPARAM)ThisClassName );
if( hFirstInstance == FParentForm->Handle ) hFirstInstance = hSecondInstance;
::SendMessage( hFirstInstance, SI_CUSTOM_MESSAGE, 0, 0 );
::SetForegroundWindow( hFirstInstance );
Application->Terminate();
}
else
{
Application->HookMainWindow( AppWndProcHook );
FHooked = true;
WndReturnHook = ::SetWindowsHookEx( WH_CALLWNDPROCRET, (int (__stdcall*)())CallWndRetCallBackProc, HInstance, ::GetCurrentThreadId() );
::PostMessage( Application->Handle, SI_CUSTOM_MESSAGE, 0, 0 );
}
}
}
//-------------------------------------------------------------
__fastcall TSingleInstance::~TSingleInstance()
{
if( FHooked ) Application->UnhookMainWindow( AppWndProcHook );
if( WndReturnHook ) ::UnhookWindowsHookEx( WndReturnHook );
if( hMutex ) ::CloseHandle( hMutex );
ThisSingleInstance = NULL;
}
//-------------------------------------------------------------
bool __fastcall TSingleInstance::AppWndProcHook( TMessage &Message )
{ /*
There is a problem with windows correctly recording the window state
when the form's exStyle does not include WS_EX_APPWINDOW. To be more
exact, without WS_EX_APPWINDOW, when the form is minimized, windows will
report the last state prior to minimizing so API's such as IsIconic will
fail to detect the correct window state. This is important because if
one blindly restores the first instance when it is already in a restored
state, it will exibit strange behavior when the user tries to minimize
the first instance.

The only way around this is to not manipulate the first instance's window
state directly and instead monitor the application's window state so that
the first instance can determine what it wants to do when it recieves a
custom restore message. */

if( Message.Msg == WM_SYSCOMMAND )
{
switch( Message.WParam )
{
case SC_RESTORE:
case SC_MAXIMIZE: FMinimized = false; break;
case SC_MINIMIZE: FMinimized = true;
}
}
else if( Message.Msg == SI_CUSTOM_MESSAGE )
{
// SI_CUSTOM_MESSAGE only reaches here once and is used to complete
// initialization. I could have used a seperate message but there was
// no need to register a seperate message.
if( FParentForm != Application->MainForm )
{
// The application is already running at this point. I had to wait
// to check if the object was owned by the main form and this is
// important because this hooks into the owner and it needs to be
// hooked into the main form.
::MessageBox(Application->MainForm->Handle, "TSingleInstance : Object can only be placed on the Main Form.", Application->Title.c_str(), MB_APPLMODAL | MB_ICONERROR | MB_OK );
Application->Terminate();
}
}
return false;
}
//-------------------------------------------------------------
int __stdcall TSingleInstance::CallWndRetCallBackProc( int Code, WPARAM WParam, LPARAM LParam )
{
if( Code == HC_ACTION )
{
CWPRETSTRUCT* cwp = (CWPRETSTRUCT *) LParam;
if( cwp->message == ThisSingleInstance->SI_CUSTOM_MESSAGE )
{
if( ThisSingleInstance->FMinimized )
{
::SendMessage( Application->Handle, WM_SYSCOMMAND, SC_RESTORE, 0 );
}
}
}
return ::CallNextHookEx( ThisSingleInstance->WndReturnHook, Code, WParam, LParam );
}
//-------------------------------------------------------------
namespace Singleinstance
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TSingleInstance)};
RegisterComponents("JD", classes, 0);
}
}
//-------------------------------------------------------------

~ JD


Back to top
Shiv Sarna
Guest





PostPosted: Thu Apr 28, 2005 7:52 am    Post subject: Re: How to prevent an application running twice? Reply with quote

I had this in the WinMain function of one of my programs (replace
PROGRAMNAME)


// Create mutex for application
HANDLE hInstanceMutex = ::CreateMutex(NULL, TRUE, "PROGRAMNAME");

// Check to see if mutex already exists
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
if(hInstanceMutex)
CloseHandle(hInstanceMutex);

HWND hPrevApp = ::FindWindow(NULL, "PROGRAMNAME");
if(hPrevApp)
PostMessage(hPrevApp, WM_SYSCOMMAND, SC_RESTORE, 0);
return 0;
}

// Release the mutex for this application
ReleaseMutex(hInstanceMutex);
CloseHandle(hInstanceMutex);
return 0;

and this worked fine. Its a lot shorter than the other thing. I'm not sure
how a mutex is flagged in windows, maybe its a value put temporarily in the
registry or something. But this thing just checks if the mutex has already
been made, and if so just gives focus to the window of the already open
program. It was a long time ago I used this, and i could'nt find any code in
my project for destroying the mutex afterwards, so i guess its done
automatically.

Amit


Back to top
JD
Guest





PostPosted: Fri Apr 29, 2005 8:02 am    Post subject: Re: How to prevent an application running twice? Reply with quote


"Shiv Sarna" <ss012b4953 (AT) blueyonder (DOT) co.uk> wrote:
Quote:
I had this in the WinMain function of one of my programs (replace
PROGRAMNAME) [...] and this worked fine.

You should test it. I think that you'll be surprised to see
what happens when you restore the first instace when it's not
minimized or maximized.

You can mimic what would happen by adding a TApplication::OnDeactivate
event where you post that message to the main form. Then just
play with minimizing and restoring it. You'll get the picture...

In addition, your method of using FindWindow is flawed because
you could get a handle to the second instance because the
PROGRAMNAME is the same for both.

Quote:
Its a lot shorter than the other thing.

Your method would be more involved if it handled the above.
At a minimum, you'd need to override the main form's WndProc
method. Besides, being able to drop a component on the form
is much more re-usable and that's exactly what this group is
about ... writing components.

Your method is also unreliable if used with an MDI application
because PROGRAMNAME changes to include the active MDI Child
(if any) caption.

Which would you prefere: a component that you can drop on the
form and forget about or would you rather hand craft the code
each and every time you needed it and forget about supporting
MDI application?

Quote:
[...] and if so just gives focus to the window of the
already open program.

The code is flawed. If the window's state is restored, it
won't get focus unless it's by chance at the top of the Z-
order.

Quote:
[...] destroying the mutex afterwards, so i guess its done
automatically.

That is an incorrect assumption.

~ JD


Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (VCL Components Development) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.