问题
I am trying to make my app run only once on a computer, My app needs to comunicate to a webservice so it is bad to let it run more than once, currently im using Mutex with this:
MyMsg := RegisterWindowMessage('My_Unique_App_Message_Name');
Mutex := CreateMutex(nil, True, 'My_Unique_Application_Mutex_Name');
if (Mutex = 0) OR (GetLastError = ERROR_ALREADY_EXISTS) then
exit;
Currently this works to limit 1 instance of application per user, but my app is being used in a Windows Server Environment where there are 20+ users loged in at a time, so i need to strict it to only run once per server, what i am trying to do is to declare that Mutex as a Global mutex but i fail to do so when i do the next code it doesnt work at all.
MyMsg := RegisterWindowMessage('My_Unique_App_Message_Name');
Mutex := CreateMutex(nil, True, 'Global\My_Unique_Application_Mutex_Name');
if (Mutex = 0) OR (GetLastError = ERROR_ALREADY_EXISTS) then
begin
exit
So am i doing something wrong? is there any other reliable way of not letting a second instance of my app to run?
回答1:
By default, lpMutexAttributes = nil
created mutexes are accessible only by the user running the process. The mutex needs to be accessible to all users.
Null DACL security descriptor
Do this by using a security descriptor with a null DACL. Please find below the code that I use for single instance applications/services
//Creates a mutex to see if the program is already running.
function IsSingleInstance(MutexName : string; KeepMutex : boolean = true):boolean;
const MUTEX_GLOBAL = 'Global\'; //Prefix to explicitly create the object in the global or session namespace. I.e. both client app (local user) and service (system account)
var MutexHandel : THandle;
SecurityDesc: TSecurityDescriptor;
SecurityAttr: TSecurityAttributes;
ErrCode : integer;
begin
// By default (lpMutexAttributes =nil) created mutexes are accessible only by
// the user running the process. We need our mutexes to be accessible to all
// users, so that the mutex detection can work across user sessions.
// I.e. both the current user account and the System (Service) account.
// To do this we use a security descriptor with a null DACL.
InitializeSecurityDescriptor(@SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(@SecurityDesc, True, nil, False);
SecurityAttr.nLength:=SizeOf(SecurityAttr);
SecurityAttr.lpSecurityDescriptor:=@SecurityDesc;
SecurityAttr.bInheritHandle:=False;
// The mutex is created in the global name space which makes it possible to
// access across user sessions.
MutexHandel := CreateMutex(@SecurityAttr, True, PChar(MUTEX_GLOBAL + MutexName));
ErrCode := GetLastError;
// If the function fails, the return value is 0
// If the mutex is a named mutex and the object existed before this function
// call, the return value is a handle to the existing object, GetLastError
// returns ERROR_ALREADY_EXISTS.
if {(MutexHandel = 0) or }(ErrCode = ERROR_ALREADY_EXISTS) then
begin
result := false;
closeHandle(MutexHandel);
end
else
begin
// Mutex object has not yet been created, meaning that no previous
// instance has been created.
result := true;
if not KeepMutex then
CloseHandle(MutexHandel);
end;
// The Mutexhandle is not closed because we want it to exist during the
// lifetime of the application. The system closes the handle automatically
//when the process terminates.
end;
来源:https://stackoverflow.com/questions/20669917/one-instance-of-app-per-computer-how