Rollo62 536 Posted August 9 (edited) Hi there, I was looking into @Uwe Raabe's CmonLib at Github and found here a global TUtilities record. type TUtilities = record private class var FAppName: string; FCompanyName: string; public ... class property AppName: string read FAppName write FAppName; class property CompanyName: string read FCompanyName write FCompanyName; end; I'm doing something similar, to provide the global CompanyName and AppName for various purposes, but best of all as early as possible in the process, for example for logging, or the like. Where doese CompanyName, AppName come from,. do you do this in code? What would be the best approach to provide such data for each project in a simple way, as early as possible from external data? - I would love to load such data from settings-file *.json, *ini, *yaml or whatever before compilation, unfortunately I think there is no option to do so. - Using ressources, deployment or the like to include such settings-file could work, but when analysing the content, its already much too late in the startup process. This might work only for certain cases, but not the most earliest. - Ok, I could use the IDE's global defines option manually, to add each of the desired data, but I really don't like to fumble in that nasty options dialog by hand. - Yes, I could use pre-build-events to manage that from a settings-file, but thats also only a half-cool solution. - And I could write my IDE expert doing this, perhaps there are already some available, but I like to have my IDE as clean from experts as possible. - I could use my own StartUpCopy.pas in the *.dpr, to define the earliest settings there, also a too clumsy solution. - Actually I simply added a local settings-include-file (*.inc) , with defining data as defines, and include this wherever needed, which is also not the best solution. Do you have similar needs and how do you do that, is there any cool solution I have not considered yet? Edited August 9 by Rollo62 Share this post Link to post
Uwe Raabe 2057 Posted August 9 1 hour ago, Rollo62 said: but best of all as early as possible in the process, I'd like to ask for more details about the term early in this context. Is this targeting the initialization sections of some units or more the code in the dpr begin end section? I admit that I often fell into the trap to put too much code into the initialization section, but I found that it heavily reduces the possibility to tweak the behavior based on a configuration or on a per project basis in case these units were used in several projects. That was a driving force for the invention of Cmon.Initializing. Quote Cmon.Initializing establishes a way to control initialize code for other units into the call to Application.Initialize. This allows to make adjustments before, which would be near to impossible if the initialize code would execute in the units initialization section. While it is still a long way to get all (probably better most of) my projects suffering from the above drawback, this approach is almost mandatory for new projects now. As a couple of units of CmonLib make use of this, one can find some hints for usage in the examples (still successfully procrastinating the CmonLib documentation, I know). Let me show a simple example from Cmon.Messaging.Dialogs.Vcl. This is how it would be written the old way: var Instance: TDlgMessageHandlerVcl = nil; initialization Instance := TDlgMessageHandlerVcl.Create; finalization Instance.Free; end. As a result, simply using this unit will create the instance, which registers itself catching the corresponding messages. And this how it looks making use of Cmon.Initializing: var Instance: TDlgMessageHandlerVcl = nil; { will be called in Application.Initialize after all other initialization code has been executed } procedure InitHandler; begin if TDlgMessage.AutoRegisterHandler and TDlgMessageHandlerVcl.AutoRegisterHandler then Instance := TDlgMessageHandlerVcl.Create; end; initialization TDlgMessageHandlerVcl.AutoRegisterHandler := True; TInitialize.AddInitProc(InitHandler); finalization Instance.Free; end. Now creating the instance will take place during Application.Initialize, which allows us to write some code tweak the behavior. As of my personal preference I put all this pre-initialize code in s similar named procedure, called immediately before: program DialogsDemoVCL; uses Vcl.Forms, Cmon.Messaging.Dialogs.Vcl, Main.VclForm in 'Main.VclForm.pas' {MainForm}, Utilities in 'Utilities.pas'; {$R *.res} procedure PreInitialize; begin { Per default using Cmon.Messaging.Dialogs.Vcl will automatically register the containing message handler during Application.Initialize. To optionally disable auto registering of all DlgMessage handlers this is one place to do. You need to add Cmon.Messaging to the uses to make it compile. } // TDlgMessage.AutoRegisterHandler := False; { You can as well disable automatic registration of indivudual handlers. That implies to leave the corresponding setting above at True of course. } // TDlgMessageHandlerVcl.AutoRegisterHandler := False; end; begin PreInitialize; Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TMainForm, MainForm); Application.Run; end. You can find a similar approach in Cmon.Messaging.Logging.TextFile Share this post Link to post
Kas Ob. 121 Posted August 9 3 hours ago, Rollo62 said: as early as possible in the process, Something like this set filename=MyAppConsts.pas @echo on echo building %filename% @echo off (echo unit Unit1;& echo.& echo interface& echo.& echo const) > %filename% echo APPLICATION_APP_NAME = 'MyApp';>> %filename% echo APPLICATION_COMPANY_NAME = 'MyCompany';>> %filename% (echo.& echo implementation& echo.& echo end.) >> %filename% @echo on @echo done building %filename% #exit 0 the result a file "MyAppConsts.pas" unit Unit1; interface const APPLICATION_APP_NAME = 'MyApp'; APPLICATION_COMPANY_NAME = 'MyCompany'; implementation end. there is no earlier than that ! Share this post Link to post
Rollo62 536 Posted August 9 (edited) @Uwe Raabe Very interesting, I will look into that. Its perhaps not needed to be before unit initializations, but yes, if that is possible, then its OK too. I have two main topics currently for that, "Logging" and "Setup file access". By the latter I mean, to load variable settings from files, not at compile time, but at runtime. For this I could see sometimes the need to access that as soon as possible, while the "FileNamesAndPaths" might not be setup yet. Of course I can hardcode the fractions or subfolders in the "FileNamesAndPaths", but exactly this I want to avoid. I usually avoid initialization sections and try to make such lazy app initializations only in the FormShow event, to stay as mobile friendly, as possible. But that doesn't always work. At least a handful of fixed constants would be good to be store outside the IDE project, to easy handle it. Regarding your proposal, my thought was to encapsule this in its own StartUp unit: uses My.StartUp, Vcl.Forms, Main.VclForm in 'Main.VclForm.pas' {MainForm}; {$R *.res} begin TMyStartUp.PreInitialize; Application.Initialize; ... But again, if needed earlier it might fail. @Kas Ob. I'm not getting your point 100%, but assume you mean an Pre-Build-Event calling an batch file. Yes, that would be possible, but again, I have to setup all this in the IDE before. Or do you mean there is the possibility in the Tools/Options or else, to set such event globally, one for all projects? Yes, maybe creating my own initial project in the repository is an option too, but this I would need to maintain too, with each IDE update. Edited August 9 by Rollo62 Share this post Link to post
Kas Ob. 121 Posted August 9 46 minutes ago, Rollo62 said: Or do you mean there is the possibility in the Tools/Options or else, to set such event globally, one for all projects? Well that is possible, but it might be an unneeded extra work. What i meant is something like this Just include the batch file which can have relative path, also it can take a parameter for the output path, even the name of the output file. and from the dproj file <PropertyGroup Condition="'$(Base)'!=''"> <PostBuildEvent><![CDATA[BuildConst.bat $(PostBuildEvent)]]></PostBuildEvent> Also i did always prefer using the inc files in place for naming and versioning, over batch files, thus i have their content in the project and in the EXE description ... 1 Share this post Link to post