Ctl32 FormState

ctl32_formstate

Links
MSDN GetWindowPlacement Function
MSDN SetWindowPlacement Function
MSDN WINDOWPLACEMENT Structure
MSDN About Multiple Display Monitors

Overview
ctl32_formstate is a class that can be dropped in any VFP form, or used with the _Screen. This class performs the following actions:
  • Saves in the Windows registry the form position, size, and state (minimized, normal, maximized) when the form is closed.
  • Reads from the Windows registry the saved data and restores the form position/size/state when the form is instantiated.
  • Adjusts the form position/size/state taking into account changes in size and dimensions of its container (The VFP Screen, a Top Level Form, the Windows desktop, the Windows virtual screen).
  • The way the position/size/state is restored can be controlled by class properties.
It can be used with standard forms, top level forms, or the VFP _Screen. It supports multiple monitor configurations.
There is no need to change any of the default properties of the class, it will work right out of the box. For those that want more, a set of properties control how the class behaves.

Class Hierarchy
ctl32
ctl32_formstate

Properties, Events & Methods
You can find a complete reference to all properties, events & methods in the class help file.


Pictures
No pictures available.

Quick Start
If you want to use ctl32_formstate on a form, drag the ctl32_formstate control from the Project Manager window and drop it into the Form. You can only have ONE instance of the class in a form.

Sample Project
See the sample project included in the Sample folder to see examples of how to use the control and what can be done.

BindEvent
This class does Bindevents to the following windows and window messages:
NONE
If you hook to those same window/event pairs in some other part of your code, recall what the Help file says:
"When binding to Windows message (Win Msg) events, only one hWnd to Windows message pairing can exist."
Icon files used should be included in the project. There is no need to redistribute the icon files to end users. The icon files should contain one 16x16 256 color icon, that is used to display in the statusbar.

Bugs

Known Problems

Change Log

Under The Hood
This attempts to briefly describe how this class works, basically it just uses the Windows API functions GetWindowPlacement and SetWindowPlacement on steroids.
Init event
In the class Init event, the required dll functions of the Windows API are declared, some objects and properties are added to the control. Then, if the parent form of the control is the VFP _Screen, nothing else happens, until ctlRestoreState is called. This is done this way so the programmer can assign non default values to the ctl32_formstate control before the state restoring is done for the main VFP Screen. For best results and less flickering, the _Screen should start hidden via a SCREEN=OFF command in config.fpw
If the form is a standard form or a top level form, the _BindEvents method is called, this will bind the _EventHandlerFormShow0 and  _EventHandlerFormShow1 to the Show event of the form, one will execute before the form Show event, the other after it.
 _EventHandlerFormShow0 method
This method just unbinds itself and then calls _StateRestore0
_EventHandlerFormShow1 method
This method just unbinds itself and then calls _StateRestore1
ctlRestoreState method
This method just calls _StateRestore0 then it makes the VFP Screen visible and then calls _StateRestore1
_StateRestore0 method
Checks the values of ctlRestoreStyle and ctlRestoreInIDE to see if it should run, then saves the name of the form to use it in the registry operations as a value name, and then attempts to restore the form postion/size/state data from the registry. If there is no saved data, it will use the actual form position/size/state as default data, by calling the GetWindowPlacement Window API function
The it moves the form out of view to help reduce flicker.
_StateRestore1 method
This is where 90% of the action takes place. Basically we start with a WindowPlacement structure, obtained from the registry or by calling the GetWindowPlacement Window API function if there was no registry data.
This WindowPlacement structure has the information about the position/size/state of the form, and in this method its values are changed depending on the values of some properties like:
ctlAutoCenter, ctlHideMinimized, ctlRestoreMaxState, ctlRestoreMinPosition, ctlRestoreMinState, ctlRestoreStyle, ctlRestoreToPrimary, ctlWindowState
Also some other things are considerd, like number of monitors, if the form is maximized, etc. After the WindowPlacement structure is changed, it is sent to the form window via a SetWindowPlacement API call.
Since I found some strange bugs in the use of SetWindowPlacement for top level forms, I had to work around them, for example, a maximized top level form in the primary monitor of a two monitor setup got a maximized width and height of around 9000 pixels, so I just maximize the form after calling SetWindowPlacement. This produces some flicker when restoring a maximized top level form in machines with more than one monitor.
Also, SetWindowPlacement would always place a maximized form in the primary monitor, instead of the monitor where the restored form is shown, had to work around that too.
What seemed like millions of other glitches and strange and unexplained results where also a hurdle. I tried to keep the flickering to a minimum, but before being too critical, try comparing the class to the way other programs and even Windows programs behave when restoring a form position/size/state.
That is all there is to restoring the form position/size/state, all that is left now is to save the position/size/state of the form when the form closes:
Destroy event
In the Destroy event, the _StateSave method is called.
_StateSave method
Here we save the actual window position/size/state in the registry, by calling GetWindowPlacement and storing the WindowPlacement structure in the registry.

Saving data in the Windows registry
An oRegistry object is added in the class init, based in the _Registry class of ctl32_Common.vcx. This object will handle registry reading/writing. By default, the form position/size/state data will be saved in the registry in the following key:


"vfp9" is the name of the executable, and is determined by using:
Juststem(Application.ServerName)
So in the case of the VFP IDE it will be "vfp9". If your exe name is "myprogram.exe" then the registry key will be "HKEY_CURRENT_USER\Software\myprogram\FormState"
FormState is determined by the ctlRegEntryName property of the ctl32_FormState class, so this can be changed with easy if you don't like the name.
And form2, form3, toplevelform1, etc. are determined by the Name property of the form, so each form must have an unique name assigned to it. (If you can think of a better way to uniquely identify each form, I am open to suggestions)
Since the form name property is read by the class just before the form show event, you have time to change it to a suitable value in the form Init for example.
The data saved is of type REG_BINARY and it is just the data provided by the GetWindowPlacement Window API function, a WindowPlacement structure of 44 bytes, that contains all the information of the form position/size/state:
typedef struct _WINDOWPLACEMENT {
    UINT length;
    UINT flags;
    UINT showCmd;
    POINT ptMinPosition;
    POINT ptMaxPosition;
    RECT rcNormalPosition;
} WINDOWPLACEMENT;


 

No comments:

Post a Comment