2011-01-25 8 views
5

Windows PC上のすべてのユーザーセッションで単一インスタンスのアプリケーションである必要があるアプリケーションがあります。これまでの私の研究では、これを達成するためにミューテックスを使用していましたが、実際に問題があるかどうかはわかりませんが、これは本当にベストプラクティスの質問です。 、今VB6:すべてのユーザーセッションでシングルインスタンスアプリケーション

Private Const AppVer = "Global\UNIQUENAME" ' This is not what i am using but the name is unique 

Public Sub Main() 

    Dim mutexValue As Long 

    mutexValue = CreateMutex(ByVal 0&, 1, AppVer) 
    If (Err.LastDllError = ERROR_ALREADY_EXISTS) Then 
     SaveTitle$ = App.Title 
     App.Title = "... duplicate instance." 
     MsgBox "A duplicate instance of this program exists." 
     CloseHandle mutexValue 
     Exit Sub 
    End If 
    ' Else keep on truckin' 

this記事に基づいて、私は私が私の上だとしてCreateMutex関数にNULLポインタを渡すことで、基本的に何でもセキュリティ記述子を割り当てることだと理解し信じる:

は、ここで最初にすべてのコードです現在ログインしているユーザーに関連付けられています。

これは、ログインした他のユーザーが元のユーザーのセッションで作成されたミューテックスを「見る」ことができないことを私に伝える(これ以上のガイダンスが必要な場合があります)同じ名前のミューテックスを作成することができます。

今、天皇の証拠がこれを裏付けるようです。私はメッセージボックスを使って "LastDLLError"をポップアップし、別のユーザーがアプリケーションを起動しようとしたときに(別のユーザーアカウントで既に実行中)、ERROR_ACCESS_DENIEDコードを受け取ります。私はこれに対してERROR_ALREADY_EXISTSコードと一緒にテストして、どちらかで終了してもOKです。しかし、これは一種のハックを感じ、私は誰かが代替案を提案できるかどうか疑問に思います。 "正しい"ことは、CreateMutex関数に適切なポインタを渡して、どのユーザにも既存のmutex(mutices?)を見るための適切な権限が与えられているようですが、現在はなくても可能ですログインしているユーザーは管理者です(これは容認できません)。いかなる援助/指導も大変ありがとうございます。前もって感謝します!

答えて

1

私は昨年末VB6で同様のソリューションを探していました。当時、私はユーザー境界を越えて通信するVB6アプリケーションの例を見つけることができなかったので、自分で作成しなければなりませんでした。

参照:Interprocess Communication via Semaphores

あなたが作成し、既にアプリで任意のユーザーで実行されているかどうかを教えてくれるグローバルセマフォをチェックするためにクラスを使用することができます。私はMutex APIを見ていませんでしたが、その使い方は非常に似ています。 GetSecurityDescriptor関数は、すでにMutexコードが書かれている場合に移調したいものです。

+0

フィードバックのお寄せいただきありがとうございます。Joeのクラスのコードのように振る舞うようにコードを修正するつもりです。付属のテストアプリでは、それを動作させることができるはずです。これを閉じてください。 –

1

あなたの本能はまさに正しいと思います。 ERROR_ACCESS_DENIEDから他のプロセスにミューテックスがあることを推測するのは安全ではない理由はわかりません(実際にはERROR_ALREADY_EXISTSと同じです)。しかし、同時に、かなり正しい。

適切なセキュリティ記述子を設定するのが正しい方法です。 MSDNによると、MUTEX_ALL_ACCESS権限を付与すると、ユーザーが管理者でなければならないというリスクが高まり、MUTEX_ALL_ACCESSが必要になると思います。しかし私の経験では、非管理者にとってうまく動作します。

あなたの質問は私には興味がありました。それは私がいくつかのソースコードを持っていることを意味し、そうここにある:

