Board index » cppbuilder » Re: Prevent Multiple Instance

Re: Prevent Multiple Instance


2006-09-01 07:47:01 PM
cppbuilder113
Remy,
Thank you very much for your explanation. I would have found the
documentation much clearer if
it had added your comment below:
Quote
>Note, my interpretation:
>
>GetLastError associated with CreateMutex returns either
ERROR_ALREADY_EXISTS
>OR ZERO.

If the function succeeds, yes. // (Remy's Comment) This would make the
documentation so much easier to understand

Thanks again,
Roger
 
 

Re:Re: Prevent Multiple Instance

"Roger" < XXXX@XXXXX.COM >wrote:
Quote

Do a google groups for TSingleInstance. It's a component that
does exactly what you're looking for.
~ JD
 

Re:Re: Prevent Multiple Instance

"JD" < XXXX@XXXXX.COM >wrote:
Quote

Do a google groups for TSingleInstance.
I did and found that the latest version wasn't posted. Click
File | New | Unit and make it look like:
//-------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//-------------------------------------------------------------
#include <Classes.hpp>
//-------------------------------------------------------------
#define UWM_INITIALIZE (WM_USER + 100)
//-------------------------------------------------------------
class TSingleInstance : public TComponent
{
private:
HANDLE hMutex;
HWND hFirstInstance;
HWND FHandle;
TForm *FParentForm;
protected:
virtual void __fastcall WndProc( TMessage &Message );
static bool __stdcall EnumWindowsCallBack( HWND hWnd, LPARAM lParam );
public:
__fastcall TSingleInstance(TComponent* Owner);
__fastcall ~TSingleInstance();
};
//-------------------------------------------------------------
#endif
//-------------------------------------------------------------
#include <vcl.h>
#include <basepch.h>// only needed for a compenent
//-------------------------------------------------------------
#pragma hdrstop
//-------------------------------------------------------------
#include "Unit2.h"
#pragma package(smart_init)
//-------------------------------------------------------------
TSingleInstance *ThisSingleInstance = NULL;
//-------------------------------------------------------------
__fastcall TSingleInstance::TSingleInstance(TComponent* Owner) : TComponent(Owner)
{
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.");
if( ThisSingleInstance ) throw Exception("TSingleInstance : Only one instance of TSingleInstance is allowed per application.");
hMutex = NULL;
FHandle = NULL;
ThisSingleInstance = this;
if( !ComponentState.Contains(csDesigning) )
{
char ThisClassName[ 256 ] = { 0 };
::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 );
HWND hWnd = reinterpret_cast<HWND>( ::GetWindowLong(hFirstInstance, GWL_HWNDPARENT) );
if( IsIconic(hWnd) ) ::ShowWindow( hWnd, SW_RESTORE );
::SetForegroundWindow( hWnd );
Application->Terminate();
}
else
{
// 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, UWM_INITIALIZE, 0, 0 );
}
}
}
//-------------------------------------------------------------
__fastcall TSingleInstance::~TSingleInstance()
{
if( FHandle ) DeallocateHWnd( FHandle );
if( hMutex ) ::CloseHandle( hMutex );
ThisSingleInstance = NULL;
}
//-------------------------------------------------------------
void __fastcall TSingleInstance::WndProc( TMessage &Message )
{
if( Message.Msg == UWM_INITIALIZE )
{
if( FParentForm != Application->MainForm )
{
MessageDlg("TSingleInstance : Object can only be placed on the Main Form.", mtError, TMsgDlgButtons() << mbOK, 0);
Application->Terminate();
}
}
Message.Result = DefWindowProc( FHandle, Message.Msg, Message.WParam, Message.LParam );
}
//-------------------------------------------------------------
bool __stdcall TSingleInstance::EnumWindowsCallBack( HWND hWnd, LPARAM lParam )
{
char WindowClassName[256] = { 0 };
if( ::GetClassName(hWnd, WindowClassName, 255) )
{
if( stricmp(WindowClassName, reinterpret_cast<char*>(lParam)) == 0 )
{
if( hWnd != ThisSingleInstance->FParentForm->Handle )
{
ThisSingleInstance->hFirstInstance = hWnd;
return FALSE;
}
}
}
return TRUE;
}
//-------------------------------------------------------------
Then, in the main form's constructor, allocate an instance
of TSingleInstance. The only trick is to make the main form's
class name unique. For example, instead of TForm1, assign the
main form thr name of TCompanyNameAppName.
You can also make it into a component that you can add to the
IDE. It works as desired and has been in service for almost 3
years without problems.
~ JD
 

{smallsort}