2

I have a form that calls TOpenDialog. When the window comes up I right clicked one of the displayed files and clicked properties. After closing the Windows properties window the open dialog window falls to the bottom of the Z-Order behind the calling form and main application. Using alt+tab (as I have read in similar posts here) will bring the open dialog window to the front, but i'd like a better solution. Most of the research I've done seems to apply only to the TForm class. Is there a way to better control the Z-Order of TOpenDialog? I am using Delphi 2006. I have similar code in a Delphi 2007 application and this problem doesn't occur (if that helps any). Thanks in advance.

CodeMonkey
  • 135
  • 2
  • 13
  • In my experience, the VCL code of that era was basically rubbish at handling window ownership. That's the key point. An owned window is always on top of its owner. Personally I use my own wrappers to the underlying APIs so that I can do it right. – David Heffernan Jul 09 '14 at 19:30
  • @David Heffernan: I actually have only heard of wrappers. I will admit that I don't know what they are exactly. I'll look into it for the future. Thanks for commenting. – CodeMonkey Jul 09 '14 at 19:43
  • TOpenDialog is a wrapper. – David Heffernan Jul 09 '14 at 19:44

1 Answers1

10

In Delphi 2006 and later, TOpenDialog.Execute() has an optional ParentWnd parameter. When not specified, Execute() does some hunting to decide which parent window to use for z-order purposes:

  1. If Application.ModalPopupMode is not pmNone, Application.ActiveFormHandle is used.

  2. If Application.ModalPopupMode is pmNone, or Application.ActiveFormHandle is 0, Application.Handle is used instead. In Delphi 2007 and later, with the introduction of the TApplication.MainFormOnTaskbar property, if MainFormOnTaskbar is true and Application.MainForm is assigned, Application.MainFormHandle is used instead of Application.Handle. Application.MainFormHandle triggers the TApplication.OnGetMainFormHandle event if assigned. If not assigned, or if it returns 0, Application.MainForm.Handle is used.

In Delphi versions up to, and including, 2006, TOpenDialog always uses the legacy Win32 API GetOpenFileName() function. In Delphi 2007 and later, TOpenDialog uses the newer IFileOpenDialog API if all of the following criteria are met, otherwise it falls back to GetOpenFileName():

  1. the app is running on Vista or later.

  2. the Dialogs.UseLatestCommonDialogs global variable is true.

  3. the TOpenDialog.Template property is nil.

  4. no OnIncludeItem, OnClose, or OnShow event handler is assigned to TOpenDialog.

When TOpenDialog uses IFileOpenDialog, Execute() respects the specified parent window.

When TOpenDialog uses GetOpenFileName(), Execute() IGNORES the specified parent window if Application.ModalPopupMode is pmNone and uses Application.MainFormHandle/Application.Handle instead!

So, to solve your problem in all Delphi versions from 2006 onwards, pass your form's Handle to the ParentWnd parameter, and set Application.ModalPopupMode to a value other than pmNone, then the dialog will use your form's window as its parent and thus can never appear behind it. Don't let the VCL decide which parent window to use.

BTW, everything I have said applies to TSaveDialog as well.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I am passing Self.Handle as the parameter when calling TOpenDialog.Execute. It still is doing it. Maybe I am missing something. – CodeMonkey Jul 09 '14 at 19:16
  • @CodeMonkey: Did you miss the rest of that paragraph about setting `Application.ModalPopupMode` as well? – Ken White Jul 09 '14 at 19:32
  • @Ken White: Yes I read right over it because I was trying to multitask. I apologize. I tried the solution with setting ModalPopupMode to pmExplicit as its explanation seemed to be the most appropriate and It seems to be working. Thank you both. – CodeMonkey Jul 09 '14 at 19:40