program Only_One_Mutex;
//undefine this {.$define useMutex} to make it a multi instance app.
{$define useMutex}
uses
Forms,
Windows,
Messages,
MainForm in 'MainForm.pas' {frmMain};
{$R *.res}
{$ifdef useMutex}
var
Mutex : THandle;
{$endif}
function pBuffStr( Var S1: String; S:String ): PChar;
begin
FillChar(S1,SizeOf(S1),#0); {clear out the destination string}
S1:= S+#0; {set it equal the source}
Result:= @S1[1]; {result is a PChar pointer }
end;
procedure WindowToTop( WN: String );
var
iTitle: integer;
S1,S : String;
Done: Boolean;
begin
Done:= False;
While NOT Done do begin
if Pos(';',WN) > 0 then begin
S:= Copy(WN,1,Pos(';',WN)-1);
WN:= Copy(WN,Pos(';',WN)+1,Length(WN));
end else begin
S:= WN;
Done:= True;
end; {if Pos}
iTitle:= FindWindow( nil, pBuffStr(S1,S) );
if iTitle <> 0 then
if NOT SetForegroundWindow( iTitle ) then
GetLastError();
Application.ProcessMessages;
end; {while NOT Done}
end;
procedure RestoreWindow( WN: String );
var
iTitle: integer;
Dest, S : String;
Done: Boolean;
begin
Done:= False;
While NOT Done do begin
if Pos(';',WN) > 0 then begin {is there more than ONE name}
S:= Copy(WN,1,Pos(';',WN)-1); {copy the first name of the original}
WN:= Copy(WN,Pos(';',WN)+1,Length(WN)); {reduce the original string}
end else begin
S:= WN; {only one name, so copy it}
Done:= True; {this loop is done}
end; {if Pos}
iTitle:= FindWindow( nil, pBuffStr(Dest,S) ); {search for the window name}
if iTitle <> 0 then {if found, then restore it}
DefWindowProc(iTitle, WM_SYSCOMMAND, SC_RESTORE, SC_RESTORE);
end; {while NOT Done}
end;
//=================================================================
procedure AppRun;
begin
Application.Initialize;
Application.Title := 'Only One Prog';
Application.CreateForm(TfrmMain, frmMain);
Application.Run;
end;
begin
{$ifdef useMutex}
//global var declarations in the mainform.
{=====================================================================}
//ATitle MUST match the assigned Application.Title in AppRun
//and Application.Title can "NOT" be a constant or var.
ATitle := 'Only One Prog';
{ THIS IS HOW IT KEEPS THE SECOND INSTANCE FROM STARTING,
by using a MUTEX, and a MAINFORM window title }
//any text appender will work.
AMutex := ATitle + ' Mutex Thu, Jul/12/2012';
//mainform's caption
ACaption := ATitle + ', Mainform Caption';
//a label on the mainform
ALabel := ATitle + ', MainForm Label-using mutex';
{=====================================================================}
Mutex := CreateMutex(nil, True, PAnsiChar( AMutex ));
if (GetLastError = ERROR_ALREADY_EXISTS) then begin
try
RestoreWindow( ACaption );
WindowToTop( ACaption ); //main form's name
finally
CloseHandle(Mutex);
end;
end else
if (Mutex <> 0)
AND (GetLastError <> ERROR_ALREADY_EXISTS)
then begin
try
AppRun;
finally
CloseHandle(Mutex);
end;
end;
{$else}
//global var declarations in the mainform.
{=====================================================================}
ATitle := 'More than One'; //global declaration in the mainform.
//mainform's caption - THIS IS HOW IT KEEPS THE SECOND INSTANCE FROM STARTING
ACaption := ATitle + ', Mainform Caption';//global declaration in the mainform.
//a label on the mainform
ALabel := ATitle + ', MainForm Label-multi exe'; //global declaration in the mainform.
{=====================================================================}
AppRun;
{$endif}
end.
unit MainForm;
interface
uses
Windows, Messages, SysUtils,
Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, LblEffct;
type
TfrmMain = class(TForm)
le1: TLabelEffect;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
//these GLOBAL vars, are assigned values in the program source (.dpr) file.
ATitle,
ACaption,
ALabel,
AMutex :String;
implementation
{$R *.dfm}
procedure TfrmMain.FormCreate(Sender: TObject);
begin
Caption := ACaption; //used to ID this form...
le1.Caption := ALabel;
end;
end.