Setting MainFormOnTaskBar Causing Issues with Modal Dialogs

216 views Asked by At

I am working on Delphi 11.2 with an older Delphi project, pre Application.MainFormOnTaskBar's introduction, so by default it was set to False. I tried adding the following line to the project's .dpr file after Application.Initialize; like the Delphi documentation suggests:

Application.MainFormOnTaskBar := True;

My goal was to mimic every other modern Windows application and show a preview of the current MainView on the Windows taskbar. While my change did achieve this, it also resulted in undesirable behavior with modal dialogs.

The logic for determining modal dialogs' parents and window z-order differs from an application that has Application.MainFormOnTaskBar := False;. This now frequently shows modal dialogs behind other floating windows in the application, making the modal dialogs unclickable and locking up the application.

Many others have seen the same behavior, and it is noted in Delphi's documentation. Unfortunately, the most helpful information that I could find about getting the old z-ordering back had dead links, as it was from 2007/2008 around when Application.MainFormOnTaskBar was introduced. The older forum posts point to using PopupParent, PopupMode and Application.ModalPopupMode to reproduce the older modal dialog behavior. I have not had any success with those.

One workaround that I found to work was setting Params.WndParent := 0; in a Form's CreateParams(). However, I would prefer to find a universal solution for all modal dialogs, as I use built-in VCL methods like ShowMessage() and the System object TMsgDlgType to display simple modal dialogs.

I would like to have the old modal dialog z-ordering and have the live MainView preview appear on the Windows taskbar. Is there a new best way to achieve this? Have there been any advancements with this feature since its introduction? Can I show the live MainView preview on the Windows taskbar without setting Application.MainFormOnTaskBar?

EDIT:

Here is some more information about the overall flow of the project with Application.MainFormOnTask := False;.

I start by showing a login form, which is a custom form inheriting from TForm, by calling LoginForm.ShowModal(). The Windows taskbar icon appears for the project and the preview shows the login form. The preview stays updated as information is entered. Once information is entered, I proceed to show another custom 'TForm' while things are being created in the background. This is also reflected in the Windows task bar preview. Once creation is complete I show the MainView. The taskbar now shows the login form as the taskbar preview even though it is no longer present anywhere on the screen. Then I show other popup custom forms by calling one of the two functions below depending on if I want it to be modal or not.

  // Set form to stay on top
  SetWindowPos(Self.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOSENDCHANGING);

  Self.Show();
  // Set form to stay on top
  SetWindowPos(Self.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOSENDCHANGING);

  Result := Self.ShowModal();

Things are slightly different when Application.MainFormOnTask := True;. I show the login and creation forms same as before. However, the taskbar icon does not appear until the MainView is shown. Throughout its runtime the preview stays updated. However, when showing modal forms the z-ordering will be behind those forms which are not modal, using the methods above.

1

There are 1 answers

0
user23687521 On

In the hope this helps someone, I have found the only reliable way to have your modal forms appear above a StayOnTop form is to set the PopupMode immediately before calling ShowModal.

You can easily recreate the issue whereby Modal forms appear behind a StayOnTop form by creating a new Delphi 11 application that has two forms, Form1 (FormStyle := fsStayOnTop;) and Form2 containing a TComboBox and a public method, SetEnvironment.

Form2 SetEnvironment simply clears the TComboBox.Items:

procedure TForm2.SetEnvironment;
begin
  // Comment out the below line and it doesn't matter where PopupMode is set
  // it always works as expected
  ComboBox1.Items.Clear;
end;

Form1 has FormStyle := fsStayOnTop and has a single button which shows Form2 modally:

procedure TForm1.Button1Click(Sender: TObject);
begin

  Form2 := TForm2.Create(nil);
//  Form2.PopupMode := pmAuto; {---> Uncomment this line and Form2 will appear BEHIND Form1}
  Form2.SetEnvironment;
//  Form2.PopupMode := pmAuto;  {---> Uncomment this line and Form2 will appear IN FRONT of Form1}
  Form2.ShowModal;
  Form2.Free;

end;

If you comment out ComboBox1.Items.Clear in Form2 then the order of setting PopupMode doesn't matter, Form2 is always displayed above Form1.