У меня есть приложение, которое обращается к некоторым файлам и системным ресурсам, поэтому может быть только один экземпляр приложения активным. Это достигается путем создания имени семафора и остановки приложения, когда семафор уже назначен. В прошлом (читал: когда Windows XP была самой распространенной операционной системой), которая работала хорошо, но теперь мы заметили, что старый код не работал с несколькими сеансами пользователя.Глобальный Семафор игнорирует локальный Семафор
Вот старый код:
hInstanceSem := CreateSemaphore(nil, 0, 1, PChar(GetProductName(Application.ExeName)));
if (hInstanceSem <> 0) and (GetLastError = ERROR_ALREADY_EXISTS) then
// do not run the Application
Так что я сделал некоторые исследования, узнали о глобальных семафоров и изменил код для этого:
function CreateGlobalSemaphor(SemaphorName: String): Cardinal;
var
desc: SECURITY_DESCRIPTOR;
att : TSecurityAttributes;
sem : Cardinal;
begin
att.nLength := SizeOf(TSecurityAttributes);
att.bInheritHandle := true;
att.lpSecurityDescriptor := @desc;
InitializeSecurityDescriptor(att.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(att.lpSecurityDescriptor, True, nil, False);
sem := CreateSemaphore(@att, 0, 1, PChar('Global\' + SemaphorName));
if (sem <> 0) and (GetLastError() <> ERROR_ALREADY_EXISTS) then begin
Result := sem;
end else begin
Result := 0;
CloseHandle(sem);
end;
end;
if CreateGlobalSemaphor(GetProductName(Application.ExeName)) = 0 then
// do not run the Application
Теперь, когда я запустить приложение на Пользователя1, измените на User2 и попробуйте запустить приложение, оно не будет запускаться (как предполагалось).
Но когда я запускаю старую версию своей программы и запускаю текущую версию с новым кодом в том же сеансе пользователя, новый код игнорирует Семафор, созданный старым кодом, и запускается второй экземпляр моего приложения. (Само собой разумеется, что он сбой ...)
Мне кажется, что локальный Семафор выходит за рамки глобального Семафора, иначе не может быть создан второй объект с тем же именем. Мой вопрос: как глобальный Семафор (новый код) обнаруживает, что уже назначен локальный Семафор (старый код) с тем же именем?
Обратите внимание, что это проблема обратной совместимости. Я не могу просто перекомпилировать и перераспределить старые версии моего приложения.
Позвольте мне предположить, что вызов функции GetLastError возвращает 5 ('ERROR_ACCESS_DENIED'). Нет, серьезно, что он возвращается? – TLama
Почему бы вам не попробовать * и создать локальный семафор (через старый код) в своем новом коде и сначала проверить результат, прежде чем обращаться с глобальным семафором? – kobik
@TLama: 'GetLastError' возвращает 0 (NO_ERROR) – YElm