简体   繁体   中英

How to restore single instance application from system tray when clicking on desktop shortcut?

This is my project example.

App.xaml.cs

using BackgroundApplication.Single_Instance_App;
using System.ComponentModel;
using System.Windows;

namespace BackgroundApplication
{    
    public partial class App : Application
    {
        private System.Windows.Forms.NotifyIcon _notifyIcon;
        private bool _isExit;

     protected override void OnStartup(StartupEventArgs e)
        {
            WpfSingleInstance.Make("MyWpfApplication", this);

            base.OnStartup(e);

        }

    }
}

WpfSingleInstance.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace BackgroundApplication.Single_Instance_App
{
  public  class WpfSingleInstance
    {

        internal static void Make(String name, Application app)
        {

            EventWaitHandle eventWaitHandle = null;
            String eventName = Environment.MachineName + "-" + Environment.CurrentDirectory.Replace('\\', '-') + "-" + name;

            bool isFirstInstance = false;

            try
            {
                eventWaitHandle = EventWaitHandle.OpenExisting(eventName);
            }
            catch
            {
                // it's first instance
                isFirstInstance = true;
            }

            if (isFirstInstance)
            {
                eventWaitHandle = new EventWaitHandle(
                    false,
                    EventResetMode.AutoReset,
                    eventName);

                ThreadPool.RegisterWaitForSingleObject(eventWaitHandle, waitOrTimerCallback, app, Timeout.Infinite, false);

                // not need more
                eventWaitHandle.Close();


            }
            else
            {
                eventWaitHandle.Set();

                // For that exit no interceptions
                Environment.Exit(0);


            }
        }


        private static void waitOrTimerCallback(Object state, Boolean timedOut)
        {
            Application app = (Application)state;
            app.Dispatcher.BeginInvoke(new activate(delegate () {
                Application.Current.MainWindow.Activate();
            }), null);
        }


        private delegate void activate();

    }
}

MainWindow.xaml.cs

using Microsoft.Win32;
using System.Windows.Forms;
namespace BackgroundApplication
{   
    public partial class MainWindow : Window
    {    
        public MainWindow()
        {
            InitializeComponent();
        }
        private System.Windows.Forms.NotifyIcon _notifyIcon;

        private void CloseCustomButton_Click(object sender, RoutedEventArgs e)
        {
            this.ShowInTaskbar = false;
            this.Hide();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _notifyIcon = new System.Windows.Forms.NotifyIcon();
            _notifyIcon.DoubleClick += (s, args) => NormalMainWindow();
            _notifyIcon.Icon = BackgroundApplication.Properties.Resources.MyIcon;
            _notifyIcon.Visible = true;
            _notifyIcon.BalloonTipText = "Background Processing is running";
            _notifyIcon.BalloonTipTitle = "Information";
            _notifyIcon.ShowBalloonTip(50);
            CreateContextMenu();
        }
        private void CreateContextMenu()
        {        
            _notifyIcon.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
            _notifyIcon.ContextMenuStrip.Items.Add("Background Application").Click += (s, e) => NormalMainWindow();
            _notifyIcon.ContextMenuStrip.Items.Add("Maximize").Click += (s, e) => MaxMainWindow();
            _notifyIcon.ContextMenuStrip.Items.Add("Minimize").Click += (s, e) => MinMainWindow();
            _notifyIcon.ContextMenuStrip.Items.Add("Exit").Click += (s, e) => ExitApplication();

        }

        private void NormalMainWindow()
        {
            if (this.IsVisible)
            {
                if (this.WindowState == WindowState.Minimized)
                {
                    this.WindowState = WindowState.Normal;
                    this.ShowInTaskbar = true;
                }
                this.Activate();
            }
            else
            {
                this.Show();
            }
        }
        private void MaxMainWindow()
        {
            if (this.IsVisible)
            {
                if (this.WindowState == WindowState.Normal)
                {
                    this.WindowState = WindowState.Maximized;
                    this.ShowInTaskbar = true;
                }
                this.Activate();
            }
            else
            {
                this.Show();
                this.WindowState = WindowState.Maximized;
                this.Activate();
            }
        }
        private void MinMainWindow()
        {
            if (this.IsVisible)
            {
                if ((this.WindowState == WindowState.Normal) || (this.WindowState == WindowState.Maximized))
                {
                    this.WindowState = WindowState.Minimized;
                    this.ShowInTaskbar = true;
                }
                this.Activate();
            }
            else
            {
                return;
            }
        }
        private void ExitApplication()
        {
            _isExit = true;        
            System.Windows.Application.Current.Shutdown();
            _notifyIcon.Dispose();
            _notifyIcon = null;
        }     
    }
 }

It is exactly ok for single instance application & tray system.

But How can I restore this application from system tray when clicking on desktop shortcut (By clicking "Background Application.exe") ????

Have a look at What is the correct way to create a single-instance application?

Basically the idea is when you fire up your second instance of the application, and detect that you're already running, you broadcast a window message that your other instance (the real instance) will catch and then bring itself back to the foreground. And your second instance exits as soon as it's sent the message.

Try with this:

[DllImport("user32.dll")]
private static extern IntPtr FindWindow(String lpClassName, String lpWindowName);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM