告诉是否有任何登录的用户正在运行即将安装/卸载的应用程序
本文关键字:运行 安装 应用程序 卸载 是否 任何 用户 登录 | 更新日期: 2023-09-27 18:16:46
我的程序使用Inno Setup安装/卸载它。在我的应用程序代码中,我使用CreateMutex
Windows API函数创建了一个Global互斥锁。然后在我的Inno Setup程序中,我有以下代码:
AppMutex=Global'MyProgramMutex.2A23834B-2919-4007-8C0A-3C7EDCA7186E
function InitializeSetup(): Boolean;
begin
Result := True;
if (CreateMutex(0, False, '{#SetupSetting('AppId')}') <> 0) and (DLLGetLastError = ERROR_ALREADY_EXISTS) then
begin
Result := False;
MsgBox('Another instance of the Setup program is already running. Please close it and try again', mbCriticalError, MB_OK);
end;
if CheckForMutexes('{#SetupSetting('AppMutex')}') then
begin
Result := False;
MsgBox('{#SetupSetting('AppName')} ' + 'appears to be running. Please close all instances of the program before continuing.', mbCriticalError, MB_OK);
end;
end;
对于运行Inno Setup程序的用户来说,正如预期的那样,这非常有效。我遇到的问题是:如果我"切换用户"并以不同的用户启动应用程序,然后切换回原始用户,安装程序不会检测到应用程序在不同的用户下运行。
我的知识还不够全面,不知道安装程序是否能检测到正在运行的应用程序。
在Inno Setup KB中使用AppMutex检测在任何用户会话中运行的实例:
要检测在其他会话中创建的互斥锁,应用程序必须创建两个互斥锁:一个有
Global'
前缀,另一个没有。任何用户会话都可以访问
Global'
前缀的互斥锁。如果由于安全限制或缺乏操作系统支持(Windows NT 4.0之前的终端服务器版不支持Global'前缀),则必须在会话命名空间中创建一个类似名称的互斥锁(即不带Global'
前缀)。此外,必须在每个CreateMutex()调用中传递一个特殊的安全描述符,以确保不同的用户可以访问互斥锁。
要在c#中让所有用户都可以访问互斥锁,请参见:
在c#中使用全局互斥锁的好模式是什么?
const string mutexId = "MyProg";
MutexAccessRule allowEveryoneRule =
new MutexAccessRule(
new SecurityIdentifier(WellKnownSidType.WorldSid, null),
MutexRights.FullControl, AccessControlType.Allow);
MutexSecurity securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
Mutex globalMutex = null;
try
{
bool createdNew;
globalMutex =
new Mutex(false, "Global''" + mutexId, out createdNew, securitySettings);
}
catch (UnauthorizedAccessException)
{
// Ignore
}
Mutex localMutex = new Mutex(false, mutexId);
try
{
// Run your program here
}
finally
{
// These have to be called only after the application (its windows) closes.
// You can also remove these calls and let the system release the mutexes.
if (globalMutex != null)
{
globalMutex.Dispose();
}
localMutex.Dispose();
}
在Inno Setup端,您所需要的就是在AppMutex
指令中列出两个互斥体:
[Setup]
AppMutex=MyProg,Global'MyProg
您不需要在InitializeSetup
函数中调用CreateMutex
和CheckForMutexes
。
好主意,Martin。这是我在WPF中使用互斥对象的完整解决方案,即使其他登录用户正在运行WPF应用程序,Inno Setup程序也会检测到。我用的是Visual Studio。
- 假设WPF应用程序和项目都名为"MyWPFApp" 打开MyWPFApp的项目属性;在'Application'选项卡上确保启动对象为'MyWPFApp.App'。
- 将App.xaml的构建动作从ApplicationDefinition更改为Page。
- 从App.xaml中删除StartupUri属性,如果使用的话。
- 如果是应用程序。使用启动事件时,删除所有实例化并显示主窗口的代码。
将以下或类似的代码添加到App.xaml.cs中,作为App类的一部分。
public partial class App : Application { private static readonly string _MutexID = "MyWPFApp"; // or whatever [STAThread] public static void Main() { var application = new App(); application.InitializeComponent(); MutexAccessRule allowEveryoneRule = new MutexAccessRule( new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow); MutexSecurity securitySettings = new MutexSecurity(); securitySettings.AddAccessRule(allowEveryone); Mutex globalMutex = null; try { bool createdNew; globalMutex = new Mutex(false, "Global''" + _MutexID, out createdNew, securitySettings); } catch (UnauthorizedAccessException) { // ignore } Mutex localMutex = new Mutex(false, _MutexID); try { MainWindow mainWin = new MainWindow(); application.Run(mainWin); } finally { if (globalMutex != null) { globalMutex.Dispose(); } localMutex.Dispose(); } } }
[Setup]
AppMutex=MyWPFApp,Global'MyWPFApp
我尝试用c# using
语句为两个互斥体构建代码,但是我的大脑冻结了。
或者,也可以创建一个单独的类,其中包含Main
方法,并将上面的代码放在那里。这需要上面的第4步和第5步,并在第2步中将Startup对象更改为包含Main
方法的新类。
谢谢马丁。鲍勃