In the December 1997 article "Starting Your Application Minimized," we showed you how to start your application with the main form minimized, maximized, or in its normal state. This month, we'll demonstrate how to make the state, position, and size of your application's main form persistent. To make the form persistent, we'll make a few modifications to the TMinMaxForm class we created last time, and we'll add a new class: WWindowPlacement.
Listing A: WWindowPlacement header
#ifndef winplace_h
#define winplace_h
#include <vcl\vcl.h>
#pragma hdrstop
class WWindowPlacement : public WINDOWPLACEMENT
{
friend ostream & operator <<
(ostream & os, const
WWindowPlacement & placement);
friend istream & operator >>
(istream & is,
WWindowPlacement & winplace);
public:
WWindowPlacement(TForm *form = 0);
virtual ~WWindowPlacement() {}
void Get(TForm *form);
void Set(TForm *form);
};
Listing B: WWindowPlacement source
#include <vcl\vcl.h>
#pragma hdrstop
#include "winplace.h"
WWindowPlacement::WWindowPlacement
(TForm *form)
{
length = sizeof(WINDOWPLACEMENT);
if (form == 0)
{
if (::GeWWindowPlacement
(::GetDesktopWindow(), this)
== FALSE)
{
ptMinPosition.x = ptMinPosition.y = -1;
ptMaxPosition.x = ptMaxPosition.y = -1;
}
flags = 0;
showCmd = SW_SHOWNORMAL;
rcNormalPosition.left=rcNormalPosition.top = 0;
rcNormalPosition.right = 639;
rcNormalPosition.bottom = 479;
}
else
Get(form);
}
void WWindowPlacement::Get
(TForm *form)
{
::GeWWindowPlacement(form->Handle, this);
// If no parent, then this window is on the
// desktop and when minimized we should let
// Windows place the icon
if (form->ParentWindow == 0)
flags &= ~WPF_SETMINPOSITION;
}
void WWindowPlacement::Set
(TForm *form)
{
::SeWWindowPlacement(form->Handle, this);
}
ostream & operator <<(ostream &os,
const WWindowPlacement &placement)
{
char sep = ',';
os << '[' << placement.flags << sep
<< placement.showCmd << sep;
os << placement.ptMinPosition.x << sep
<< placement.ptMinPosition.y << sep;
os << placement.ptMaxPosition.x << sep
<< placement.ptMaxPosition.y << sep;
os << placement.rcNormalPosition.left << sep
<< placement.rcNormalPosition.top << sep;
os << placement.rcNormalPosition.right << sep
<< placement.rcNormalPosition.bottom << ']';
return(os);
}
istream & operator >>(istream &is,
WWindowPlacement &placement)
{
char sep;
is >> sep >> placement.flags >> sep
>> placement.showCmd >> sep;
is >> placement.ptMinPosition.x >> sep
>> placement.ptMinPosition.y >> sep;
is >> placement.ptMaxPosition.x >> sep
>> placement.ptMaxPosition.y >> sep;
is >> placement.rcNormalPosition.left >> sep
>> placement.rcNormalPosition.top >> sep;
is >> placement.rcNormalPosition.right >> sep
>> placement.rcNormalPosition.bottom >> sep;
return(is);
}
Listing C: TMinMaxForm header
//------------------------------------
#ifndef Main2H
#define Main2H
//------------------------------------
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
//------------------------------------
class TMinMaxForm : public TForm
{
__published:
void __fastcall
FormCreate(TObject *Sender);
void __fastcall
FormClose(TObject *Sender,
TCloseAction &Action);
private:
bool restoreToMaximized;
public:
__fastcall
TMinMaxForm(TComponent* Owner);
void __fastcall
OnRestore(TObject *Sender);
};
//------------------------------------
extern TMinMaxForm *MinMaxForm;
//------------------------------------
#endif
Listing D: TMinMaxForm source//------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop
#include "Main2.h"
#include "winplace.h"
#include <fstream.h>
//------------------------------------
#pragma resource "*.dfm"
TMinMaxForm *MinMaxForm;
//------------------------------------
__fastcall
TMinMaxForm::TMinMaxForm(TComponent*
Owner) : TForm(Owner)
{
restoreToMaximized = false;
Application->OnRestore = OnRestore;
}
//------------------------------------
void __fastcall
TMinMaxForm::FormCreate(TObject *Sender)
{
WWindowPlacement place;
ifstream is("minmax.set");
is >> place;
int cmdShow = System::CmdShow;
if (cmdShow == SW_SHOWDEFAULT ||
cmdShow == SW_HIDE)
{
STARTUPINFO startupInfo;
GetStartupInfo(&startupInfo);
if ((startupInfo.dwFlags &
STARTF_USESHOWWINDOW) &&
startupInfo.wShowWindow != SW_NORMAL &&
startupInfo.wShowWindow != SW_RESTORE)
cmdShow = startupInfo.wShowWindow;
else
cmdShow = place.showCmd;
}
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;
if (cmdShow == SW_MINIMIZE ||
cmdShow == SW_SHOWMINIMIZED ||
cmdShow == SW_SHOWMINNOACTIVE)
{
::ShowWindow(Application->Handle, SW_HIDE);
::ShowWindow(Application->Handle, SW_MINIMIZE);
Application->ShowMainForm = false;
if (place.showCmd == SW_MAXIMIZE)
place.flags |= WPF_RESTORETOMAXIMIZED;
cmdShow = SW_HIDE;
}
place.showCmd = cmdShow;
place.Set(this);
if (place.flags & WPF_RESTORETOMAXIMIZED)
restoreToMaximized = true;
}
//------------------------------------
void __fastcall
TMinMaxForm::OnRestore(TObject *Sender)
{
if (restoreToMaximized)
{
restoreToMaximized = false;
WindowState = wsMaximized;
}
Visible = true;
}
//------------------------------------
void __fastcall
TMinMaxForm::FormClose(
TObject *Sender,
TCloseAction &Action)
{
WWindowPlacement place(this);
if (::IsIconic(Application->Handle))
{
if (::IsZoomed(Handle))
place.flags |= WPF_RESTORETOMAXIMIZED;
place.showCmd = SW_MINIMIZE;
}
ofstream os("minmax.set");
if (os) os << place;
}
//------------------------------------
You'll first change the FormCreate() function. The added code creates an instance of WWindowPlacement called place, then attempts to fill place with the state, position, and size data stored in a file named minmax.set.
If the user has specified a special startup state for the form, through a Windows shortcut or some other means, the code sets place.showCmd equal to that state. Otherwise, you use the state already stored in place.
Finish FormCreate() by checking to see whether place.flags has the WPF_RESTORETOMAXIMIZED flag set. If this flag is set, then set restoreToMaximized to true. You've declared restoreToMaximized as a bool in the private section of TMinMaxForm. You'll need restoreToMaximized in the TMinMaxForm::OnRestore() function.
If a form is maximized, then minimized, and then closed, WwindowPlacement will store this information. The form will appear minimized the next time the application runs. When the user restores the form, it should appear maximized. You accomplish this by checking restoreToMaximized in OnRestore(). If restoreToMaximized is true, you set the form's WindowState property to wsMaximized.
The new function FormClose() handles the OnClose event. In FormClose() you create an instance of WWindowPlacement that contains the data for the TMinMaxForm and saves it to your settings file.
You'll recall from last month's article that the main form is never really minimized. Rather, the VCL hides the main form and minimizes the application's hidden main window. Before writing place to your settings file, you need to check whether the application's main window, Application->Handle, is minimized. If it is, you set place.showCmd equal to SW_MINIMIZE. If the main window is minimized and your main form is maximized, you need to add the WPF_RESTORETOMAXIMIZED flag to place.flags.