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.
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.
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...
Related
When I generate new application project on Delphi, the first Line of Implementation in source Project1.pas is the following.
Application.Initialize;
Application.CreateForm(Tform1, form1);
Application.Run;
Then in event OnCreate of Form1 I realize all initialization I need, like
Open FdConnections, Activate Queries and so on.
I am also closing all Queries and Connection in OnClose of form. Would be Initialization and Finalization one good alternative to do do that? What's this commands purpose, and what different of OnCreate?
var Form1:TForm1;
Implementation
Initialization
Begin
FdConnection1.Open;
FdQuery1.open;
FdQuery2.Open;
...
End;
Finalization
Begin
FdQuery1.Close
...
FdConnection.Close;
End; {Could It works?}
The Initialization and Finalization sections execute exactly once, no matter how many instances of a Form are created. Contrast that with the OnCreate, OnClose, and OnDestroy events of a Form, which execute once for each instance.
In your example, the Form in question is only created once, so the difference really applies more to Forms that are (or can be) created (instantiated) multiple times, whether each instance is closed or not.
To follow the order of events when a Delphi application starts up, try the following:
Create an Initialization section in your Form1's unit, put some inconsequential code
in it and set a debug breakpoint on it. The point of this code is simply so that you can
put a breakpoint on it.
Create a Finalization section in your Form1's unit, put some code in that and put
a breakpoint on it.
Put a break point on Application.Initialize in your .Dpr file.
Compile and run the app.
The debugger will stop on the breakpoint you created in step 1. If you view the call stack,
you will see that the code is being called as a result of being called from the RTL routine
InitUnits which calls in turn the initialization section of each unit compiled into your
.Exe. The exact order they are called is determined by the compiler at compile time
and presumably determined by a depth-first traversal of the USEd units.
Next, the debugger will stop on the Application.Initialize BP in the .Dpr file. By the time
execution reaches there, the Initialization sections of all the units compiled into the
.Exe will have been called.
When you close the application, the debugger will stop on the Finalization BP you set
in step 2. If you trace out of it, you will find that it calls the Finalization sections
of the units in the reverse order to the order the Initialization sections were called. And
these Initialization and Finalization sections are called only once per execution of
the .Exe.
It ought to be apparent from the above that the calls to the Initialization/Finalization
sections are unrelated to whether any classes in the units are ever instantiated. The prime
reason to instantiate a class in an Initialization section is to ensure that the class
instance exists before Application.Initialize is called (or the equivalent of Main() is
called in a console application).
I'm making a mdi application with many child forms, one of which is the form to display the report.
on the report form I use dll files to display all the components on the form and look for value
in each component, I use the following code to do that.
// this code i write in dll or bpl file
procedure getReportParams(Form : Tform); stdcall;
var
i : integer;
str, cbstr : string;
b : boolean;
begin
for i:=0 to Form.ComponentCount-1 do
begin
str:=str+Form.Components[i].Name+' - '+Form.Components[i].ClassName+', ';
if (Form.Components[i] is TcxLookupComboBox) then
begin
showmessage('test 1');
// if i uncomment the code below, the program get error Einvalidcast
// cbstr:=(Form.Components[i] as TcxDBLookupComboBox).Text;
// if (Form.Components[i] as TcxDBLookUpCombobox).Parent=Form.FindComponent('pnledit') then
// showmessage((Form.Components[i] as TcxDBLookUpCombobox).Name);
end;
end;
showmessage(str);
// this showmessage work well in dll, bpl, or other unit
if b then
showmessage(cbstr+' true') else showmessage(cbstr+' false');
end;
simple question is how to write code cbstr:=(Form.Components[i] as TcxDBLookupComboBox).Text; with corecly without get EInvalidCast error?
Btw if i write this code in other unit, dll and bpl program get error but if i write that code in same unit (unit report) the code work well. thank for advance.
Your problem is that the classes in your DLL are different from the classes in your executable. You have two instances of these classes, even thought they are compiled from the same code. The compiler is accurate when it says that the object is not the class that you cast it to. You simply cannot share Delphi classes using DLLs.
The solution is either:
Compile all your code into a single executable.
Use runtime packages to share classes.
In your scenario it's not enough that you put your code in a package. The problem are the devexpresses classes. You need to link to those using runtime packages. Because you are not doing so you have multiple different versions of those classes.
You note that the results of the is operator appear to be at odds with the ClassName function. Well, that's because all the different versions of the class have the same name.
I also note that the issue you are encountering is the same as in your earlier question: How can I pass TForm to a DLL as parameter? The explanation and advice from the answer you accepted there apply equally here.
If you already used a (Foo is TSomething) type check, then you know that foo is a TSomething and you can use a static cast: TSomething(Foo)
If you are trying to link this code in another Executable or dll, you probably have not included the correct units IF IT FAILS TO COMPILE, AND IF it fails at runtime, you didn't turn the BPL link option on (Use Runtime PACKAGES, and make sure the list of package names is complete). Remember that checking "something is TSomething" you are comparing a class declaration with another live object's class. A class is not defined by the string name. It's actually type information linked into your application.
When you link a DLL (without runtime packages) you actually may have linked TSomething into your main EXE and into your DLL, and they are TWO DIFFERENT copies of the class with the same name and the name matters not one bit. When you compare for identity, there's no way to know at runtime that they were the same thing. SO they aren't.
You think about code the way you see it written on the screen. When it runs, it's been compiled into code, and the types are simply data in the exe or DLL. So TSomething-in-myexe.exe is not the same class as TSomething-in-mydll.dll.
If you want them to be the same, turn on Use Runtime Packages (BPLs) for all places where you want to compare type information between different compiled parts. In particular passing pointers or references to VCL types between non-bpl-enabled linked targets is not going to work the way you thought it would.
You should also make sure that the list of runtime packages contains the package that defines that class you're using. (TcxSomething is probably a developer express component, go find what package BPL it is defined in.)
I have several custom VCL components that do important tasks in their override of the TComponent Loaded() method. This creates a nuisance when creating instances dynamically since the Loaded() method is not called by the Delphi global loader during run-time, like it does for components that were placed on forms/frames at design-time. I also have to place the Loaded override in the public section of the class declaration so whatever code that creates an instance of the component can call it. Finally I have to remember to call Loaded() for dynamically created instances or subtle bugs will creep into the application, a problem that has bit me several times already.
Is there a better solution or approach to this?
If you need to call Loaded in your code you're doing it wrong. If you depend on a third party control that does, then I would fix that person's control. See below for how.
Let me make up a hypothetical example: Suppose I had 5 published properties, which once they are all loaded, can generate a complex curve or even better, generate a fractal, something that takes a long time.
At designtime I want to preview this curve, as soon as it's loaded, but I don't want the curve to be recalculated 5 times during DFM streaming, because each parameter P1 through P5 (type Double) has a SetP1 method, which invokes a protected method called Changed, and rebuilds my curve. Instead I have the SetP1 method return if csDesigning or csLoading are in the component states, and I then invoke Changed once, from Loaded. Clearly I can't rely on property setter methods alone, in all cases, to invoke all changes. So I need Loaded to tell me to do my first generation of some expensive work, that I want to be done 1 time exactly, not N times, where N is the number of DFM properties that would have been loaded that had method set procedures that invoked a method named Changed or something like that.
In your case, at runtime, you should not be relying on Loaded getting invoked at all. You should be instead, having your property set methods call Changed. If you need some way to change multiple properties at once, and then do some expensive thing only once, then implement a TMyComponent.BeginUpdate/TMyComponent.EndUpdate type of method call, and avoid extra work.
I can think of NO useful places where doing something from Loaded makes any sense, except for cases like the ones above, which should be specific to designtime and DFM based class use. I would expect a properly designed TComponent or TControl to properly initialize itself merely by being created in code, and by having its properties set.
So for my hypothetical TMyFractal component, I would do this when creating it in code without it ever having used DFM loading, or invoking Loaded:
cs := TMyFractal.Create(Self);
cs.Parent := Self; {Parent to a form}
cs.Align := alClient;
cs.BeginUpdate;
cs.P1 := 1.03; // does NOT trigger Regenerate
cs.P2 := 2.3;
cs.P3 := 2.4;
cs.P4 := 2.5;
cs.EndUpdate; // triggers expensive Regenerate method .
cs.Show;
// later someone wants to tweak only one parameter and I don't want to make them
// call regenerate:
cs.P5 := 3.0; // Each param change regenerates the whole curve when not loading or in a beginupdate block.
In my TMyFractal.Change method, I would invoke the expensive RegenerateCurve method once, each time any coefficient P1-P4 is modified at runtime, after initial setup, and once exactly when the component is streamed in from DFM, where Loaded is only used to handle the fact that I can hardly expect to do a beginupdate/endupdate in my control like I would have done in the code above.
We are trying to figure out if we have memory leaks in our software. So, I have been using various tools and programs to help me find possible memory leaks. One of the software I used was AQTime. As it came with Delphi XE, it was only a demo. So, I was not really able to get any useful information from it. Then, I decided to use free software, MemProof. So far, it has shown me many issues with our software that requires attention. One of which is an error.
As soon as I start my program through MemProof, it lists 2 errors, which is attempting to destroy non-existent object from the unit file, system.pas. So, when I actually put a break point within TObject.Free procedure, it breaks even before my program started all the way. Stepping through the procedure Free in system.pas, I found out that TIconimage is trying to destroy or free itself. In other word, free procedure is not invoked from within my program prior to actually starting up.
Here is the actual Free procedure:
procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;
After that observation, I removed the breakpoint and let the program run all the way. My programs main window popped up ready for user input. However, I also found out that TObject.Free procedure is invoked non-stop if any part of my program's WINDOW is displayed on the screen. I don't understand that at all. Why is that? Can anyone explain? How is TForm is related to TObject.Free in any shape or form as the procedure is constantly invoked when the TForm is displayed on the screen?
Thanks in advance.
Regarding why TObject.Free executes a lot, every single time an object is destroyed, any object, that method will be called. All classes derive from TObject, it's the common ancestor, so almost any action in a Delphi program involves large numbers of object create/destroy pairs and consequently will hit TObject.Free.
Regarding detection of memory leaks, you have all you need built in to Delphi to solve this. The FastMM memory manager can be run in "report memory leaks" mode and it will give you loads of diagnostics of any memory that you leak.
Consider the following trivial program:
program Leaker;
begin
ReportMemoryLeaksOnShutdown := True;
TObject.Create;
end.
This results in the following output:
You just need to set ReportMemoryLeaksOnShutdown to True somewhere in your app (the start of the .dpr file is as good a place as any).
If you wish to receive more information in the report then you can download the full version of FastMM and configure it to your heart's content.
Then you get output like this:
A memory block has been leaked. The size is: 84
This block was allocated by thread 0x1304, and the stack trace (return addresses) at the time was:
40455E [System][System.#GetMem]
405A2F [System][System.TObject.NewInstance]
40602E [System][System.#ClassCreate]
4474C2 [Classes][Classes.TStringList.Create]
C275A3 [Main.pas][Main][Main.TMainForm.CreateAuxiliaryForms][997]
C84C8A [OrcaFlex.dpr][OrcaFlex][OrcaFlex.OrcaFlex][351]
75E633CA [BaseThreadInitThunk]
77519ED2 [Unknown function at RtlInitializeExceptionChain]
77519EA5 [Unknown function at RtlInitializeExceptionChain]
The block is currently used for an object of class: TStringList
It's truly wonderful. It tells me that the leaking memory was allocated in Main.pas line 997, and that's precisely where I put my intentional leak!
As you know, TApplication has an Icon property which you can f.i. assign in the application settings in project options. This property is reflected with an FIcon field of TApplication which is created in the constructor of the Application object. TIcon has a TIconImage field representing the actual image which gets created in its constructor. When the Application object loads and assigns the icon from the project resource file, this initial 'TIconImage' has to be freed in order to prevent a leak. All this happens even before Application.Initialize is called in the project source, because the Application object is constructed from the initialization section of 'controls.pas'.
Lots of things are happening when an application is launching or running. When launching, the streaming mechanism creates objects (resource streams, readers, class finders, component lists ..) and then frees them. Even a blank VCL form (with no controls on it) when running, creates a list each time it gets activated to find a control to put the focus on, and then frees this list. With complex GUI applications, a variety of graphics objects can be created and freed even if you hover the mouse on something. Or the alignment/arrangement code can create/free objects even if you press your mouse on to something.
To debug leaks you can take the course outlined by David's answer, or when using a 3rd party product concentrate on what it says leaked, not on every object which gets created/freed. :)
TObject.Free will be called whenever ANY instance of a class in Delphi is Free'd.
This includes a whole host of objects that are created and destroyed simply as part of the normal execution of a Delphi program, including in response to events processed automatically by a TForm object in response to the messages generated by the system simply to maintain the window object itself in existence in the Windows own Window Manager.
For example, consider this snipped fragment of code from the TCustomForm WndProc:
WM_MEASUREITEM:
begin
:
Canvas := TControlCanvas.Create;
with Canvas do
try
:
finally
Canvas.Free;
end;
:
end;
The key here being that in response to a WM_MEASUREITEM message, a custom form (and therefore a standard TForm derived class, since this ultimately derives from TCustomForm) creates a temporary TControlCanvas, which it then Free's when it is finished with it.
This may not necessarily be the source of the TObject.Free calls that you are seeing in your particular form's case, it is just an example, but shows how a TForm merely existing can result in other objects being brought into existence and destroyed in response to automatic, system generated messages.
Delphi 2007/2009 odd question here:
It's possible, based on a component property defined in design-time, to include files in linking or leave them ?
Example: If I leave SomeProperty true, when compiling, the unit SomeUnit will be included into my project. Otherwise it will not be included.
My second approach to this problem is to deploy a second component, which when dropped in the form (or not) will include the unit in uses clause. But if it can be done with a property, that'll be better.
I want to avoid conditional compilation via IFDEF because that forces the component to be built every time the projects are built. Or not?
I am trying to achieve an easy way of including some units in project, and then those units will provide support for specific databases. Having these into an option, at the connection component, will be ideally easy: Check support and that's done. Uncheck, and get some less KBs in your compiled APP.
edit: I'll stay with the component way for instance. I knew the IFDEF method and things, but that forces the component to be built everytime the projects are built. Or not?
I was trying to achieve an easy way of including some units in project, and then that units will provide support for specific databases. Having these into an option, at the connection component, will be ideally easy: Check support and that's done. Uncheck, and get some less KBs in your compiled APP.
No.
What are you trying to solve?
You could add a postcompiling step that would optionally include some resource based on a component property - but you'd have to do some coding to implement such a feature.
You can use the {$IFDEF youridentifier} optional code {$ENDIF} method to conditionally compile data in to your application and then to enable it just go to your project options and enter youridentifier into the appropriate option field. Another method of doing this is to add the following to the top of your unit (or in an include file):
{$DEFINE youridentifier}
which will force youridentifier on. To disable, just place a period right before the $:
{.$DEFINE youridentifier}
Using these techniques its easy to conditionally bring in code or replace code with each compile.
Write an IDE add-in. Handle the "before compile" notification and check whether any forms or data modules in the project have components of the type you're interested in, and then check their properties. Based on what you find there, you can try modifying the contents of a unit to use the other unit of your choice. It certainly doesn't sound easy, but it seems possible.
Your second idea is very easy. It's exactly what the TXPManifest component does, for example. Beware that removing such a component from a form does not "unuse" the associated unit.
To conditionally add support for different databases, you might consider using run-time packages. (That's how the IDE manages to support so many different kinds of components, after all.) Put each database's custom code into a different package. Then, the databases you support are simply whichever ones have packages available at run time. No compile-time or design-time configuration required. The obstacle to this, however, is to manage which packages are available, and determine which of them are the packages that provide database support.
Your second approach will not necessarily work the way you want it to. While Delphi will helpfully add the necessary unit to your uses list when you drop the component onto the form, it will not remove the unit when you delete the component. And even if you don't use the component or any other exported entitiy from that unit, it is possible that the unit will be linked to your application anyway, when there is code in the initialization or finalization part of the unit. This is unfortunately very often the case, even when it would be possible to initialize stuff on-demand.
There is no way to do what you are asking, but something you might not be aware of is that units which are included in your uses list but never referenced will have a minimal impact on the size of your executable. The smart linker that is in Delphi does a very good job of removing code which is never used. If you are careful about your "optional unit" which is referenced by the component, and don't have any code in it which is executed globally (everything is self contained in a class or classes) then it shouldn't matter if it is in the uses clause and not used, or not in the uses clause at all.
This would easily allow you to do what I think your wanting to do, which would be to drop a component on a form which includes a unit that then can be linked to your application. Removing the component would have the effect of not linking in the unit. I believe, however, that any resources (for example forms or other items included by the $R directive) which are in the used unit would still be included in the executable.
You could use DesignIntf.RegisterSelectionEditor to register a selection editor (see comments in Delphi source code about ISelectionEditor), then use the RequiresUnits procedure to include extra units in uses clause.
TMySelectionEditor = class(TSelectionEditor)
public
procedure RequiresUnits(Proc: TGetStrProc); override;
end;
procedure Register;
implementation
procedure TMySelectionEditor.RequiresUnits(Proc: TGetStrProc);
var
comp: TMyComponent;
I: Integer;
begin
inherited RequiresUnits(Proc);
Proc('ExtraUnit');
// might be a better way of doing the code from here onwards?
if (Designer=nil)or(Designer.Root=nil) then Exit;
for I := 0 to Designer.Root.ComponentCount - 1 do
begin
if (Designer.Root.Components[i] is TMyComponent) then
begin
comp := TMyComponent(Designer.Root.Components[i]);
if comp.SampleProperty = True then
Proc('ExtraUnit2');
Proc(comp.ObjProperty.UnitName);
end;
end;
end;
procedure Register;
begin
RegisterSelectionEditor(TMyComponent, TMySelectionEditor);
end;