让程序只运行一次该程序即同一时刻在内存里面运行的只有一个实例有时是必要的,有些程序运行多个实例毫无意义,比如字典程序(金山词霸)。本文介绍不同语言实现Windows程序运行单个实例的一些方法。
c/c++
Windows程序的4个入口函数:main,wmain, WinMain,wWinMain,在入口函数出判断程序时候有实例(进程)在运行,这里要用到进程间共享的内核对象:信号量(Mutex),相关信息会写到注册表。示例代码如下:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, int nCmdShow)
- {
- ::SetLastError(NO_ERROR); //保证GetLastError返回值不受干扰
- ::CreateMutex(NULL, false, "NutexName");
- if (::GetLastError() == ERROR_ALREADY_EXISTS)
- {
- //return;.....程序已经有实例在运行
- }
- //程序第一次运行,继续执行
- }
说明:CreateMutex是Windows提供的系统API,当程序的一个实例创建后如果有另外程序再创建就会失败,设置错误码为
ERROR_ALREADY_EXISTS,因此可用另一个API函数GetLastError查看时候返回该错误码,确定程序时候已经有实例在运行。
c#
在C#中可以通过查看指定名字进程的数量来判断程序实例的个数,实例代码如下:
- string processName = System.Diagnostics.Process.GetCurrentProce().ProcessName;
- System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(processName );
- if(processes.Length > 1)
- {
- //return;.....程序已经有实例在运行
- }
- //程序第一次运行,继续执行
java
c/c++Java与c#实现单实例程序都利用了Windows平台本身的特性,但Java的平台无关性使得它很难利用这些东西。借鉴信号量的思想,在Java程序中找到类似于信号量的替代品。
方式一,利用文件。在程序运行时检查是否有一个特定的文件存在,如果不存在创建该文件,表明程序已经在运行,在程序退出后即删除该文件,类似于信号量对象的释放。该程序的另一个实例如果运行,检查到该文件已经存在,表明已有实例在运行,则退出。该方法的缺陷在于:程序因异常退出时可能没能删除标识文件,导致程序以后不能运行。
方式二,鉴于文件在程序退出可能不被删除,可以占用端口号来替代信号量,当程序启动时检查该端口号是否被占用,如果没有就建立该端口好的连接,在程序退出后释放端口号。当检查到端口号已经被占用时表明有实例在运行,执行退出。该方法的缺陷是端口号可能被其他程序占用,导致判断失误而不能启动程序。因此在选端口号时应尽量避免冲突。
由于Java难有进程间共享变量可用,以上方法都有缺陷,为减低出错率,可将两种方法共用,即只有文件存在并且端口号被占用是才判定为有实例在运行,这样可以大大减少误判的可能。