无法阻止来自不同用户的同一程序的多个实例

时间:2019-04-03 18:46:55

标签: c++ winapi mfc windows-10

我有以下代码。它可以防止同一用户下同一应用程序的多个实例。但是,我还想防止其他用户已经在运行同一台计算机上的其他用户来运行该应用程序。即使应用程序已经由其他用户运行,该代码也成功创建了互斥锁。无法找出我在这里做错了。任何帮助表示赞赏。

m_hMutex = ::CreateMutex(NULL, FALSE, PREDEFINED_UNIQUE_ID);
if (::GetLastError() == ERROR_ALREADY_EXISTS)
{
    if (m_hMutex)
        ::CloseHandle(m_hMutex);

    //in case the previous instance of APP is still in the process of closing
    ::Sleep(5*1000);
    m_hMutex = ::CreateMutex(NULL, FALSE, PREDEFINED_UNIQUE_ID);
    if (::GetLastError() == ERROR_ALREADY_EXISTS)
    {
        EndSplashWindow();
        AfxMessageBox( _T("An instance of APPis already running."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
        return FALSE;
    }
}

1 个答案:

答案 0 :(得分:2)

您没有显示PREDEFINED_UNIQUE_ID的实际值,但是我猜测它不是在Global kernel namespace中创建互斥锁,而是在每个会话的名称空间中创建互斥锁。跨用户会话需要使用Global名称空间:

  

单独的客户端会话名称空间使多个客户端可以运行相同的应用程序而不会互相干扰。对于在客户端会话下启动的进程,系统默认使用会话名称空间。但是,这些进程可以通过在对象名称前添加“ Global \”前缀来使用全局名称空间。例如,以下代码调用CreateEvent并在全局名称空间中创建一个名为CSAPP的事件对象:

CreateEvent( NULL, FALSE, FALSE, "Global\\CSAPP" );
     

...

     

全局命名空间的另一用途是用于应用程序,这些应用程序使用命名对象来检测所有会话中系统中是否都在运行该应用程序的实例。此命名对象必须在全局命名空间(而不是每个会话命名空间)中创建或打开。更常见的情况是,默认情况下,每个会话运行一次应用程序是受支持的,因为命名对象是在每个会话命名空间中创建的

更新:您还需要处理CreateMutex()由于安全权限而无法在另一个会话中访问互斥锁的情况。您需要处理GetLastError()返回ERROR_ACCESS_DENIED的情况,这本身就意味着互斥体存在。

尝试更多类似的方法:

#define PREDEFINED_UNIQUE_ID _T("Global\\MyUniqueMutexName");

m_hMutex = ::CreateMutex(NULL, FALSE, PREDEFINED_UNIQUE_ID);
// or: m_hMutex = ::CreateMutexEx(&sa, PREDEFINED_UNIQUE_ID, 0, SYNCHRONIZE);
DWORD dwErrorCode = ::GetLastError();

if ((m_hMutex) && (dwErrorCode == ERROR_ALREADY_EXISTS))
{
    ::CloseHandle(m_hMutex);

    //in case the previous instance of APP is still in the process of closing
    ::Sleep(5*1000);
    // consider using WaitForSingleObject() instead, in case the app takes less than 5 seconds to close...

    m_hMutex = ::CreateMutex(NULL, FALSE, PREDEFINED_UNIQUE_ID);
    // or: m_hMutex = ::CreateMutexEx(&sa, PREDEFINED_UNIQUE_ID, 0, SYNCHRONIZE);
    dwErrorCode = ::GetLastError();
}

if (dwErrorCode != 0)
{
    EndSplashWindow();

    switch (dwErrorCode)
    {
        case ERROR_ALREADY_EXISTS:
        case ERROR_ACCESS_DENIED:
            AfxMessageBox( _T("An instance of APP is already running."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
            break;

        default:
            AfxMessageBox( _T("Error checking if an instance of APP is already running."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
            break;
    }

    return FALSE;
}

// OK to run now!
return TRUE;

或者,为了最大程度地减少报告ERROR_ACCESS_DENIED的机会,您可以为CreateMutex()提供NULL DACL:

PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); 
if (!pSD) 
{ 
    EndSplashWindow();
    AfxMessageBox( _T("Error allocating security descriptor."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
    return FALSE;
}

if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) 
{ 
    LocalFree(pSD); 
    EndSplashWindow();
    AfxMessageBox( _T("Error initializing security descriptor."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
    return FALSE;
}

if (!SetSecurityDescriptorDacl(pSD, TRUE, NULL, FALSE))
{ 
    LocalFree(pSD); 
    EndSplashWindow();
    AfxMessageBox( _T("Error setting access for security descriptor."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
    return FALSE;
}

SECURITY_ATTRIBUTES sa = {};
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;

m_hMutex = ::CreateMutex(&sa, FALSE, PREDEFINED_UNIQUE_ID);
...

LocalFree(pSD);