Recreating Application object during runtime lazarus / 62-General ---------------------------------------------------------------------- flowCRANE · 2020-04-24 18:14 Is it safe to dispose and create again the TApplication and assign new reference to the Application global object? I mean do something like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i // code generated by IDERequireDerivedFormResource := True; Application.Initialize();Application.CreateForm(TMainForm, MainForm);Application.Run(); // here are extra codeif SomethingHappened thenbegin  Application.Free();  Application := TApplication.Create(nil);   Application.Initialize();  Application.CreateForm(TOtherForm, OtherForm);  Application.Run();end; I just tested something like this and the control flow is correct, no memory leaks. However, when I run application under debugger (standard run by F9 key), I get SIGSEGV after closing the OtherForm (see attachment). So, it is safe and somewhere in the TApplication is a bug, or is this UB? I'm just curious. ---------------------------------------------------------------------- howardpc · 2020-04-24 18:33 I think you're the kind of rider who likes to shoot the horse you're riding as you try to jump onto another stallion as it gallops past. Exciting, but hardly safe. ---------------------------------------------------------------------- flowCRANE · 2020-04-24 18:47 I just like to know how different things works — nothing more. That's why I like to do some experiments, and in this case, I'm trying to show another form after closing the main form. But the structure of the TApplication prevent from this, because the Run method starts the main message loop, and when it finished, any other window cannot be shown, because it disappears immediately. That's why I came up with the idea to release Application, create it again, create another form using CreateForm method and call Run a second time. ---------------------------------------------------------------------- MarkMLl · 2020-04-24 18:58 Quote from: howardpc on April 24, 2020, 08:33:30 pmI think you're the kind of rider who likes to shoot the horse you're riding as you try to jump onto another stallion as it gallops past. Exciting, but hardly safe. If somebody wants to do that sort of thing he ought to be using Smalltalk for it. But even the canonical Smalltalk books drew the line at doing things like replacing the garbage collection algorithm in the middle of a running environment. @OP: let's assume for the moment that it should work. Presumably you can track that exception down using the Lazarus (or some other) debugger, is the behaviour consistent across all supported platforms or is it peculiar to the (rather elderly) version of Windows you claim to be running? Knowing the answer to that it /might/ be possible to "fix" it, but you'd have to produce a fairly convincing usage case... what are you trying to do, restart a checkpointed GUI app? MarkMLl ---------------------------------------------------------------------- 440bx · 2020-04-24 19:14 Quote from: furious programming on April 24, 2020, 08:47:56 pmBut the structure of the TApplication prevent from this, because the Run method starts the main message loop, and when it finished, any other window cannot be shown, because it disappears immediately. That's why I came up with the idea to release Application, create it again, create another form using CreateForm method and call Run a second time. First, I'm going to re-iterate the fact that when it comes to any part of LCL or VCL, I haven't got a clue (and I don't want one either.) With that out of the way, in Windows and with pure API, you can make the main thread use/service a different WndProc.  I have no idea what TAPPLICATION does but, instead of terminating it/freeing it, maybe it's possible to simply hand it a different main form and once that is done, get rid of the original form. Using the Windows API,  doing that is trivial.  You can even have an array of main windows.  The monitor is the limit. ---------------------------------------------------------------------- flowCRANE · 2020-04-24 19:17 Quote from: MarkMLl on April 24, 2020, 08:58:27 pm@OP: let's assume for the moment that it should work. Presumably you can track that exception down using the Lazarus (or some other) debugger, is the behaviour consistent across all supported platforms or is it peculiar to the (rather elderly) version of Windows you claim to be running? This exception comes from Application object, not from my code. I tested it on Windows XP (as in my signature) and only on this system, so I don't know if it will work on other platforms. QuoteKnowing the answer to that it /might/ be possible to "fix" it, but you'd have to produce a fairly convincing usage case... Maybe, but I'm just experimenting, not doing something important. I don't know if it should work and if somebody doing this, that's why I'm asking. Quotewhat are you trying to do, restart a checkpointed GUI app? use the main message loop many times,avoid creating all forms at the beginning (before loading data),keep the data and logic separated and independent from the forms,avoid using WinAPI (platform independent solution),avoid hiding main form and calling saving data methods in the main form's OnClose event,probably many more. ---------------------------------------------------------------------- marcov · 2020-04-24 19:21 (if application not configured run a setup "subapp", and if successful, run the whole app ?) ---------------------------------------------------------------------- flowCRANE · 2020-04-24 19:42 @marcov: my friend ask me today about implementation a logging system in the application, that shows appropriate main form depends on the user privileges (regular user or admin). It should work as follows: - start application by showing login form, - pass the user name and password, - if the user is administrator:     - create and show form for administrator (standard form for clicking) - otherwise     - create and show form for regular user (with touching support). Whole in the form of single application, without restarting it after logging. The problem is that the Application.Run must be called to show the login form, and after logging, the appropriate form should be created. Of course it's possible to hide the login form and show another, but it looks dirty. We treat it rather as a puzzle, a thought experiment. ---------------------------------------------------------------------- jwdietrich · 2020-04-24 20:04 furious programming: Your name seems to say it all... ---------------------------------------------------------------------- eljo · 2020-04-24 20:07 You set the login's form FormStyle to fsSplash that style is hard coded to never be made as the applications main form. You show it as modal after a successful login you continue to create the appropriate form as needed with out the existing application object ever gets killed. Or if you want to keep on using fsNormal style you simply set a global variable to false enclose the the basic lines of the projects source code in a repeat until not global is false and you keep calling application.initialize; create form; application.run; over and over again. The only reason to create the application object it self is to change the type of application ee from normal windows to a service application or something along those lines. ---------------------------------------------------------------------- lucamar · 2020-04-24 20:19 I was going to suggest using a Splash form too. Nevertheless, it is an interesting experiment; I'll try some things tomorrow (getting late here) and see which (if any) might work ... ---------------------------------------------------------------------- flowCRANE · 2020-04-24 21:00 Quote from: jwdietrich on April 24, 2020, 10:04:20 pmfurious programming: Your name seems to say it all...  I admit that I do not understand. Sometimes I am furious if something does not work, although it should, but in this case I have not been damned yet. Quote from: eljo on April 24, 2020, 10:07:59 pmYou set the login's form FormStyle to fsSplash that style is hard coded to never be made as the applications main form. Yes, it is a solution for the login form. Thank you! But... No, fsSplash forces the window border to be removed, and this should not be the case. QuoteThe only reason to create the application object it self is to change the type of application ee from normal windows to a service application or something along those lines. There may be much more reasons, so I was interested in this topic and I did some experiments. Still I'm trying several things and looking for reasons to use this approach. Despite the fact that currently it is not safe. ---------------------------------------------------------------------- eljo · 2020-04-24 21:38 Quote from: furious programming on April 24, 2020, 11:00:46 pmQuote from: jwdietrich on April 24, 2020, 10:04:20 pmfurious programming: Your name seems to say it all...  I admit that I do not understand. Sometimes I am furious if something does not work, although it should, but in this case I have not been damned yet. Quote from: eljo on April 24, 2020, 10:07:59 pmYou set the login's form FormStyle to fsSplash that style is hard coded to never be made as the applications main form. Yes, it is a solution for the login form. Thank you! But... QuoteThe only reason to create the application object it self is to change the type of application ee from normal windows to a service application or something along those lines. ...there may be much more reasons, so I was interested in this topic and I did some experiments. Still I'm trying several things and looking for reasons to use this approach. Despite the fact that currently it is not safe. You missed my point if you are going to use the same type of application there is no need to recreate the object. Simple reinitialize it and keep working as this is the first time. OR the initialization does not initialize some variable you are interested in? And yes there many reasons to restart an application and you can find even more I bet but why recreate the application object if the recreation does not change anything? Why waste the resources? ---------------------------------------------------------------------- flowCRANE · 2020-04-24 22:07 Jesus Christ, I just found the solution to reuse the Application object — for now for the logging system. Is seems to work — no exceptions, no memory leaks. I prepared a small test program to illustrate the solution (see the attachment). The main unit looks like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i begin  RequireDerivedFormResource := True;  Application.Scaled := True;   while UserID <> -1 do  begin    Application.Initialize();    Application.CreateForm(TLoginForm, LoginForm);    Application.Run();     if UserID <> -1 then    begin      Application.MainForm.Free();    Application.Initialize();       case UserID of        0: Application.CreateForm(TAdminForm, AdminForm);        1: Application.CreateForm(TUserForm, UserForm);      end;       Application.Run();      Application.MainForm.Free();    end;  end;end. For this to work, you must manually release Application.MainForm and then call Application.Initialize so that the main form is actually removed. But I still don't know what if, after logging in, many forms are created using Application.CreateForm — how to release them all? There are no method in the TApplication class to do this. ---------------------------------------------------------------------- eljo · 2020-04-24 22:52 Quote from: furious programming on April 25, 2020, 12:07:45 amFor this to work, you must manually release Application.MainForm and then call Application.Initialize so that the main form is actually removed. Actually just write an onClose event for the main form and set the CloseAction var parameter to caFree. That will free the form and since the application is registered to be called when the mainform is destroyed it will set the mainform property to nill. Quote from: furious programming on April 25, 2020, 12:07:45 amBut I still don't know what if, after logging in, many forms are created using Application.CreateForm — how to release them all? There are no method in the TApplication class to do this. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure FreeAllForms;var  Idx: Integer;begin  for Idx := Screen.FormCount -1 downto 0 do begin    if Screen.Forms[Idx] <> Application.MainForm then Screen.Forms[Idx].Free;  end;  Application.MainForm.Free;end; ---------------------------------------------------------------------- flowCRANE · 2020-04-24 23:43 Quote from: eljo on April 25, 2020, 12:52:03 amActually just write an onClose event for the main form and set the CloseAction var parameter to caFree. That will free the form and since the application is registered to be called when the mainform is destroyed it will set the mainform property to nill. I modified my test application and applied your tip, but it doesn't work. I generated OnClose events for all forms and assigned caFree to CloseAction, but the second call to the Run method ends immediately and LoginForm appears again. So the login form is not closed and must be freed by Application.MainForm.Free. Thanks for the code snippet. IMO something like this should be implemented in TApplication class. ---------------------------------------------------------------------- avra · 2020-04-25 11:00 Quote from: furious programming on April 24, 2020, 09:42:58 pmmy friend ask me today about implementation a logging system in the application, that shows appropriate main form depends on the user privileges (regular user or admin).No need for run time decision what main form is. It is much simpler to use one main form and 2 frames, and then in runtime decide which frame to show in main form. Depending on your use case, things might be even simpler then that if main form can be login dialogue. For logging you might want to look at https://github.com/blikblum/multilog. It can even log multiple threads to the same memo or file. ---------------------------------------------------------------------- flowCRANE · 2020-04-25 12:12 @avra: of course. However, the logging system was only a first example — there are a lot of different reasons to use Application multiple times, because why not? There will always be a use of such a scheme, for simple applications, but also for more sophisticated ones. ---------------------------------------------------------------------- PascalDragon · 2020-04-25 13:03 Quote from: furious programming on April 24, 2020, 08:14:08 pmI just tested something like this and the control flow is correct, no memory leaks. However, when I run application under debugger (standard run by F9 key), I get SIGSEGV after closing the OtherForm (see attachment). So, it is safe and somewhere in the TApplication is a bug, or is this UB? I'm just curious. No this is not safe as some code somewhere might have stored a reference to the TApplication instance or some code is still running inside the instance. If you simply free it the code will now access invalid memory. There is no way to solve this in a clean way. ---------------------------------------------------------------------- flowCRANE · 2020-04-25 15:14 Quote from: PascalDragon on April 25, 2020, 03:03:07 pmThere is no way to solve this in a clean way. I also talked to various Polish developers and one of them found a similar structure in a large project developed in Borland C++ Builder 2009, which he worked on: Code: C++  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Application->Initialize();Application->MainFormOnTaskBar = true;Application->CreateForm(__classid(TForm1), &Form1);Application->Run(); delete Application;Application = new TAppl ication(NULL);Application->Initialize();Application->MainFormOnTaskBar = true;Application->CreateForm(__classid(TForm2), &Form2);Application->Run(); So Borland apparently has the TApplication class written in such a way that it is actually independent, because the above code works fine even under the debugger. ---------------------------------------------------------------------- PascalDragon · 2020-04-25 15:30 Quote from: furious programming on April 25, 2020, 05:14:03 pmSo Borland apparently has the TApplication class written in such a way that it is actually independent, because the above code works fine even under the debugger. Even if Borland has written the TApplication class this way, as soon as a third party component stores a reference to the Application instance you're done for. Or if you have an application that uses threads and some thread function is inside the code of TApplication and wants to access a field after the application instance has been freed. ---------------------------------------------------------------------- flowCRANE · 2020-04-25 17:44 Quote from: PascalDragon on April 25, 2020, 05:30:10 pmEven if Borland has written the TApplication class this way, as soon as a third party component stores a reference to the Application instance you're done for. Of course, but storing reference to the global object, which exists during the whole session IMO has no sense. Well, unless you have several instances of this class. Ok, I'm just kidding. ---------------------------------------------------------------------- eljo · 2020-04-25 18:04 Quote from: PascalDragon on April 25, 2020, 05:30:10 pmQuote from: furious programming on April 25, 2020, 05:14:03 pmSo Borland apparently has the TApplication class written in such a way that it is actually independent, because the above code works fine even under the debugger. Even if Borland has written the TApplication class this way, as soon as a third party component stores a reference to the Application instance you're done for. Or if you have an application that uses threads and some thread function is inside the code of TApplication and wants to access a field after the application instance has been freed. yeah but then I'm responsible of being stupid and I have the chance to correct it. As things are now you are being stupid and I can't do anything about it. ---------------------------------------------------------------------- Martin_fr · 2020-04-25 18:33 Quote from: furious programming on April 25, 2020, 07:44:27 pmOf course, but storing reference to the global object, which exists during the whole session IMO has no sense. Well, unless you have several instances of this class. Not necessarily Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i MessageBoxProc := @Application.MessageBox;Totally plausible, if you have other ways to show messageboxes (to be selected, depending on whatever your code does). MessageBoxProc includes a reference to the object.