int wmain(int argc, wchar_t* argv[]) 
{ 
    ACL *existing_dacl = NULL; 
    ACL *new_dacl = NULL; 
    PSECURITY_DESCRIPTOR security_descriptor = NULL; 

    bool owner = false; 
    HANDLE mutex = CreateMutex(NULL,FALSE,L"Global\\blah"); 
    if(mutex == NULL) 
     wprintf(L"CreateMutex failed: 0x%08x\r\n",GetLastError()); 
    if(GetLastError() == ERROR_ALREADY_EXISTS) 
     wprintf(L"Got handle to existing mutex\r\n"); 
    else 
    { 
     wprintf(L"Created new mutex\r\n"); 
     owner = true; 
    } 

    if(owner) 
    { 
     // Get the DACL on the mutex 
     HRESULT hr = GetSecurityInfo(mutex,SE_KERNEL_OBJECT, 
            DACL_SECURITY_INFORMATION,NULL,NULL, 
            &existing_dacl,NULL, 
            &security_descriptor); 
     if(hr != S_OK) 
      wprintf(L"GetSecurityInfo failed: 0x%08x\r\n",hr); 

     // Add an ACE to the ACL 
     EXPLICIT_ACCESSW ace; 
     memset(&ace,0,sizeof(ace)); 
     ace.grfAccessPermissions = MUTEX_ALL_ACCESS; 
     ace.grfAccessMode = GRANT_ACCESS; 
     ace.grfInheritance = NO_INHERITANCE; 
     ace.Trustee.pMultipleTrustee = NULL; 
     ace.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; 
     ace.Trustee.TrusteeForm = TRUSTEE_IS_NAME; 
     ace.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; 
     ace.Trustee.ptstrName = L"EVERYONE"; 
     hr = SetEntriesInAcl(1,&ace,existing_dacl,&new_dacl); 
     if(hr != S_OK) 
      wprintf(L"SetEntriesInAcl failed: 0x%08x\r\n",hr); 

     // Set the modified DACL on the mutex 
     hr = SetSecurityInfo(mutex,SE_KERNEL_OBJECT, 
          DACL_SECURITY_INFORMATION,NULL,NULL,new_dacl,NULL); 
     if(hr != S_OK) 
      wprintf(L"SetSecurityInfo failed: 0x%08x\r\n",hr); 
     else 
      wprintf(L"Changed ACL\r\n"); 

     LocalFree(existing_dacl); 
     LocalFree(new_dacl); 
     LocalFree(security_descriptor); 
    } 

    wprintf(L"Press any key..."); 
    _getch(); 
    CloseHandle(mutex); 
    return 0; 
} 
4

自分のミューテックスにセキュリティを設定するために管理者特権は必要ありません。ここでは基本的にミューテックスにEveryone/Fullコントロールを与える簡単なデモアプリケーションがあります。

Option Explicit 

Private Const STANDARD_RIGHTS_REQUIRED    As Long = &HF0000 
Private Const SYNCHRONIZE       As Long = &H100000 
Private Const MUTANT_QUERY_STATE     As Long = &H1 
Private Const MUTANT_ALL_ACCESS      As Long = (STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or MUTANT_QUERY_STATE) 
Private Const SECURITY_DESCRIPTOR_REVISION   As Long = 1 
Private Const DACL_SECURITY_INFORMATION    As Long = 4 

Private Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Any, ByVal bInitialOwner As Long, ByVal lpName As String) As Long 
Private Declare Function OpenMutex Lib "kernel32" Alias "OpenMutexA" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal lpName As String) As Long 
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long 
Private Declare Function InitializeSecurityDescriptor Lib "advapi32.dll" (pSecurityDescriptor As Any, ByVal dwRevision As Long) As Long 
Private Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" (pSecurityDescriptor As Any, ByVal bDaclPresent As Long, pDacl As Any, ByVal bDaclDefaulted As Long) As Long 
Private Declare Function SetKernelObjectSecurity Lib "advapi32.dll" (ByVal Handle As Long, ByVal SecurityInformation As Long, pSecurityDescriptor As SECURITY_DESCRIPTOR) As Long 

Private Type SECURITY_DESCRIPTOR 
    Revision   As Byte 
    Sbz1    As Byte 
    Control    As Long 
    Owner    As Long 
    Group    As Long 
    pSacl    As Long 
    pDacl    As Long 
End Type 

Private Const MUTEX_NAME   As String = "Global\20b70e57-1c2e-4de9-99e5-20f3961e6812" 

Private m_hCurrentMutex   As Long 

Private Sub Form_Load() 
    Dim hMutex   As Long 
    Dim uSec   As SECURITY_DESCRIPTOR 

    hMutex = OpenMutex(MUTANT_ALL_ACCESS, 0, MUTEX_NAME) 
    If hMutex <> 0 Then 
     Call CloseHandle(hMutex) 
     MsgBox "Already running", vbExclamation 
     Unload Me 
     Exit Sub 
    End If 
    m_hCurrentMutex = CreateMutex(ByVal 0&, 1, MUTEX_NAME) 
    Call InitializeSecurityDescriptor(uSec, SECURITY_DESCRIPTOR_REVISION) 
    Call SetSecurityDescriptorDacl(uSec, 1, ByVal 0, 0) 
    Call SetKernelObjectSecurity(m_hCurrentMutex, DACL_SECURITY_INFORMATION, uSec) 
End Sub 

Private Sub Form_Unload(Cancel As Integer) 
    If m_hCurrentMutex <> 0 Then 
     Call CloseHandle(m_hCurrentMutex) 
     m_hCurrentMutex = 0 
    End If 
End Sub 
関連する問題