问题
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.
回答1:
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 callFinalizePackage
. 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 callInitializePackage
yourself. Likewise,UnloadPackage
will finalize everything for you.
回答2:
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
回答3:
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.
回答4:
How are you loading the bpl? Are you leaving it to Delphi to do the loading or are you manually loading the bpl? If you are manually loading the bpl, are you loading it as a "straight" dll or are you using LoadPackage to load it as a delphi package? I would think that either letting the vcl load it (through the requires processing) or using LoadPackage is required for the initialization sections to be run by the vcl...
来源:https://stackoverflow.com/questions/4618650/delphi-unit-initialization-not-always-called