告诉是否有任何登录的用户正在运行即将安装/卸载的应用程序

本文关键字:运行 安装 应用程序 卸载 是否 任何 用户 登录 | 更新日期: 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#中使用全局互斥锁的好模式是什么?

总之,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函数中调用CreateMutexCheckForMutexes

好主意,Martin。这是我在WPF中使用互斥对象的完整解决方案,即使其他登录用户正在运行WPF应用程序,Inno Setup程序也会检测到。我用的是Visual Studio。

  1. 假设WPF应用程序和项目都名为"MyWPFApp"
  2. 打开MyWPFApp的项目属性;在'Application'选项卡上确保启动对象为'MyWPFApp.App'。
  3. 将App.xaml的构建动作从ApplicationDefinition更改为Page。
  4. 从App.xaml中删除StartupUri属性,如果使用的话。
  5. 如果是应用程序。使用启动事件时,删除所有实例化并显示主窗口的代码。
  6. 将以下或类似的代码添加到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();
            }
        }
    }
    
最后一步是在Inno Setup脚本中包含以下行:
[Setup]
AppMutex=MyWPFApp,Global'MyWPFApp

我尝试用c# using语句为两个互斥体构建代码,但是我的大脑冻结了。

或者,也可以创建一个单独的类,其中包含Main方法,并将上面的代码放在那里。这需要上面的第4步和第5步,并在第2步中将Startup对象更改为包含Main方法的新类。

谢谢马丁。鲍勃