View Issue Details

IDProjectCategoryView StatusLast Update
0012877LazarusLCLpublic2010-05-10 19:17
ReporterBart BroersmaAssigned ToPaul Ishenin 
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Platformi386OSWinMeOS VersionMS
Product Version0.9.27 (SVN)Product Build17968 
Target Version1.0.0Fixed in Version0.9.29 (SVN) 
Summary0012877: TCustomForm.ActiveControl fires DoExit before form is shown at programstart
DescriptionA TWinControl (or as far as I tested: TMemo, TEdit, TButton) that is the ActivControl on a form fires it's DoExit procedure at startup of the program, before the form is shown.
Steps To ReproducePlace a TWinControl on a form
In it's OnExit event do "something" (e.g. DebugLn('OnExit'); {needs LCLProc))
Compile, run
The "something" will be performed before the form is shown.

This is not the case in Delphi, so I consider this bug.
Additional InformationSomewhere in the process from creating the form to actually displaying it, it seems that the ActiveControl gets the WMKillFocus message. Why, is unclear to me.

This is potentially harmful if in the OnExitEvent of the control an exception can be raised (as is the case in TMaskEdit). In that case, the form will never be shown (and on Windows the user will not see the output the default exceptionhandler, because most of the times Windows apps are comoile as WinGUI).

