VB6: приложение с одним средством во всех пользовательских сеансах

StackOverflow https://stackoverflow.com/questions/4799954

  •  24-10-2019
  •  | 
  •  

Вопрос

У меня есть приложение, которое должно быть приложением для одного инстанса во всех пользовательских сеансах на ПК Windows. Мое исследование до сих пор было сосредоточено на использовании мутекса для достижения этого, но у меня есть проблема, которую я не уверен, действительно проблема, я верю, что это действительно лучший вопрос.

Вот код в первую очередь:

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'

Теперь, основываясь на это Статья, я считаю, что я понимаю, что, передавая нулевый указатель функции CreateMutex, так как я выше, я в основном назначаю любой дескриптор безопасности, связанный с в настоящее время регистрированным в пользователе.

Если это означает, что я думаю, что это делает (мне может понадобиться больше рекомендаций здесь), которое говорит мне, что другие пользователи, которые входят Мутекс с тем же именем.

Теперь, кажется, что эмпиционные данные подтверждают это. Я использовал окно сообщений, чтобы разместить «LastDllerror», который я получал, и когда другой пользователь попытался запустить приложение (в то время как оно уже работало под другой учетной записью пользователя), я получу код error_access_dyed. Я в порядке с тестированием против этого вместе с кодом error_already_exists и просто выхожу на либо/или. Тем не менее, это кажется немного хакерским, и мне интересно, может ли кто -то предложить альтернативу. Похоже, что «правильная» предназначена для передачи правильного указателя функции CreateMutex, так что у любого пользователя есть правильные разрешения на просмотр любых существующих мутекс (mitices?), Но я не так уверен, что это возможно без в настоящее время Зарегистрированный пользователем является администратором (что неприемлемо). Любая помощь/руководство высоко ценится. Заранее спасибо!

Это было полезно?

Решение

Я искал подобное решение в VB6 в конце прошлого года. В то время я не смог найти примеры приложений VB6, общающихся по границе пользователя, поэтому мне пришлось написать свой собственный.

Видеть: Межпроцессная связь с помощью семафоров

Вы можете использовать класс для создания и проверки глобального семафора, который сообщит вам, работает ли ваше приложение при любом пользователе. Я не смотрел на API Mutex, но их использование очень похоже. А GetSecurityDescriptor Функция - это то, что вы захотите перенести, если у вас уже есть какой -то код Mutex.

Другие советы

Вам не нужны администраторы Priveleges, чтобы установить безопасность на собственных мутекс. Вот простое демонстрационное приложение, которое в основном дает всем/полный контроль 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

Я думаю, что ваши инстинкты точно правы. Я не знаю никакой причины, по которой не было бы безопасно сделать вывод из ошибки_акульс_акул_, что у некоторых других процессов есть мутекс, так что это то же самое, что 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top