Как открыть основной интерфейс приложения из исполняемого файла вместо этого на иконке в трее в C # - PullRequest
2 голосов
/ 17 ноября 2009

Вот сценарий, я открыл свое приложение, после чего отображается значок в трее, если дважды щелкнуть значок в трее, отобразится основной интерфейс. если я снова открою свое приложение, основной интерфейс должен получить фокус, или, если он еще не показан, его следует показать вместо открытия другого экземпляра моего приложения.

вот как выглядит мой код:

//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();
}

Ответы [ 3 ]

5 голосов
/ 17 ноября 2009

РЕДАКТИРОВАТЬ: ОК, кажется, что для корректного переопределения 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 для одного экземпляра



Мьютекс, наверное, лучший путь. Добавьте к этому пользовательское сообщение Windows, которое ваше приложение ожидает, чтобы сфокусироваться (см. Межпроцессное взаимодействие VB.NET, VB6 и C # через Window Messaging ).

Проверьте этот образец: C # - один экземпляр приложения

0 голосов
/ 18 ноября 2009

Вы также можете взглянуть на функцию SwitchToThisWindow .

Когда запускается второй экземпляр приложения, вы можете просто вызвать эту функцию с помощью дескриптора главного окна первого экземпляра. Вы можете получить дескриптор главного окна с помощью свойства Process.MainWindowHandle .

0 голосов
/ 17 ноября 2009

Не думаю, что вы можете вызывать события в окнах другого приложения (даже если это один и тот же исполняемый файл).

Хотя я бы решил эту проблему, используя некоторый механизм IPC , чтобы указать запущенному экземпляру открыть главное окно. Тот же механизм IPC также можно использовать для определения, работает ли другой экземпляр.

...