Analysis of Methods of WinForm to Prevent Repeated Running of Programs

  • 2021-12-13 09:03:34
  • OfStack

In this paper, an example is given to describe the method of preventing programs from running repeatedly by WinForm. Share it for your reference, as follows:

Requirements:

1. When you click the "Close" button, the program is minimized to the tray and does not exit. At this time, the program will be run again, and the running program will not be repeated, but the running program will be displayed;
2. Support different directories;
3. Support to modify the name.

Code (name modification and different directories are not supported):


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Tool;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
namespace  Calculator 
{
  static class Program
  {
    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    /// <summary>
    ///  This function sets the display state of windows generated by different threads. 
    /// </summary>
    /// <param name="hWnd"> Window handle </param>
    /// <param name="cmdShow"> Specifies how the window is displayed. To view a list of allowed values, see ShowWlndow The description section of the function. </param>
    /// <returns> If the function was originally visible, the return value is non-zero; If the function was originally hidden, the return value is zero. </returns>
    [DllImport("User32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
    /// <summary>
    ///  This function sets the thread that created the specified window to the foreground and activates the window. Keyboard input turns to the window and changes various visual marks for the user. The system assigns slightly higher permissions to the thread that creates the foreground window than other threads. 
    /// </summary>
    /// <param name="hWnd"> The window handle that will be activated and called into the foreground. </param>
    /// <returns> If the window is set in the foreground, the return value is non-zero; If the window is not set to the foreground, the return value is zero. </returns>
    [DllImport("User32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);
    private const int SW_SHOWNORMAL = 1;
    /// <summary>
    ///  The main entry point for the application. 
    /// </summary>
    [STAThread]
    static void Main()
    {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Process processes = RunningInstance();
      if (processes == null)
      {
        Application.Run(new Form1());
      }
      else
      {
        HandleRunningInstance(processes);
      }
    }
    /// <summary>
    ///  Gets the running instance, and the instance that is not running returns null;
    /// </summary>
    public static Process RunningInstance()
    {
      Process current = Process.GetCurrentProcess();
      Process[] processes = Process.GetProcessesByName(current.ProcessName);
      foreach (Process process in processes)
      {
        if (process.Id != current.Id)
        {
          if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
          {
            return process;
          }
        }
      }
      return null;
    }
    /// <summary>
    ///  Displays programs that have been run. 
    /// </summary>
    public static void HandleRunningInstance(Process instance)
    {
      try
      {
        IntPtr formHwnd = FindWindow(null, " Calculator ");
        ShowWindow(formHwnd, SW_SHOWNORMAL);  // Display 
        SetForegroundWindow(formHwnd);     // Put it on the front end 
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message);
      }
    }
  }
}

Code (support for changing names and supporting different directories):


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Tool;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
namespace  Calculator 
{
  static class Program
  {
    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    /// <summary>
    ///  This function sets the display state of windows generated by different threads. 
    /// </summary>
    /// <param name="hWnd"> Window handle </param>
    /// <param name="cmdShow"> Specifies how the window is displayed. To view a list of allowed values, see ShowWlndow The description section of the function. </param>
    /// <returns> If the function was originally visible, the return value is non-zero; If the function was originally hidden, the return value is zero. </returns>
    [DllImport("User32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
    /// <summary>
    ///  This function sets the thread that created the specified window to the foreground and activates the window. Keyboard input turns to the window and changes various visual marks for the user. The system assigns slightly higher permissions to the thread that creates the foreground window than other threads. 
    /// </summary>
    /// <param name="hWnd"> The window handle that will be activated and called into the foreground. </param>
    /// <returns> If the window is set in the foreground, the return value is non-zero; If the window is not set to the foreground, the return value is zero. </returns>
    [DllImport("User32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);
    private const int SW_SHOWNORMAL = 1;
    /// <summary>
    ///  The main entry point for the application. 
    /// </summary>
    [STAThread]
    static void Main()
    {
      Common.AutoRegister();
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      bool createNew;
      using (System.Threading.Mutex m = new System.Threading.Mutex(true, Application.ProductName, out createNew))
      {
        if (createNew)
        {
          FileOperator.SetValue("ProcessId", Process.GetCurrentProcess().Id.ToString()); // Process ID Write to a file 
          Application.Run(new Form1());
        }
        else
        {
          try
          {
            string strProcessId = FileOperator.GetValue("ProcessId"); // Get a process from a file ID
            int processId = Convert.ToInt32(strProcessId);
            Process process = Process.GetProcessById(processId);
            HandleRunningInstance(process);
          }
          catch
          {
            FileOperator.SetValue("ProcessId", Process.GetCurrentProcess().Id.ToString()); // Process ID Write to a file 
            Application.Run(new Form1());
          }
        }
      }
    }
    /// <summary>
    ///  Displays programs that have been run. 
    /// </summary>
    public static void HandleRunningInstance(Process instance)
    {
      try
      {
        IntPtr formHwnd = FindWindow(null, " Calculator ");
        ShowWindow(formHwnd, SW_SHOWNORMAL);  // Display 
        SetForegroundWindow(formHwnd);     // Put it on the front end 
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message);
      }
    }
  }
}

Actually, IntPtr formHwnd = FindWindow (null, "calculator"); This code has BUG. For example, if you open a folder called "Calculator", FindWindow will actually find this folder, not the calculator program. We can write down the window handle when the main form is displayed for the first time. The code is as follows:


private void Form1_Shown(object sender, EventArgs e)
{
  FileOperator.SetValue("hwnd", Process.GetCurrentProcess().MainWindowHandle.ToString());
}

Then, when the running program is displayed, read the window handle recorded before from the file. The code is as follows:


/// <summary>
///  Show running programs 
/// </summary>
public static void HandleRunningInstance(Process instance)
{
  try
  {
    IntPtr hwnd = new IntPtr(Convert.ToInt32(FileOperator.GetValue("hwnd")));
    ShowWindow(hwnd, SW_SHOWNORMAL); // Display 
    SetForegroundWindow(hwnd); // Put it on the front end 
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message);
  }
}

To sum up, after finishing one more time, you can get a perfect solution.

For more readers interested in C # related content, please check the topics on this site: "WinForm Control Usage Summary", "C # Form Operation Skills Summary", "C # Data Structure and Algorithm Tutorial", "C # Common Control Usage Tutorial", "C # Object-Oriented Programming Introduction Tutorial" and "C # Programming Thread Use Skills Summary"

I hope this article is helpful to everyone's C # programming.


Related articles: