在我的 WPF 应用程序的
App.xaml.cs
中,我有一个覆盖函数来启动应用程序。当应用程序启动时,它首先会检查是否有另一个实例正在运行。如果是这样,第二个实例将关闭。然后,它将检查应用程序是否在用户计算机启动时自动启动。如果自动打开,它将使用 MainWindow.Hide()
隐藏该应用程序。然后它订阅主窗口的更改。如果有任何更改,将显示主窗口。
我的代码的目的是在计算机启动时隐藏窗口。然后,如果用户单击 exe 图标,则会显示该窗口。一切工作正常,除了当我单击 exe 图标时,我收到错误消息“应用程序的另一个实例已在运行”。而应用程序实际上在后台进程中运行(我在任务管理器中检查过)。有没有办法在用户单击 exe 时恢复主窗口?
protected override void OnStartup(StartupEventArgs e)
{
const string mutexName = "YourAppMutexName";
_mutex = new Mutex(true, mutexName, out bool isNewInstance);
if (isNewInstance)
{
// Another instance of the application is already running
MessageBox.Show("Another instance of the application is already running.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
Current.Shutdown();
}
else
{
base.OnStartup(e);
bool startedAutomatically = IsStartedAutomatically(e.Args);
NavigationStore navigationStore = new();
navigationStore.CurrentVM = new LoginVM(navigationStore);
if (startedAutomatically)
{
// The application was started automatically by Windows during startup
// Do whatever you need to do in this case (e.g., hide the main window)
MainWindow = new MainWindow()
{
DataContext = new MainWindowVM(navigationStore)
};
MainWindow.Hide();
MessageBox.Show("App running but hidden because of auto startup");
MainWindow.StateChanged += (sender, args) =>
{
if (MainWindow.WindowState == WindowState.Normal)
{
MainWindow.Show();
}
};
}
else
{
// The application was started manually by the user
// Do whatever you need to do in this case (e.g., show the main window)
MainWindow = new MainWindow()
{
DataContext = new MainWindowVM(navigationStore)
};
MainWindow.Show();
MessageBox.Show("App running...");
}
AddToStartup();
}
private bool IsStartedAutomatically(string[] args)
{
// Check if the "--startup" command-line argument is present
return Array.Exists(args, arg => arg.Equals("--startup", StringComparison.OrdinalIgnoreCase));
}
您可以使用同步原语来同步两个进程。 让第一个进程等待第二个进程触发的信号。
出于安全原因,我建议使用
EventWaitHandle
而不是 Mutex
。
一些备注:
Window.Hide
是没有意义的。Mutex
是新实例时关闭应用程序。const
,因为这会导致全局变量在程序集外部对其他进程可见。Window.StateChanged
事件是多余的,因为窗口不仅不可见,而且永远不会加载。这意味着它是无状态的。您必须先显示 Window
,然后它才能具有窗口状态。App
引用您的 Application.Curent
类也是多余的。这并没有什么坏处,但有些人可能会觉得你不知道自己在做什么。代码的改进示例如下所示:
protected override void OnStartup(StartupEventArgs e)
{
bool isProcessAlreadyRunning = EventWaitHandle.TryOpenExisting("YourAppMutexName", out EventWaitHandle eventWaitHandle);
if (!isProcessAlreadyRunning)
{
eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "YourAppMutexName");
var eventSecurity = new EventWaitHandleSecurity();
SecurityIdentifier? currentUser = WindowsIdentity.GetCurrent().User;
var accessRule = new EventWaitHandleAccessRule(currentUser, EventWaitHandleRights.Modify | EventWaitHandleRights.Synchronize, AccessControlType.Allow);
eventSecurity.AddAccessRule(accessRule);
eventWaitHandle.SetAccessControl(eventSecurity);
var mainWindow = new MainWindow();
// TODO::Do some initialization and when you are done wait for the signal
MessageBox.Show("App running but hidden because of auto startup");
eventWaitHandle.WaitOne();
// We were finally signalled and continue to show the application window
mainWindow.Show();
}
else // Another process of this application is already running
{
MessageBox.Show("Another instance of the application is already running.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
// Signal the other waiting process and allow it to proceed
eventWaitHandle.Set();
// End the current process
Shutdown();
return;
}
}