我有一个访问某些文件和系统资源的应用程序,所以可能只有一个应用程序活动实例。这是通过创建一个命名的信号量并在已经分配了信号量时停止应用程序运行来实现的。在过去(阅读:当Windows是最常见的操作系统),但现在我们注意到旧代码不适用于多个用户会话。
在这里,旧代码:
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现在,当我在User1上启动应用程序时,更改为User2并尝试启动应用程序,它将不会运行(按预期运行)。
但是,当我运行一个较旧版本的程序,并在同一个用户会话中使用新代码启动当前版本时,新代码将忽略由旧代码创建的信号量,并启动我的应用程序的第二个实例。(不用说它崩溃了.)
在我看来,本地信号量超出了全局信号量的范围,否则无法创建同名的第二个对象。我的问题是:全局信号量(新代码)如何检测到已经分配了同名的本地信号量(旧代码)?
请记住,这是一个向后兼容性问题。我不能简单地重新编译和重新分发我的应用程序的旧版本。
发布于 2014-12-01 12:21:43
kernel object namespaces的文档解释说:
对于在客户端会话下启动的进程,系统默认使用会话命名空间。
由于旧程序没有显式地包含名称空间,所以使用了Local\。这意味着旧程序创建一个名为Local\xxx的信号量。现在,新程序使用了一个名为Global\xxx的信号量。因此,您有两个不同的信号量和程序完全不知道自己。
Local\xxx的对象。Global\xxx的对象。这里得出的明显结论是,您需要创建两个对象。一个名为Local\xxx,另一个命名为Global\xxx。
请注意,不可能将交叉会话排除移植到现有程序中。他们已经使用了Local\xxx,您现在无法改变这种情况。
还必须修复新代码中的错误处理。您调用CreateSemaphore,然后继续调用GetLastError,而不首先检查调用CreateSemaphore返回的值。
https://stackoverflow.com/questions/27226992
复制相似问题