Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Prevent User from starting Myprog more than once

8 views
Skip to first unread message

JV

unread,
Oct 3, 2005, 9:07:41 AM10/3/05
to
Hi,

How can I prevent my users to start my program more than one time?

Thanks very much

Jan


Andrew Fedoseev

unread,
Oct 3, 2005, 9:39:33 AM10/3/05
to
I think you should take a look at this
http://www.codeproject.com/Purgatory/single_instance.asp


"JV" <xs...@hotmail.com> сообщил/сообщила в новостях следующее:
news:4341...@newsgroups.borland.com...

poojo hackma

unread,
Oct 3, 2005, 11:04:21 AM10/3/05
to
> How can I prevent my users to start my program more than one time?

Here is another approach:

//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
// determine if another instance is running:
HWND hWnd1, hWnd2;
hWnd1 = FindWindow("TMyForm", NULL);
if (hWnd1) {
MessageBox(NULL, "A version is already running.", "App Msg", MB_OK);
hWnd2 = GetLastActivePopup(hWnd1);
BringWindowToTop(hWnd1);
if (hWnd1 != hWnd2) {
BringWindowToTop(hWnd2);
return false;
}
} else {
try {
Application->Initialize();
}
catch (Exception &exception) {
Application->ShowException(&exception);
}
catch (...) {
try {
throw Exception("");
}
catch (Exception &exception) {
Application->ShowException(&exception);
}
}
}
return 0;
}


JD

unread,
Oct 3, 2005, 1:28:01 PM10/3/05
to

"Remy Lebeau \(TeamB\)" <no....@no.spam.com> wrote:
>
>
> Prevent multiple instances of the program from running
> http://web.archive.org/web/20030626080800/www.bcbdev.com/faqs/faq74.htm

While that code will prevent multiple instances, it does not
correctly restore the first instance 100% of the time.

~ JD

Remy Lebeau (TeamB)

unread,
Oct 3, 2005, 1:20:36 PM10/3/05
to

"JV" <xs...@hotmail.com> wrote in message
news:4341...@newsgroups.borland.com...

> How can I prevent my users to start my program more than one time?

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


Gambit


JD

unread,
Oct 3, 2005, 1:28:18 PM10/3/05
to

"poojo hackma" <poojo.com/mail> wrote:
>
> [...]
> BringWindowToTop(hWnd1);

Won't work if the application is minimized.

~ JD

JD

unread,
Oct 3, 2005, 1:26:03 PM10/3/05
to

"JV" <xs...@hotmail.com> wrote:
>
>
>How can I prevent my users to start my program more than one time?

There are many ways that one can use to determine if a the
application has already been launched. However, if you want
to set the first instance of you application as the current
window, there is only one 100% reliable way to do that and
that's because of how windows works. If the first instance
is minimized, you need to restore it first before you bring
it to front. However, unless you apply WS_APPWINDOW to the
window's ExStyle (which causes 2 icons on the taskbar) all
attempts to determine a minimized window's state will fail.

If you blindly restore a restored window, you'll really mess
up how Window's reads the window's state. The only reliable
way to correctly restore the first instance is to manually
keep track of the state and then send it a custom message
and let it decide to restore or not.

The following class keeps does exactly that and is ready to be
made into a component. The only thing that it needs from you
is a unique main form class name. Something like:

TCompanyNameProgramName


//-------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//-------------------------------------------------------------
#include <Classes.hpp>
//-------------------------------------------------------------
class TSingleInstance : public TComponent
{
private:
bool FMinimized,
FMainWindowHooked;
HANDLE hMutex;
HWND FHandle;
HHOOK FMainThreadHook;
UINT SI_RESTORE,
SI_INITIALIZE;
TForm* FParentForm;
protected:
bool __fastcall MainWindowHook( TMessage &Message );
virtual void __fastcall WndProc( TMessage &Message );
static int __stdcall MainThreadWndProcRetHook( int Code, WPARAM WParam, LPARAM LParam );
public:
__fastcall TSingleInstance(TComponent* Owner);
__fastcall ~TSingleInstance();
__published:
};
//-------------------------------------------------------------
#endif

