很多情况下,程序会要求同一时间内只能运行一个实例,以免发生系统崩溃、数据遭破坏等后果。最常用被使用的是创建一个有名字的Mutex(互斥)的方法。程序的实例或对象含有Mutex之后,同一时间内将只能被一个线程访问。
Windows给我们提供了CreateMutex函数来创建Mutex。原型如下:
HANDLE WINAPI CreateMutex( __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes, __in BOOL bInitialOwner,//Mutex的所有者的句柄。 __in_opt LPCTSTR lpName//Mutex对象的名称。 );
我们为互斥体起一个名字,作为CreateMutex的第三个参数。那么程序运行时,将使用CreateMutex创建一个互斥体,再次运行将再创建一个同名的互斥体从而引发错误信息,此时GetLastError函数将返回ERROR_ALREADY_EXISTS错误信息。
利用这一点,我们可以达到只让程序运行一个实例的目的。代码如下。
1 #include <windows.h> 2 #include <tchar.h> 3 int _stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCMD) 4 { 5 CreateMutex(NULL,FALSE,_T("Mutex")); 6 if(GetLastError()==ERROR_ALREADY_EXISTS) 7 return FALSE; 8 MessageBox(NULL,_T("Program Success !"),_T("Mutex"),MB_OK); 9 return 0; 10 }
但这样并不完善。当用户想要运行该程序时,如果已经有实例正在运行,最好能激活运行中实例的窗口,如果该窗口处于最小化则将其弹出。
1 BOOL MyMUTEX() 2 { 3 //1、创建Mutex 4 HANDLE hMutex=CreateMutex(NULL,TRUE,_T("Mutex")); 5 if (hMutex == NULL) 6 { 7 return FALSE; 8 } 9 //2、如果Mutex已经存在并且正在运行 10 if (GetLastError() == ERROR_ALREADY_EXISTS) 11 { 12 //3、获取窗口名称 13 HWND hProgramWnd =FindWindow(NULL,_T("WindowsName")); 14 if (hProgramWnd) 15 { 16 WINDOWPLACEMENT* pWndpl = NULL; 17 WINDOWPLACEMENT wpm; 18 19 GetWindowPlacement(hProgramWnd,&wpm); 20 pWndpl =&wpm; 21 if (pWndpl) 22 { 23 //4、将运行的程序窗口还原成正常状态 24 pWndpl->showCmd = SW_SHOWNORMAL; 25 SetWindowPlacement(hProgramWnd,pWndpl); 26 SetWindowPos(hProgramWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); 27 //激活窗口 28 SetForegroundWindow(hProgramWnd); 29 } 30 } 31 //6、关闭进程互斥体 32 CloseHandle(hMutex); 33 hMutex = NULL; 34 return FALSE; 35 } 36 return TRUE; 37 }
也可以使用下面这种更为简短的代码。但不知为什么,在我的电脑上运行时,感觉上面这段代码比下面代码的运行速度要快很多。
1 BOOL MyMUTEX() 2 { 3 HANDLE hMutex=CreateMutex(NULL,TRUE,_T("Mutex")); 4 if (hMutex == NULL) 5 { 6 return FALSE; 7 } 8 if (GetLastError() == ERROR_ALREADY_EXISTS) 9 { 10 HWND hProgramWnd =FindWindow(NULL,_T("WindowsName")); 11 ShowWindow(hProgramWnd,SW_RESTORE); 12 SetForegroundWindow(hProgramWnd); 13 14 CloseHandle(hMutex); 15 hMutex = NULL; 16 return FALSE; 17 } 18 return TRUE; 19 }