限制程序只打开一个实例(转载)
但是,问题就出在如何判别是否有一个与自己相同的进程开着上面。我在网上搜索了一下相关的文章,发现对于这个问题的解决不外乎以下几种方式:
1、在进程初始化时使用::CreateMutex创建一个互斥对象,通过检测互斥对象是否已存在来确定该程序是否已经运行。
该方式的确可以很容易的实现判别程序实例是否已存在,只需要在InitInstance方法开头添加以下语句:
m_hUnique = ::CreateMutex(NULL, FALSE, UNIQUE_ID);
if (GetLastError() == ERROR_ALREADY_EXISTS) return FALSE;
UNIQUE_ID为具有唯一性的字符串,一般可以用VC++为主程序头文件自动生成的包含标识宏(就是.h文件顶上的那一长串宏定义),当然,也可以用工具自己手动生成,随君所好了^^。要注意的是别忘了在ExitInstance方法中用 CloseHandle(m_hUnique) 将该互斥对象关闭。但这种方式存在一个很大的问题,就是很难获取已打开程序实例的主窗口句柄。而我们绝大多数时候,都需要将那个程序实例的主窗口激活。为了获取主窗口句柄,就需要再用到后面提到的其他方法。
2、遍历所有已经打开的进程主窗口,比较窗口标题,如果找到满足条件的标题,则表示程序已经运行,并激活该窗口。
这种方式虽然可以找到程序的主窗口,但问题明显:A.如果窗口标题经常变化怎么办(比如标题中会带有打开文档的文件名)?B.如果其他程序的主窗口标题恰好与该程序的相同怎么办?
第一个问题可以通过写注册表或者写INI文件的方式来解决。即当主窗口标题改变时,将新标题写入注册表或者INI文件。不过这种解决方式也忒麻烦了吧-_-|| 第二个问题就麻烦了,至少我还没有找到好的解决方案。如果非要说一个,那我提议你“想尽办法”“不择手段”的将窗口标题设的和别的程序绝对不同。不过估计搞定了这步,你半条命也快没了。
3、用::SetProp给主窗口添加一个具有唯一性的属性值,以便在进程初始化的时候可以通过遍历所有窗口的该属性来判断。
添加属性值的代码一般可以放在InitInstance方法的最后,如下:
::SetProp(m_pMainWnd->m_hWnd, "UNIQUE_ID", (HANDLE)UNIQUE_ID);
UNIQUE_ID是一个具有唯一性的整数值(为什么不能用字符串?因为字符串的比较需要将字符串读取出来,而这儿只能记录字符串地址,在别的程序里这个地址无意义,所以无法读出这个字符串)。这种方式仅有的问题就出在如何确定该整数值是具有唯一性的。我们后面提出的解决方法,就是在这种方法的基础上发展出来的。
在总结了上述几种方式的利弊之后,我发现,只需要为程序建立一个具有唯一性的整数值,一方面可以通过这个值是否存在来判断程序是否已经运行(::CreateMutex其实也是类似的概念),另一方面可以通过将这个值赋给主窗口,以便能够找到已打开的程序实例的主窗口句柄。于是,ATOM量便派上用场了(ATOM变量类型等同于WORD,因而是一个整数值)。
ATOM量本质上就是散列表的键标识符,其对应键值为一个字符串。每个程序都有自己的ATOM量表,同时Windows也有一个全局的ATOM表。我们要用的方法就是,为程序创建一个全局的ATOM量,通过这个量是否存在来判断程序是否已经运行,并通过将这个量作为属性值添加到主窗口来标识这个主窗口。具体过程如下:
1、给主程序App类添加一个ATOM类型的成员变量:m_aAppId,作为程序ID。
2、在InitInstance方法开头添加以下代码(UNIQUE_ID是具有唯一性的字符串宏):
m_aAppId = ::GlobalFindAtom(UNIQUE_ID); //查找程序ID是否存在
if (m_aAppId) //程序ID存在,激活已打开的程序实例的主窗口
{
HWND hWnd = ::GetWindow(::GetForegroundWindow(), GW_HWNDFIRST);
for (; hWnd; hWnd = ::GetWindow(hWnd, GW_HWNDNEXT))
{
if ((ATOM)::GetProp(hWnd, "APP_ID") == m_aAppId)
{
if (::IsIconic(hWnd)) ::ShowWindow(hWnd, SW_RESTORE); //还原最小化的窗口
::SetForegroundWindow(hWnd); //激活窗口
m_aAppId = 0; //赋值0是为了防止ExitInstance中将找到的ATOM量删除
break;
}
}
return FALSE;
}
else //程序ID不存在,创建程序ID
{
m_aAppId = ::GlobalAddAtom(APP_ID);
}
3、在InitInstance方法最后为主窗口添加标识属性:
::SetProp(m_pMainWnd->m_hWnd, "APP_ID", (HANDLE)m_aAppId);
4、在ExitInstance方法中添加下面代码以删除程序ID:
if (m_aAppId) ::GlobalDeleteAtom(m_aAppId);
心得:该方法所用到的ATOM量是一个应用广泛的技术,如::CreateMutex、::SetProp等API函数都间接用到了ATOM量。利用它,我们可以做很多需要用到唯一性验证的事情。
转载于:https://www.cnblogs.com/flying_bat/archive/2007/07/14/818052.html
相关文章:

