Link to home
Start Free TrialLog in
Avatar of Wim ten Brink
Wim ten BrinkFlag for Netherlands

asked on

[Challenge] The annoying Application Window...

Okay, I finally got too annoyed by the following problem. Please follow my instructions and then help me solve this... :-)

1) Start your Delphi version. (Doesn't matter which one.)
2) Create a new application.
3) Save the new application. (Make whatever modifications that you like.)
4) Compile the new application.
5) Close Delphi.
6) Close all other applications you're running.
7) Start the application you just created. (Start/Run...)
8) Right-click on the taskbar.
9) From the popup menu, click on 'Tile Windows Vertically" or the other tile option.

After these 9 steps, your newly created application will occupy half the screen...

10) Close your application.
11) Start Notepad (Start/Run...)
12) Right-click on the taskbar.
13) From the popup menu, click on 'Tile Windows Vertically" or the other tile option.

After these additional 4 steps, you'll see Notepad filling your whole screen, just as all Windows applications are supposed to behave...

Now, about the why... This happens because every Delphi application which uses the VCL will actually create two forms. One is your mainform and this one should be visible of course. The other is a form of class TApplication. Yeah, that's right! TApplication is also a very special kind of form. It has a width and height of 0 but it is still visible. (But smaller than a pixel so you won't see it. Delphi needs this window to be visible so it can handle all kinds of Windows messages. In other programming languages, such behaviour would be linked to the mainform instead but not with Delphi. So when the Delphi application gets ordered to tile it's windows, it knows it has two windows which both need to fill the screen. So each window will occupy half the screen. Since TApplication maintains it's size of 0x0, it's still not visible yet you will see the mainform on half your screen.

This annoys me and today it just bugged me too much. So here's the challenge...

Write a simple application using the VCL which will work just like all other Windows applications. Thus, when tiling it fills the whole screen instead of half the screen but also, TApplication must still be able to process all messages. (Which means you can't make TApplication invisible, except for a very, very short time!!!)

400 points plus A-grade for the best solution! And 100 points for the second-best...
(The best solution would be implemented as a component that you can drop on your form...)
Avatar of Wim ten Brink
Wim ten Brink
Flag of Netherlands image

ASKER

(-: Or 500 points if your solution is the only solution. :-)
Can you do this?
I would have thought even if you create a component wrapping it, that starting a new application would drop this form in again.
How you would remove it from your project I have no idea.
Avatar of TName
TName

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellApi;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Privatew declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
 aInfo: TStartUpInfo;
begin

  GetStartUpInfo(aInfo);
  ShowWindow(Handle, aInfo.wShowWindow);
  ShowWindow(Handle, cmdShow);

  Application.ShowMainForm := False;
  ShowWindow(Application.Handle, SW_HIDE);

end;

end.
You don't need ShellApi in uses, I first tried to catch ABN_WINDOWARRANGE (couldn't make it work) and forgot ShellApi there...
>but also, TApplication must still be able to process all messages. (Which means you can't make TApplication invisible, except for a very, very short time!!!)

Ok, back to the drawing board... ;)
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ShellApi;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
 aInfo: TStartUpInfo;
begin
  Application.Name:='StillHere';
  Application.OnMessage := AppMessage;
  GetStartUpInfo(aInfo);
  ShowWindow(Handle, aInfo.wShowWindow);
  ShowWindow(Handle, cmdShow);
end;

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
 if Msg.wParam=ABN_WINDOWARRANGE and Msg.lParam then
    ShowWindow(Application.Handle, SW_HIDE);

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Application.ProcessMessages;
ShowMessage(Application.Name);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Application.Terminate;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 Application.OnMessage := nil;
end;

end.
TName, your first solution would not work, of course. Once TApplication is invisible it won't respond to certain messages anymore. And your second one? When do you make TApplication visible again? :-)

Yeah, it might be more complicated than it seems at first glance... (Especially since this has been bugging me for about 8 years now...)
Strange... On Windows 95, the problem doesn't exist!
On 98+, it occurs...
I fixed the problem on my machine with 1 line of code... but i use Delphi 5 / 2K so it might be a quirk with my Delphi...

procedure TForm1.FormCreate(Sender: TObject);
begin
 Application.Minimize;
end;



Put it in, compile it / run it, then close everything run the exe, and then tile the windows :-)
>> Application.Minimize;

Works with D2006 on 98 and XP, but the minimize button of the main form losses its functionality.
Also, the task bar button incorrectly behaves as if, well, the application is minimized.
Workshop_Alex, you're right. Sorry, I should have dived into the matter more thoroughly and tested before posting. ;)

>Especially since this has been bugging me for about 8 years now...
Well, then I guess it *is* hopeless (a 100% working solution, that is)
Yep. alkisq is pointing out a few of the problems with minimizing the TApplication window, or hiding it. Basically, if you minimize TApplication, then Windows will consider your whole application to be minimized and thus you'll end up with a bit flawed functionality.
The trick is to get this Tile function to work properly without affecting the functionality of the application itself. Then again, I might be asking for miracles here... :-)
It's just that this has always been one of the minor annoyances that Delphi had, ever since Delphi 1. In the beginning I didn't have much problems with it but it slowly started to annoy me.

Btw, this is a good trick to see if an application is built with the Delphi VCL or not. No need for any tools or whatever... Just make sure the application window is the only visible window and then tile all windows. If it occupies the whole screen, it's probably written with VS from MS. If it fills half the screen, it's written in Delphi or maybe C++Builder. At least, written in something that uses the VCL.
(Turbo Delphi .NET) Well... Delphi .NET (Winform app) fails to do this.

However

(Turbo Delphi VCL .NET) DOES do this....

Not only that, but

SendMessage(Form1.Handle,wm_close,0,0);

works fine

yet if i Define P: Pointer; in the Variable Section..

[Pascal Error] vcl1.pas(28): E2410 Unsafe pointer variables, parameters or consts only allowed in unsafe procedure

I don't get it... If i can use SendMessage then i can use Win32 calls, if i can use win32 calls, then it's not a .NET application if it's not a .NET application why can't i declare a pointer ....

my god Borland, what are you doing.
Yeah, I know. Borland is trying to keep Delphi for .NET compatible with Delphi for WIN32, which gives some funny results sometimes. :-)
Actually, this annoying feature is a VCL bug that they never fixed in the first place. It is annoying since it means that any application which uses the Forms unit will create this invisible window. Real annoying sometimes...

And as I said, I don't know a solution and I even worry that no real solution exists and that we'll end up with this bug until the End of Times. (Or the end of Delphi, whatever comes first.)
ASKER CERTIFIED SOLUTION
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
YES!

YES! YES! YES!

That's more like it. It works now. Added it to a large project of mine and it still performs as expected. And so simple. :-)