I have only tested this on Win9x as of yet.
TagsNo tags attached.
Fixed in Revision25255
LazTarget1.0
WidgetsetWin32/Win64
Attached Files
  • onexitbug.ZIP (159,276 bytes)
  • onexitbugfix.patch (2,814 bytes)
    Index: lcl/include/customform.inc
    ===================================================================
    --- lcl/include/customform.inc	(revision 18350)
    +++ lcl/include/customform.inc	(working copy)
    @@ -403,41 +403,6 @@
       end;
       DebugLn('');
       {$ENDIF}
    -  if (fsShowing in FFormState) then exit;
    -  Include(FFormState, fsShowing);
    -  try
    -    // only fire event if reason is not some other window hide/showing etc.
    -    if Message.Status = 0 then
    -    begin
    -      if Message.Show then begin
    -        if (ActiveControl = nil) and (not (csDesigning in ComponentState))
    -        and (Parent=nil) then begin
    -          // automatically choose a control to focus
    -          {$IFDEF VerboseFocus}
    -          DebugLn('TCustomForm.WMShowWindow ',DbgSName(Self),' Set ActiveControl := ',DbgSName(FindDefaultForActiveControl));
    -          {$ENDIF}
    -          ActiveControl := FindDefaultForActiveControl;
    -        end;
    -        if ([csLoading,csDestroying]*ComponentState=[])
    -        and (Parent=nil) then begin
    -          NewFocusControl:=FActiveControl;
    -          if (NewFocusControl=nil)
    -          or (not NewFocusControl.CanFocus)
    -          then
    -            NewFocusControl:=Self;
    -          if NewFocusControl.HandleAllocated and NewFocusControl.IsVisible
    -          then begin
    -            {$IFDEF VerboseFocus}
    -            DebugLn('TCustomForm.WMShowWindow ',DbgSName(Self),' SetFocus NewFocusControl=',DbgSName(NewFocusControl),' FActiveControl=',DbgSName(FActiveControl));
    -            {$ENDIF}
    -            LCLIntf.SetFocus(NewFocusControl.Handle);
    -          end;
    -        end;
    -      end;
    -    end;
    -  finally
    -    Exclude(FFormState, fsShowing);
    -  end;
     end;
     
     {------------------------------------------------------------------------------
    @@ -1865,27 +1830,6 @@
         WidgetSet.AttachMenuToWindow(FMenu);
       end;
     
    -  // activate focus if visible
    -  if Visible then begin
    -    if (ActiveControl = nil) and (not (csDesigning in ComponentState))
    -    and (Parent=nil) then begin
    -      // automatically choose a control to focus
    -      {$IFDEF VerboseFocus}
    -      DebugLn('TCustomForm.CreateWnd ',DbgSName(Self),' Set ActiveControl := ',DbgSName(FindDefaultForActiveControl));
    -      {$ENDIF}
    -      ActiveControl := FindDefaultForActiveControl;
    -    end;
    -    if (Parent=nil)
    -    and (FActiveControl<>nil) and FActiveControl.HandleAllocated
    -    and FActiveControl.CanFocus
    -    and ([csLoading,csDestroying,csDesigning]*ComponentState=[]) then begin
    -      {$IFDEF VerboseFocus}
    -      DebugLn('TCustomForm.CreateWnd A ',DbgSName(Self),' FActiveControl=',DbgSName(FActiveControl));
    -      {$ENDIF}
    -      LCLIntf.SetFocus(FActiveControl.Handle);
    -    end;
    -  end;
    -  
       // set allow drop files
       TWSCustomFormClass(WidgetSetClass).SetAllowDropFiles(Self, FAllowDropFiles);
       // update icon
    
    onexitbugfix.patch (2,814 bytes)
  • OnExitBug.txt (9,476 bytes)
    TCustomForm.WndProc START [1] :TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    TCustomForm.WndProc END   [1] :TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    TCustomForm.WndProc START [2] Form1:TForm1 TheMessage.Msg = 45074 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    TCustomForm.WndProc END   [2] Form1:TForm1 TheMessage.Msg = 45074 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    TCustomForm.WndProc START [3] Form1:TForm1 TheMessage.Msg = 45100 .LParam = 00000001 .WParam = 00FC1598 .Result = 0000
    TCustomForm.WndProc END   [3] Form1:TForm1 TheMessage.Msg = 45100 .LParam = 00000001 .WParam = 00FC1598 .Result = 0000
    TCustomForm.WndProc START [4] Form1:TForm1 TheMessage.Msg = 45110 .LParam = 00000001 .WParam = 00FC1598 .Result = 0000
    TCustomForm.WndProc END   [4] Form1:TForm1 TheMessage.Msg = 45110 .LParam = 00000001 .WParam = 00FC1598 .Result = 0000
    
    TCustomForm.SetActiveControl START
    TCustomForm.SetActiveControl Form1:TForm1 FActive=False OldActiveControl=nil
     NewActiveControl=Edit1:TEdit
    TCustomForm.SetActiveControl END
    
    TCustomForm.Loaded Self=Form1:TForm1 FActiveControl=Edit1:TEdit
    TCustomForm.SetActiveControl START  //this one is called from within TCustomForm.Loaded
    TCustomForm.SetActiveControl Form1:TForm1 FActive=False OldActiveControl=nil
     NewActiveControl=Edit1:TEdit
    TCustomForm.SetActiveControl END
    
    TCustomForm.CreateWnd START TForm1
    TCustomForm.WndProc START [5] Form1:TForm1 TheMessage.Msg = 45085 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    TCustomForm.WndProc END   [5] Form1:TForm1 TheMessage.Msg = 45085 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    TCustomForm.CreateWnd END TForm1
    
    TCustomForm.WndProc START [6] Form1:TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000001 .Result = 0000
    TCustomForm.UpdateShowing A Form1:TForm1 FActiveControl=Edit1:TEdit
    
      TCustomForm.WndProc START [7] Form1:TForm1 TheMessage.Msg = LM_SETFOCUS .LParam = 58A70000 .WParam = 00000080 .Result = 0000
      TCustomForm.WndProc [7]Form1:TForm1 FActiveControl=Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 58A70000 .WParam = 00000080 .Result = 0000
      TCustomForm.WndProc A [7]Form1:TForm1 FActiveControl=Edit1:TEdit FocusHandle=00000A24 TheMessage.Msg = LM_SETFOCUS .LParam = 58A70000 .WParam = 00000080 .Result = 0000 (get focushandle)
      TCustomForm.WndProc [7]Form1:TForm1 FActiveControl=Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 58A70000 .WParam = 00000080 .Result = 0000 (redirect focus to child)
      //no .WndProc END for this instance of WndProc, because it exits from the procedure after the call to LCLIntf.SetFocus(FocusHandle);
    
        TCustomForm.WndProc START [8] Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000224 .WParam = 00000A24 .Result = 0000  //Note: A24 = FocusHandle
        TWinControl.WndProc LM_KillFocus Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000224 .WParam = 00000A24 .Result = 0000
        TCustomForm.WndProc END   [8] Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000224 .WParam = 00000A24 .Result = 0000
      TWinControl.WndProc LM_SetFocus Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 00000224 .WParam = 00000A24 .Result = 0001
      TCustomForm.SetFocusedControl Self=Form1:TForm1 Control=Edit1:TEdit Control.HandleAllocated=True
    
    > Edit1: OnEnter  /Form1.Edit1Enter
    
      TCustomForm.WndProc START [9] Form1:TForm1 TheMessage.Msg = LM_ACTIVATE .LParam = 02020000 .WParam = 00008784 .Result = 0000
      TCustomForm.WMActivate A Form1:TForm1 Msg.Active=True
      TCustomForm.SetWindowFocus Form1:TForm1 NewFocusControl=Edit1:TEdit HndAlloc=True
    
    > Form1: OnActivate  //Form1.FormActivate
    
      TCustomForm.WMActivate END Form1:TForm1 Msg.Active=True
      TCustomForm.WndProc END   [9] Form1:TForm1 TheMessage.Msg = LM_ACTIVATE .LParam = 02020000 .WParam = 00008784 .Result = 0000
    
      //This next message has not been handled by TCustomForm.WndProc, where does it originate from?
      TWinControl.WndProc LM_KillFocus Edit1:TEdit TheMessage.Msg = LM_KILLFOCUS .LParam = 00000000 .WParam = 00000A24 .Result = 0001
    
    > Edit1: OnExit  //Form1.Edit1Exit
    
      TWinControl.WndProc LM_SetFocus Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 00000000 .WParam = 00000A24 .Result = 0001
      TCustomForm.SetFocusedControl Self=Form1:TForm1 Control=Edit1:TEdit Control.HandleAllocated=True
    
    > Edit1: OnEnter  //Form1.Edit1Enter
    
    TCustomForm.WndProc END   [6] Form1:TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000001 .Result = 0000
    
    TCustomForm.WndProc START [10] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201FA4C .WParam = 00000000 .Result = 0000
    TCustomForm.WndProc END   [10] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201FA4C .WParam = 00000000 .Result = 0000
    
    TCustomForm.WndProc START [11] Form1:TForm1 TheMessage.Msg = 45081 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    
    > Form1: OnShow  Form1.FormShow
    
      TCustomForm.WndProc START [12] Form1:TForm1 TheMessage.Msg = 24 .LParam = 00000000 .WParam = 0000FFFF .Result = 0000
      TCustomForm.WMShowWindow A Form1:TForm1 fsShowing=False Msg.Show=True FActiveControl=Edit1:TEdit HandleAllocated=True
      TCustomForm.WndProc END   [12] Form1:TForm1 TheMessage.Msg = 24 .LParam = 00000000 .WParam = 0000FFFF .Result = 0000
    
      TCustomForm.WndProc START [13] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
      TCustomForm.WndProc END   [13] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
      
      TCustomForm.WndProc START [14] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201F67A .WParam = 00000000 .Result = 0000
      TCustomForm.WndProc END   [14] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201F67A .WParam = 00000000 .Result = 0000
    
      TCustomForm.WndProc START [15] Form1:TForm1 TheMessage.Msg = 5 .LParam = 01F0024D .WParam = 00000080 .Result = 0000
      TCustomForm.WndProc END   [15] Form1:TForm1 TheMessage.Msg = 5 .LParam = 01F0024D .WParam = 00000080 .Result = 0000
    TCustomForm.WndProc END   [11] Form1:TForm1 TheMessage.Msg = 45081 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    
    TCustomForm.UpdateShowing A Form1:TForm1 FActiveControl=Edit1:TEdit
    
    TCustomForm.WndProc START [16] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
    TCustomForm.WndProc END   [16] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0001
    
    TCustomForm.WndProc START [17] Form1:TForm1 TheMessage.Msg = 66592 .LParam = 0201F974 .WParam = 0000122E .Result = 5522B4
    TCustomForm.WndProc END   [17] Form1:TForm1 TheMessage.Msg = 66592 .LParam = 0201F974 .WParam = 0000122E .Result = 5522B4
    
    TCustomForm.WndProc START [18] Form1:TForm1 TheMessage.Msg = 66622 .LParam = 00F700BC .WParam = 00530E00 .Result = 0000
    TCustomForm.WndProc END   [18] Form1:TForm1 TheMessage.Msg = 66622 .LParam = 00F700BC .WParam = 00530E00 .Result = 0000
    
    TCustomForm.WndProc START [19] Form1:TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    
      TCustomForm.WndProc START [20] Form1:TForm1 TheMessage.Msg = 45081 .LParam = 00000000 .WParam = 00000000 .Result = 0000
      TCustomForm.WndProc END   [20] Form1:TForm1 TheMessage.Msg = 45081 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    
    TCustomForm.WndProc END   [20] Form1:TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000000 .Result = 0000
    
    TCustomForm.WndProc START [21] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
    TCustomForm.WndProc END   [21] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
    TWinControl.WndProc LM_KillFocus Edit1:TEdit TheMessage.Msg = LM_KILLFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0001
    
    TCustomForm.WndProc START [22] Form1:TForm1 TheMessage.Msg = LM_SETFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0000
    TCustomForm.WndProc [22]Form1:TForm1 FActiveControl=Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0000
    TWinControl.WndProc LM_SetFocus Form1:TForm1 TheMessage.Msg = LM_SETFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0000
    TCustomForm.WndProc END   [22] Form1:TForm1 TheMessage.Msg = LM_SETFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0000
    
    TCustomForm.WndProc START [23] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201F92C .WParam = 00000000 .Result = 0000
    TCustomForm.WndProc END   [23] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201F92C .WParam = 00000000 .Result = 0000
    
    TCustomForm.WndProc START [24] Form1:TForm1 TheMessage.Msg = 66624 .LParam = 00000047 .WParam = 58A7776A .Result = 0000
    TCustomForm.WndProc END   [24] Form1:TForm1 TheMessage.Msg = 66624 .LParam = 00000047 .WParam = 58A7776A .Result = 0000
    
    TCustomForm.WndProc START [25] Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000250 .WParam = 00000000 .Result = 0000
    TWinControl.WndProc LM_KillFocus Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000250 .WParam = 00000000 .Result = 0000
    TCustomForm.WndProc END   [25] Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000250 .WParam = 00000000 .Result = 0000
    
    TCustomForm.WndProc START [26] Form1:TForm1 TheMessage.Msg = 2 .LParam = 00000000 .WParam = 00000004 .Result = 0000
    TCustomForm.WndProc END   [26] Form1:TForm1 TheMessage.Msg = 2 .LParam = 00000000 .WParam = 00000004 .Result = 0000
    
    OnExitBug.txt (9,476 bytes)

Activities

Leslie Kaye

2009-01-05 14:14

reporter   ~0024191

Last edited: 2009-01-05 14:19

Bug exists for M$ XP and all win32/win64 (and other platforms?)

The problem is that LCLIntf.SetFocus(FActiveControl.Handle) is repeatedly called when creating and showing the Form. It should only be called after the form has been shown and when the form is activated (Active).

Test project file attached.

To fix the problem chop out the offending code in the customform.inc file for the TCustomForm.WMShowWindow and the TCustomForm.CreateWnd methods. It is corectly called in TCustomForm.SetWindowFocus so that form activation will then work as expected.

procedure TCustomForm.WMShowWindow(var message: TLMShowWindow);
var
  NewFocusControl: TWinControl;
begin
  {$IFDEF VerboseFocus}
  DbgOut('TCustomForm.WMShowWindow A ',Name,':'+ClassName+' fsShowing='+dbgs(fsShowing in FFormState)+' Msg.Show='+dbgs(Message.Show));
  if FActiveControl<>nil then begin
    DbgOut(' FActiveControl=',FActiveControl.Name,':',FActiveControl.ClassName,' HandleAllocated=',dbgs(FActiveControl.HandleAllocated));
  end else begin
    DbgOut(' FActiveControl=nil');
  end;
  DebugLn('');
  {$ENDIF}
 { // removed ljk *********************************************************
  if (fsShowing in FFormState) then exit;
  Include(FFormState, fsShowing);
  try
    // only fire event if reason is not some other window hide/showing etc.
    if Message.Status = 0 then
    begin
      if Message.Show then begin
        if (ActiveControl = nil) and (not (csDesigning in ComponentState))
        and (Parent=nil) then begin
          // automatically choose a control to focus
          {$IFDEF VerboseFocus}
          DebugLn('TCustomForm.WMShowWindow ',DbgSName(Self),' Set ActiveControl := ',DbgSName(FindDefaultForActiveControl));
          {$ENDIF}
          ActiveControl := FindDefaultForActiveControl;
        end;
        if ([csLoading,csDestroying]*ComponentState=[])
        and (Parent=nil) then begin
          NewFocusControl:=FActiveControl;
          if (NewFocusControl=nil)
          or (not NewFocusControl.CanFocus)
          then
            NewFocusControl:=Self;
          if NewFocusControl.HandleAllocated and NewFocusControl.IsVisible
          then begin
            {$IFDEF VerboseFocus}
            DebugLn('TCustomForm.WMShowWindow ',DbgSName(Self),' SetFocus NewFocusControl=',DbgSName(NewFocusControl),' FActiveControl=',DbgSName(FActiveControl));
            {$ENDIF}
            LCLIntf.SetFocus(NewFocusControl.Handle);
          end;
        end;
      end;
    end;
  finally
    Exclude(FFormState, fsShowing);
  end;
  } // end removed ljk *********************************************************
end;

procedure TCustomForm.CreateWnd;
begin
  //DebugLn('TCustomForm.CreateWnd START ',ClassName);
  FFormState:=FFormState-[fsBorderStyleChanged,fsFormStyleChanged];
  inherited CreateWnd;

  FPixelsPerInch:=0;

  Assert(False, 'Trace:[TCustomForm.CreateWnd] FMenu.HandleNeeded');
  if FMenu <> nil then
  begin
    FMenu.HandleNeeded;
    WidgetSet.AttachMenuToWindow(FMenu);
  end;
 { // removed ljk *********************************************************
  // activate focus if visible
  if Visible then begin
    if (ActiveControl = nil) and (not (csDesigning in ComponentState))
    and (Parent=nil) then begin
      // automatically choose a control to focus
      {$IFDEF VerboseFocus}
      DebugLn('TCustomForm.CreateWnd ',DbgSName(Self),' Set ActiveControl := ',DbgSName(FindDefaultForActiveControl));
      {$ENDIF}
      ActiveControl := FindDefaultForActiveControl;
    end;
    if (Parent=nil)
    and (FActiveControl<>nil) and FActiveControl.HandleAllocated
    and FActiveControl.CanFocus
    and ([csLoading,csDestroying,csDesigning]*ComponentState=[]) then begin
      {$IFDEF VerboseFocus}
      DebugLn('TCustomForm.CreateWnd A ',DbgSName(Self),' FActiveControl=',DbgSName(FActiveControl));
      {$ENDIF}
      LCLIntf.SetFocus(FActiveControl.Handle);
    end;
  end;
  } // end removed ljk *********************************************************
  
  // set allow drop files
  TWSCustomFormClass(WidgetSetClass).SetAllowDropFiles(Self, FAllowDropFiles);
  // update icon
  Perform(CM_ICONCHANGED, 0, 0);
  //DebugLn('TCustomForm.CreateWnd END ',ClassName);
end;

2009-01-05 14:14

 

onexitbug.ZIP (159,276 bytes)

Vincent Snijders

2009-01-19 14:03

manager   ~0024537

Leslie can you create a patch like subscribed in http://wiki.lazarus.freepascal.org/Creating_A_Patch

2009-01-20 09:32

 

onexitbugfix.patch (2,814 bytes)
Index: lcl/include/customform.inc
===================================================================
--- lcl/include/customform.inc	(revision 18350)
+++ lcl/include/customform.inc	(working copy)
@@ -403,41 +403,6 @@
   end;
   DebugLn('');
   {$ENDIF}
-  if (fsShowing in FFormState) then exit;
-  Include(FFormState, fsShowing);
-  try
-    // only fire event if reason is not some other window hide/showing etc.
-    if Message.Status = 0 then
-    begin
-      if Message.Show then begin
-        if (ActiveControl = nil) and (not (csDesigning in ComponentState))
-        and (Parent=nil) then begin
-          // automatically choose a control to focus
-          {$IFDEF VerboseFocus}
-          DebugLn('TCustomForm.WMShowWindow ',DbgSName(Self),' Set ActiveControl := ',DbgSName(FindDefaultForActiveControl));
-          {$ENDIF}
-          ActiveControl := FindDefaultForActiveControl;
-        end;
-        if ([csLoading,csDestroying]*ComponentState=[])
-        and (Parent=nil) then begin
-          NewFocusControl:=FActiveControl;
-          if (NewFocusControl=nil)
-          or (not NewFocusControl.CanFocus)
-          then
-            NewFocusControl:=Self;
-          if NewFocusControl.HandleAllocated and NewFocusControl.IsVisible
-          then begin
-            {$IFDEF VerboseFocus}
-            DebugLn('TCustomForm.WMShowWindow ',DbgSName(Self),' SetFocus NewFocusControl=',DbgSName(NewFocusControl),' FActiveControl=',DbgSName(FActiveControl));
-            {$ENDIF}
-            LCLIntf.SetFocus(NewFocusControl.Handle);
-          end;
-        end;
-      end;
-    end;
-  finally
-    Exclude(FFormState, fsShowing);
-  end;
 end;
 
 {------------------------------------------------------------------------------
@@ -1865,27 +1830,6 @@
     WidgetSet.AttachMenuToWindow(FMenu);
   end;
 
-  // activate focus if visible
-  if Visible then begin
-    if (ActiveControl = nil) and (not (csDesigning in ComponentState))
-    and (Parent=nil) then begin
-      // automatically choose a control to focus
-      {$IFDEF VerboseFocus}
-      DebugLn('TCustomForm.CreateWnd ',DbgSName(Self),' Set ActiveControl := ',DbgSName(FindDefaultForActiveControl));
-      {$ENDIF}
-      ActiveControl := FindDefaultForActiveControl;
-    end;
-    if (Parent=nil)
-    and (FActiveControl<>nil) and FActiveControl.HandleAllocated
-    and FActiveControl.CanFocus
-    and ([csLoading,csDestroying,csDesigning]*ComponentState=[]) then begin
-      {$IFDEF VerboseFocus}
-      DebugLn('TCustomForm.CreateWnd A ',DbgSName(Self),' FActiveControl=',DbgSName(FActiveControl));
-      {$ENDIF}
-      LCLIntf.SetFocus(FActiveControl.Handle);
-    end;
-  end;
-  
   // set allow drop files
   TWSCustomFormClass(WidgetSetClass).SetAllowDropFiles(Self, FAllowDropFiles);
   // update icon
onexitbugfix.patch (2,814 bytes)

Leslie Kaye

2009-01-20 09:33

reporter   ~0024572

patch file attached.

Zeljan Rikalo

2009-01-20 10:08

developer   ~0024576

I've just tested with qt on linux,win32 & mac , no harm with this patch (but also no difference :) ).Seem that it hurts win32 only :)

Vincent Snijders

2009-01-20 13:09

manager   ~0024584

The only question I have about this patch: is there always a control focused on the form, when the form is shown for the fist time?

Leslie Kaye

2009-01-21 13:23

reporter   ~0024611

Last edited: 2009-01-27 09:59

Yes Vincent. Activate is called immediately after Show. A control is focused by Activate.
The behaviour of Form.Activate is to focus the ActiveControl or if this is unassigned then Controls[0]. The behavior in Delphi is to only focus the ActiveControl if one is assigned, otherwise the form is focused until the user does some input.

Zeljan Rikalo

2010-03-10 11:56

developer   ~0035162

@Leslie can you retest with 0.9.29 >= r23911 ?

Bart Broersma

2010-03-14 14:33

developer   ~0035492

Tested with r23964 on Win9x (fpc 2.4.1)
If you set ActiveControl to (none) in OI, the first control you placed on the form will fire it's OnExit, otherwise ActiveControl fires OnExit.
So the behaviour I described originally still seems to persist.

Bart Broersma

2010-03-14 19:08

developer   ~0035508

FWIW: I tried to trace the messages in TCustomForm.WndProc and TWinControl.WndProc.

1 form, 1 TEdit that is ActiveControl (set at designtime).
See attached OnExitBug.txt for the output.
(I tried to indent the subsequent calls to TCustomForm.WndProc)

It seesm that, right after the LM_ACTIVATE message is handled by TCustomForm.WndProc a LM_KILLFOCUS is sent to Edit1.
This message is not handled (seen) by TCustomForm.WndProc.

Not sure if this experiment sheds any light at all on the problem ;-)

2010-03-14 19:09

 

OnExitBug.txt (9,476 bytes)
TCustomForm.WndProc START [1] :TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000000 .Result = 0000
TCustomForm.WndProc END   [1] :TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000000 .Result = 0000
TCustomForm.WndProc START [2] Form1:TForm1 TheMessage.Msg = 45074 .LParam = 00000000 .WParam = 00000000 .Result = 0000
TCustomForm.WndProc END   [2] Form1:TForm1 TheMessage.Msg = 45074 .LParam = 00000000 .WParam = 00000000 .Result = 0000
TCustomForm.WndProc START [3] Form1:TForm1 TheMessage.Msg = 45100 .LParam = 00000001 .WParam = 00FC1598 .Result = 0000
TCustomForm.WndProc END   [3] Form1:TForm1 TheMessage.Msg = 45100 .LParam = 00000001 .WParam = 00FC1598 .Result = 0000
TCustomForm.WndProc START [4] Form1:TForm1 TheMessage.Msg = 45110 .LParam = 00000001 .WParam = 00FC1598 .Result = 0000
TCustomForm.WndProc END   [4] Form1:TForm1 TheMessage.Msg = 45110 .LParam = 00000001 .WParam = 00FC1598 .Result = 0000

TCustomForm.SetActiveControl START
TCustomForm.SetActiveControl Form1:TForm1 FActive=False OldActiveControl=nil
 NewActiveControl=Edit1:TEdit
TCustomForm.SetActiveControl END

TCustomForm.Loaded Self=Form1:TForm1 FActiveControl=Edit1:TEdit
TCustomForm.SetActiveControl START  //this one is called from within TCustomForm.Loaded
TCustomForm.SetActiveControl Form1:TForm1 FActive=False OldActiveControl=nil
 NewActiveControl=Edit1:TEdit
TCustomForm.SetActiveControl END

TCustomForm.CreateWnd START TForm1
TCustomForm.WndProc START [5] Form1:TForm1 TheMessage.Msg = 45085 .LParam = 00000000 .WParam = 00000000 .Result = 0000
TCustomForm.WndProc END   [5] Form1:TForm1 TheMessage.Msg = 45085 .LParam = 00000000 .WParam = 00000000 .Result = 0000
TCustomForm.CreateWnd END TForm1

TCustomForm.WndProc START [6] Form1:TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000001 .Result = 0000
TCustomForm.UpdateShowing A Form1:TForm1 FActiveControl=Edit1:TEdit

  TCustomForm.WndProc START [7] Form1:TForm1 TheMessage.Msg = LM_SETFOCUS .LParam = 58A70000 .WParam = 00000080 .Result = 0000
  TCustomForm.WndProc [7]Form1:TForm1 FActiveControl=Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 58A70000 .WParam = 00000080 .Result = 0000
  TCustomForm.WndProc A [7]Form1:TForm1 FActiveControl=Edit1:TEdit FocusHandle=00000A24 TheMessage.Msg = LM_SETFOCUS .LParam = 58A70000 .WParam = 00000080 .Result = 0000 (get focushandle)
  TCustomForm.WndProc [7]Form1:TForm1 FActiveControl=Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 58A70000 .WParam = 00000080 .Result = 0000 (redirect focus to child)
  //no .WndProc END for this instance of WndProc, because it exits from the procedure after the call to LCLIntf.SetFocus(FocusHandle);

    TCustomForm.WndProc START [8] Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000224 .WParam = 00000A24 .Result = 0000  //Note: A24 = FocusHandle
    TWinControl.WndProc LM_KillFocus Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000224 .WParam = 00000A24 .Result = 0000
    TCustomForm.WndProc END   [8] Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000224 .WParam = 00000A24 .Result = 0000
  TWinControl.WndProc LM_SetFocus Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 00000224 .WParam = 00000A24 .Result = 0001
  TCustomForm.SetFocusedControl Self=Form1:TForm1 Control=Edit1:TEdit Control.HandleAllocated=True

> Edit1: OnEnter  /Form1.Edit1Enter

  TCustomForm.WndProc START [9] Form1:TForm1 TheMessage.Msg = LM_ACTIVATE .LParam = 02020000 .WParam = 00008784 .Result = 0000
  TCustomForm.WMActivate A Form1:TForm1 Msg.Active=True
  TCustomForm.SetWindowFocus Form1:TForm1 NewFocusControl=Edit1:TEdit HndAlloc=True

> Form1: OnActivate  //Form1.FormActivate

  TCustomForm.WMActivate END Form1:TForm1 Msg.Active=True
  TCustomForm.WndProc END   [9] Form1:TForm1 TheMessage.Msg = LM_ACTIVATE .LParam = 02020000 .WParam = 00008784 .Result = 0000

  //This next message has not been handled by TCustomForm.WndProc, where does it originate from?
  TWinControl.WndProc LM_KillFocus Edit1:TEdit TheMessage.Msg = LM_KILLFOCUS .LParam = 00000000 .WParam = 00000A24 .Result = 0001

> Edit1: OnExit  //Form1.Edit1Exit

  TWinControl.WndProc LM_SetFocus Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 00000000 .WParam = 00000A24 .Result = 0001
  TCustomForm.SetFocusedControl Self=Form1:TForm1 Control=Edit1:TEdit Control.HandleAllocated=True

> Edit1: OnEnter  //Form1.Edit1Enter

TCustomForm.WndProc END   [6] Form1:TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000001 .Result = 0000

TCustomForm.WndProc START [10] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201FA4C .WParam = 00000000 .Result = 0000
TCustomForm.WndProc END   [10] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201FA4C .WParam = 00000000 .Result = 0000

TCustomForm.WndProc START [11] Form1:TForm1 TheMessage.Msg = 45081 .LParam = 00000000 .WParam = 00000000 .Result = 0000

> Form1: OnShow  Form1.FormShow

  TCustomForm.WndProc START [12] Form1:TForm1 TheMessage.Msg = 24 .LParam = 00000000 .WParam = 0000FFFF .Result = 0000
  TCustomForm.WMShowWindow A Form1:TForm1 fsShowing=False Msg.Show=True FActiveControl=Edit1:TEdit HandleAllocated=True
  TCustomForm.WndProc END   [12] Form1:TForm1 TheMessage.Msg = 24 .LParam = 00000000 .WParam = 0000FFFF .Result = 0000

  TCustomForm.WndProc START [13] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
  TCustomForm.WndProc END   [13] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
  
  TCustomForm.WndProc START [14] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201F67A .WParam = 00000000 .Result = 0000
  TCustomForm.WndProc END   [14] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201F67A .WParam = 00000000 .Result = 0000

  TCustomForm.WndProc START [15] Form1:TForm1 TheMessage.Msg = 5 .LParam = 01F0024D .WParam = 00000080 .Result = 0000
  TCustomForm.WndProc END   [15] Form1:TForm1 TheMessage.Msg = 5 .LParam = 01F0024D .WParam = 00000080 .Result = 0000
TCustomForm.WndProc END   [11] Form1:TForm1 TheMessage.Msg = 45081 .LParam = 00000000 .WParam = 00000000 .Result = 0000

TCustomForm.UpdateShowing A Form1:TForm1 FActiveControl=Edit1:TEdit

TCustomForm.WndProc START [16] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
TCustomForm.WndProc END   [16] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0001

TCustomForm.WndProc START [17] Form1:TForm1 TheMessage.Msg = 66592 .LParam = 0201F974 .WParam = 0000122E .Result = 5522B4
TCustomForm.WndProc END   [17] Form1:TForm1 TheMessage.Msg = 66592 .LParam = 0201F974 .WParam = 0000122E .Result = 5522B4

TCustomForm.WndProc START [18] Form1:TForm1 TheMessage.Msg = 66622 .LParam = 00F700BC .WParam = 00530E00 .Result = 0000
TCustomForm.WndProc END   [18] Form1:TForm1 TheMessage.Msg = 66622 .LParam = 00F700BC .WParam = 00530E00 .Result = 0000

TCustomForm.WndProc START [19] Form1:TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000000 .Result = 0000

  TCustomForm.WndProc START [20] Form1:TForm1 TheMessage.Msg = 45081 .LParam = 00000000 .WParam = 00000000 .Result = 0000
  TCustomForm.WndProc END   [20] Form1:TForm1 TheMessage.Msg = 45081 .LParam = 00000000 .WParam = 00000000 .Result = 0000

TCustomForm.WndProc END   [20] Form1:TForm1 TheMessage.Msg = 45067 .LParam = 00000000 .WParam = 00000000 .Result = 0000

TCustomForm.WndProc START [21] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
TCustomForm.WndProc END   [21] Form1:TForm1 TheMessage.Msg = 20 .LParam = 00000000 .WParam = 0000122E .Result = 0000
TWinControl.WndProc LM_KillFocus Edit1:TEdit TheMessage.Msg = LM_KILLFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0001

TCustomForm.WndProc START [22] Form1:TForm1 TheMessage.Msg = LM_SETFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0000
TCustomForm.WndProc [22]Form1:TForm1 FActiveControl=Edit1:TEdit TheMessage.Msg = LM_SETFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0000
TWinControl.WndProc LM_SetFocus Form1:TForm1 TheMessage.Msg = LM_SETFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0000
TCustomForm.WndProc END   [22] Form1:TForm1 TheMessage.Msg = LM_SETFOCUS .LParam = 0201FF68 .WParam = 00000A48 .Result = 0000

TCustomForm.WndProc START [23] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201F92C .WParam = 00000000 .Result = 0000
TCustomForm.WndProc END   [23] Form1:TForm1 TheMessage.Msg = 71 .LParam = 0201F92C .WParam = 00000000 .Result = 0000

TCustomForm.WndProc START [24] Form1:TForm1 TheMessage.Msg = 66624 .LParam = 00000047 .WParam = 58A7776A .Result = 0000
TCustomForm.WndProc END   [24] Form1:TForm1 TheMessage.Msg = 66624 .LParam = 00000047 .WParam = 58A7776A .Result = 0000

TCustomForm.WndProc START [25] Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000250 .WParam = 00000000 .Result = 0000
TWinControl.WndProc LM_KillFocus Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000250 .WParam = 00000000 .Result = 0000
TCustomForm.WndProc END   [25] Form1:TForm1 TheMessage.Msg = LM_KILLFOCUS .LParam = 00000250 .WParam = 00000000 .Result = 0000

TCustomForm.WndProc START [26] Form1:TForm1 TheMessage.Msg = 2 .LParam = 00000000 .WParam = 00000004 .Result = 0000
TCustomForm.WndProc END   [26] Form1:TForm1 TheMessage.Msg = 2 .LParam = 00000000 .WParam = 00000004 .Result = 0000
OnExitBug.txt (9,476 bytes)

Paul Ishenin

2010-05-08 18:41

manager   ~0037367

Please test and close if ok.

Bart Broersma

2010-05-10 19:17

developer   ~0037421

Fixed. Thanks.

Issue History

Date Modified Username Field Change
2008-12-29 00:13 Bart Broersma New Issue
2008-12-29 00:13 Bart Broersma Widgetset => Win32
2009-01-05 14:14 Leslie Kaye Note Added: 0024191
2009-01-05 14:14 Leslie Kaye File Added: onexitbug.ZIP
2009-01-05 14:19 Leslie Kaye Note Edited: 0024191
2009-01-19 14:03 Vincent Snijders Note Added: 0024537
2009-01-19 14:03 Vincent Snijders LazTarget => 1.0
2009-01-19 14:03 Vincent Snijders Status new => acknowledged
2009-01-19 14:03 Vincent Snijders Target Version => 1.0.0
2009-01-20 09:32 Leslie Kaye File Added: onexitbugfix.patch
2009-01-20 09:33 Leslie Kaye Note Added: 0024572
2009-01-20 10:08 Zeljan Rikalo Note Added: 0024576
2009-01-20 13:09 Vincent Snijders Note Added: 0024584
2009-01-21 13:23 Leslie Kaye Note Added: 0024611
2009-01-27 09:59 Leslie Kaye Note Edited: 0024611
2010-03-10 11:56 Zeljan Rikalo Note Added: 0035162
2010-03-10 11:56 Zeljan Rikalo Status acknowledged => feedback
2010-03-14 14:33 Bart Broersma Note Added: 0035492
2010-03-14 19:08 Bart Broersma Note Added: 0035508
2010-03-14 19:09 Bart Broersma File Added: OnExitBug.txt
2010-05-08 18:41 Paul Ishenin Fixed in Revision => 25255
2010-05-08 18:41 Paul Ishenin Status feedback => resolved
2010-05-08 18:41 Paul Ishenin Fixed in Version => 0.9.29 (SVN)
2010-05-08 18:41 Paul Ishenin Resolution open => fixed
2010-05-08 18:41 Paul Ishenin Assigned To => Paul Ishenin
2010-05-08 18:41 Paul Ishenin Note Added: 0037367
2010-05-10 19:17 Bart Broersma Status resolved => closed
2010-05-10 19:17 Bart Broersma Note Added: 0037421