dao.xml
<select id"selectItemkindByPolicyNo" resultMap"BaseResultMap" parameterType"java.util.List"> select * from prpcitemkind kind where kind.PolicyNo in <foreach collection"list" item"item&q…

(C++)字符数组初始化的两种方法
#include<cstdio> //字符数组的两种赋值方法 int main(){//1.方法一char str1[14] {I, ,l,o,v,e, ,m,y, ,m,o,m,.};for(int i 0;i<13;i){printf("%c",str1[i]);}printf("\n");//2.方法二,直接赋值字符串(注意,只有初始化…

SQL Server 中update的小计
update中涉及到多个表的: 1.update TableA set a.ColumnCb.ColumnC from TableA a inner join TableB b on a.ColumnDb.ColumnD 这样是不对的,报错如下: 消息 4104,无法绑定由多个部分组成的标识符 “xxxx” 虽然前面的TableA和后…

MFC中的字符串转换
在VC中有着一大把字符串类型。从传统的char*到std::string到CString,简直是多如牛毛。期间的转换相信也是绕晕了许多的人,我曾就是其中的一个。还好,MS还没有丧失功德心,msdn的一篇文章详细的解析了各种字符串的转换问题ÿ…

tf.nn.relu
tf.nn.relu(features, name None) 这个函数的作用是计算激活函数 relu,即 max(features, 0)。即将矩阵中每行的非最大值置0。 import tensorflow as tfa tf.constant([-1.0, 2.0]) with tf.Session() as sess:b tf.nn.relu(a)print sess.run(b) 以上程序输出的结…

(C++)字符数组的四种输入输出方式
scanf/printf%s getchar()/putchar() 前者不带参数后者带 gets()/puts() 二者都带参数,为一维字符数组或二维字符数组的一维 运用指针scanf/printf或getchar/putchar #include<cstdio> //字符数组的3种输入输出方式int main(){//1.scanf/printf%schar st…

css制作对话框
当你发现好多图都能用css画出来的时候,你就会觉得css很有魅力了。//我是这么觉得的,先不考虑什么兼容问题 像漫画里出现的对话框,往往都是一个对话框然后就加入一个箭头指向说话的那一方,来表示这个内容是谁述说的。 今天认真学了…

Git相关二三事(git reflog 和彩色branch)【转】
转自:https://www.jianshu.com/p/3622ed542c3b 背景 git太常用了,虽然,用起来不难,但也有很多小技巧的东西... 1. 后悔药 哪天不小心,写完代码,没commit,直接reset了或者checkout了,怎么办&…

MS SQL入门基础:备份和恢复系统数据库
系统数据库保存了有关SQL Server 的许多重要数据信息,这些数据的丢失将给系统带来极为严重的后果,所以我们也必须对系统数据库进行备份。这样一旦系统或数据库失败,则可以通过恢复来重建系统数据库。在SQL Server 中重要的系统数据库主要有ma…

(C++)输入输出字符矩阵(二维字符数组)的三种方法
想输出一个这样的字符矩阵 CSU ZJU PKUscanf和printf #include<cstdio> #include<cmath>int main(){char schools[3][3];printf("请输入:\n");for(int i0;i<2;i){scanf("%s",schools[i]);}printf("以下为输出:…

C# async await 学习笔记2
C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程是无法直接更新UI线程上的控件的问题。 于是做了如下测试: using System; using System…

不走寻常路 设计ASP.NET应用程序的七大绝招
随着微软.NET的流行,ASP.NET越来越为广大开发人员所接受。作为ASP.NET的开发人员,我们不仅需要掌握其基本的原理,更要多多实践,从实践中获取真正的开发本领。在我们的实际开发中,往往基本的原理满足不了开发需求&#…

记录Linux下的钓鱼提权思路
参考Freebuf上的提权文章(利用通配符进行Linux本地提权):http://www.freebuf.com/articles/system/176255.html 以两个例子的形式进行记录,作为备忘: 0x01 Chown的--reference特性 存在三个用户:root、yuns…

(C++)strlen(),strcmp(),strcpy(),strcat()用法
string.h中包含了许多用于字符数组的函数。使用前需要在程序开头加string.h©或cstring(C)头文件 strlen() 作用:得到字符数组第一个结束符\0前的字符的个数 #include<cstdio> #include<cstring>int main(){char str[50];gets(str);printf("…

springMvc+mybatis+spring 整合 包涵整合activiti 基于maven
2019独角兽企业重金招聘Python工程师标准>>> 最近自己独立弄一个activiti项目,写一下整合过程: 环境:jdk1.7 tomcat7.0 maven3.5 eclipse mysql5.5 --我的工程结构,怎么创建一个maven项目就不在这里写了: …

