form_WM_CLOSE vs FF_CloseForm

Started by John Montenigro, November 07, 2006, 10:12:00 PM

Previous topic - Next topic

John Montenigro

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...

TechSupport

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.  :)

John Montenigro

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

Paul D. Elliott

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?

TechSupport

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.