Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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

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.

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...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top