2013-12-18 33 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

相關問題