Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi unit initialization not always called

I have a unit within a .bpl, and I need a stringlist for a new function that I wrote. I want to the stringlist to persist for the lifetime of the app, so that each call can build on what the prior call found.

So it's declared globally within the unit, and I initialize it in the Initialization section, like this:

var
  ProductLookup : TStrings;  
...

function foo : boolean;
begin
  result := (ProductLookup.IndexOfName('bar') >=0); //blow up here. It's nil. Why?
end;
....

initialization
  ProductLookup := TStringList.Create;  // This should get run, but doesn't.

finalization
  FreeAndNil(ProductLookup);

end.

When I unit tested it, everything was fine. But when it gets run from the main app, I was blowing up with an access violation because the stringlist was nil. So now I'm resorting to checking for nil in the foo function and creating if necessary. But I'm at a loss as to why the initialization isn't working for me. I put a debug message right there in the Initialization, and it doesn't get run when this loads as a BPL, but DOES get run if I compile directly into my dUnit exe. Any ideas? Delphi2005.

like image 201
Chris Thornton Avatar asked Jan 06 '11 18:01

Chris Thornton


3 Answers

Darian reminds me that I've answered this before:

If the operating system loads the BPL as part of loading the associated EXE, then not all the initialization sections will get called. Instead, only the sections from the units that are explicitly used by something else in the program get called.

If the code in the initialization section registers a class, and then you only refer to that class indirectly, say by looking for it by name in a list, then the unit's initialization section might not get called. Adding that unit to any "uses" clause in your program should solve that problem.

To work around this problem, you can initialize the package's units yourself by calling the InitializePackage function, in the SysUtils unit. It requires a module handle, which you can get by calling the GetModuleHandle API function. That function will only call the initialization sections of the units that haven't already been initialized. That's my observation, anyway.

If you call InitializePackage, then you should also call FinalizePackage. When your package gets unloaded, the finalization sections will get called for all the units that were automatically initialized.

If the OS does not automatically load your package, then you are loading it with the LoadPackage function. It initializes all the package's units for you, so you don't need to call InitializePackage yourself. Likewise, UnloadPackage will finalize everything for you.

like image 72
Rob Kennedy Avatar answered Oct 15 '22 06:10

Rob Kennedy


Only found one reference in Quality Central, but there may be more. Includes LoadPackage referenced workaround.

http://qc.embarcadero.com/wc/qcmain.aspx?d=61968

like image 38
Darian Miller Avatar answered Oct 15 '22 06:10

Darian Miller


Not every unit in a BPL will necessarily be initialized, under certain circumstances. If I had to guess, I'd say that this BPL is linked to your program at load time and not dynamically loaded later? Try putting the name of the unit you're using into the program's uses list in the DPR. That should fix it.

like image 36
Mason Wheeler Avatar answered Oct 15 '22 05:10

Mason Wheeler