In Delphi 2009, I do a simple:
FindDialog.Execute;
The FindDialog window stays on top of my program's main window as it should.
However, if I open another window from some other program over my own program's window, the FindDialog window remains on top of the other window.
If I try this with a FindDialog from another program (e.g. Notepad), this does not happen. Opening another program's window over Notepad and its FindDialog will cover both the Notepad and FindDialog windows. This seems to be the correct and expected behavior.
Is this something I'm doing wrong or is this a problem with the way Delphi has implemented the FindDialog? Is there something I can do to make it work the Notepad way?
Thank you all for the comments. The fact that you cannot reproduce my problem is already a clue that it is something else causing this. This will help me track it down. I'll research a little more and post additional info here when I find out something.
Very interesting. My PrintDialog doesn't stay on top. Still don't know why my FindDialog does. Still researching...
I changed the call to: FindDialog.Execute(Handle); Still on top.
I added another FindDialog (this time FindDialog1) to my main form and I execute it at startup of my program. It has the same stay-on-top behavior. That at least indicates it wasn't anything to do with my FindDialog or customizations I made to do with it. So it must be a setting in my main form.
It doesn't look like I'm the only one who's encountered this. See: Resource Tuner: Version History which appears to be a Delphi application, where under Version 1.99 it states: "Bugfix: The (search) dialog preview window stayed on top when switching to another application." I might try contacting them and see if they might remember what their fix was.
I add some new dialogs to my form and put these calls in one place:
FindDialog1.Execute();
PrintDialog1.Execute();
ReplaceDialog1.Execute();
FontDialog1.Execute();
The FindDialog and ReplaceDialog stay on top in front of other windows. The PrintDialog and FontDialog do not stay on top and work as they should.
So what is different between the two sets of dialogs that make the first two do it wrong?
Also, this problem happens in an old version of my program that was compiled with Delphi 4. Whoops. Now I see this problem did not happen in my old version that used Delphi 4.
And it was a user who reported this problem. He uses Windows XP, and I'm developing on Vista, so it happens under different OS's.
Confirmation: Yes, I create a new form and add a FindDialog on it. The FindDialog does NOT have the problem. This indicates something in my program is causing the FindDialog to stay on top. Now, I've just got to find out what that is. Any more ideas? If someone gives me an answer that even gives me a clue to help me solve this, then they'll get the accepted answer.
Solution: Sertac's edit to his answer gave me the workaround:
Application.NormalizeTopMosts;
FindDialog.Execute();
Application.RestoreTopMosts;
Doing this prevents the FindDialog from being TopMost when the Application is not TopMost.
... But I still really don't understand this (the Delphi help on NormalizeTopMosts) is very confusing and doesn't indicate that it should do this.
Hopefully this "fix" won't cause other problems.
Looking at the VCL code, the only possible way a Find Dialog Box stays on top is, there's already a top-most window when 'Execute' is called. This is how it is coded, the dialog gets owned by a 'TRedirectorWindow' which gets owned by the top window in z-order in the application. If this 'top window' is a top-most window then the find dialog also is.
procedure TForm1.Button1Click(Sender: TObject);
var
f: TForm;
begin
f := TForm.CreateNew(Self);
f.FormStyle := fsStayOnTop;
f.Show;
FindDialog1.Execute;
end;
or,
procedure TForm1.Button1Click(Sender: TObject);
begin
FormStyle := fsStayOnTop;
FindDialog1.Execute;
FormStyle := fsNormal;
end;
The above samples will create a top-most find dialog. But a stay-on-top form possibly wouldn't go unnoticed, so I guess this wouldn't be the source of your problem.
In any case, it is either that or you're somehow changing the styles on the dialog by some other code piece.
BTW, do not bother testing passing various handles to FindDialog1.Execute()
, it won't have an effect, see my comment to your question.
edit:
How about this one:
procedure TForm1.Button4Click(Sender: TObject);
var
f: TForm;
begin
f := TForm.CreateNew(Self);
f.FormStyle := fsStayOnTop;
f.Show;
f.Hide;
FindDialog1.Execute;
end;
The point is, a window does not have to be visible to get enumerated by EnumThreadWindows
. So any existing stay-on-top form could cause the find dialog to exhibit this behavior.
Better test and see than to guess. Run the below test just before you launch your Find Dialog. This incorporates the logic 'dialogs.pas' performs to find the dialog a base, and would raise an exception if the dialog would go top-most.
function EnumThreadWndProc(hwnd: HWND; var lParam: LPARAM): Bool; stdcall;
var
Window: TWinControl;
begin
Result := True;
Window := FindControl(hwnd);
if Assigned(Window) and (Window is TForm) then begin
Result := False;
lParam := Longint(Window);
end;
end;
procedure TForm1.Button6Click(Sender: TObject);
var
OnTopForm: Longint;
begin
OnTopForm := 0;
EnumThreadWindows(GetCurrentThreadId, @EnumThreadWndProc, LPARAM(@OnTopForm));
// if (OnTopForm <> 0) and (TForm(OnTopForm).FormStyle = fsStayOnTop) then
if (OnTopForm <> 0) and (GetWindowLong(TForm(OnTopForm).Handle,
GWL_EXSTYLE) and WS_EX_TOPMOST = WS_EX_TOPMOST) then
raise Exception.Create('darn! got one: ' + TForm(OnTopForm).Name);
end;
One other test could be to call NormalizeTopMosts
of the Application before launching the dialog, but I know with some Delphi versions this method is broken and does not do its job.