您的位置:首页 > 其它

如何判断程序是否重复运行的几种方法

2014-08-27 13:51 435 查看
如何判断程序是否重复运行的几种方法

判断程序的实例是否已经启动,无非是通过设立某个标识,让下次启动程序时知道该实例已经运行。嗯,可是在WIN32中每个进程都有自已独立的空间,那么如何处理呢,下面提供两种方案:

方案一,使用内核对象

因为内核对象是可以跨进程存在的,因此我们可以通过创建一个命名互斥体(Mutex)内核对象来判断,当用同一个名字的来创建Mutex时,CreateMutex会返回一个指向该互斥体的句柄,但是GetLastError会得到ERROR_ALREADY_EXISTS的返值。因此我们就可以判断程序已有一个实例在运行。下面是其中的关键代码

m_hmutex = ::CreateMutex( NULL,FALSE,appID);

if(m_hmutex == NULL)
return FALSE;
//

if( ::GetLastError() == ERROR_ALREADY_EXISTS )
//
{
return FALSE;
}
else
{
return TRUE;
}

方案二,使用共享数据段

背景知识:EXE和DLL文件映像由许多区组成如代码在.text段中,初始化数据在.data段中,未初始化数据在.bss段中。系统在加载EXE和DLL时,实际上是使用了内存映射,为了减少加载时间,同一EXE文件多个实例实际在系统中只有一份。但一般地如果其中某个实例对某个数据区进行写时,系统会使用Copy-On-Write机制将这个数据区在虚拟内存中复制一份出来,并映射到该实例原先的地址空间,也就实现了进程数据的唯一性,而不会干扰其它进程。但是我们可以通过设置让系统关闭掉这个机制。哪么如何做呢?

在Visual Studio中你可以程序中加上以下几行:

#pragmacomment(linker,"/SECTION:Share,RWS") //指示编译器Share是可读写和共享的,当然你也可以通过设置链接器选项直接加上 /SECTION:Share,RWS,不过我更喜欢这个,因此其他朋友就不必自已去设置这个选项了。
#pragmadata_seg("Share") //
开始自已的数据段
int g_AppInit =0; //必需初始化,否则不会将编译器不会将其放入Share这个区
#pragmadata_seg()

还有一种将某个变量置于特别数据段的方式

__declspec(allocate("Share"))
int g_AppInit =0;

这种方式的好处是无论你初不初始化这个变量都将置于该Share段内

哪么如何判断呢是否启动了实例呢,很简单,看以下代码

g_AppInit ++ ;
if(g_AppInit >1)
{
AfxMessageBox("A instance are runed!");
return FALSE;
}

相关的问题:如何通知前一个实例

解决了重复启动的问题,为了获得更佳的用户体验,往往我们要使前一个实例激活,如何做呢?使用消息是一个不错的方法。首先你需要在启动程序时登记一个全局消息。

WM_APPACTIVE = ::RegisterWindowMessage(appID);

相同的appID字符串会给出相同的消息值,并且总是在0xC000- 0xFFFF区间中,然后当你发现已启动程序实例时通知前一个实例:

DWORD dectype = BSM_APPLICATIONS;
//仅向应用程序发送

BroadcastSystemMessage(BSF_POSTMESSAGE,
&dectype,
WM_APPACTIVE,
0,0);

前一个程序实例收到这个消息后,进行处理,可以前置窗口激活等等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: