C# 告知是否有登录用户正在运行即将安装/卸载的应用程序

C# 告知是否有登录用户正在运行即将安装/卸载的应用程序,c#,inno-setup,mutex,C#,Inno Setup,Mutex,我的程序使用Inno安装程序来安装/卸载它。在我的应用程序代码中,我使用CreateMutexwindowsapi函数创建了一个Global互斥体。然后在Inno安装程序中,我有以下代码: AppMutex=Global\MyProgramMutex.2A23834B-2919-4007-8C0A-3C7EDCA7186E 函数InitializeSetup():Boolean; 开始 结果:=真; 如果(CreateMutex(0,False,“{SetupSetting('AppId')}”

我的程序使用Inno安装程序来安装/卸载它。在我的应用程序代码中,我使用
CreateMutex
windowsapi函数创建了一个Global互斥体。然后在Inno安装程序中,我有以下代码:

AppMutex=Global\MyProgramMutex.2A23834B-2919-4007-8C0A-3C7EDCA7186E
函数InitializeSetup():Boolean;
开始
结果:=真;
如果(CreateMutex(0,False,“{SetupSetting('AppId')}”)0和(DLLGetLastError=ERROR_已经存在),那么
开始
结果:=假;
MsgBox('安装程序的另一个实例已在运行。请关闭它并重试',mbCriticalError,MB_OK);
结束;
如果CheckForMutexes(“{#SetupSetting('AppMutex')}”),则
开始
结果:=假;
MsgBox(“{#SetupSetting('AppName')}”+”似乎正在运行。请在继续之前关闭程序的所有实例。“,mbCriticalError,MB#u OK);
结束;
结束;
正如预期的那样,对于运行Inno安装程序的用户来说,这非常有效。我遇到的问题是:如果我“切换用户”并以其他用户的身份启动应用程序,然后切换回原始用户,则安装程序不会检测到应用程序正在其他用户下运行


我对安装程序是否能检测到正在运行的应用程序还不够了解。

如Inno Setup KB中所述:

要检测在其他会话中创建的互斥体,应用程序必须创建两个互斥体:一个带有
Global\
前缀,另一个不带前缀

带有
Global\
前缀的互斥体可以从任何用户会话访问。如果由于安全限制或缺乏操作系统支持(4.0终端服务器版之前的Windows NT版本不支持全局\前缀),全局互斥体的创建失败,则还必须在会话名称空间中创建一个类似命名的互斥体(即不带
全局\
前缀)

此外,必须在每个CreateMutex()调用中传递一个特殊的安全描述符,以确保不同的用户可以访问互斥体。

要使C#中的所有用户都可以访问互斥,请参阅:

总之,C#应用程序中的代码应该如下所示:

常量字符串mutexId=“MyProg”; MutexAccessRule允许每个人= 新MutexAccessRule( 新的SecurityIdentifier(WellKnownSidType.WorldSid,null), MutexRights.FullControl、AccessControlType.Allow); MutexSecurity securitySettings=新的MutexSecurity(); securitySettings.AddAccessRule(AllowEveryoneUrle); 互斥对象globalMutex=null; 尝试 { 布尔创造了新的; globalMutex=新互斥体(false,“Global\\”+mutexId,out createdNew,securitySettings); } 捕获(未经授权的访问例外) { //忽略 } Mutex localMutex=新的互斥(false,mutexId); 尝试 { //在这里运行您的程序 } 最后 { //只有在应用程序(其窗口)关闭后才能调用它们。 //您还可以删除这些调用,让系统释放互斥锁。 if(globalMutex!=null) { globalMutex.Dispose(); } localMutex.Dispose(); }
在Inno设置端,您只需在以下列表中列出两个互斥体:

[设置]
AppMutex=MyProg,全局\MyProg

InitializeSetup
函数中,您不需要调用
CreateMutex
CheckForMutexes

好主意。下面是我在WPF中使用互斥对象的完整解决方案,Inno安装程序将检测到这些对象,即使其他登录用户正在运行WPF应用程序。顺便说一句,我用的是Visual Studio

  • 假设WPF应用程序和项目都称为“MyWPFApp”
  • 打开MyWPFApp的项目属性;在“应用程序”选项卡上,确保启动对象为“MyWPFApp.App”
  • 将App.xaml的生成操作从ApplicationDefinition更改为Page
  • 从App.xaml中删除StartupUri属性(如果使用)
  • 如果使用了Application.Startup事件,请删除实例化和显示主窗口的所有代码
  • 将以下或类似代码添加到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]
    AppMutex=MyWPFApp,Global\MyWPFApp
    
    我试图用C#
    为两个互斥体使用
    语句来构建代码,但我的大脑被冻结了

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

    谢谢你,马丁


    Bob

    似乎应该可以正常工作,因为您根据使用了\global作为前缀。上面的代码是来自安装程序集还是应用程序集?您不需要为AppMutex添加代码,我怀疑应用程序中有代码。关于它的知识库条目。是一个关于应用程序方面的问题。马丁,我为误用“答案”功能道歉。我这样做是出于无知。所以,今天早上我很快把你的建议写进了我的申请代码。在Inno设置脚本中,我从“InitializeSetup”函数中删除了互斥代码,并在[Setup]部分修改了我的AppMutex设置。我安装并运行了我的应用程序。然后我再次运行安装程序,但它没有检测到正在运行的应用程序。它确实检测到有一个程序(我的应用程序)正在使用它继续运行所需的文件。我看不出我错过了什么?再次感谢…您的整个程序运行在哪里?
    //在这里运行您的程序
    注释在哪里?如果我创建一个简单的控制台应用程序,并将
    console.ReadLine
    放在该位置,在另一个会话中运行该应用程序,安装程序会完美地检测到。是的。这是一个WPF应用程序,您已经指出,我有
    code
    MainWindow mainWin=new MainWindow();缅因州