Каждый пользователь, вошедший в систему, работает в своем собственном сеансе рабочего стола. Чтобы получить доступ к объекту ядра named, такому как мьютекс, между сеансами пользователя, вам необходимо добавить к имени объекта префикс пространства имен 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 {
//...
}
08.11.2018
OpenMutex
? просто позвонитеCreateMutexEx
с доступомSYNCHRONIZE
. также вместо мьютекса мы можем использовать, скажем,CreateEventEx
, если нам нужен только объект, существующий не им 08.11.2018CreateEventEx
(CreateMutexEx
) начинаются с Vista -ZwCreateEvent
(NtCreateMutant
) существуют даже в win2000 08.11.2018CreateMutexEx()
(илиCreateEventEx()
) вообще существует. 08.11.2018ZwCreateEvent
. обычная история когда win32 оболочка менее функциональна по сравнению с родной. и только начиная с Vista добавлен дополнительный функционал с префиксом Ex 08.11.2018Global
, тогда он БУДЕТ использовать глобальное пространство имен, и это невозможно. Это означает, что ваш код отслеживания, вероятно, ошибочен. 12.11.2018