已经存在,这就是应用程序的第二个事例.
//注意:当应用
程序结束时,互斥元自动关闭.
CreateMutex(Nil, TRUE, PChar(mutexName));
if (GetLastError() = ERROR_ALREADY_EXISTS) then
begin
//查找该应用程序的前一个主窗口句柄.
hPrevWnd := GetDesktopWindow();
hPrevWnd := GetWindow(hPrevWnd, GW_CHILD);
while (IsWindow(hPrevWnd)) do
begin
//判断此窗口属性标志是否与设置的主窗口或登录窗口标志相符.
hData := GetProp(hPrevWnd, PChar(mutexName));
if (hData = 1) or (hData = 2) then
begin
//判断是主窗口还是登录窗口,并将窗口获得焦点.
if hData = 1 then //主窗口
ShowWindow(hPrevWnd, SW_MAXIMIZE)
else //登录窗口
ShowWindow(hPrevWnd,SW_RESTORE);
SetForegroundWindow(hPrevWnd);
//如果此窗口有弹出窗口,设置焦点到弹出窗口.
SetForegroundWindow(GetLastActivePopup(hPrevWnd));
break;
end else
//没有找到窗口,转到窗口列表中下一个窗口.
hPrevWnd := GetWindow(hPrevWnd, GW_HWNDNEXT);
end;
Application.Terminate;
exit;
end;
5.删除登录窗口先前实例标识符
删除步骤3中创建的窗口标记。
procedure TLoginForm.FormDestroy(Sender: TObject);
begin
RemoveProp(Handle, PChar(Application.ExeName));
end;
6.删除主窗体先前实例表示符
删除步骤4中创建的窗口标记。
procedure TMainForm.FormDestroy(Sender: TObject);
begin
RemoveProp(Handle, PChar(Application.ExeName));
end;
二、技术要点
1.定位先前窗口,使用mutex比用FindWindow更安全,因为在实例完成创建主窗口之前,应用程序的第二个实例有可能启动。使用mutex可以防止此类情况发生。
2.要寻找应用程序先前实例主窗口,可用FindWindow寻找有标题的窗口。该方法需要知道主程序窗口的标题,但如果应用程序动态更新标题,则该方法不适用。也可用FindWindow来寻找具有具体注册窗口类的窗口。但该方法需要
注册用户自己的窗口类,而且以后版本升级时,可能需要修改代码。而采用SDK的SetProp函数来“标记”窗口可以避免上述问题。
3.通过调用API函数GetDesktopWindow和GetWindow可以搜索所有的顶层窗口。再通过判断窗口标记找到先前实例窗口。