For a long time (well over a year), there has been an annoying issue when uninstalling kbmMW that results in the need to kill the IDE before attempting to install a newer version of kbmMW.
I have spent dozens of hours trying to track the bug down, but its precise origin eluded me for a long time.
Since the bug as such only relates to the kbmMW designtime package in Delphi, there has never been any related instabilities in applications developed with kbmMW. However I do not like having unexplainable issues in the code, and it was seriously annoying since a recompilation of either kbmMW’s runtime or designtime packages would trigger the bug requiring a kill and a restart.
I have now found how to avoid the issue happening. The bug is a Delphi bug, related to its internal handling of RTTI, and surfaces the moment the affecting package is uninstalled and Delphi attempts to clean up its understanding of the world, before building a new understanding.
Brute force debugging did unfortunately not really explain where the bug was, only by divide and conquer between the hundreds of thousands of lines of code in kbmMW, pinpointed the troublemaker.
It turns out to be the combination of the definition of the class TkbmMemTableWithDefinition in kbmMWONMarshal.pas, along with registering of the class with Delphi (happens first time some RTTI related call is made on the class), in combination with having defined an attribute on the class, in combination with (currently a guess) the parent class being declared in a different package (the kbmMemTable runtime package).
So by not doing just one of the following :
- Registering the descending class resulting in RTTI being aware about it
- Declaring an attribute for the descending class
- Declaring the descending class in a different package than its parent is in (not proven yet)
results in the bug disappearing.
How is TkbmMemTableWithDefinition declared?
[kbmMW_Dataset([mwdsfIncludeDefinitions])] TkbmMemtableWithDefinition = class(TkbmMemTable);
The idea is simply to be able to return a memtable with definitions in a very easy way from a Smart service. It works beautifully at runtime, but causes troubles at designtime uninstallation.
It seems that it results in Delphi attempting to access an RTTI registration after it has already freed it earlier on. I deduced that it most likely have (correctly) freed the RTTI info for the parent (TkbmMemTable), but since there were no additional features (methods, fields or properties) in TkbmMemTableWithDefinition, then the compiler or the RTTI might have misinterpreted something as a class alias rather than a separate class type. Unfortunately adding a dummy virtual method did not change anything.
To solve the problem, without having to move the responsibility over to the developer for registering the streaming classes related to this class, the easiest way was to find a way to detect if the code is currently running as part of a designtime package within the Delphi IDE or not.
class function TkbmMWRTTI.IsDesignTime:boolean enters the stage. It checks for if designtime only features are available or not. If they are, it will return true, else false.
Hence marshalling support for that particular class will only be registered when the code is NOT running as part of a designtime unit.
Now its possible to whistle while eating polvoron… at least Delphi wise 🙂
If you like our products please “like” our posts and share them widely to support our continued effort in constantly improving the most complete middleware for Delphi.
17,605 total views, 1 views today