3

i have one problem with this ?! i use this way for run only one instance of program. it's do very good.but when i use this way in other app . when i run one of them programs via shortcut from desktop , both programs invoke and show in desktop. note : both programs run in windows system try .

    static bool ok;
    static Mutex mutex = new Mutex(true, "{123Newsoft-Cleaner Portable Program123}",out ok);

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]

    static void Main()
    {
        //Application.EnableVisualStyles();
        //Application.SetCompatibleTextRenderingDefault(false);
        //Application.Run(new Form1());

        if (mutex.WaitOne(TimeSpan.Zero, true))  
        {

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);


            var mainForm = new Form1c();

            try
            {                                    

                    mainForm.Visible = false;


                    mainForm.WindowState = FormWindowState.Normal;                  

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            Application.Run(mainForm);               

        }
        else
        {

            NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_SHOWME, IntPtr.Zero, IntPtr.Zero);

        }

//---------------- in main form

    protected override void WndProc(ref Message M_C)
    {

        if (M_C.Msg == NativeMethods.WM_SHOWME)
        {               
            ShowMe();
        }
        base.WndProc(ref M_C);
    }

    //*************
    private void ShowMe()
    {

        if (WindowState == FormWindowState.Minimized)
        {
            Show();
            WindowState = FormWindowState.Normal;
        }

        // get our current "TopMost" value (ours will always be false though)
        bool top = TopMost;
        // make our form jump to the top of everything
        TopMost = true;
        // set it back to whatever it was
        TopMost = top;

    }  
TheBuzzSaw
  • 8,648
  • 5
  • 39
  • 58
pepero
  • 33
  • 1
  • 3

2 Answers2

12

This is already well supported by the .NET Framework. You want to use the WindowsFormsApplicationBase class. Set the IsSingleInstance property to true. You can override the OnStartupNextInstance method to do anything you like when another instance gets started. Like restoring the window of the first instance. Rewrite your Program.cs file to look like this:

using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;   // Add reference to Microsoft.VisualBasic

namespace WindowsFormsApplication1 {
    class Program : WindowsFormsApplicationBase {
        [STAThread]
        static void Main(string[] args) {
            var app = new Program();
            app.Run(args);
        }
        public Program() {
            this.IsSingleInstance = true;
            this.EnableVisualStyles = true;
            this.MainForm = new Form1();
        }
        protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) {
            if (this.MainForm.WindowState == FormWindowState.Minimized) this.MainForm.WindowState = FormWindowState.Normal;
            this.MainForm.Activate();
        }
    }
}
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks :)i use .net 3.5 this not work : Microsoft.VisualBasic.ApplicationServices; – pepero Aug 12 '12 at 17:40
  • 1
    This works fine for 3.5. Look at the comment, use Project + Add Reference. – Hans Passant Aug 12 '12 at 17:42
  • mersi.its work.unfortunately have old problem.when run one app, show both :( – pepero Aug 13 '12 at 02:23
  • hi again.pre problem solved.but other is this : http://www.8pic.ir/images/xzwh8dkwx7j3oozxjk8m.png show taskbar icon ? – pepero Aug 13 '12 at 04:21
  • Be forewarned: You have to watch out for crossing threads. You'll want to use the InvokeRequired on the form to ensure that you aren't crossing threads. – Ben Keene Aug 16 '16 at 19:19
1

To add to what Hans Passant wrote, I added an extra method on the main form that handles restoring the window and activating it. This was to wrap the invoke required condition of the form.

So the added method on the form is:

/// <summary>
/// Recovers this instance of the form.
/// </summary>
public void RestoreFromTray()
{
   if(this.InvokeRequired)
   {
      this.Invoke(new Action(RestoreFromTray) );
      return;
   }
   this.Visible = true;
   this.WindowState = FormWindowState.Normal;
   this.Activate();
}

Then in Hans' method, I changed the override to simply:

protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) 
{
    ((formClassName)this.MainForm).RestoreFromTray();
}

Where formClassName is the class name of the form.

Ben Keene
  • 459
  • 4
  • 7
  • If you need this then you are doing something **very** wrong. The kind of wrongness that is going to hang your app some rainy day that requires [this kind of debugging](https://blogs.msdn.microsoft.com/dsui_team/2012/10/31/debugging-windows-forms-application-hangs-during-systemevents-userpreferencechanged/). *Never* display UI on worker threads, the SystemEvents class will eat your liver. – Hans Passant Aug 16 '16 at 19:26
  • I think I missed something - I added the InvokeRequired test to ensure that the window is restored on the correct thread. Where did I get this wrong? – Ben Keene Aug 16 '16 at 19:50