gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 14:46:08 32 4
gpt4 key购买 nike

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

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

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

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;
}

最佳答案

我建议您使用一种不同的方法,结合使用 System.Threading.Mutex 类和 UIAutomation AutomationElement 类。

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

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

注意 :
使用 "Global\" 前缀来定义 Mutex 的范围。如果未指定前缀,则假定并使用 "Local\" 前缀。当多个桌面处于事件状态或终端服务在服务器上运行时,这将阻止进程的单个实例。

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

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

在这里,您有一个窗口应用程序(它有一个 UI),因此已经可以过滤列表,不包括那些没有 MainWindowHandle 的进程。
Process[] windowedProcesses = 
Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero).ToArray();

为了识别正确的,我们可以测试 Process.ProcessName 是否相同。
但此名称与可执行文件名称相关联。如果文件名更改(有人出于某种原因更改它),我们将永远不会以这种方式识别进程。

识别正确进程的一种可能方法是测试 Process.MainModule.FileVersionInfo.ProductName 并检查它是否相同。

找到后,可以使用已识别进程的 AutomationElement 创建的 MainWindowHandle 将原始应用程序置于最前面。 AutomationElement 可以自动化不同的模式(一种为 UI 元素提供自动化功能的控件)。
WindowPattern 允许控制基于窗口的控件(平台无关,可以是 WinForms 的表单或 WPF 的窗口)。
AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
WindowPattern wPattern = element.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
wPattern.SetWindowVisualState(WindowVisualState.Normal);

To use the UIAutomation functionalities, you have to add these refereneces in your Project:
- UIAutomationClient
- UIAutomationTypes



更新:
由于应用程序的窗体可能被隐藏, Process.GetProcesses() 将找不到它的窗口句柄,因此 AutomationElement.FromHandle() 不能用于识别 Form 窗口。

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

仅当应用程序需要作为单实例运行时才注册该事件。引发事件时,会将新的进程 AutomationElement 名称(Windows 标题文本)与当前进行比较,如果相同,隐藏的表单将取消隐藏并显示为正常状态。
作为故障安全措施,我们提供信息 MessageBoxMessageBox 标题与应用程序 MainForm 具有相同的标题。
(使用 WindowsState 设置为 MinimizedVisible 属性设置为 false 的表单进行测试)。

将原始进程带到前面后,我们只需要关闭当前线程并释放我们创建的资源(在本例中主要是 Mutex)。
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();
}));
}
});
}
}

关于c# - 将当前应用程序作为单个实例运行并显示上一个实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50552592/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com