Why is the code in any part of the finalization section of the package not executed when shutting down?

I have an application that uses statically linked runtime packages, as well as development-time packages that use them. For some reason, the code in some section of the section completion section does not run at runtime (I cannot tell when this happened).

finalization ShowMessage('Goodbye'); end. 

Disabling Delphi down shows a message, but not when my application shuts down. It gets weirder if I set a breakpoint on ShowMessage, it breaks there, but doesn't execute the line. If there are several lines in the finalization, the debugger stops in the first line, does not execute it, and then jumps to the end.

 procedure ProcOne; begin SomeObject.Free; // Debugger does not enter or stop here SomeObject := nil; end; finalization ProcOne; // Debugger stops here, doesn't execute, jumps to "end." ProcTwo; // Every line has a blue dot ShowMessage('Bye'); end. 

The call stack at the ProcOne checkpoint displays @ Halt0 => FinalizeUnits => MyPackage.MyUnit.Finalization.

If I include the device in an application that does not use packages, everything is done correctly.

Does anyone have an idea what could be causing this?

EDIT:

Thanks to Allen Bauer's remark pointing in the right direction, I managed to isolate the problem. It seems that the problem occurs if the application is built with a run-time package, and then dynamically loads another package, which also refers to this package and block.

I created a test project that demonstrates the problem: TestFinalization

Does anyone know the reason for this and / or the workaround? Usually you will not notice that your finalization is not performed until you notice that external resources are not cleared.

+4
source share
1 answer

Before disconnecting, make sure that you call UnloadPackage for each dynamically loaded package. If you simply call UnloadLibrary (or simply rely on the OS to unload them), then the final steps for this will not be called units in this package and all units from other packages. Initialization and finalization are carried out using a reference counting system, because in the face of packages with diamond loading it is impossible to know which units will be initialized and when. Only when you balanced the finalization calls with the initialization calls will the last finalization call actually execute the code block in the finalization section. Similarly, only the first call to the initialization section will actually execute a block of code.

Initialization / finalization is performed using the table generated by the compiler for this module. When you create exe or dll related to packages, this table contains links to all used units, even those of related packages. Note that only actual links are actually initialized. IOW, if you have 100 units in PackageA, and exe refers to only one of them, then only that block and any units that it uses will be initialized.

For dynamically loaded packages, there is no way to know which units will actually be used, so the compiler generates an init / finit table as if each unit was initialized. This table is not processed when loading a package during a call to LoadLibrary, but is processed by calling a special export named Initialize (). The LoadPackage function ensures that this function is called. This table provides only the initialization of all blocks in the boot package. Only those parts that really relate to any other package are initialized, similar to the exe / dll case that I mentioned above. UnloadPackge does the opposite and invokes a special export of Finalize () before calling UnloadLibrary ().

Finally, if you make changes to the use lists of any packed units and only recompile the package, you can confuse running cases where initialization / finalization may not be called, even if your units in a particular package correctly "use" each other. This is because init / finit is controlled by the load module, not internally. Only if the package is explicitly loaded using LoadPackage, each unit in this package (and only this package) will be initialized / terminated.

+8
source

All Articles