The Objective:
-----------------
WHENEVER WE CLOSE A FORM, we want to write its placement position data to the INI file.
The Situation:
-----------------
1. Each of my app's forms has a system menu at the right side of the title bar that contains buttons for: minimize, maximize, and CLOSE ("X")
2. Each form has a command button named Stop, Exit, or Quit with a Clicked routine like this:
Function FRMINPUT_CMDQUIT_BN_CLICKED ( _
ControlIndex As Long, _ ' index in Control Array
hWndForm As Dword, _ ' handle of Form
hWndControl As Dword, _ ' handle of Control
idButtonControl As Long _ ' identifier of button
) As Long
FF_CloseForm hWndForm
End Function
3. Each form has a CLOSE routine that writes the WINDOWPLACEMENT values to the .INI file:
Function FRMINPUT_WM_CLOSE ( _
hWndForm As Dword _ ' handle of Form
) As Long
WriteWindowPlacementToIniFile (hWndForm, "frmInput")
End Function
WHAT HAPPENS:
-----------------
A. If I close the form using the system X button, the INI data is written.
B. If I close the form using the QUIT button, the INI data is NOT written.
The Questions:
-----------------
Why the difference? Doesn't the FF_CloseForm trigger FRMINPUT_WM_CLOSE ?
If not, why not? ("Enquiring minds want to know...")
***** More importantly: How do I get the desired behavior?
Thanks,
-John
P.S. I tried using the _DESTROY event instead of the _CLOSE event, and I had all kinds of problems with phantom form images hanging around and not going away for a long time...
Hi John,
By design, the clicking on the "X" close button, pressing Alt+F4 or selecting "Close" from the sytem menu generates a %WM_SYSCOMMAND message. FireFly forwards this message to WM_CLOSE for convenience for the programmer in order to allow the close to continue or stop it by returning %TRUE from that message handler.
On the other hand, FF_CloseForm does not forward a WM_CLOSE message. This is also by design. When someone invokes FF_CloseForm, FireFly naturally assumes that the programmer wants to close the form. You can see exactly what FireFly does by looking at the FF_CloseForm source that is located in your project's *_UTILITY.INC generated code.
To solve your problem you may want to keep your INI saving function call in the WM_CLOSE message and create a second function that wraps the FF_CloseForm with your INI save function call. For example, when "Exit" is pressed, instead of calling FF_CloseForm you would call something like CloseFormSaveINI. That function would look like the following:
Function CloseFormSaveINI( ByVal hWndForm As DWord, ByVal sFormName As String ) As Long
WriteWindowPlacementToIniFile hWndForm, sFormName
Function = FF_CloseForm hWndForm
End Function
Hope this helps a little bit. :)
Helps a LOT! And is no big deal to change. Biggest adjustment is in my
original presumptions. Thanks for the specific and clear explanation.
Lots of good little nuggets in your reply, like what fires when and why, and checking *_UTILITY.INC...
This could be useful to others - might I suggest it be flagged for inclusion
into the online help?
-John
That brings a question to my mind.
What about WM_Destroy? Does this get triggered when you do a
FF_CloseForm? How about on the WM_Close?
The reason being that I put the TRM file closes in the WM_Destroy function
so that it would be done no matter how the user exited the program and
didn't need to be called from multiple locations. ( meaning much simpler
for me )
Do I need to re-think that logic?
Yes, FF_CloseForm does call WM_DESTROY.
Sub FF_CloseForm (ByVal hwndForm As Dword, Optional ByVal ReturnValue As Long)
If IsWindow( hWndForm ) = %FALSE Then Exit Sub
Local ff As FF_DATA Ptr
ff = GetProp(hwndForm, "FF_PTR")
If ff Then
If @ff.IsModal Then
' Reset the focus back to the parent of the modal form.
' Enable Mouse and keyboard input for the Parent Form
Call EnableWindow(@ff.ModalParent, %TRUE)
Call SetActiveWindow(@ff.ModalParent)
End If
End If
'Destroy the window. This will delete any font objects and release
'the memory held by the type structure.
DestroyWindow hWndForm
'Set the value that will be returned to the calling program.
App.ReturnValue = ReturnValue
End Sub
Likewise, if you do not cancel WM_CLOSE then Windows will automatically send a WM_DESTROY message.