//-------------------------------------------------------------
#include <vcl.h>
#include <basepch.h>
//-------------------------------------------------------------
#pragma hdrstop
//-------------------------------------------------------------
#include "Unit2.h"
#pragma package(smart_init)
//-------------------------------------------------------------

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)
{
FParentForm = dynamic_cast<TForm*>(Owner);
if( !Owner )
{
throw Exception("TSingleInstance : You must assign an Owner.");
}
if( !FParentForm )
{
throw Exception("TSingleInstance : The Owner must be a TForm.");
}
if( ThisSingleInstance )
{
throw Exception("TSingleInstance : Only one instance of TSingleInstance is allowed per application.");
}

hMutex = NULL;
FHandle = NULL;
FMainThreadHook = NULL;
FMainWindowHooked = false;
ThisSingleInstance = this;

if( !ComponentState.Contains(csDesigning) )
{
char ThisClassName[ 256 ] = { 0 };

SI_RESTORE = ::RegisterWindowMessage( "TSingleInstanceRestoreMessage" );
SI_INITIALIZE = ::RegisterWindowMessage( "TSingleInstanceInitializeMessage" );
if( ! SI_RESTORE || ! SI_INITIALIZE )
{
throw Exception("TSingleInstance : RegisterWindowMessage failed.");
}

::GetClassName( FParentForm->Handle, ThisClassName, 255 );
hMutex = ::CreateMutex( NULL, TRUE, ThisClassName );
if( GetLastError() == ERROR_ALREADY_EXISTS )
{
::ShowWindow( Application->Handle, SW_HIDE );
Application->ShowMainForm = false;
hFirstInstance = hSecondInstance = NULL;
::EnumWindows((WNDENUMPROC)EnumWindowsCallBack, (LPARAM)ThisClassName );
if( hFirstInstance == FParentForm->Handle )
{
hFirstInstance = hSecondInstance;
}
::SendMessage( hFirstInstance, SI_RESTORE, 0, 0 );
::SetForegroundWindow( hFirstInstance );
Application->Terminate();
}
else
{
// Need to monitor main form window state
Application->HookMainWindow( MainWindowHook );
FMainWindowHooked = true;

// To catch messages sent to the HWND found by the above win32 API EnumWindows
FMainThreadHook = ::SetWindowsHookEx( WH_CALLWNDPROCRET, (int (__stdcall*)())MainThreadWndProcRetHook, HInstance, ::GetCurrentThreadId() );
if( !FMainThreadHook )
{
throw Exception("TSingleInstance : Hooking Main Thread failed.");
}

// Still need some final initialization but it needs to be delayed until Application::MainForm is valid.
FHandle = AllocateHWnd( WndProc );
if( !FHandle )
{
throw Exception("TSingleInstance : AllocateHWnd failed.");
}
::PostMessage( FHandle, SI_INITIALIZE, 0, 0 );
}
}
}
//-------------------------------------------------------------
__fastcall TSingleInstance::~TSingleInstance()
{
if( FHandle ) DeallocateHWnd( FHandle );
if( FMainWindowHooked ) Application->UnhookMainWindow( MainWindowHook );
if( FMainThreadHook ) ::UnhookWindowsHookEx( FMainThreadHook );
if( hMutex ) ::CloseHandle( hMutex );
ThisSingleInstance = NULL;
}
//-------------------------------------------------------------
void __fastcall TSingleInstance::WndProc( TMessage &Message )
{
if( Message.Msg == SI_INITIALIZE )
{
if( FParentForm != Application->MainForm )
{
MessageDlg("TSingleInstance : Object can only be placed on the Main Form.", mtError, TMsgDlgButtons() << mbOK, 0);
Application->Terminate();
}
else
{
if( Application->MainForm->WindowState == wsMinimized ) FMinimized = true;
else FMinimized = false;
}
}
Message.Result = DefWindowProc( FHandle, Message.Msg, Message.WParam, Message.LParam );
}
//-------------------------------------------------------------
bool __fastcall TSingleInstance::MainWindowHook( TMessage &Message )
{
if( Message.Msg == WM_SYSCOMMAND )
{
switch( Message.WParam )
{
case SC_RESTORE:
case SC_MAXIMIZE: FMinimized = false; break;
case SC_MINIMIZE: FMinimized = true;
}
}
return false;
}
//-------------------------------------------------------------
int __stdcall TSingleInstance::MainThreadWndProcRetHook( int Code, WPARAM WParam, LPARAM LParam )
{
if( Code == HC_ACTION )
{
CWPRETSTRUCT* cwp = (CWPRETSTRUCT *) LParam;
if( cwp->message == ThisSingleInstance->SI_RESTORE )
{
if( ThisSingleInstance->FMinimized )
{
::SendMessage( Application->Handle, WM_SYSCOMMAND, SC_RESTORE, 0 );
}
}
}
return ::CallNextHookEx( ThisSingleInstance->FMainThreadHook, Code, WParam, LParam );
}
//-------------------------------------------------------------


To use it as is, click File | New | Unit and cut and paste.
Then include the header in the main unit and simple dynamically
allocate an instance of it in the main form's contructor.

~ JD

poojo hackma

unread,
Oct 3, 2005, 2:51:30 PM10/3/05
to
> The following class keeps does exactly that and is ready to be
> made into a component. The only thing that it needs from you
> is a unique main form class name. Something like:

nice!


JV

unread,
Oct 4, 2005, 2:38:24 AM10/4/05
to

>
> There are many ways that one can use to determine if a the
> application has already been launched. However, if you want
> to set the first instance of you application as the current
> window, there is only one 100% reliable way to do that and
> that's because of how windows works. If the first instance
> is minimized, you need to restore it first before you bring
> it to front.

> ~ JD
>

Thank you JD.
(also to the others)

Jan


0 new messages