`
isiqi
  • 浏览: 16706426 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

程序只运行一次并激活原来的程序

阅读更多

我们的程序有时候只允许运行一次,并且最好的情况是,如果程序第二次运行,就激活原来的程序。网上有很多的方法实现程序只运行一次,但对于激活原来的窗口却都不怎么好。

关键就在于激活原来的程序,一般的做法是在工程开始时,打开互斥量对象,如果打不开表示程序还没有运行,创建一个互斥量对象;如果打得开表示程序已经运行了,查找程序中一个特定的窗口,一般是主窗口,然后发送一个自定义消息,主窗口在这个消息处理中激活自己。我原来就是这么做的,却发现有很多问题。

主窗口在消息处理函数中激活不了自己,众所周知激活一个窗口最有效的方法当然就是SetForegroundWindow,但在主窗口中调用这个函数激活自己的效果却是只在标题栏闪了一闪,如果在其他进程调用该函数则不会有问题;另外,如果程序是最小化的,它连闪都不闪了。

对于这些问题,我想了下面的办法,在知道原程序已经运行后,用FindWindow找原程序主窗口的句柄,找到了,就发送一个自定义消息过去,而在原程序主窗口的消息处理函数中,只是调用Application.Restore方法,这样如果原程序是最小化的就会还原过来。在发送消息之后,紧接着我调用SetForegroundWindow并传入原程序主窗口的句柄,由于上面的处理,原程序肯定不是最小化了,且调用SetForegroundWindow的地方已经不是原程序了(是第二次运行的程序,也可以说是另一个进程),所以原程序可以很好的被激活。

看来一切都很好,当然不是,不然就不会有下面的代码了,我又发现了一些问题,首先当主窗体不是活动窗口时,比如主窗体被隐藏了,而目前活动的窗体是其他窗体,则上面的代码无效。另一个,如果主窗体前面有一个ShowModal的窗体,则上面的代码后,主窗体跑到ShowModal窗体的前面了。

只有继续探索了,看来问题出在SetForegroundWindow上,激活那个窗体都不好,因为那个窗体都有可能不在,有没有办法激活工程呢,我在Application中找方法,我找到Application.BringToFront,也许这个有点用,于是新建一个工程,加一个Timer控件,然后每隔3秒调用一次Application.BringToFront,运行看结果。可惜窗体仍然只是闪一下,并没有激活,这和我上面说的在自己进程中激活自己的结果一样,可能BringToFront方法里面也调用了SetForegroundWindow了吧,但它激活哪个窗口呢,这让我好奇,打开源码来看,看到了如下有代码:

procedureTApplication.BringToFront;
var
TopWindow:HWnd;
begin
ifHandle<>0then
begin
TopWindow:=GetLastActivePopup(Handle);
if(TopWindow<>0)and(TopWindow<>Handle)and
IsWindowVisible(TopWindow)
andIsWindowEnabled(TopWindow)then
SetForegroundWindow(TopWindow);
end;
end;

原来是用GetLastActivePopup这个API找到程序拥有的窗体中最近激活的窗体,然后再激活它。

哈,我有了一个技术方案,首先我要在第二次运行的程序中找到第一次运行的程序的ApplicationHandle,然后调用SendMessage(APPHandle, WM_SYSCOMMAND, SC_RESTORE, 0)Application类有处理这个消息的,最终它会调用Application.Restore方法,让自己变为显示的状态,即最大化或正常。接着,就执行上面方法中的代码,让第一次运行的程序激活。现在关键是怎么找到第一次运行的ApplicationHandle,自然而然就想到了共享内存的技术,程序第一次运行时,先打开一个内存映射文件,如果打不开,则表示程序第一次运行,建一个内存映射文件对象,开辟一块共享的内存,这块内存保存ApplicationHandle。程序第二次运行,打开内存映射文件,可以打开了,得到一块共享内存,并取得了第一次运行程序的ApplicationHandle,然后,用我上面说的方法,即可大功告成。

花了一个小时的试验,最终有了下面的代码,结果非常成功:

unitwdRunOnce;

{*******************************************
*brief:让程序只运行一次
*autor:linzhenqun
*date:<chsdate w:st="on" year="2005" month="12" day="28" islunardate="False" isrocdate="False">2005-12-28</chsdate>
*email:linzhengqun@163.com
*blog:http://blog.csdn.net/linzhengqun
********************************************}

interface

(*程序是否已经运行,如果运行则激活它*)
functionAppHasRun(AppHandle:THandle):Boolean;


implementation
uses
Windows,Messages;

const
MapFileName=
'{CAF49BBB-AF40-4FDE-8757-51D5AEB5BBBF}';

type
//共享内存
PShareMem=^TShareMem;
TShareMem=
record
AppHandle:THandle;
//保存程序的句柄
end;

var
hMapFile:THandle;
PSMem:PShareMem;

procedureCreateMapFile;
begin
hMapFile:=OpenFileMapping(FILE_MAP_ALL_ACCESS,False,PChar(MapFileName));
ifhMapFile=0then
begin
hMapFile:=CreateFileMapping($FFFFFFFF,
nil,PAGE_READWRITE,0,
SizeOf(TShareMem),MapFileName);
PSMem:=MapViewOfFile(hMapFile,FILE_MAP_WRITE
orFILE_MAP_READ,0,0,0);
ifPSMem=nilthen
begin
CloseHandle(hMapFile);
Exit;
end;
PSMem^.AppHandle:=
0;
end
elsebegin
PSMem:=MapViewOfFile(hMapFile,FILE_MAP_WRITE
orFILE_MAP_READ,0,0,0);
ifPSMem=nilthen
begin
CloseHandle(hMapFile);
end
end;
end;

procedureFreeMapFile;
begin
UnMapViewOfFile(PSMem);
CloseHandle(hMapFile);
end;

functionAppHasRun(AppHandle:THandle):Boolean;
var
TopWindow:HWnd;
begin
Result:=False;
ifPSMem<>nilthen
begin
ifPSMem^.AppHandle<>0then
begin
SendMessage(PSMem^.AppHandle,WM_SYSCOMMAND,SC_RESTORE,
0);
TopWindow:=GetLastActivePopup(PSMem^.AppHandle);
if(TopWindow<>0)and(TopWindow<>PSMem^.AppHandle)and
IsWindowVisible(TopWindow)
andIsWindowEnabled(TopWindow)then
SetForegroundWindow(TopWindow);
Result:=True;
end
else
PSMem^.AppHandle:=AppHandle;
end;
end;

initialization
CreateMapFile;

finalization
FreeMapFile;

end.

你所要做的,就是将这个单元加进你的程序中,然后在你的工程文件中调用AppHasRun,并传入ApplicationHandle,你的程序就可以只运行一次了,工程大概如下:

programProject1;

uses
Forms,
Unit1
in'Unit1.pas'{Form1}
wdRunOnce
in'wdRunOnce.pas',
Unit2
in'Unit2.pas'{Form2}

{$R*.res}

begin
Application.Initialize;
ifnotAppHasRun(Application.Handle)then
Application.CreateForm(TForm1,Form1);
Application.Run;
end.

多新建一些窗口测试一下吧,不过要注意新建的窗口得不能是自动创建的。

目前还没有发现什么问题,如果你发现了什么问题,可以在留言中说明,如果你要完整的Demo程序,当然可以,Email给我就行了,别告诉我你不知道我的Email,到我的Blog的首页去找吧。。

分享到:
评论

相关推荐

    delphi程序只运行一次

    ### Delphi程序只运行一次的方法详解 在Delphi开发中,有时我们需要确保应用程序只能运行一个实例,即当用户尝试再次启动程序时,已存在的程序实例能够成为焦点或者阻止新的实例创建。这种需求常见于需要避免资源...

    单例模式_让程序只运行一个实例,并激活前一个实例

    程序只运行一个实例,并激活前一个实例

    应用程序只能运行一次

    在IT领域,"应用程序只能运行一次"的问题通常指的是单实例应用程序设计。这种设计模式确保一个应用程序在同一时间只能有一个实例在运行,不允许用户启动第二个实例。这样的限制有助于避免资源浪费、数据冲突和其他...

    程序只运行一个实例,并激活前一个实例.zip_一个实例_只运行一个实例_激活

    标题“程序只运行一个实例,并激活前一个实例”所指的就是这类应用场景。这样的设计可以防止用户无意中打开多个相同程序的窗口,消耗不必要的系统资源。 实现这个功能主要涉及以下几个技术点: 1. **进程检查**:...

    C# 应用程序中控制应用程序只启动一次 代码

    标题中的“C#应用程序中控制应用程序只启动一次”就是指实现这样的功能,确保同一时间只有一个实例运行。这个功能在很多类型的软件中都很常见,比如下载管理器、音乐播放器等。 要实现这一目标,我们可以利用...

    VC防止程序重复运行,并激活+闪烁

    VC防止程序重复运行,并激活+闪烁

    QtSingleApplication实现软件只能启动一次

    在开发桌面应用程序时,有时我们需要确保用户在同一时间只能运行一个程序实例,这通常被称为单例模式。在Qt框架中,可以使用QtSingleApplication类来实现这样的功能。QtSingleApplication是Qt提供的一种特殊类型的...

    VB防止程序重复运行

    因此,设计一种机制来确保程序只运行一个实例是非常有必要的。 #### 二、实现原理 要实现防止程序重复运行的功能,主要思路是检测当前是否有其他实例正在运行。如果已经有一个实例正在运行,则不再启动新的实例,...

    C# 只能运行一个winForm进程

    C# 只能运行一个winForm进程是指在C#中实现单实例应用程序,确保同一个应用程序只能运行一个实例,以避免资源浪费和混乱。下面将详细介绍如何实现单实例应用程序。 单实例应用程序的实现 在C#中,实现单实例应用...

    完整版禁止重运行(自动激活还原已最小化运行窗口).rar

    标题中的“完整版禁止重运行(自动激活还原已最小化运行窗口).rar”似乎指的是一个软件或程序的压缩包,这个程序具有防止自身被多次启动(禁止重运行)的功能,并且在用户将其最小化后,能够自动激活并恢复到最小化...

    VB6如何让程序只能启动一个实例

    运行编译后的程序,当尝试再次启动时,程序会检测到已有实例并激活它,而不是创建新的实例。 通过以上方法,VB6程序可以有效地实现单实例运行,提供更高效且一致的用户体验。这种方法在许多应用中都十分常见,尤其...

    禁止电脑任意程序运行工具_禁止电脑指定程序运行

    【标题】"禁止电脑任意程序运行工具_禁止电脑指定程序运行"所指的是一款能够帮助用户控制电脑上运行程序的应用。这款工具的主要功能是让用户能够阻止特定程序的启动和运行,以达到保护系统安全、提高工作效率或者...

    C#编程中设置程序只可被运行一次的方法

    而我想要实现的是:在程序运行多个实例时激活的是第一个实例,使其获得焦点,并在前端显示. 主要用到两个API 函数: ShowWindowAsync 该函数设置由不同线程产生的窗口的显示状态。 SetForegroundWindow 该函数将创建指定...

    nero 第三方插件激活程序

    在Nero 8的情况下,这个激活程序可能是为了帮助用户跳过官方的授权验证过程,使Nero 8的组件能够无限制地运行。这可能涉及到修改软件的许可证验证机制或者利用某种漏洞来实现激活。 值得注意的是,使用这样的第三方...

    感染EXE运行程序

    当被感染的程序运行时,病毒会复制自身并可能传播到其他文件或系统。 4. **感染机制**: 感染EXE运行程序的恶意软件通常使用注入技术,例如DLL注入、API钩子、内存篡改等,将自身的代码插入到正常程序的执行流程中...

    VS2010/MFC 启动程序检查自身是否已经在运行

    VS2010/MFC 启动程序检查自身是否已经在运行。如果已经有一个在运行,则退出当前,并把原来已经运行的程序激活显示在当前窗口中。

    可互斥可自动激活的程序示例

    总的来说,这个示例程序展示了如何在C#中实现一个单实例应用程序,利用进程管理和互斥对象确保同一版本的程序只能运行一次,以及如何通过进程间通信自动激活已运行的实例。这样的设计在很多软件中都非常常见,例如...

    程序只运行一个实例,并将前一个实例提到前台

    标题中的“程序只运行一个实例,并将前一个实例提到前台”是一个常见的软件设计模式,称为“单例模式”。在计算机编程中,单例模式确保一个类只有一个实例,并提供一个全局访问点,通常用于控制共享资源或者需要全局...

    430关于仿真时工作正常程序固化后却不能运行的几种情况

    芯片坏了可能会导致程序不能正常工作,例如仿真器仿真时一切 OK,固化后不行了,原来芯片坏了,一部分程序正常,一部分怎么调都不行,换新片子就都 OK。 (16)串行接口的 EEROM 读写问题 串行接口的 EEROM 读写...

Global site tag (gtag.js) - Google Analytics