【问题标题】:How to open an app main interface from the executable instead on the tray icon in c#如何从可执行文件而不是在c#中的托盘图标上打开应用程序主界面
【发布时间】:2009-11-17 18:32:28
【问题描述】:

这是场景,我打开我的应用程序然后显示托盘图标,如果我双击托盘图标,将显示主界面。如果我再次打开我的应用程序,主界面应该获得焦点,或者如果它尚未显示,那么应该显示它而不是打开我的应用程序的另一个实例。

这是我的代码的样子:

//Program.cs
.....

if(myAppIsNotRunningYet) //the program has not been open yet
{
MyTray = new MyTray();
Application.Run();
}

else //the program is already on the tray
{
//the code to give focus to the mainForm or open it up if not yet open
}

//MyTray.cs
.....
public MyTray()
{
notifyIcon = new NotifyIcon();
....
notifyIcon.Visible = true;
}

private void notifyIcon_DoubleClick(object sender, EventArgs e)
{
MainForm mainForm = new MainForm();
mainForm.ShowDialog();
}

【问题讨论】:

    标签: c# forms show tray


    【解决方案1】:

    编辑: 好的,看来要正确覆盖 WndProc,您必须使用/已经可见的表单。所以下面是使用MessageFilter 的不同解决方案。这确实有效,所以希望你能从这里开始!

     internal sealed class Program
     { 
      /// <summary>
      /// Program entry point.
      /// </summary>
      [STAThread]
      public static void Main(string[] args)
      {
        bool newMutex;
        System.Threading.Mutex mutex = new System.Threading.Mutex(true, "{9F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}", out newMutex);
    
         // Attempt aquire the mutex
         if(newMutex)
         {
          // If we are able to aquire the mutex, it means the application is not running.
             Application.EnableVisualStyles();
             Application.SetCompatibleTextRenderingDefault(false);
    
             // Create the new tray icon
             MyTray myTray = new MyTray();
    
             Application.AddMessageFilter(myTray);
             Application.Run();
    
             // Release the mutex on exit
             mutex.ReleaseMutex();
         }
         else
         {
            // If the aquire attempt fails, the application is already running
            // so we broadcast a windows message to tell it to wake up.
             NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_SHOWME, IntPtr.Zero, IntPtr.Zero);
         }
         }
     }
    }
    
    internal class NativeMethods
     {
         public const int HWND_BROADCAST = 0xffff;
         public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
    
         [DllImport("user32")]
         public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
    
         [DllImport("user32")]     
         public static extern int RegisterWindowMessage(string message);
     }
    
     public class MyTray : IMessageFilter
     {
      private NotifyIcon notifyIcon = new NotifyIcon();
      private Form myForm = new Form();
    
      public MyTray()
      {
         this.notifyIcon.Icon = System.Drawing.Icon.FromHandle(new System.Drawing.Bitmap(16,16).GetHicon());
         this.notifyIcon.Visible = true;
         this.notifyIcon.DoubleClick += delegate(object sender, EventArgs e) { ShowForm(); };
      }
    
         void ShowForm()
         {
            this.notifyIcon.Visible = false;            
            this.myForm.ShowDialog();   
            this.notifyIcon.Visible = true;
          }
    
        public bool PreFilterMessage(ref Message m)
        {
           // If the message is the 'show me' message, then hide the icon and show the form.
           if(m.Msg == NativeMethods.WM_SHOWME)
           {
                if (!this.myForm.Visible)
                {
                    ShowForm();
                    return true; // Filter the message
                }
           }
    
           return false; // Forward the message
        }
     }
    

    编辑:我整理了一个更接近您的场景的示例:

     internal sealed class Program
     {
      static System.Threading.Mutex mutex = new System.Threading.Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    
      /// <summary>
      /// Program entry point.
      /// </summary>
      [STAThread]
      private static void Main(string[] args)
      {
       // Attempt aquire the mutex
             if(mutex.WaitOne(TimeSpan.Zero, true))
             {
              // If we are able to aquire the mutex, it means the application is not running.
                 Application.EnableVisualStyles();
                 Application.SetCompatibleTextRenderingDefault(false);
    
                 // Create the new tray icon
                 MyTray myTray = new MyTray();
    
                 Application.Run();
    
                 // Release the mutex on exit
                 mutex.ReleaseMutex();
             }
             else
             {
                // If the aquire attempt fails, the application is already running
                // so we broadcast a windows message to tell it to wake up.
                 NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_SHOWME, IntPtr.Zero, IntPtr.Zero);
             }
         }
     }
    
     internal class NativeMethods
     {
         public const int HWND_BROADCAST = 0xffff;
         public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
    
         [DllImport("user32")]
         public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
    
         [DllImport("user32")]     
         public static extern int RegisterWindowMessage(string message);
     }
    
     public class MyTray : Control
     {
      private NotifyIcon notifyIcon = new NotifyIcon();
    
      public MyTray()
      {
       this.notifyIcon.Visible = true;
      }
    
      /// <summary>
      /// This method listens to all windows messages either broadcast or sent to this control
      /// </summary>
      protected override void WndProc(ref Message m)
      {
       // If the message is the 'show me' message, then hide the icon and show the form.
       if(m.Msg == NativeMethods.WM_SHOWME)
       {
        this.notifyIcon.Visible = false;
        using (Form mainForm = new Form())
        {
         mainForm.ShowDialog();
         this.notifyIcon.Visible = true;
        }  
       }
       else
       {
        base.WndProc(ref m);    
       }   
      }
     }
    

    编辑:我在 C# 中找到了一个结合互斥锁和 windows 消息的示例:

    C# .NET Single Instance Application



    互斥锁可能是最好的方法。将此与您的应用程序侦听的自定义 Windows 消息相结合以使其成为焦点(请参阅VB.NET, VB6 and C# Interprocess communication via Window Messaging)。

    查看此示例: C# - Single Application Instance

    【讨论】:

    • 链接中的代码是vb代码我不是vb程序员所以我看不懂抱歉...
    • 看看我发布的新链接。它拥有我试图描述的一切......
    • 尝试过但不起作用,因为我的主要方法只有 Application.Run() 而不是 Application.Run(new Form())。就像我说的,打开 MainForm 的是我的通知图标。
    • 让 MyTray 继承自 NotifyIcon。然后您可以监听 Windows 消息并覆盖 OnDoubleClick 以打开您的 MainForm。
    • 监听消息并覆盖 OnDoubleClick 是什么意思? notifyicon 有这样的方法吗?引发 DoubleClick 事件的 notifyicon 不是 Mainform 吗?
    【解决方案2】:

    我认为您不能在另一个应用程序的窗口上引发事件(即使它们是同一个可执行文件)。

    我解决它的方法是使用一些IPC mechanism 来告诉正在运行的实例打开主窗口。同样的 IPC 机制也可以用来判断另一个实例是否正在运行。

    【讨论】:

      【解决方案3】:

      您还可以查看SwitchToThisWindow 函数。

      当应用程序的第二个实例启动时,您可以使用第一个实例的主窗口句柄调用该函数。您可以使用Process.MainWindowHandle 属性获取主窗口句柄。

      【讨论】:

      • 你说得有道理,我从未尝试过使用最小化到托盘的应用程序。如果窗口只是被隐藏,它仍然可以工作,但不能保证......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-30
      • 2017-12-03
      • 1970-01-01
      • 2010-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多