Windows下运行单一实例

4 篇文章 0 订阅

运行单一实例

确保运行一个进程实例的实现方法有很多,它可以通过扫描进程列表来实现,可以通过枚举程序窗口的方式来实现,也可以通过共享全局变量来实现。下面介绍一种使用广泛而且简单的方法,即通过创建系统命名互斥对象的方式来实现。

编码实现

新建控制台新项目,添加一个 .cpp 文件,添加如下代码:

#include <windows.h>
#include <iostream>

BOOL IsAlreadyRun()
{
	HANDLE hMutex = NULL;
	hMutex = ::CreateMutex(NULL, FALSE, L"ALREADYRUN_TEST");
	if (hMutex)
	{
		if (ERROR_ALREADY_EXISTS == ::GetLastError())
		{
			return TRUE;
		}
	}
	return FALSE;
}

int main()
{
	if (IsAlreadyRun())
	{
		std::cout << "Already run..." << std::endl;
	}
	else
	{
		std::cout << "Not already run..." << std::endl;
	}

	system("pause");
	return 0;
}

函数介绍

CreateMutex 函数
作用:创建或打开一个已命名或为命名的互斥对象。
函数声明

HANDLE WINAPI CreateMutex(
	_In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
  _In_  BOOL         bInitialOwner,
  _In_opt_LPCTSTR        lpName
);

参数:
lpMutexAttributes [om,optional] - 指向SECURITY_ATTRIBUTES结构的指针。如果此参数为NULL,则该句柄不能由子进程继承。
bInitialOwner [in] - 如果此值为TRUE并且调用者创建了互斥锁,则调用线程将获得互斥对象的初始所有权。否则,调用线程不会获得互斥锁的所有权。
lpName [in,optional] - 互斥对象的名称。该名称仅限于MAX_PATH字符,名称区分大小写。如果lpName为NULL,则会创建不带名称的互斥对象。
如果lpName与现有事件、信号量、等待定时器、作业或文件映射对象的名称匹配,且这些对象共享相同的名称空间,则该函数将失败,并且GetLastError函数返回ERROR_INVALID_HANDLE。

** 返回值**:
如果函数成功,则返回值是新创建的互斥对象的句柄。
如果函数失败,则返回值为NULL。要获得扩展的错误信息,请调用GetLastError。
如果互斥锁是一个已命名的互斥锁,并且该对象在此函数调用之前就存在,则返回值是现有对象的句柄,GetLastError返回ERROR_ALREADY_EXISTS。

实现原理

通常情况下,系统中的进程是相互独立的,每个进程都拥有自己的独立资源和地址空间,进程间互不影响。所以,同一个程序可以重复运行,但系统上的进程互不影响。但是,在一些特殊情况下,程序在系统上需要只保存一份进程实例,这就引出了进程互斥的问题。
微软提供了CreateMutex函数来创建或者打开一个已命名或未命名的互斥对象,程序在每次运行的时候,通过判断系统中是否存在相同命名的互斥对象来确定程序是否重复运行。
CreateMutex函数一共有3个参数,第一个参数表示互斥对象的安全设置,是一个指向SECURITY_ATTRIBUTES结构的指针,在该程序中直接设置为NULL即可。第二个参数表示线程是否获得互斥锁对象的初始所有权,在该程序中,无论该参数为TRUE还是FALSE,均不影响程序的正常运行。第三个参数表示互斥对象的名称,对于通过互斥对象来判断进程实例是否重复运行的程序来说,该参数一定要设置,而且要保证设置名称的唯一性。
程序的判断原理是通过CreateMutex函数创建一个命名的互斥对象,如果对象创建成功,而且通过调用GetLastError函数获取的返回码为ERROR_ALREADY_EXISTS,则表示该命名互斥对象存在,即程序重复运行。否则,认为程序是首次运行。

测试

直接运行上面的程序。第一次运行的时候,程序提示“Not already run…”,意思是系统中没有运行该实例。继续双击执行程序,这次程序提示“Already run…”,如下图所示,意思是系统上已经存在该实例且正在运行。所以,程序成功地判断出程序是否重复运行。
在这里插入图片描述

注意

在调用CreateMutex函数来创建命名的互斥对象时,注意互斥对象的名称不要与现有事件、信号量或者文件映射对象等名称相同,否则创建互斥对象会失败。
在实现过程中,特别要注意,程序一定不要调用CloseHandle函数来关闭由CreateMutex函数创建出来的互斥对象的句柄,否则会导致互斥对象判断失败。因为CloseHandle函数会关闭互斥对象的句柄,释放资源。这样,系统上便不会存在对应的命名互斥对象了,通过CreateMutex创建的命名互斥对象都是不会重复的。

提示

使用CreateMutex函数创建的互斥对象,可以通过调用CloseHandle函数来关闭互斥对象的句柄,从属于它的所有句柄都关闭后,就会删除该对象。
在线程同步操作中,ReleaseMutex函数可以释放线程对互斥对象的控制权。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Windows编程实例可以包括设置窗口的可视状态、以管理员权限运行程序以及获取窗口指针、句柄和ID的相关转换。 一个示例是使用MFC编写的程序,通过调用ShowWindow函数设置窗口的可视状态。在每个应用程序中,只应该调用一次ShowWindow函数来设置主窗口的可视状态,并且以后的调用应该使用预定义的值来代替CWinApp::m_nCmdShow指定的值。\[1\] 另一个示例是使用ShellExecuteEx函数以管理员权限运行程序。通过设置SHELLEXECUTEINFO结构体的相关参数,可以指定要运行的程序的路径和参数,并且设置nShow参数为SW_HIDE以隐藏窗口。如果启动失败,可以显示一个消息框提示。\[2\] 还有一个示例是获取窗口指针、句柄和ID之间的转换。可以使用AfxGetApp()->GetMainWnd()函数获取主窗口的指针,使用GetSafeHwnd()函数获取窗口的句柄。另外,可以使用GetDlgItem函数通过窗口句柄和ID获取控件的句柄,使用CWnd::FromHandle函数将句柄转换为指针。同样地,可以使用GetWindowLong函数通过窗口句柄获取控件的ID,使用GetWindowLong函数通过句柄获取控件的ID。\[3\] 这些是Windows编程的一些实例,可以根据具体需求进行调整和扩展。 #### 引用[.reference_title] - *1* *2* *3* [windows常用案例收集](https://blog.csdn.net/watson_pillow/article/details/122562151)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值