December 1997

Starting your application minimized

by Mark G. Wiseman

I want you to try something before your users do. First, create a Windows shortcut to an application you've written with C++ Builder. Then, right-click on the shortcut, choose Properties from the speed menu, and select the Shortcut tab in the resulting dialog box. In the Run dropdown box, select either Minimized or Maximized, as shown in Figure A.

Figure A: Set the Run property to Minimized.
[ Figure A ]

Now run your application using the shortcut. Did your application's main window appear minimized or maximized? No? Then read on. In this article, we'll explain why your application didn't appear in the proper state and how you can easily work around this problem.

The bug and the hidden window

Borland constructed two obstacles in the VCL that make it difficult to run an application minimized or maximized. The first is a bug in the VCL's start-up code. Windows passes the parameter nCmdShow to applications through the WinMain() startup function. This parameter, an int, specifies how your main window or form should be shown to the user. Borland hard-coded this parameter with the value SW_SHOWDEFAULT--and that's the bug. The code in this article works around the bug, and should continue to work after Borland fixes the bug. Working around this bug will allow your programs to start maximized. To make your application start minimized, you'll need to surmount the second obstacle.

Borland included the following obstacle in the VCL on purpose: Every VCL-based application is a hidden window. The VCL makes Windows, the operating system, think this hidden window--rather than your main form--is your application's main window.When a user minimizes your application, this hidden window is minimized and the VCL hides your main form. Your main form is never actually minimized. Borland has tried to ease your pain by including methods and events in the TApplication class such as Minimize() and OnMinimize. We'll use another event from Tapplication--OnRestore--in our code. Let's see how to use our workaround.

Working around

Listing A includes all the code our sample project needs. (You can download our project files from

www.cobb.com/cpb

as part of the file dec97.zip; click the Source Code hyperlink.) To begin, create a new project with a single form named MinMaxForm. Add an OnCreate event named FormCreate() to the form, as shown in Listing A. FormCreate() will do nearly all the work.

Listing A: TMinMaxForm

//------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop

#include "Main.h"
//------------------------------------
#pragma resource "*.dfm"

TMinMaxForm *MinMaxForm;
//------------------------------------
__fastcall
TMinMaxForm::TMinMaxForm(TComponent*
   Owner) : TForm(Owner)
   {
   Application->OnRestore = OnRestore;
   }
//------------------------------------
void __fastcall
TMinMaxForm::FormCreate(TObject
   *Sender)
   {
   int cmdShow = System::CmdShow;

   if (cmdShow == SW_SHOWDEFAULT ||
      cmdShow == SW_HIDE)
      {
      STARTUPINFO startupInfo;
      GetStartupInfo(&startupInfo);

      if (startupInfo.dwFlags &
         STARTF_USESHOWWINDOW)
         cmdShow =
            startupInfo.wShowWindow;
      }

   if (cmdShow == SW_MINIMIZE ||
      cmdShow == SW_SHOWMINIMIZED ||
      cmdShow == SW_SHOWMINNOACTIVE)
      {
      ::ShowWindow(
         Application->Handle,
            SW_HIDE);
      ::ShowWindow(
         Application->Handle,
            SW_MINIMIZE);
      Application->ShowMainForm =
         false;
      }
   else if (cmdShow == SW_MAXIMIZE ||
      cmdShow == SW_SHOWMAXIMIZED)
      WindowState = wsMaximized;
}
//------------------------------------
void __fastcall
   TMinMaxForm::OnRestore(TObject
      *Sender)
      {
      Visible = true;
      }
//------------------------------------
First, you declare a cmdShow variable and set it equal to System::nCmdShow. This should be the value passed into your program by Windows--but due to Borland's bug, it will be SW_SHOWDEFAULT or SW_HIDE. You check the value here so the program will still work when Borland fixes the bug.If cmdShow is equal to SW_SHOWDEFAULT or SW_HIDE, the code checks the application's STARTUPINFO structure. You fill in startupinfo--an instance of this structure--by calling the Windows API function GetStartupInfo(). If the STARTF_USESHOWWINDOW flag is set in startupinfo.dwFlags, then you set cmdShow equal to the value in startupInfo.wShowWindow; otherwise, you ignore the STARTUPINFO structure.

At this point in the code, you've worked around the bug. Now it's time to tackle the hidden window. If the value of cmdShow indicates that you need to minimize your window, the code hides the hidden window and then minimizes it. Next, you tell TApplication not to show the main form. This step is equivalent to setting the main form's Visible property to false.

Why do you need to hide the hidden window? Actually, the "hidden" window isn't hidden at all--it's visible, but its width and height are set to zero, so you can't see it! If you didn't hide it first, you'd see the Windows zoom animation when the window minimized.

Not enough zoom

You may have noticed that the animation Windows displays when minimizing a window doesn't work with the main form in C++Builder programs. This flaw is caused by the hidden window problem we describe in the accompanying article. If you'd like to make your main form animate when minimizing, see the article "Zooming Main Forms Under Windows 95" in the October 1996 issue of The Cobb Group's Delphi Developer's Journal (www.cobb.com/ddj).

If cmdShow indicates that you should maximize the main form, the code simply sets the WindowState property to wsMaximized. There's one final detail to address. Remember, if cmdShow has you minimize your main form, you're really minimizing the hidden window and hiding the main form. If you then try to restore the main form, the hidden window will be restored (and still invisible) but the main form won't be made visible. To make everything work as expected, create an OnRestore() function in TminMaxForm; in TminMaxForm's constructor, assign the function to Tapplication's OnRestore event. In the OnRestore() function, you simply make sure the main form's Visible property is set to true.

Make life easier

Other examples that work around the problem of starting a C++Builder application minimized modify the WinMain() function code in the project source file. As a result, every time you create a new C++Builder application, you must remember to modify this code. I encourage you to make life easier. Use the code in this article and save TMinMaxForm into C++Builder's Repository. Then, you can use TMinMaxForm as the base form for all your applications, and your C++Builder programs will work as your users expect them to.

Your users will also expect your application to remember its size, position, and state between uses. In a future article, we'll show you how to enhance TMinMaxForm to do just this.