Introduction
Imagine a form and some data modules. Some of the data modules have lookup
fields into each other. The form uses the data sources of the data modules.
Now imagine that you need to specialize one of the data modules. You create
a new project based on the original project, and you add a data module derived
from a data module in the base project.
There's just one problem here. All of the other data module and form references
to components in the base class data module disappear. The base class data module
global variable isn't initialized.
What Causes The Problem
When the streaming system streams in the project forms, it knows that some
"global" components, like data modules and forms, may reference components
within each other. So at the end of the streaming process, all of the intercomponent
references at the global level undergo a fixup process. The fixup process is
based on calls to Forms::FindGlobalComponent for each reference. The problem
is that only the actual forms created with new or CreateForm, not their ancestors,
are in Screen->DataModules and Screen->Forms, which the default FindGlobalComponent
uses as its source for returning the component pointers. Naturally, this means
the fixup process fails to find ancestor forms.
As for the failure to initialize the global variable for the form or data module,
well, that just happens. I don't know why, but it's a lot easier to fix that
the fixup process.
Fixing The Problem
First, every form constructor should assign this to its global variable.
For instance:
Account = this;
For the inheritance problem, there are two solutions.
- Level the inheritance so that all modules in the project are at the same
level. In other words, if a data module is extended with a descendant, then
all modules in the project must be extended with a descendant that uses the
other extended classes. This is difficult and expensive, since the IDE will
instantiate all ancestors of a descendant form, which can quickly spend you
out of resources.
- Modify the FindGlobalComponent function.
Modifying Find Global Component
The following is the pattern for a basic modification of FindGlobalComponent.
It goes in the project .cpp file.
TFindGlobalComponent OldFindGlobalComponent;
TComponent* __fastcall FindGlobalComponentExtended(const System::AnsiString
Name)
{
if (Name == "Base1") return (TComponent *) (Base1 *) Special1;
if (Name == "Base2") return (TComponent *) (Base2 *) Special2;
return OldFindGlobalComponent(Name);
}
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
OldFindGlobalComponent = FindGlobalComponent;
FindGlobalComponent = FindGlobalComponentExtended;
...
In this example, the base class is represented by Base1 and Base2 - their descendants
are Special1 and Special2 respectively.
Conclusion
This rather straightforward process can certainly be made simpler and more
abstract. But the basic technique is sufficient to overcome this deficiency
in form inheritance.
|