将当前应用程序作为单实例运行并显示前一个实例

2024-01-30

我刚刚实现了这段保护应用程序单个实例的代码,以免应用程序运行两次。

现在我想知道如何显示已经运行的原始应用程序进程。

这是我在程序类中的代码:

static class Program
{
    [STAThread]
    static void Main()
    {
        const string appName = "MyappName";
        bool createdNew;
        mutex = new Mutex(true, appName, out createdNew);

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Form form = new Form1();

        if (!createdNew)
        {
            form.Show();  <<=========================== NOT WORKING
            form.Visible = true; <<===================== None
            form.TopMost = true; <<===================== of
            form.BringToFront(); <<===================== these working!
            form.WindowState = FormWindowState.Maximized;
            return;
        }
        Application.Run(form);
    }        private static Mutex mutex = null;
}

我向您建议一种不同的方法,结合使用类和UI自动化 https://learn.microsoft.com/en-us/dotnet/api/system.windows.automation.automation?view=netframework-4.7.2 班级。

A Mutex正如您所知,可以是一个简单的字符串。您可以以 GUID 的形式为应用程序分配互斥体,但也可以是其他任何形式。
我们假设这是当前的应用程序Mutex:

string ApplicationMutex = "BcFFcd23-3456-6543-Fc44abcd1234";
//Or
string ApplicationMutex = "Global\BcFFcd23-3456-6543-Fc44abcd1234";

Note:
使用"Global\"定义互斥量范围的前缀。如果没有指定前缀,则"Local\"假定并使用前缀。当多个桌面处于活动状态或终端服务在服务器上运行时,这将阻止该进程的单个实例。

如果我们想验证另一个正在运行的进程是否已经注册了相同的进程Mutex,我们尝试注册我们的Mutex如果失败,则我们的应用程序的另一个实例已经在运行。
我们让用户知道该应用程序仅支持单个实例,然后切换到正在运行的进程,显示其界面,最后退出重复的应用程序,处理掉Mutex.

激活应用程序的先前实例的方法可能会根据应用程序的类型而有所不同,但只有一些细节发生变化。
我们可以用检索正在运行的进程的列表并验证其中一个进程是否具有与我们相同的详细信息。

在这里,您有一个窗口应用程序(它有一个 UI),因此已经可以过滤列表,排除那些没有窗口的进程.

Process[] windowedProcesses = 
    Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero).ToArray();

为了确定正确的,我们可以测试是一样的。
但是这个name与可执行文件名称相关。如果文件名发生变化(有人出于某种原因更改了它),我们将永远不会以这种方式识别进程。

识别正确流程的一种可能方法是测试并检查是否相同。

找到后,可以将原始应用程序置于前面AutomationElement使用创建的MainWindowHandle已识别的流程。
The AutomationElement可以自动化不同的Patterns(为 UI 元素提供自动化功能的控件)。
A 允许控制基于窗口的控件(平台无关,可以是 WinForms 的窗体或 WPF 的窗口)。

AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
WindowPattern wPattern = element.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
wPattern.SetWindowVisualState(WindowVisualState.Normal);

要使用UIAutomation功能,您必须在项目中添加这些引用:
- UIAutomationClient
- UIAutomationTypes

UPDATE:
由于申请表可能被隐藏,Process.GetProcesses()不会找到它的窗口句柄,因此AutomationElement.FromHandle()不能用来识别Form窗户。

一种可能的解决方法是在不放弃 UIAutomation“模式”的情况下注册一个 Automation 事件,使用,它允许在发生 UI 自动化事件时接收通知,例如即将显示新窗口(程序正在运行)。

仅当应用程序需要作为单实例运行时才会注册该事件。当事件发生时,新的进程AutomationElement名称(Windows 标题文本)与当前名称进行比较,如果相同,则隐藏的窗体将取消隐藏并以正常状态显示。
作为一种故障安全措施,我们提供了一个信息MessageBox. The MessageBox标题与应用程序具有相同的标题MainForm.
(使用表格进行测试WindowsState set to Minimized和它的Visible属性设置为false).


在原始进程被带到前面后,我们只需要关闭当前线程并释放我们创建的资源(在本例中主要是互斥体)。

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows.Automation;
using System.Windows.Forms;

