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

Not able to prevent multiple instances of the same program from different users

本文关键字:程序 实例 用户      更新时间:2023-10-16

我有以下代码。它可以防止同一用户下同一应用程序的多个实例。但是,我还想防止同一台计算机上的其他用户在另一个用户已经在运行该应用程序时运行该应用程序。即使应用程序已由其他用户运行,该代码也会成功创建互斥锁。无法弄清楚我在这里做错了什么。任何帮助,不胜感激。

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;
}
}

您没有显示PREDEFINED_UNIQUE_ID的实际值,但我猜测它不是在Global内核命名空间中创建互斥锁,而是在每个会话命名空间中创建互斥锁。 使用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的机会,您可以提供空 DACL 以CreateMutex()

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);