主窗口挡住对话框的问题(50分)

  • 主题发起人 主题发起人 keyz
  • 开始时间 开始时间
K

keyz

Unregistered / Unconfirmed
GUEST, unregistred user!
防止程序多个实例运行,所以第二个实例运行时检测是否有实例运行,如果有则使用
SetForegroundWindow把第一个实例的主窗口放到前面来,但是如果第一个实例正好打
开了对话框的话,则主窗口会在Z-Order的最前面挡住对话框,而无法得到焦点了。

请问如何解决。或者如何得知是否打开了对话框?
 
不会吧?如果你的对话框是模态的,应该会一直位于主窗体的前面。
如果你的对话框是非模态的,哪也不会影响到输入的啊??
 
如果你用SetForegroundWindow提前主窗口,是会挡住模态对话框。
 
你为什么不使用Application.MainForm.BringtoFront或Application.BringtoFront呢?
 
我知道了,你是在第二个实例中进行操作的,所以无法直接对原先的Application进行操作,
但是你可以在第一个实例中返回当前窗口的句柄阿。
这是我的程序的写法,用它替代了标准的WndProc,绝对可行。
function NewWndProc(Handle: HWND; Msg: Integer; wParam, lParam: Longint):
Longint; stdcall;
begin
Result := 0;
if Msg = MessageID then
begin
case wParam of
MI_QUERYWINDOWHANDLE:
begin
if IsIconic(Application.Handle) then
begin
Application.MainForm.WindowState := wsNormal;
Application.Restore;
end;
PostMessage(HWND(lParam), MessageID, MI_RESPONDWINDOWHANDLE,
Screen.ActiveForm.Handle);
end;
MI_RESPONDWINDOWHANDLE:
begin
SetForegroundWindow(HWND(lParam));
Application.ShowMainForm := False;
Application.Terminate;
end;
end;
end
else
Result := CallWindowProc(WProc, Handle, Msg, wParam, lParam);
end;
 
呵呵,我就是用这段代码的呀!你看
当执行这一段时,
MI_RESPONDWINDOWHANDLE:
begin
SetForegroundWindow(HWND(lParam));
Application.ShowMainForm := False;
Application.Terminate;
end;
其中SetForegroundWindow中的参数是第一个实例的主窗口,问题是如果这个主窗口
打开了对话框,则主窗口会挡在对话框前面!!
 
很简单
在主窗体中加一个自定义消息处理过程,收到特定消息后,就Application.BringtoFront;
在工程文件中写一段,通过FindWindow,把上一个实例的主窗体的Handle找出来,
把定义的消息PostMessage过去,然后退出。前一个实例就弹出来了,TApplicaton会帮你处理模态窗口的。

如果用FindWindow有问题,可以考虑在程序重载主窗体的CreateParem过程,
自己定义一个TCreateParams的WindowClass
 
to szf:
可是我用Application.BringToFront根本不会把窗口放到前面来,
只是在标题栏上闪动!其实在本线程中用SetForegroundWindow
也是这样,窗口不会到前面,只会闪动。
我用的的是 Win2000 adv server + Delphi 6
 
to keyz:
sorry,这是以前在win95下实现过的,确实不知道Win2000的GUI会怎么变化了。
看DELPHI7的WIN32SDK也没有看到什么新的消息,可能MSDN里面会有,查查吧。
 
看我的前贴: http://www.delphibbs.com/delphibbs/dispq.asp?lid=1312128
 
解决了!
看了MSDN上对Setforgroundwindow的描述,果然95和2000不同。
With this change, an application cannot force a window to the foreground
while the user is working with another window. Instead, Foreground and
Background Windows will activate the window (see SetActiveWindow) and call
the function to notify the user. However, on Microsoft® Windows® 98 and
Windows Millennium Edition (Windows Me), if a nonforeground thread calls
SetForegroundWindow and passes the handle of a window that was not created
by the calling thread, the window is not flashed on the taskbar.

在2000下只有当前的进程才能放到最前面,所以自己是不能激活的(不在当前)。

不过解决的方法却不是按照微软提供的修改系统参数:
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);

而是仿照Application的BringToFront,找到最Application中的最上面的窗口,并激活。
if lParam <> 0 then
begin
TopWindow := GetLastActivePopup(lParam);
if (TopWindow <> 0) and
IsWindowVisible(TopWindow) and IsWindowEnabled(TopWindow) then
SetForegroundWindow(TopWindow);
end;

谢谢诸位给我的提示。
 
多人接受答案了。
 
虽然你接受答案了,但是你根本没有看到我的代码的特殊的地方啊!
PostMessage(HWND(lParam), MessageID, MI_RESPONDWINDOWHANDLE,
Screen.ActiveForm.Handle);
看到了传送过来的并不是Application.MainForm.Handle而是Screen.ActiveForm.Handle啊,
所以这样就不会出问题了。
 
是的,没有看清楚。不好意思。
 
恩,我也没注意看,看了就不来分分了。 :-)
 
后退
顶部