单实例程序
单实例运行程序其实很常见,比如微信,QQ。这些程序重复打开是无效的,这种程序我们就称之为单实例程序。
单实例程序与单例模式区别
单例模式是以一个程序(进程)作为系统,在这个系统里的某个单例类只能有一个实例。而单实例程序的系统是整个操作系统,也就是在这个系统里只有一个实例。它们的实现方式不同,单例模式可以使用语言特性防止其创建实例。而单实例程序的实现可以有很多种方式,我们在本篇文章只介绍其中一种。
进程互斥锁
这种方式就是利用Win32API提供的CreateMutex
函数创建进程间的互斥锁,创建了进程互斥体,如果打开了第二个程序,检测到同样的互斥体对象名,则创建不成功。
CreateMutex
CreateMutex
的声明如下:
WINBASEAPI HANDLE WINAPI CreateMutexW (
LPSECURITY_ATTRIBUTES lpMutexAttributes,
WINBOOL bInitialOwner,
LPCWSTR lpName
);
参数:
-
lpMutexAttributes:指向
struct SECURITY_ATTRIBUTES
的指针。 如果此参数为 NULL,则子进程无法继承句柄。 -
bInitialOwner:如果此值为 TRUE ,并且调用方创建了互斥体,则调用线程获取互斥体对象的初始所有权。 否则,调用线程不会获取互斥体的所有权。
-
lpName:互斥体对象的名称。
返回值:
- 如果函数成功,则返回值是新创建的互斥体对象的句柄。
- 如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。如果互斥体是命名互斥体,并且此函数调用之前存在对象,则返回值是现有对象的句柄, 并且 GetLastError 函数返回 ERROR_ALREADY_EXISTS。
函数实现
bool isProgramRunning(){
HANDLE hMutex = nullptr;
hMutex = CreateMutexW(nullptr, false, L"MutexObjName");
if (hMutex){
if (ERROR_ALREADY_EXISTS == ::GetLastError()){
MessageBoxW(nullptr, L"Failed to start the program. An instance of this program is already running.", L"Error", MB_OK|MB_ICONSTOP);
CloseHandle(hMutex);
return true;
}
}
return false;
}
代码实战
#define UNICODE
#include <iostream>
#include <Windows.h>
using namespace std;
BOOL isProgramRunning() {
HANDLE hMutex = NULL;
hMutex = ::CreateMutexW(NULL, FALSE, L"WinApp");
if (hMutex) {
if (ERROR_ALREADY_EXISTS == ::GetLastError()) {
MessageBoxW(nullptr, L"Failed to start the program. An instance of this program is already running.", L"Error", MB_OK | MB_ICONSTOP);
CloseHandle(hMutex);
return TRUE;
}
}
return FALSE;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR pCmdLine, int nCmdShow) {
if (isProgramRunning()) {
return -1;
}
const wchar_t* CLASS_NAME = L"Window Class";
WNDCLASSW wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowExW(
0, CLASS_NAME, L"Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL
);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
效果:
windows c++程序单实例演示 - 进程互斥