1. If none of the processes with the same name has been created yet, the process continues to perform its tasks;
2. If there exists a process with the same name, the process activates it, bring it to the top level of screen and exits, especially when the type of the process is winform.
To meet the first requirement, the mutex or the semaphore can be used in VC, and Process.GetProcessesByName( ) method can be used in C#. It isn't the focus of this article. How to meet the second requirement is discussed here.
The following way is recommended on many websites:
/* VC example */
if(hWnd) /* assuming that hwnd is the handle of the program window */
{
HWND hForeWnd = ::GetForegroundWindow();
DWORD dwForeID = ::GetWindowThreadProcessId(hForeWnd,NULL);
DWORD dwCurID = ::GetCurrentThreadId();
::AttachThreadInput(dwCurID,dwForeID,TRUE);
::ShowWindow(hWnd,SW_SHOWNORMAL);
::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0, SWP_NOSIZE|SWP_NOMOVE);
::SetForegroundWindow(hWnd);
::AttachThreadInput(dwCurID,dwForeID,FALSE);
}
The operating system in my computer is Win7-64bits. I tried to use such codes in my program. It was surprising that it worked only when the EXE file was run in the debug or release folder of Visual Studio 2010, in the search box of the Start menu, and in the Run command dialog (invoked by pressing Win+R). After I copied the EXE file to another folder of the same disk or to a USB disk, I found this method didn't work. Even if I double clicked the icon of the program, the new process exited directly. It couldn't bring the process already running in the background to the foreground and activate the program window. I had been puzzled for weeks before one of my friends suggested that a program window be restored by receiving restore message. He told me the following solution in VC:
1. find the program window handle by its title;
2. send restore message to that program window;
3. bring that program window to the foreground of the screen.
I tried the solution and found it did work. The code snippet is as follows:
/* VC example: check if this program has been started */
BOOL CMyApp::InitInstance()
{
TCHAR MutexObjectName[MAX_PATH] = {_T("MutexObjectNameInMyExampleProgram")};
ghMutex = CreateMutex(NULL, FALSE, MutexObjectName);
if (!ghMutex)
{
MessageBox(NULL, _T("Creating mutex object failed!"), _T("Example program"), MB_ICONERROR);
return FALSE;
}
if ( GetLastError() == ERROR_ALREADY_EXISTS )
{
HWND hPrgWnd = FindWindow(NULL, ProgramWindowTitle); /* ProgramWindowTitle is the window title of the winform program */
if (!hPrgWnd)
{
MessageBox(NULL, _T("Finding window failed!"), ProgramTitle, MB_ICONERROR);
return FALSE;
}
SendMessage(hPrgWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
SetForegroundWindow(hPrgWnd);
}
return FALSE;
}
I transplanted the codes to C#. The code snippet is as follows:
/**************************************************
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: May 26th, 2016
* Description: demonstrate how to check if the process
of the winform program has been started in C#
* File name: Program.cs
**************************************************/
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace MyExampleProgram
{
static class Program
{
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string ClassName, string WindowName);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hWnd);
const uint WM_SYSCOMMAND = 0x112;
const uint SC_RESTORE = 0xf120;
[STAThread]
static void Main()
{
const string strPrgName = "MyExampleProgramName"; /* This variable denotes the
executable file name. Note the EXE sufix is not needed */
const string strProgramWindowTitle = "MyExampleProgramWindowTitle"; /* This
variable denotes the window title of the winform program. */
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Process[] processes = Process.GetProcessesByName(strPrgName);
if (processes.Length > 1) /* There exists a process with the same program name. */
{
IntPtr hPrgWnd = FindWindow(null, strProgramWindowTitle);
if (hPrgWnd == null)
{
return;
}
SendMessage(hPrgWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
if (SetForegroundWindow(hPrgWnd) == 0)
{
return;
}
return;
}
else
{
Application.Run(new Form1()); /* Form1 is the main form of the program.
Operation is performed by user in Form1. */
}
}
}
}