有时候我们的程序需要只能运行一次,并且再次运行的时候能够自动激活已经运行的程序并且跳到最前面。我找了网上的许多代码,发现只运行一次是很容易实现的,但激活已经运行的程序这一功能总是有点问题。
一般方法都是找到已经运行的程序之后发一个消息过去,然后执行这两个API函数:
ShowWindowAsync(Application.Handle, SW_NORMAL ); //设置窗口的显示模式为NORMAL(WindowStatus)
SetForegroundWindow(Application.Handle); //设置程序为前台窗口
但是我发现这两个函数经常只能达到让在后台的窗口在任务栏上的按钮闪烁。而在有的电脑上就能把在后台的窗口调到前台。而且我发现,用C#写的程序只需要调用这两个API函数就能达到目的。
另外,经过实验发现,在我的电脑上,如果运行此程序的时候运行VS2005,并且随便打开一个项目,那么这个程序就能正常运行了...目前还是想不明白是什么原因造成的。
最后研究了很久之后又在后面加了下面几行代码:
ID1 := GetWindowThreadProcessId(GetForegroundWindow(), nil); //获取前台线程的ID
ID2 := GetCurrentThreadId; //获取当前线程的ID
AttachThreadInput(ID1, ID2, TRUE); //把前提线程附加到当前线程
AttachThreadInput(ID1, ID2, FALSE); //取消附加 这样程序运行就完全达到要求了。另外如果把最后一个取消附加去掉,那么在运行两次程序之后再运行的时候,窗口获得焦点的速度就会慢上半拍。
给出完整代码:
[Project1.dpr]
program Project1;
uses
Forms, Messages, Windows,
Unit1 in 'Unit1.pas' {Form1};
const
hfck = wm_user + $1000;
appname = 'singleinstance';
var
myhandle: hwnd;
{$R *.res}
begin
myhandle := findwindow(appname, nil);
if myhandle > 0 then
begin
postmessage(myhandle, hfck, 0, 0);
exit;
end;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
[Unit1.pas]
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, tlhelp32, StdCtrls;
const
hfck = wm_user + $1000;
appname = 'singleinstance';
type
TForm1 = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure createparams(var params: tcreateparams); override;
procedure restorerequest(var msg: tmessage); message hfck;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.createparams(var params: tcreateparams);
begin
inherited createparams(params);
params.WinClassName := appname;
end;
procedure TForm1.restorerequest(var msg: tmessage);
var
ID1, ID2: Cardinal;
begin
if IsIconic(Application.Handle) then
ShowWindowAsync(Application.Handle, SW_NORMAL ); //设置窗口的显示模式为NORMAL(WindowStatus)
SetForegroundWindow(Application.Handle); //设置程序为前台窗口
ID1 := GetWindowThreadProcessId(GetForegroundWindow(), nil); //获取前台窗口的线程ID
ID2 := GetCurrentThreadId; //获取当前线程的ID
AttachThreadInput(ID1, ID2, TRUE); //把前提线程附加到当前线程
AttachThreadInput(ID1, ID2, FALSE); //取消附加
end;
procedure TForm1.btn1Click(Sender: TObject);
begin
ShowMessage(appname);
end;
end.