(原)Eclipse 字体过小问题
刚解压/安装的eclipse(或者myeclipse,sts等因为默认使用Consolas字体的原因,中文字会显得非常小 解决办法搜索网络无非两种:1.不想太麻烦去下字体的话,就将eclipse的字体改为Courier New,方法如下:A.进入eclipse配置,找到编辑字体的地方: window->perferences->General-&…

一个饼形图形报表
最近在做一个统计投票数量的图形报表,主要借鉴了一个51aspx中的一个例子,因为要在一页中显示多个图形,所以选择了在pannel中动态添加Image控件.效果图如下:/// <summary>/// 饼形图形报表/// </summary>/// <param name"target">Stream对象的实例&…

(C++)从字符串中取出整形、浮点型和字符串
目的:从字符串"330:20.20:yoyo"中取出整数330,浮点数20.20和字符串"yoyo" #include<cstdio> #include<cstring>int main(){char str[50]"330:20.20:yoyo";int n;double g;char sstr[40];sscanf(str,"%d…

[C#]网络编程系列专题二:HTTP协议详解
转自:http://www.cnblogs.com/zhili/archive/2012/08/18/2634475.html 我们在用Asp.net技术开发Web应用程序后,当用户在浏览器输入一个网址时就是再向服务器发送一个HTTP请求,此时就使用了应用层的HTTP协议,在上一个专题我们简单介…

Python3 与 C# 并发编程之~ Net篇
NetCore并发编程 示例代码:https://github.com/lotapp/BaseCode/tree/master/netcore/4_Concurrency 先简单说下概念(其实之前也有说,所以简说下): 并发:同时做多件事情多线程:并发的一种形式并…

tomcat5.5.9+sql2000数据库连接池配置
终于解决了困扰多天的连接池的问题,写下这编文章与大家一起分享。我是在tomcat5.5.9下配置的,tomcat5.5.X和以前的版本有一些差别,所以配置上也有差别。我就说一下在tomcat5.5.9配置的基本步骤:(确定你以安装好tomcat5…

(C++)第一个字母变成第26个字母,第i个字母变成第(26-i+1)个字母,非字母字符不变。要求根据密码译回原文,并输出。
题目描述 有一行电文,已按如下规律译成密码: A–>Z a–>z B–>Y b–>y C–>X c–>x … … 即第一个字母变成第26个字母,第i个字母变成第(26-i1)个字母,非字母字符不变。要求根据密码译回原文&a…

mysql++读写BLOB数据
mysql读写BLOB数据 1、使用sql_create_n宏函数,建立数据库表字段与对象。 #define sql_create_2(NAME, CMP, CONTR, T1, I1, T2, I2) \ sql_create_complete_2(NAME, CMP, CONTR, T1, I1, #I1, T2, I2, #I2) \ //NAME:表名࿱…

oracle RAC的VIP和scan
我们都知道Oracle RAC中每个节点都有一个虚拟IP,简称VIP,与公网IP在同一个网段。 没有VIP时,Oracle客户端是靠“TCP/IP协议栈超时”来判断服务器故障。而TCP/IP协议栈是作为OS Kernel的一部分来实现,不同的OS有不同的阀值…

2007年你必须学习的10项.NET技术
1、WCF (Windows Communication Foundation):虽然WCF显然没有WPF或SilverLight那么吸引人,但是它却是在.NET框架下解决业务问题的基础。所以你今年至少要学习一门.NET的新技术,那你就选择WCF吧。 2、ADO.NET (and LINQ):这是让你与数据层打交道的技术。并且LINQ提供了将各种数据…

(C++)用指针实现两数交换函数swap()的两种方法
#include<cstdio>//用指针写swap()函数 void swap_1(int* p1,int* p2){int temp *p1;*p1 *p2;*p2 temp; } //用指针和指针的引用写swap()函数 void swap_2(int* &p1,int* &p2){int* temp p1;p1 p2;p2 temp; } int main(){int a 2020,b2021;int *p1&a,…

【转】《iOS7 by Tutorials》系列:iOS7的设计精髓(上)
简介: 本文翻译自《iOS7 by Tutorials》一书的第一章“Designing for iOS 7”,主要从程序员角度介绍了iOS7的新设计理念,堪称神作!本文翻译仅作学习交流之用,版权归原作者所有,有删减。非专业翻译人士粗糙之…

有兴趣的执行一下这段代码
有兴趣的执行一下这段代码:staticpublicstringGetConfigiuageConnString() { Guid dataLinksGuid new Guid("2206cdb2-19c1-11d1-89e0-00c04fd7a829"); Type dataLinksType Type.GetTypeFromCLSID(dataLinksGuid, true); …

python爬虫知识点总结(二十三)Scrapy中Download Middleware的用法
待更新转载于:https://www.cnblogs.com/cthon/p/9424551.html

(C++)输入3个字符串,按从小到大的顺序输出。
#include<cstdio> #include<cstring> //1.利用指针编写两个字符串的比较函数 //2.利用二位字符数组接收3个字符串 //3.输出排序后的字符串 void s_to_b(char str1[10],char str2[10]){char temp[10];strcpy(temp,str1);strcpy(str1,str2);strcpy(str2,temp); }void…