2013-12-18 6 views
6

I私のアプリは、コンピュータ上で一度だけ実行させるためにしようとしています、私のアプリは、複数回実行させるために悪いですので、Webサービスにcomunicateする必要が、現在これでミューテックスを使用してイム:コンピュータごとのアプリケーションの1つのインスタンス、方法?

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つに制限していますが、私のアプリケーションは一度に20人以上のユーザーがログインしているWindows Server環境で使用されているため、サーバーごとに1回だけ実行するよう厳密にする必要があります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 

何か間違っていますか?私のアプリの2番目のインスタンスを動かさないという信頼できる方法がありますか?

+1

「全く動作しません」という意味を定義する必要があると思います。 'CreateMutex'は0を返しますか?もしそうなら、 'GetLastError'は何を返しますか?おそらく 'ERROR_ACCESS_DENIED'ですか? –

+0

@SertacAkyuz:元のチェックが正しい。 'CreateMutex()'が失敗するか、mutexが既に存在する場合は、アプリケーションを終了します。 CreateMutex()が既存のmutexへのハンドルを返すので、mutexハンドルが0でない場合、変更は "already exists"チェックをバイパスします。 Delphiはデフォルトでブール式を短絡しています。 –

+0

@Remy - それでいいよ、ありがとう。また、私は混在していると...混乱の原因にならないようにコメントを削除しました.. –

答えて

9

デフォルトでは、lpMutexAttributes = nilの作成されたmutexは、プロセスを実行しているユーザーのみがアクセスできます。 mutexは、すべてのユーザーがアクセスできる必要があります。

ヌルDACLのセキュリティ記述子がnull 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

答えをお寄せいただきありがとうございます。ここでの主な質問は、これを使用した場合と、セキュリティ属性なしでmutexを宣言した場合の違いは何ですか?現時点では、この 'CreateMutex(nil、True、 'Global \ mutex-name');のようなセキュリティパラメータなしでテストし、セキュリティパラメータが実際に何をするのかを理解するだけです。プログラムは管理者権限で開かれていません。サーバー内のすべてのユーザーが管理者アカウントを持っています –

+0

アプリケーションとサービスの間のミューテックス検出のセキュリティ属性を追加する必要がありました。 Win XP、Windows Server 2003、およびそれ以前のバージョンでは、すべてのサービスがアプリケーションと共にセッション0で実行されます。 Windows Vista、Windows Server 2008、およびそれ以降のバージョンでは、オペレーティングシステムはセッション0でサービスを分離し、他のセッションでアプリケーションを実行します。 – Lars

+0

Miguel、あなたの質問は正当なものです。あなたの例に基づいて、私はbInitialOwner = trueを変更し、Service Wrapper(srvany.exe)で実行していれば私のアプリケーションを検出することができました。これは以前は不可能でした。 (私は他の "ユーザー"のケースをテストしていません)あなたは、私のルーチンをより一般的で堅牢なものにしてくれました。 PS。私は上記の私の答えを変更しました:CreateMutex(@SecurityAttr、false、...)To:CreateMutex(@SecurityAttr、true、...) – Lars

関連する問題