In C programming the method of setting the program to be run only once

  • 2021-08-28 20:50:36
  • OfStack

There are many ways to prevent a program from running multiple instances, such as using mutex and process name. What I want to achieve is that when the program runs multiple instances, it activates the first instance, so that it can get focus and be displayed in the front end.

Two API functions are mainly used:

ShowWindowAsync This function sets the display state of windows generated by different threads.
SetForegroundWindow 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.
The code is as follows:
Refer to the following namespaces:


using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;
//*****************************************************
 static class Program
  {
    /// <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 ShowWindowAsync(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 WS_SHOWNORMAL = 1;

    /// <summary>
    ///  The main entry point for the application. 
    /// </summary>
    [STAThread]
    static void Main()
    {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Process instance = RunningInstance();
      if (instance == null)
      {
        Form1 frm = new Form1();
        Application.Run(new Form1());
      }
      else
      {
        HandleRunningInstance(instance);
      }

    }
    /// <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)
    {
      ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL); // Display, you can comment out 
      SetForegroundWindow(instance.MainWindowHandle);      // Put it on the front end 
    }
  }

Implementation allows the program to open only 1 instance (other methods)


//===== Create Mutex Method: =====
bool blnIsRunning;
Mutex mutexApp = new Mutex(false, Assembly.GetExecutingAssembly().FullName, out  blnIsRunning);
if (!blnIsRunning)
{
  MessageBox.Show(" The program is already running! ", " Prompt ",
  MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
  return;
}  



// Guarantee that only at the same time 1 Clients are running   
System.Threading.Mutex mutexMyapplication = new System.Threading.Mutex(false, "OnePorcess.exe");
if (!mutexMyapplication.WaitOne(100, false))
{
  MessageBox.Show(" Program " + Application.ProductName + " Already running! ", Application.ProductName,
  MessageBoxButtons.OK, MessageBoxIcon.Error);
  return;
}


//===== Judgment process method: ( It can still be executed after modifying the program name )=====
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach (Process process in processes)
{
  if (process.Id != current.Id)
  {
    if (process.MainModule.FileName
    == current.MainModule.FileName)
    {
      MessageBox.Show(" The program is already running! ", Application.ProductName,
      MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
      return;
    }
  }
}

Realize program self-restart
In the process of running the program, there can be no multiple instances to run, and the program itself can be restarted (rerun), so the code if the following code:


static void Main() 
{ 
  bool createNew; 
  using (System.Threading.Mutex m = new System.Threading.Mutex(true, Application.ProductName, out createNew)) 
  { 
    if (createNew) 
    { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new Form1()); 
    } 
    else 
    { 
      MessageBox.Show("Only one instance of this application is allowed!"); 
    } 
  } 
}
Boolean createdNew; // Returns whether the mutex of the using thread is given initial ownership 
System.Threading.Mutex instance = new System.Threading.Mutex(true, "MutexName", out createdNew); // Synchronization primitive variable 
if (createdNew) // The thread is given initial ownership, that is, the mutex is used for the first time 
{
Application.Run(new Form1()); /s/ This sentence is written automatically by the system 
instance.ReleaseMutex();
}
else
{
MessageBox.Show(" Has been activated 1 A program, please exit first! "," System prompt ",MessageBoxButtons.OK,MessageBoxIcon.Error);
Application.Exit();
}

With the above code, the function of prohibiting multiple startup is realized.
At the same time, the program closes and restarts through the following code:


Process.Start(Process.GetCurrentProcess().ProcessName + ".exe");
Application.Exit();

At this time, there is a problem. When the program is automatically closed and restarted, it will prompt that a program has been started.
How should I solve it?
It is no problem to restart after shutting down for a while.
But now automatic shutdown and automatic restart can sometimes succeed, and sometimes they are intercepted by the one that prohibits multiple startup.
Then you must restart it manually.
For example, when you click the "Restart" button, execute the following code:


Process.Start(Process.GetCurrentProcess().ProcessName + ".exe");
Application.Exit();

At this time, it starts a new Process before exiting the current program.
In Program. cs, you will encounter the code that prohibits multiple startup. It won't start automatically.
Solution:
Solution 1:
1 general procedure:
Because the process has not been aborted and still occupies memory, an error will be reported.
This can occur when multithreading is used, where threads do not finish execution and are not set as background threads, so the process still resides in memory even though the application is closed.
You can use Application. ExitThread (); Aborts all threads in the process.
You can also get the process's ID during process execution, then get the process through Process. GetProcessById (), then drop it Kill, and start a new process.

Solution 2:
Why don't you release mutex first when the user clicks [restart]? You may need to make that mutex variable an global so that you can access it in both places. Then, when the program exits (the sentence below Application. Run), check 1. If mutex has been released, don't release it again.

Solution 3:
Or just set another different semaphore at the point [restart]. When the second program reenters, if you see this semaphore indicating that it is an automatic restart, you will go down normally without reporting an error. This semaphore can be released after the first program [reboot] is executed, but it should also be released when the whole program exits by checking 1 if it exists.


Related articles: