Old-style Delphi objects have been broken since the release of Delphi 2, perhaps earlier. They do not do inheritance well when they have fields of compiler-managed types, such as string
or dynamic arrays. There was a discussion about it in 2004 on comp.lang.pascal.delphi.misc. Here was the code to reproduce it:
type
TBase = object
public
s: string;
end;
TDerived = object(TBase)
end;
procedure test;
var
obj: TDerived; //okay for TBase!
begin
assert(obj.s = '', 'uninitialized dynamic variable');
end;
And in fact it's only OK for TBase
by accident because of how the function's prologue code happens to be generated. Putting additional code in that function can make it crash anyway.
Indeed, it's exactly as you've observed — old-style objects don't get initialized properly. Their string fields don't start out holding an empty string; instead, they hold garbage, and so it's not even possible to initialize them yourself without using something like FillChar
.
This appears to be due to the variables being local variables. Unit-scope ("global") variables seem to work OK. Variables that are declared at unit scope but only used by the unit's initialization section, or at program scope and used only in the DPR file's main begin-end block, are treated by the compiler as local variables, so they're not set to all-bits-zero like their global counterparts. When you move your variable declaration to a unit but continue to use it in your DPR file, it's elevated to "global" status.
Your TGUI_Element
type has a string
member called DbgName
, and it looks like that's the only string field you have in the type hierarchy. Take that out, or change it to ShortString
, and I'll bet your crashes go away, at least temporarily.