shineworld 73 Posted December 21, 2020 (edited) Hi all, I'm moving a big project, about 1.500.000 code lines from Delphi 2006 to Syndey, but I'm in trouble with how Syndey destroys objects in program termination. Sample: A very Dummy application with 1 form without any other code than a comment in TForm3.FormDestory to place a breakpoint: unit Unit3; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; type TForm3 = class(TForm) procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form3: TForm3; implementation {$R *.dfm} procedure TForm3.FormDestroy(Sender: TObject); begin // < placed breakpoint here!!! // end; end. A very simple project with a string assignment to catch the main flow (in S := ''; ) after Application Run: program Project2; uses Vcl.Forms, Unit3 in 'Unit3.pas' {Form3}; {$R *.res} var S: string; begin S := 'asdfasdf'; Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TForm3, Form3); Application.Run; S := ''; ; << placed break point here end. In BDS 2006 if I run this code and exit program first break at Form3.FormDestroy, then breaks in main at S := ''. RIGHT ! In Sydney first, break in the main at S := '', then goes to Form3.FormDestry. What has changed so much the Delphi behavior? if I add a Form3.DoubleClick event with Application.Terminate I got also an environment error: [50164E97]{rtl270.bpl } System.Classes.TList.Get (Line 4972, "System.Classes.pas" + 2) + $A [50EBFC4B]{vcl270.bpl } Vcl.AppEvnts.TMultiCaster.GetAppEvents (Line 657, "Vcl.AppEvnts.pas" + 1) + $B [50EBF60E]{vcl270.bpl } Vcl.AppEvnts.TMultiCaster.DoActivate (Line 425, "Vcl.AppEvnts.pas" + 5) + $9 [50E5A73F]{vcl270.bpl } Vcl.Forms.TApplication.WndProc (Line 10617, "Vcl.Forms.pas" + 126) + $C [50181450]{rtl270.bpl } System.Classes.StdWndProc (Line 18021, "System.Classes.pas" + 😎 + $0 [50E5B23F]{vcl270.bpl } Vcl.Forms.TApplication.ProcessMessage (Line 11028, "Vcl.Forms.pas" + 23) + $1 [50E5B282]{vcl270.bpl } Vcl.Forms.TApplication.HandleMessage (Line 11058, "Vcl.Forms.pas" + 1) + $4 [50E5B5B5]{vcl270.bpl } Vcl.Forms.TApplication.Run (Line 11196, "Vcl.Forms.pas" + 26) + $3 [0051E178]{bds.exe } bds.bds (Line 222, "" + 13) + $2 😞 test.7z Edited December 21, 2020 by shineworld Share this post Link to post
Guest Posted December 21, 2020 (edited) my test in RAD 10.3.3 Arch and RAD 10.4.1 Arch = same behavior! BUT none error! Application.Terminate; // Debug stop 1 S := ''; // Debug stop 2 lStopHere := ''; // Debug stop 3 // DPR file Application.Run; S := ''; // Debug stop 2 // unit TForm {$R *.dfm} procedure TForm3.FormDblClick(Sender: TObject); begin Application.Terminate; // Debug stop 1 end; procedure TForm3.FormDestroy(Sender: TObject); var lStopHere:string; begin lStopHere := ''; // Debug stop 3 end; I don't know if you know, but a "FORM" is in an eternal loop when running, that is, inside a loop and the system is attentive to any message to process. Thus, when the "RUN" loses focus, the variable "S" will be processed, and, the system seeing that there are other tasks before destroying the form, it continues to execute the other messages ... Quote unit Vcl.Forms.pas, line 10888 .... REPEAT looping Quote Call Terminate to end the application programmatically. By calling Terminate rather than freeing the application object, you allow the application to shut down in an orderly fashion. Terminate calls the Windows API PostQuitMessage function to perform an orderly shutdown of the application. Terminate is not immediate. Terminate is called automatically on a WM_QUIT message and when the main form closes. NOTE: It reminds me of when I used "Clipper Summer 87", and, we had to use "WHILE" to show screens or a pseudo-DBGrid try this: // DPR file Application.Run; S := ''; // Debug DONT stop here // unit FORM procedure TForm3.FormDblClick(Sender: TObject); begin Halt; //Application.Terminate; // Debug stop 1 end; procedure TForm3.FormDestroy(Sender: TObject); var lStopHere:string; begin lStopHere := ''; // Debug stop 2 end; Quote HALT( code ); Initiates the abnormal termination of a program. Halt performs an abnormal termination of a program and returns to the operating system. To perform a normal termination of a Delphi application, call the Terminate method on the global Application object. If the application does not use a unit that provides an Application object, call the Exit procedure from the main Program block. Exitcode is an optional expression that specifies an exit code for the program hug Edited December 21, 2020 by Guest Share this post Link to post
nglthach 23 Posted December 21, 2020 You should take a look on AddExitProc: http://docwiki.embarcadero.com/Libraries/Sydney/en/System.SysUtils.AddExitProc procedure DoOnExit; var s: string; begin s := ''; // Set a breakpoint here end; begin AddExitProc(DoOnExit); // Put this line before Application.Run Application.Initialize; Application.DefaultFont.Assign(Screen.MenuFont); Application.MainFormOnTaskbar := True; Application.CreateForm(TMainForm, MainForm); Application.Run; end; Share this post Link to post
Guest Posted December 21, 2020 (edited) try add that 2 sections: if all unit using it, then, we have "chain" of executions same if using "HALT( code )" procedure initialization lStopHereToo := ''; // first of all finalization lStopHereToo := ''; // last of all Edited December 21, 2020 by Guest Share this post Link to post
Attila Kovacs 631 Posted December 21, 2020 2 hours ago, shineworld said: In BDS 2006 if I run this code and exit program first break at Form3.FormDestroy, then breaks in main at S := ''. RIGHT ! I don't believe you! 1 Share this post Link to post
David Heffernan 2353 Posted December 21, 2020 8 minutes ago, Attila Kovacs said: I don't believe you! Agreed. Why would the main form destroy itself before the code in the dpr completes? Share this post Link to post
shineworld 73 Posted December 21, 2020 You are right, I've checked again with an empty program in BDS2006 and worked as you had suggested. But if I debug my big program the behavior is different, so there something that has changed the rules in my code! I need to check it... Thank you for the suggestion about AddExitProc(DoOnExit); // Put this line before Application.Run I don't know it before... Share this post Link to post
Remy Lebeau 1436 Posted December 22, 2020 (edited) 14 hours ago, shineworld said: In BDS 2006 if I run this code and exit program first break at Form3.FormDestroy, then breaks in main at S := ''. RIGHT ! That has NEVER been true, in ANY version... Quote In Sydney first, break in the main at S := '', then goes to Form3.FormDestry. ... THAT is the correct behavior, in ALL versions. Auto-created Forms, like the MainForm, are owned by the Application object. They are not destroyed until the Application object is destroyed, which is after the main DPR code is done running and the VCL is being cleaned up. Quote What has changed so much the Delphi behavior? Nothing has changed. So the chance has to be something in your own code that is destroying the MainForm before the Application object is destroyed. Edited December 22, 2020 by Remy Lebeau 1 Share this post Link to post
shineworld 73 Posted December 22, 2020 @Remy Lebeau you are right, just had to do with my project which is not good structured and something happens in the phase of destroying objects (I guess because I'm waiting for some thread stops). I've to change where objects are created and how they are freed. Surely I've mistake some important thing 🙂 https://youtu.be/MNppXiVvDZI Share this post Link to post
shineworld 73 Posted December 29, 2020 I hereby want to thank all of you for the answers. I misunderstood the mechanism of creating and destroying objects in Delphi, especially when forms are destroyed. So far the code has worked but only because an unclosed thread changed the cards in play. Thank you AGAIN for your time! Share this post Link to post