Delphi - Component Debug
OK .. you have designed a component and it doesn't work.
Now what?
This page contains a few of the more difficult design problems
that I have had to work through. I hope it helps.
Constructor Missing "inherited"
| Wrong *Package* Name
Constructor Missing "inherited"
If you forget the required inherited in the constructor,
then the component will be created and work just fine .. unless ..
you place it on the form at design time.
In that case, the variable that makes the component available will not be set.
T_xyz = class(TComponent)
public
constructor Create(AOwner: TComponent); override;
end;
constructor T_xyz.Create(AOwner: TComponent);
begin
inherited; // the problem was caused by forgetting this
// additional code here
end;
|
Using the following code,
I was able to verify that
when the program started, an object of type T_xyz was created
(verified by setting a breakpoint in the constructor),
yet the variable xyz1 was not assigned a value
(was equal to nil - verified by setting a breakpoint)
when FormCreate was called.
Adding inherited to the constructor fixed the problem.
type
TForm1 = class(TForm)
xyz1: T_xyz;
abc1: T_abc;
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
procedure TForm1.FormCreate(Sender: TObject);
begin
abc1.xyz := xyz1; // xyz1 = nil when inherited was forgotten
end;
|
I found this by accident ..
after single stepping through source code for about 5 hours.
I simply noticed that the command was missing.
Wrong *Package* Name
When creating a new group of related components, I don't want to place the
new stuff in with items I have already tested and released.
Instead, I create a new package and use that to test while developing.
When the testing is done,
sometimes I merge the components into an existing package
and sometimes not.
The basic (and wrong) procedure is
- Create a new package
- Compile
- Install
This produces a default package name of
C:\Program Files\Borland\Delphi5\Projects\Package1.dcu
C:\Program Files\Borland\Delphi5\Projects\Bpl\Package1.dcp
C:\Program Files\Borland\Delphi5\Projects\Bpl\Package1.bpl
At this point you can select your new components from the tool bar
and place them on a form.
If you want to change the code,
- Just recompile the package
- The form will be automatically closed
- Reopen the form (press F12) and the new properties (and whatever) will be displayed
OK, so now you save the package and give it a proper name.
(Wow, are you screwed!!)
That's right, the old package is still there!
You can write, compile, change whatever you want,
and nothing is going to get fixed.
After 2 days of debugging a (very serious) problem, I decided to try and click Install again.
That's when I saw the error
Cannot load package 'dcl_mcXYZ_50.' It contains unit 'mcABC,';which is also contained
in package 'Package1'
|
(Boy, was I surprised)
Of course, the solution was simple
- Unload the bad package
- Load the correctly named package
There was another clue, (I know, sometimes I'm slow)
Previously, each time I compiled the package, the form would close ..
because it contained components from that package. However,
on the next day, clicking compile did not force the form to close.
I had just assumed that "Delphi was mysterious" and ignored this clue.
(You have to make some mistakes before the symptoms make sense.)
Correct Procedure
As explained in more detail at
Creating a Package,
the "more correct" procedure is
- Create a new package
- Add the *.pas files
- Save the package (*.dpk file)
- Compile
- Install
My problem was that I installed the package before saving (and therefore - naming) it.
As a result, the package was originally installed using a default name
and all source code changes made after the save were ignored.
More
By the way, the error I was getting
(a Google search found nothing)
(Access violation at address 40003CAE in module 'Vcl50.bpl'. Read of address 000000EC)
|
was caused while testing the proper operation of my component at design time.
(It worked perfectly at runtime.)
Basically, the new component has a published property that
holds a pointer to another component.
At design time, the property was set
using the Object Inspector .. and everything worked fine.
The problem occurred when I deleted the second component.
Normally, this causes the property value to be cleared
(which verifies that
the notify flags are properly set)
..
when there is a problem .. Delphi crashes.
(This is a standard test that must be tried for every
property that can hold a pointer to an object on the form.)
However, since this is a design time failure, there are no useful debug tools
(that I know of) that simplify problem identification.
As a result, I slugged through the source code trying to see what was wrong.
In desperation, I tried to reinstall the package .. and found the problem.
Deleting the old Package
To delete the a package, there are 2 methods.
- From the menu, select
Component / Install Packages...
- Open the new (properly named) package in Delphi. From the toolbar, select
the Options icon and click on the Packages tab
From this point, both methods are the same -
simply select the bad package and click Remove.
In this case, I selected
C:\Program Files\Borland\Delphi5\Projects\Bpl\Package1.bpl
None of the files were deleted, but the package was uninstalled
and the icons on the toolbar were removed.
When I installed the new (properly named) package, the icons were restored
and the design time error was fixed.
In the final analysis,
- The error was because I forget to include inherited in the constructor
- And could not be fixed because I installed the package before
I saved it with a proper name
Author:
Robert Clemenzi