static class Program
{
    static Mutex mutex = null;

    [STAThread]
    static void Main()
    {
        Application.ThreadExit += ThreadOnExit;
        string applicationMutex = @"Global\BcFFcd23-3456-6543-Fc44abcd1234";
        mutex = new Mutex(true, applicationMutex);
        bool singleInstance = mutex.WaitOne(0, false);
        if (!singleInstance)
        {
            string appProductName = Process.GetCurrentProcess().MainModule.FileVersionInfo.ProductName;
            Process[] windowedProcesses = 
                Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero).ToArray();

            foreach (Process process in windowedProcesses.Where(p => p.MainModule.FileVersionInfo.ProductName == appProductName))
            {
                if (process.Id != Process.GetCurrentProcess().Id)
                {
                    AutomationElement wElement = AutomationElement.FromHandle(process.MainWindowHandle);
                    if (wElement.Current.IsOffscreen)
                    {
                        WindowPattern wPattern = wElement.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
                        #if DEBUG
                        WindowInteractionState state = wPattern.Current.WindowInteractionState;
                        Debug.Assert(!(state == WindowInteractionState.NotResponding), "The application is not responding");
                        Debug.Assert(!(state == WindowInteractionState.BlockedByModalWindow), "Main Window blocked by a Modal Window");
                        #endif
                        wPattern.SetWindowVisualState(WindowVisualState.Normal);
                        break;
                    }
                }
            }
            Thread.Sleep(200);
            MessageBox.Show("Application already running", "MyApplicationName",
                            MessageBoxButtons.OK, MessageBoxIcon.Information, 
                            MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
        }

        if (SingleInstance) {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MyAppMainForm());
        }
        else {
            Application.ExitThread();
        }
    }
    private static void ThreadOnExit(object s, EventArgs e)
    {
        mutex.Dispose();
        Application.ThreadExit -= ThreadOnExit;
        Application.Exit();
    }
}

在应用程序中MainForm构造函数:
(这是在运行新实例时应用程序的主窗口被隐藏的情况下使用的,因此中的过程Program.cs找不到它的句柄)

public partial class MyAppMainForm : Form
{
    public MyAppMainForm()
    {
        InitializeComponent();
        Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, 
                                             AutomationElement.RootElement, 
                                             TreeScope.Subtree, (uiElm, evt) =>
        {
            AutomationElement element = uiElm as AutomationElement;
            string windowText = element.Current.Name;
            if (element.Current.ProcessId != Process.GetCurrentProcess().Id && windowText == this.Text)
            {
                this.BeginInvoke(new MethodInvoker(() =>
                {
                    this.WindowState = FormWindowState.Normal;
                    this.Show();
                }));
            }
        });
    }    
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将当前应用程序作为单实例运行并显示前一个实例 的相关文章

