2013-12-18 34 views
6

我试图让我的应用程序只运行一次在电脑上,我的应用程序需要comunicate到WebService所以它是坏让它运行多次,使用互斥这个目前即时通讯:每台计算机的应用程序的一个实例,如何?

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; 

目前这可以限制每个用户1个应用程序的实例,但是我的应用程序正在Windows Server环境中使用,其中一次有20多个用户在使用,所以我需要严格限制每个服务器只运行一次,我试图做的是将Mutex声明为全局互斥体,但是当我执行下一个代码时,它无法工作。

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 

所以我做错了什么?有没有其他可靠的方式不让我的应用程序的第二个实例运行?

+1

我认为您需要定义“根本不起作用”的含义。 'CreateMutex'是否返回0?如果是这样,GetLastError会返回什么?也许它是'ERROR_ACCESS_DENIED'? –

+0

@SertacAkyuz:原始检查无误。如果'CreateMutex()'失败,或者互斥量已经存在,请退出应用程序。如果互斥量句柄不为0,则您的更改将绕过“已存在”检查,因为'CreateMutex()'返回现有互斥量的句柄。请记住,默认情况下,Delphi会短路布尔表达式。 –

+0

@Remy - 好吧,看起来很好,谢谢。此外,我混合或与...删除注释不会导致混淆.. –

回答

9

默认情况下,lpMutexAttributes = nil创建的互斥锁只能由运行该进程的用户访问。所有用户都需要访问互斥锁。

空DACL安全描述符

通过使用安全描述符具有空DACL执行此操作。请在下面找到我用于单实例应用程序/服务的代码

//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:[email protected]; 
    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; 
+1

谢谢你的回答,这里的主要问题是使用这个或者只声明没有安全属性的互斥体的区别是什么?目前我已经测试了它,没有像这样的'CreateMutex(nil,True,'Global \ mutex-name');'和它的工作安全参数,所以只是为了理解安全参数实际上做了什么。该程序未以管理员权限打开,并且服务器中的所有用户都拥有管理员帐户 –

+0

我需要为应用程序和服务之间的互斥锁检测添加安全属性。在Win XP,Win Server 2003及更早版本中,所有服务都与会话一起在会话0中运行。在Win Vista,Win Server 2008及更高版本中,操作系统隔离会话0中的服务并在其他会话中运行应用程序。 – Lars

+0

米格尔,你的问题是有道理的。基于你的例子,我改变了bInitialOwner = true,并且能够检测到我的应用程序,如果我有它运行在服务包装器(srvany.exe)。这以前不可能。 (我没有测试其他“用户”情况。)你只是帮助我让我的例程更加通用和强大,谢谢! PS。我已经修改了我的上面的答案:CreateMutex(@SecurityAttr,false,...)为:CreateMutex(@SecurityAttr,true,...) – Lars

相关问题