2011-01-25 31 views
5

Tôi có một ứng dụng cần phải là một ứng dụng đơn lẻ trên tất cả các phiên người dùng trên PC Windows. Nghiên cứu của tôi cho đến nay đã tập trung xung quanh bằng cách sử dụng một mutex để thực hiện điều này, nhưng tôi có một vấn đề mà tôi không chắc chắn thực sự là một vấn đề, đây thực sự là một câu hỏi thực hành tốt nhất tôi tin.VB6: Ứng dụng đơn lẻ trên tất cả các phiên người dùng

Dưới đây là các mã đầu tiên của tất cả:

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' 

Bây giờ, dựa trên this bài viết Tôi tin rằng tôi hiểu rằng bằng cách thông qua con trỏ NULL đến chức năng CreateMutex như tôi ở trên tôi về cơ bản gán bất cứ mô tả bảo mật được liên kết với người dùng hiện đã đăng nhập. Nếu điều đó có nghĩa là những gì tôi nghĩ (tôi có thể cần thêm hướng dẫn tại đây) cho tôi biết rằng những người dùng khác đăng nhập sẽ không thể "nhìn thấy" mutex được tạo trong phiên của người dùng ban đầu, cũng như họ sẽ không có thể tạo một mutex có cùng tên.

Hiện tại, bằng chứng về hoàng đế dường như đã phản hồi điều này. Tôi đã sử dụng một hộp thông báo để bật "LastDLLError" mà tôi nhận được và khi một người dùng khác cố gắng khởi chạy ứng dụng (trong khi nó đang chạy dưới một tài khoản người dùng khác), tôi sẽ nhận được một mã ERROR_ACCESS_DENIED. Tôi đồng ý với thử nghiệm chống lại điều này cùng với mã ERROR_ALREADY_EXISTS và chỉ thoát trên một trong hai hoặc. Tuy nhiên, điều này cảm thấy loại hackish và tôi tự hỏi nếu ai đó có thể đề xuất một thay thế. Điều "đúng" cần làm là chuyển con trỏ thích hợp đến hàm CreateMutex sao cho bất kỳ người dùng nào có quyền thích hợp để xem bất kỳ mutexes hiện có nào (mutices?), Nhưng tôi không chắc chắn điều này là có thể nếu không có hiện tại người dùng đã đăng nhập là quản trị viên (không được chấp nhận). Bất kỳ hỗ trợ/hướng dẫn nào được đánh giá cao. Cảm ơn trước!

Trả lời

1

Tôi đang tìm một giải pháp tương tự trong VB6 vào cuối năm ngoái. Vào thời điểm đó tôi không thể tìm thấy bất kỳ ví dụ về các ứng dụng VB6 giao tiếp trên ranh giới người dùng, vì vậy tôi đã phải viết của riêng tôi.

Xem: Interprocess Communication via Semaphores

Bạn có thể sử dụng lớp để tạo ra và kiểm tra một semaphore toàn cầu mà sẽ cho bạn biết nếu ứng dụng của bạn vẫn đang chạy dưới bất kỳ người dùng. Tôi đã không nhìn vào API Mutex nhưng việc sử dụng chúng rất giống nhau. Chức năng GetSecurityDescriptor là những gì bạn sẽ muốn chuyển đổi nếu bạn đã có một số mã Mutex được viết.

+0

Cảm ơn mọi người đã phản hồi.Tôi sẽ sửa đổi mã của tôi để hành xử giống như mã trong lớp của Joe, ứng dụng thử nghiệm đi kèm với nó xác nhận rằng tôi sẽ có thể làm cho nó hoạt động. Đóng cái này ra. –

1

Tôi nghĩ bản năng của bạn là chính xác. Tôi không biết lý do tại sao nó sẽ không an toàn để suy ra từ ERROR_ACCESS_DENIED rằng một số quá trình khác có mutex, vì vậy có hiệu quả nó giống như ERROR_ALREADY_EXISTS (trong bối cảnh này.) Nhưng đồng thời, nó không cảm thấy khá đúng.

Như bạn đề xuất, việc thiết lập mô tả bảo mật thích hợp thực sự là cách phù hợp để thực hiện. MSDN nói rằng việc cấp đặc quyền MUTEX_ALL_ACCESS làm tăng nguy cơ người dùng sẽ phải là quản trị viên và tôi nghĩ bạn cần MUTEX_ALL_ACCESS. Nhưng theo kinh nghiệm của tôi, nó hoạt động tốt cho những người không phải quản trị viên.

Câu hỏi của bạn hấp dẫn tôi đủ để làm một bài kiểm tra nhanh. Điều đó có nghĩa là tôi có một số mã nguồn và vì vậy, đây là:

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

Bạn không cần quản trị viên tư nhân để đặt bảo mật khi bạn sở hữu các mutex. Đây là một ứng dụng demo đơn giản cung cấp cho mọi người/toàn quyền kiểm soát mutex.

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 
Các vấn đề liên quan