Каждый вошедший в систему пользователь работает в своем собственном сеансе рабочего стола. Чтобы получить доступ к объекту ядра с именем , например, к мьютексу, между сеансами пользователя, необходимо добавить к имени объекта префикс с префиксом пространства имен Global\
, в противном случае вы в конечном итоге создадите отдельные объекты мьютекса локально для каждого пользователя. сессия.
По документам CreateMutex()
и OpenMutex()
:
Имя может иметь префикс «Global» или «Local» для явного создания объекта в глобальном или сеансовом пространстве имен. Остальная часть имени может содержать любой символ, кроме символа обратной косой черты. Для получения дополнительной информации см. Пространства имен объектов ядра .
И согласно Пространствам имен объекта ядра Документация:
Отдельные пространства имен сеансов клиентов позволяют нескольким клиентам запускать одни и те же приложения, не мешая друг другу. Для процессов, запущенных в сеансе клиента, система по умолчанию использует пространство имен сеанса. Однако эти процессы могут использовать глобальное пространство имен, добавляя префикс "Global\"
к имени объекта. Например, следующий код вызывает `CreateEvent и создает объект события с именем CSAPP в глобальном пространстве имен:
CreateEvent( NULL, FALSE, FALSE, "Global\\CSAPP" );
...
Другое использование глобального пространства имен - для приложений, которые используют именованные объекты, чтобы обнаружить, что во всех сеансах уже есть экземпляр приложения, работающего в системе. Этот именованный объект должен быть создан или открыт в глобальном пространстве имен вместо пространства имен для сеанса . Более распространенный случай запуска приложения один раз за сеанс поддерживается по умолчанию, поскольку именованный объект создается в пространстве имен для каждого сеанса.
Кроме того, вы должны использовать CreateMutex()
вместо OpenMutex()
, чтобы избежать условия гонки, которое позволило бы другому экземпляру вашего приложения создать мьютекс до того, как текущий экземпляр сможет его создать. GetLastError()
сообщит ERROR_ALREADY_EXISTS
, если CreateMutex()
успешно и мьютекс уже существует. Не звоните OpenMutex()
, если CreateMutex()
не сообщит об ошибке ERROR_ACCESS_DENIED
, согласно CreateMutex
документации :
Если lpName
соответствует имени существующего именованного объекта мьютекса, эта функция запрашивает MUTEX_ALL_ACCESS
право доступа . В этом случае параметр bInitialOwner
игнорируется, поскольку он уже был установлен процессом создания.
...
Если мьютекс является именованным мьютексом и объект существовал до этого вызова функции, возвращаемое значение является дескриптором существующего объекта, GetLastError
возвращает ERROR_ALREADY_EXISTS
, bInitialOwner
игнорируется, а вызывающий поток не предоставлено право собственности. Однако, если у вызывающего абонента ограниченные права доступа, функция завершится ошибкой с ERROR_ACCESS_DENIED
, и вызывающий абонент должен использовать функцию OpenMutex
.
Попробуйте что-то вроде этого:
mutexName = "Global\\MyMutexName";
m_hMutex = ::CreateMutex(NULL, FALSE, mutexName.c_str());
if ((!m_hMutex) && (GetLastError() == ERROR_ACCESS_DENIED)) {
m_hMutex = ::OpenMutex(SYNCHRONIZE, FALSE, mutexName.c_str());
}
if (!m_hMutex) {
... << mutexName << " cannot be accessed! Aborting!";
//...
}
else if (GetLastError() == ERROR_ALREADY_EXISTS) {
... << mutexName << " is already running on this machine! Aborting!";
//...
}
else {
//...
}
Или в Vista и более поздних версиях вместо нее можно использовать CreateMutexEx()
:
mutexName = "Global\\MyMutexName";
m_hMutex = ::CreateMutexEx(NULL, mutexName.c_str(), 0, SYNCHRONIZE);
if (!m_hMutex) {
... << mutexName << " cannot be accessed! Aborting!";
//...
}
else if (GetLastError() == ERROR_ALREADY_EXISTS) {
... << mutexName << " is already running on this machine! Aborting!";
//...
}
else {
//...
}