A: 

Sorry if this is really stupid, but you don't have the formstyle set to fsStayOnTop do you? This would explain this behaviour.

Toby Allen
Nope - good thought though. FormStyle is fsNormal. PopupMode is pmNone. BorderStyle is bsSizeable. BorderIcons default.
mj2008
A: 

perhaps add this in the createparams

Params.ExStyle := Params.ExStyle OR WS_EX_APPWINDOW;

or try this anywhere in the code. I presonally use it on the forms .OnCreate event.

SetWindowLong(Wnd, GWL_EXSTYLE, 
  GetWindowLong(Wnd, GWL_EXSTYLE) or WS_EX_APPWINDOW) ;

the downside of this is that if the main form is minimized the other forms hide aswell, but restore when the main form does.

Aldo
Thanks - that has been tried too, but to no affect (well, not to this issue). (I should have mentioned it, but I've been working on it for a day or two now, and actually deleted that line which was commented out.)
mj2008
+5  A: 

My application works in the way you describe. Here is the approach I took. I would have liked to find a simpler approach but never did.

I started out by reading these articles. This first one is an great write up by Peter Below:

http://groups-beta.google.com/group/borland.public.delphi.winapi/msg/e9f75ff48ce960eb?hl=en

Other information was also found here, however this did not prove to be a valid solution: for my use: http://blogs.teamb.com/DeepakShenoy/archive/2005/04/26/4050.aspx

Eventually here is what I ended up with.

My splash screen doubles as the Application Main form. The Main form has a special tie to the Application Object. Using all secondary forms gets me the behavior that I was looking for.

In each form that I want on the task bar I override CreateParams. I do this on my edit forms and what the users sees as the "main form"

procedure TUaarSalesMain.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  Params.WndParent := GetDesktopWindow;
end;

My "Main" form as far as Delphi is concerned loads the true main form in its Activitate function. I use a member variable to keep track of the first activate. Then at the end of the function I hide the splash form, but do not close it. This was important for me because if the user was editing a document and closed the main form I did not want the edit screens to be forced closed at the same time. This way all of the visible forms are treated the same.

    if FFirstActivate = false then
      exit;

    FFristActivate := false;

    /* 
       Main Load code here 
       Update Splash label, repaint
       Application.CreateForm
       etc.
    */


    // I can't change visible here but I can change the size of the window
    Self.Height := 0;
    Self.Width := 0;
    Self.Enabled := false;

    //  It is tempting to set Self.Visible := false here but that is not
    // possible because you can't change the Visible status inside this
    // function.  So we need to send a message instead.
    ShowWindow(Self.Handle, SW_HIDE);

  end;

But there is still a problem. You need the main/splash window to close when all other forms are closed. I have an extra check in my close routines for Parent <> nil because I use forms as plugins (form my purposes they work better than frames).

I didn't really like using the Idle event, but I don't notice this being a drag on the CPU.

{
  TApplicationManager.ApplicationEventsIdle
  ---------------------------------------------------------------------------
}
procedure TApplicationManager.ApplicationEventsIdle(Sender: TObject;
  var Done: Boolean);
begin

  if Screen.FormCount < 2 then
    Close;
end;

{
  TApplicationManager.FormCloseQuery
  ---------------------------------------------------------------------------
}
procedure TApplicationManager.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
var
  i: integer;
begin

  for i := 0 to Screen.FormCount - 1 do
  begin
    if Screen.Forms[i] <> self then
    begin
      // Forms that have a parent will be cleaned up by that parent so
      // ignore them here and only attempt to close the parent forms
      if Screen.Forms[i].Parent = nil then
      begin
        if Screen.Forms[i].CloseQuery = false then
        begin
          CanClose := false;
          break;
        end;
      end;
    end;
  end;

end;

{
  TApplicationManager.FormClose
  ---------------------------------------------------------------------------
}
procedure TApplicationManager.FormClose(Sender: TObject;
  var Action: TCloseAction);
var
  i: integer;
begin

  for i := Screen.FormCount - 1 downto 0 do
  begin
    if Screen.Forms[i] <> self then
    begin
      // Forms that have a parent will be cleaned up by that parent so
      // ignore them here and only attempt to close the parent forms
      if Screen.Forms[i].Parent = nil then
      begin
        Screen.Forms[i].Close;
      end;
    end;
  end;

end;

This has served me well so far. I did make a small change for Vista because the icon for my "Main/Splash" screen was still showing. I don't remember what that was though. I probably don't need to set width, height, enabled, and send the hide message on the splash screen. I just wanted to make sure it didn't show up :-).

Dealing with the close events was necessary. If I remember correctly that was needed for when windows sent a shutdown message. I think only the main form gets that message.

Mark Elder
The hidden splash sounds horrible, but it might actually solve another issue too. This could be what I go with if nothing ideal appears. Thanks!
mj2008
I also took a similar approach with one of my applications and it worked well. I added some extra code to call application minimize when the "main form" was minimized, and added an event to the application.onrestore to restore the "main form".
skamradt
I agree the hidden splash is horrible. If something better appears I will be changing my code as well :-). It's too bad that stackoverflow was not around when I first wrote this.
Mark Elder
Well, the management went with "do it using a tabbed interface", so that's what we are going with. This answer has all the details (or links) so I've accepted it as the solution to the question.
mj2008