I am trying to achieve the age-old Delphi dream of having a modeless form appear in the taskbar.

What is the *correct* way to have a modeless form appear in the taskbar?

---

Research Effort
===============

These are my attempts to solve the problem. There are a lot of things needed to make it behave **correctly** - simply having a button appear on the taskbar is not a solution. Having a Windows application behave correctly as a Windows application should is my goal.

For those who know me, and how deep my *"shows research effort"* goes, hang on because it will be wild ride down a rabbit hole.

The question is in the title, as well above the horizontal line above. Everything below only serves to show why some on the oft-repeated suggestions are incorrect.

Windows only creates as taskbar button for unowned windows
----------------------------------------------------------

Initially i have my *"Main Form"*, from that i show this other modeless form:

```
procedure TfrmMain.Button2Click(Sender: TObject);
begin
    if frmModeless = nil then
        Application.CreateForm(TfrmModeless, frmModeless);

    frmModeless.Show;
end;

```

This correctly shows the new form, but no new button appears on the taskbar:

![enter image description here](https://i.stack.imgur.com/YP8xh.png)

The reason no taskbar button is created is because that is by design. [Windows will only show a taskbar button for a window that ***"unowned"***](http://blogs.msdn.com/b/oldnewthing/archive/2003/12/29/46371.aspx). This modeless Delphi form is most definitely *owned*. In my case it is owned by the `Application.Handle`:

![enter image description here](https://i.stack.imgur.com/TIiLx.png)

My project's name is `ModelessFormFail.dpr`, which is the origin of the Windows class name `Modelessformfail` associated with the owner.

Fortunately there is a way to *force* Windows to create a taskbar button for a window, even though the window is owned:

Just use `WS_EX_APPWINDOW`
--------------------------

The MSDN documentation of [`WS_EX_APPWINDOW`](https://msdn.microsoft.com/en-us/library/windows/desktop/ff700543%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396) says it:

> 
> **WS\_EX\_APPWINDOW** `0x00040000L` Forces a top-level window onto the taskbar when the window is visible.
> 
> 
> 

It also a [well-known Delphi](https://stackoverflow.com/questions/8204397/what-does-ws-ex-appwindow-do) trick to override `CreateParams` and manually add the `WS_EX_APPWINDOW` style:

```
procedure TfrmModeless.CreateParams(var Params: TCreateParams);
begin
    inherited;

    Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; //force owned window to appear in taskbar
end;

```

When we run this, the newly created modeless form *does* indeed get its own taskbar button:

![enter image description here](https://i.stack.imgur.com/0K0Rh.png)

And we're done? No, because it doesn't behave correctly. 

If the user clicks on the **frmMain** taskbar button, that window is not brought forward. Instead the other form (**frmModeless**) is brought forward:

![enter image description here](https://i.stack.imgur.com/SPR7q.png)

This makes sense once you understand the Windows concept of *ownership*. Windows will, by design, bring any child *owned* forms forward. It was the entire purpose of ownership - to keep owned forms on top of their owners.

Make the form actually unowned
------------------------------

The solution, [as some of you know](https://stackoverflow.com/questions/14502820/my-detail-form-is-hidden-behind-main-form-when-calling-the-tsavedialog) is not to fight against the taskbar heuristics and windows. If i want the form to be unowned, make it unowned. 

This is (fairly) simple. In `CreateParam` force the owner windows to be `null`:

```
procedure TfrmModeless.CreateParams(var Params: TCreateParams);
begin
    inherited;

    //Doesn't work, because the form is still owned
//  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; //force owned windows to appear in taskbar

    //Make the form actually unonwed; it's what we want
    Params.WndParent := 0; //unowned. Unowned windows naturally appear on the taskbar.
          //There may be a way to simulate this with PopupParent and PopupMode.
end;

```

As an aside, i wanted to investigate is there was a way to use the [`PopupMode`](http://docwiki.embarcadero.com/Libraries/XE8/en/Vcl.Forms.TForm.PopupMode) and [`PopupParent`](http://docwiki.embarcadero.com/Libraries/XE8/en/Vcl.Forms.TCustomForm.PopupParent) properties to make a window unowned. I ***swear*** i read a comment (from you David) somewhere on SO saying that if you passed `Self` as the `PopupParent`, e.g.:

```
procedure TfrmMain.Button1Click(Sender: TObject);
begin
    if frmModeless = nil then
    begin
        Application.CreateForm(TfrmModeless, frmModeless);
        frmModeless.PopupParent := frmModeless; //The super-secret way to say "unowned"? I swear David Heffernan mentioned it somewhere on SO, but be damned if i can find it now.
        frmModeless.PopupMode := pmExplicit; //happens automatically when you set a PopupParent, but you get the idea
    end;

    frmModeless.Show;
end;

```

it was supposed to be the super-secret way to indicate to Delphi that you want to form to have *"no owner"*. But i cannot find the comment anywhere on now. Unfortunately, no combination of `PopupParent` and `PopupMode` cause a form to *actually* be un-owned:

* PopupMode: **pmNone**
	+ Owner hwnd: `Application.Handle/Application.MainForm.Handle`
* PopupMode: **pmAuto**
	+ Owner hwnd: `Screen.ActiveForm.Handle`
* PopupMode: **pmExplicit**
	+ PopupParent: **nil**
		- Owner hwnd: `Application.MainForm.Handle`
	+ PopupParent: `AForm`
		- Owner hwnd: `AForm.Handle`
	+ PopupParent: *Self*
		- Owner hwnd: `Application.MainForm.Handle`

Nothing i could do could cause the form to actually have *no* owner (each time checking with Spy++).

Setting the `WndParent` manually during [`CreateParams`](http://docwiki.embarcadero.com/Libraries/XE8/en/Vcl.Controls.TWinControl.CreateParams): 

* **does** make the form unowned
* it **does** have a taskbar button
* and both taskbar buttons **do**behave correctly:

![enter image description here](https://i.stack.imgur.com/PwqI2.png)

And we're done, right? I thought so. I changed everything to use this new technique.

Except there are problems with my fix that seem to cause other problems - Delphi didn't like me changing to ownership of a form.

Hint Windows
------------

One of the controls on my modeless window has a tooltop:

![enter image description here](https://i.stack.imgur.com/1g11O.png)

The problem is that when this tooltip window appears, it causes the other form (**frmMain**, the modal one) to come forward. It doesn't gain activation focus; but it does now obscure the form i was look at:

![enter image description here](https://i.stack.imgur.com/ZP2p9.png)

The reason is probably logical. The Delphi **HintWindow** is probably owned either by `Application.Handle` or `Application.MainForm.Handle`, rather than being owned by the form that it should be owned by:

![enter image description here](https://i.stack.imgur.com/w4tYb.png)

I would have considered this a bug on Delphi's part; using the wrong owner.

Diversion to see the actual app layout
--------------------------------------

Now it's important that i take a moment to show that my application isn't a main form and a modeless form:

![enter image description here](https://i.stack.imgur.com/UD6v0.png)

It's actually:

* a login screen (a sacrificial main form that gets hidden)
* a main screen
* a modal control panel
* that shows the modeless form

![enter image description here](https://i.stack.imgur.com/gx489.png)

Even with the reality of the application layout, everything except for hint window ownership works. There are two taskbar buttons, and clicking them brings the proper form forward:

![enter image description here](https://i.stack.imgur.com/4W5Iq.png)

But we still have the problem of the HintWindow ownership bringing the wrong form forward:

![enter image description here](https://i.stack.imgur.com/W13kj.png)

ShowMainFormOnTaskbar
=====================

It was when i was attempting to create a minimal application to reproduce the problem when i realize i couldn't. There was something different:

* between my Delphi 5 application ported to XE6
* a new application created in XE6

After [comparing](http://www.scootersoftware.com/) everything, i finally traced it down to the fact that new applications in XE6 add the **`MainFormOnTaskbar := True`** by default in any new project (presumably to not break existing applications):

```
program ModelessFormFail;
//...
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TfrmSacrificialMain, frmSacrificialMain);
  //Application.CreateForm(TfrmMain, frmMain);
  Application.Run;
end.

```

When i added this option, then the appearance of the tooltip didn't bring the wrong form forward!:

![enter image description here](https://i.stack.imgur.com/E9eLr.png)

Success! Except, people who know what's coming [know what's coming](https://stackoverflow.com/questions/24441787/how-can-i-start-delphi-application-with-the-hidden-main-form). My *"sacrificial"* main login form shows the "real" main form, hiding itself:

```
procedure TfrmSacrificialMain.Button1Click(Sender: TObject);
var
    frmMain: TfrmMain;
begin
    frmMain := TfrmMain.Create(Application);
    Self.Hide;
    try
        frmMain.ShowModal;
    finally
        Self.Show;
    end;
end;

```

When that happens, and i *"login"*, my taskbar icon disappers entirely:

![enter image description here](https://i.stack.imgur.com/1Fmyw.png)

This happens because:

* the un-owned sacrificial main form is not invisible: so the button goes with it
* the real main form is **owned** so it does not get a toolbar button

Use WS\_APP\_APPWINDOW
----------------------

Now we have the opportunity to use `WS_EX_APPWINDOW`. I want to force my main form, which is owned, to appear on the taskbar. So i override `CreateParams` and force it to appear on the taskbar:

```
procedure TfrmMain.CreateParams(var Params: TCreateParams);
begin
    inherited;

    Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; //force owned window to appear in taskbar
end;

```

and we give it a whirl:

![enter image description here](https://i.stack.imgur.com/tncw3.png)

Looking pretty good!

* two taskbar buttons
* the tooltip doesn't pop the wrong owner form forward

except, when i click on the first toolbar button, the wrong form comes up. It shows the modal **frmMain**, rather than the currently modal **frmControlPanel**:

![enter image description here](https://i.stack.imgur.com/7GQZ3.png)

Presumably because the newly created **frmControlPanel** was PopupParented to **Application.MainForm** rather than **Screen.ActiveForm**. Check in Spy++:

![enter image description here](https://i.stack.imgur.com/5KiYc.png)

Yes, the parent is `MainForm.Handle`. This turns out to be because of another bug in the VCL. If the form's `PopupMode` is:

* **pmAuto**
* **pmNone** (if it's a modal form)

the VCL attempts to use `Application.ActiveFormHandle` as the `hWndParent`. Unfortunately it then checks if the modal form's parent is enabled:

```
if (WndParent <> 0) and (
      IsIconic(WndParent) or 
      not IsWindowVisible(WndParent) or
      not IsWindowEnabled(WndParent)) then

```

Of course the modal form's parent is not enabled. If it was, it would not be a modal form. So the VCL falls back to using:

```
WndParent := Application.MainFormHandle;

```

Manual parenting
================

This means i probably have to be sure to manually(?) set the popup parenting?

```
procedure TfrmMain.Button2Click(Sender: TObject);
var
    frmControlPanel: TfrmControlPanel;
begin
    frmControlPanel := TfrmControlPanel.Create(Application);
    try
        frmControlPanel.PopupParent := Self;
        frmControlPanel.PopupMode := pmExplicit; //Automatically set to pmExplicit when you set PopupParent. But you get the idea.
        frmControlPanel.ShowModal;
    finally
        frmControlPanel.Free;
    end;
end;

```

Except that didn't work either. Clicking the first taskbar button causes the wrong form to activate:

![enter image description here](https://i.stack.imgur.com/4wANo.png)

At this point i'm thoroughly confused. The **parent** of my modal form should be **frmMain**, and it is!:

![enter image description here](https://i.stack.imgur.com/ubVJg.png)

So what now?
------------

I have a sense of what might be going on. 

That taskbar button is a representation of **frmMain**. Windows is bringing that for forward. 

Except it behaved correctly when **MainFormOnTaskbar** was set to false.

There must be some magic in Delphi VCL that caused correctness before, but gets disabled with **MainFormOnTaskbar := True**, but what is it?

I am not the first person to want a Delphi application to behave nicely with the Windows 95 toolbar. And i've asked this question in the past, but those answers were always geared towards Delphi 5 and it's old central routing window.

I've been told that everything was fixed around Delphi 2007 timeframe.

So what is the correct solution?

Bonus Reading
-------------

* <http://blogs.msdn.com/b/oldnewthing/archive/2003/12/29/46371.aspx>
* [What does WS\_EX\_APPWINDOW do?](https://stackoverflow.com/questions/8204397/what-does-ws-ex-appwindow-do)
* [My detail form is hidden behind main form when calling the TsaveDialog](https://stackoverflow.com/questions/14502820/my-detail-form-is-hidden-behind-main-form-when-calling-the-tsavedialog)
* [The Oracle at Delphi Blog: PopupMode and PopupParent](http://blogs.embarcadero.com/abauer/2004/02/10/295)
* [DocWiki: Vcl.Forms.TForm.PopupMode](http://docwiki.embarcadero.com/Libraries/XE8/en/Vcl.Forms.TForm.PopupMode)
* [DocWiki: Vcl.Forms.TCustomForm.PopupParent](http://docwiki.embarcadero.com/Libraries/XE8/en/Vcl.Forms.TCustomForm.PopupParent)
* [How can I start Delphi application with the hidden main form?](https://stackoverflow.com/questions/24441787/how-can-i-start-delphi-application-with-the-hidden-main-form)