The Mysterious Case Of The Lost Inherited Call

Soon after I released the free version of MMX Code Explorer, I got complaints from people having problems after they tried it in Delphi 10.2 Tokyo initial release and with Update 1 installed. The version I released was compiled with Delphi 10.2 Update 3 and when loaded in a Delphi 10.2 with no update or only Update 1 it popped up with an error message about a missing procedure entry point “@Dockform@TDockableForm@DoEndDock”.

As a quick fix to this problem I released another version compiled with Delphi 10.2 Tokyo (no updates), which solved it for those versions as well as apparently made no harm to installations with Update 2 and 3  – apparently!

After I got the complaining users satisfied for the moment I investigated a bit more closely what the real cause of the problem actually was. Despite seeing no direct problems with the workaround above, I somehow felt a bit uncomfortable. Perhaps there was some little beast lurking in the dark, which may raise its ugly head some day when no one expects it. In addition, having to compile with a not up-to-date version doesn’t make life easier on the long run, too.

A straight forward search revealed one class in the code inherited from TDockableForm overriding DoEndDock. As expected there was a call to inherited DoEndDock in the implementation. All looked quite reasonable to me.

Then I moved the mouse over the inherited DoEndDock and waited for the Help Insight window to popup. This is what it looked with the initial Tokyo release:

We can see that the inherited call goes to TControl.DoEndDock. Still nothing to worry about here.

Now lets see what the same code reveals in Update 3:

Hey, that looks indeed a bit suspicious. In Update 3 the inherited call will go to TDockableForm.DoEndDock instead of TControl.DoEndDock.

Now comes the tricky part: Virtual method calling is a one way process!

When a virtual method is called, the most significant override of this method is called through the Virtual Method Table (VMT) – we know that, don’t we? Thus we don’t have to know the concrete class when we make that call. The VMT takes care of the correct method to be called.

Virtual method calling is a one way process!

On the other hand, when we call inherited in this overridden method, the compiler knows, which inherited method of which class is going to be called and resolves that call to the correct address. Seems legit – well, somehow, but yes.

Everything works as expected when we compile a single executable where all methods are linked in and entry points are known. Things look different when packages come into play.

When compiling with packages the compiler uses the DCP file to learn which method has to be called with inherited. At runtime the corresponding BPL will then provide  the proper procedure entry point. Unfortunately this mechanism fails, when the runtime package version is different. In that case the procedure entry points don’t match or are simply non-existent.

In this case Update 2 introduces an override of TDockableForm.DoEndDock adding a new procedure entry point. A compiler seeing this override will rightly call this method instead of TControl.DoEndDock. Now when a package before Update 2 is used during runtime, we cannot find that entry point any more. That is exactly the error we got in the beginning.

So, does compiling the expert against the older DCP really solve the problem? At least it makes the error message go away when run in the older environment. But what about running under Update 2 or 3? The method called for inherited is still TControl.DoEndDock and that exists and the call succeeds. The bad thing about this is that we miss to call TDockableForm.DoEndDock in this case. I have no idea what this method does, but with the current version of the expert it is simply never called for all dockforms created by the expert. I could feel a deep grumbling in my stomach when I realized that.

The conclusion to be drawn from this is: When it comes to packages and you want to be binary compatible between your package versions, you better not touch the interface sections of your units! Introducing a new inheritance level for a virtual method – or worse, removing one – will break binary compatibility. That is a direct consequence of how the compiler resolves inherited calls.

For Delphi this limits the possibilities of what can be implemented in a so called point release, where binary compatibility is key.

How can we overcome this limitation? It depends. In this case I removed the overridden method and wired an event handler for OnEndDock, hoping that nowhere in the IDE some other event handler will steel this link. I know that this will not always be an option.

The next release will incorporate this fix, which also allows me to compile with Delphi 10.2 Update 3 again. Simplifying the build process is currently my main task regarding MMX Code Explorer. The need to use a specific Tokyo version for compiling the expert threw a massive burden on my build system. Having things back to normal is a big relief.

 

 

The only new feature in MMX

The move of MMX turned out to be very welcomed in the Delphi community. Over 3000 downloads during the first 48 hours are just overwhelming and unfortunately led to some interim drop outs of the web server. Apologies for that. I will talk to the web hoster about this and see if we can get this a bit more stable in the future.

The original plan was to release with the exact same feature set as the then current version of MMX with just the licensing removed and all the references to ModelMaker Tools BV rewired to the new home. Well, that didn’t work out exactly like that. There is one new little feature in V13 that somehow slipped through. I doubt that many of you long time users found it unless you actually scrutinized the option dialog, so let me explain what it is and what it does.

This is a screenshot of the Pascal Sorting options dialog with the checkbox Group and sort uses highlighted. With this option checked any Format Uses Clause action (default Ctrl-Alt-U) will resolve unit aliases and expand unit scope names. Then units are grouped by scope names and sorted by group in the order given by the projects options scope names entry. For example:

will be changed to

As with the original uses clause formatting this works only when there are no conditional defines inside the uses clause.

I implemented this feature more as a exercise to become familiar with the code and somehow forgot to exclude it from the release. It also is not fully complete, because the only way to influence the grouping and order is to adjust the unit scope names of the project, where a project specific settings file (or a new entry in the dproj file) would be more appropriate. So I guess this will be completed in one of the next releases.

Now as it is public I hope it might be useful for some of you.

A New Home for ModelMaker Code Explorer™

I am very pleased to announce that as of today I am going to take over the award winning ModelMaker Code Explorer™ from ModeMaker Tools BV.

For over two decades ModelMaker Code Explorer™ is still an indispensable add-on to the Delphi IDE for numerous developers. Speaking for myself, a Delphi installation is simply incomplete without MMX. The benefit in using it always outweighed the price of this tool in magnitudes.

With ModelMaker Tools BV concentrating on its Mind Mapping tool SimpleMind, further development and distribution of MMX is now completely in my hands. To emphasize the movement away from ModelMaker Tools BV there will be a slight change in the name: ModelMaker Code Explorer™ will become MMX Code Explorer from now on, still shortened as MMX. The new website can be found here: https://www.mmx-delphi.de/

As a first and probably widely welcomed benefit MMX will be available for free with immediate effect. This allows even all hobbyist developers with a tight budget to make use of this tool. MMX will nevertheless stay closed source, though.

The first free release 13.0 is more or less the same as the current commercial release 12.3 in regard to functionality with all the licensing removed and (hopefully) all references to ModelMaker Tools BV changed to new targets. Alas, the Delphi 5 and 6 versions didn’t make it into this transition, as they would have required too much special treatment. The current release thus supports Delphi 7, Delphi 2007 – 2010, Delphi XE – XE8, Delphi 10 Seattle, Delphi 10.1 Berlin and Delphi 10.2 Tokyo.

My plans for the coming releases are mostly:

  • cleaning up the code base (f.i. remove all C# related code)
  • restructuring the code while removing dependencies where possible
    (we all have our own ideas when it comes to architecture, don’t we?)
  • updating the documentation and examples (videos)
  • supporting new Delphi releases (goal is from day one on if not even beta)
  • better support of newer language features
  • implementing some ideas I collected over the last years

I am not going to conceal that this will most likely lead to drop support for older Delphi versions in favor of making maintenance easier. The latest MMX supporting those retired versions will nevertheless be available for download even after that.

Finally I want to say a big THANK YOU to Gerrit Beuze from ModelMaker Tools BV for his generosity and invaluable support in the past and during this transition.

Will MMX live long and prosper!