公司开发的软件需要对串口进行操作每次打开软件后程序自动去打开串口寻找连接到串口上的设备但是如果用户不知道打开了两次那么第二次打开的程序是不能正常使用的因为对串口的操作时独占的第一个程序独占了串口的使用权其他程序无法再使用那一个串口当然如果PC机器上有两个串口那第二个程序也是可以用的为了解决这个问题必须限制对串口操作的软件只能打开一个打开软件后用户如果误操作再次想打开该软件需要提示用户软件已经打开并让已打开的软件显示在窗口最顶层
下面是Delphi版的解决方法
(方法一)
利用互斥对象
开发过多线程软件的可能都使用过互斥对象它常被用做线程间同步的技术手段简要的提一下互斥对象互斥对象把第一次建立它的程序作为主程序这样只用检测互斥对象是否已经有主程序就判断程序是否已经运行过这里需要涉及到一个api函数WaitForSingleObject该函数的第一个参数为用以检测的互斥对象第个参数的表示函数返回结果前的滞留时间如果改函数返回wait_TimeOut就表明互斥对象已经有了一个主程序
注意以下的代码都出现在工程文件中而不是单元文件中
var
myMutex:HWND;
begin
//CreateMutex建立互斥对象并且给互斥对象起一个唯一的名字
myMutex:=CreateMutex(nilfalsehkOneCopy);
//程序没有被运行过
if WaitForSingleObject(myMutex)<>wait_TimeOut then
begin
ApplicationInitialize;
ApplicationCreateForm(TForm Form);
ApplicationRun;
End;
End;
[注释]
当应用程序第一次运行的时候在应用程序中会建立一个互斥对象名称为hkOneCopy然后判断系统中有没有这个互斥对象如果没有则初始化应用程序
下面再完善一下这个程序
我们不希望程序被多次运行而是希望如果程序运行过后再运行这个程序的时候将已运行的程序做出一些响应比如说让它变为最上层的活动窗口来提示用户该程序正在运行为达到这个目的必须要获得正在运行程序的句柄然后用一个APISetForeGroundWindow(handle)来使程序的窗口最前并激活为了得到程序的句柄要使用windows枚举函数EnumWindows来遍历windows窗口列表该函数需要一个回调函数作参数用这个回调函数来对每一个系统中的窗口进行调用直到最后一个窗口或回调函数返回false为止[注关于EnumWindows函数的介绍在篇尾]只要编写这个回调函数并在其中不断的比较当前遍历到的窗口类名和我们的程序的主窗口类名以及比较窗口可执行文件的名称和我们程序的名称直到找到相同的为止将这时的窗口句柄保存下来就行了为获得窗口的类名和句柄需要一个APIGetClassName为获得可执行文件的名称需要APIGetModuleFileName
下面是详细代码
注意下面代码在delphi下运行通过但是如果窗口最小化后再次运行程序时原先已经运行的程序能够被置前并激活但是标题栏的最小化按钮却不能用了当尝试了N中方法后估计是delphi自身TForm类的问题下面给出一个解决方案在窗口上放一个ApplicationEvents控件它管理着应用程序所有的消息我们在它的OnMessage事件里写上下面的代码
if Msghwnd=FormHandle then
begin
// 是在标题栏按下鼠标
// 是在标题栏的最小化按钮上按下鼠标
if (Msgmessage= ) and (msgwParam= ) then
begin
FormWindowState:= wsMinimized;
end;
end;
[] [] []