随机推荐

  • 将 Form_validation 错误放入数组中

    我的 CodeIgniter 应用程序中有一个用于表单验证的代码 this gt load gt library form validation this gt form validation gt set rules message Me
  • ModuleNotFoundError:没有名为“neo4j.addressing”的模块和 ModuleNotFoundError:没有名为“neo4j”的模块

    我收到这个错误 只是尝试运行 Graph 方法 gt gt gt import py2neo gt gt gt graph py2neo Graph Traceback most recent call last File
  • org.hibernate.PersistentObjectException:分离的实体传递给持久异常

    我正在创建一个简单的应用程序 只需使用以下命令将一行插入表中 如果表不存在 则创建它 Java JPA 我附加了一些可运行示例的代码 这是我得到的异常和堆栈跟踪 EXCEPTION gt org hibernate PersistentOb
  • 任意颜色条

    我有使用 imshow 显示的 70 0 范围内的数据 并且希望使用非线性颜色条来表示数据 因为我的模式都在 70 60 范围和 70 范围内 0 范围 我想要使 用任意函数 参见示例 重新缩放 重新规范化颜色条的最简单方法 以便所有模式都
  • 函数返回接口意味着什么?

    我刚刚看到这样的成员函数 public Cat nextCat GameState state 但 Cat 的接口是这样的 public interface Cat void makeCat GameState state 所以我很困惑如何
  • 如何从 java.sql.Timestamp 转换为 java.util.Date?

    i e 这段代码 startDate new Date timestampValue getTime 给我 2012 16 02 05 16 17 when System out println timestampValue return
  • 全日历日双击回调

    我需要实现在 dblclick 上工作的功能 例如 dayClick 回调 我尝试了所有找到的解决方案 但对我来说没有任何作用 例如米歇尔的回答 https stackoverflow com questions 8124460 handl
  • 单击菜单时如何隐藏默认键盘?

    我已经通过在该网站中插入代码尝试了多种方法onCreateOptionsMenu Menu menu 没有成功 我想在单击菜单按钮时隐藏键盘 我有三个 EditText 我可以在其中写入一些数据 并且菜单上有插入 删除 修改数据库的选项 但
  • 带动态标题的管道 ggplot2

    我可以获取数据并在 ggplot 中使用管道制作标题吗 假设我有这样的数据 x lt c 5 17 31 9 17 10 30 28 16 29 14 34 y lt c 1 2 3 4 5 6 7 8 9 10 11 12 day lt
  • 显示高级自定义字段的 JSON API - WordPress

    I am developing a magazine WordPress site that will have a json feed for a Mobile App I set the backend up using Advance
  • 我应该在 Swift Playgrounds 的 .gitignore 文件中包含什么?

    我想使用 Git 对我的 Playground 进行版本控制 但我不确定哪些文件应该被忽略以及哪些文件应该提交 目前我使用以下 gitignore游乐场文件 Xcode user data xcuserdata 还应该有什么 来自官方Swi
  • 使用环境调用 popen

    在我的 Lua 程序中 我必须捕获外部程序的输出 该外部程序需要某些环境变量 所以我这样做 e e e A 100 e e B Hi e e C Test file io popen e bin aprogr 显然 如果环境很大 popen
  • 如何使用Python获取两个PDF文件的差异?

    我需要找出两个 PDF 文件之间的差异 有谁知道任何与Python相关的工具具有直接给出两个PDF的差异的功能吗 你所说的 差异 是什么意思 PDF 文本存在差异或某些布局发生变化 例如 调整了嵌入图形的大小 第一个很容易检测 第二个几乎不
  • SQLITE 数据库在 java 中被锁定(IDE NetBeans)

    当我执行任何操作时 它在数据库中工作 但突然显示数据库已锁定错误 假设这是在一个按钮上执行的操作 private void jButton6ActionPerformed java awt event ActionEvent evt Sah
  • 是否可以在 webpack 中创建自定义解析器?

    当需要模块时我有自己的约定 例如 require components SettingsPanel 应解决require components SettingsPanel SettingsPanel js 有什么方法可以创建这样的解析器吗
  • 在谷歌闭包库中创建自定义事件调度程序时出现问题

    我正在尝试在 google Closure js 库中创建自定义事件调度程序 我将此代码基于 fx 文件夹中的动画类 但我不断收到此错误 goog events 未定义 但我将事件包放在顶部 这是我的代码 goog provide test
  • 如何自动重新连接 Rails 6 PostgreSQL 连接?

    我有一个带有一些工作进程的 Rails 6 应用程序 该应用程序使用 PostgreSQL 作为数据库 有时数据库会重新启动 例如次要版本升级 并且工作人员会失去连接 我希望他们能够自动重新连接 但它没有发生 我尝试使用reconnect
  • GWT 中的字符串格式化程序

    如何在 GWT 中格式化字符串 我做了一个方法 Formatter format new Formatter int matches 0 Formatter formattedString format format d numbers s
  • opencv中的HoughCircles函数可以检测圆内的圆吗?

    我在 OpenCV 中遇到了用于圆检测的 HoughCircles 但它有一个参数指定检测到的圆之间的最小距离 我担心的是 如果两个圆同心 即一个圆在另一个圆内 这是否有效 谢谢 沙尚克 如果两个圆的中心相距足够远 霍夫变换将仅返回 2 个
  • 将当前应用程序作为单实例运行并显示前一个实例

    我刚刚实现了这段保护应用程序单个实例的代码 以免应用程序运行两次 现在我想知道如何显示已经运行的原始应用程序进程 这是我在程序类中的代码 static class Program STAThread static void Main con