Everything alright so far you say? Actually not because of some simple fact: initialization parts of units inside of packages might not be executed when the package gets loaded but when a binary gets loaded that uses it. Not a problem? Not really unless your initialization and finalization parts are doing the correct thing.
Let's take a look at some unit that might be part of a package:
unit Foo; interface procedure Bar; implementation uses Contrns; var list: TObjectList; procedure Bar; begin if not Assigned(list) then list := TObjectList.Create; // do something with list end; initialization finalization list.Free; end.
What do you think happens when you load a DLL that uses this unit given that no other module has used this unit yet? Yep, the initialization part gets executed. Since we are using lazy initialization here there is nothing to execute. Now we call Bar and the list variable gets initialized since as we know global variables are initialized with zero (or in our case nil). Then we unload the DLL and our finalization part gets called and cleans up the instance. What do you think happens when we load the DLL again and call Bar? Most likely an AV. Wait what? Yes, list has not been set to nil because remember this unit is part of a package and thus list has not been set to nil again!
There are several places in Delphi and 3rd party source I have seen that are coded like this. Our solution? Make sure every unit that causes trouble is referenced in the main application EXE to force initialization at startup and finalization at shutdown of the application.
P.S. Did anyone shout "Never use FreeAndNil" back there?!