Monday, January 03, 2022

How Thor Survives CLEAR ALL

You may be aware that Thor can survive a CLEAR ALL. (If you aren’t familiar with Thor, you really should be: https://github.com/VFPX/Thor.) While that seems impossible, it’s actually pretty simple but does require that Thor be designed in a certain way.

As you know, CLEAR ALL nukes all objects (among other things; see the VFP help for a complete list of what it affects). And yet, after executing CLEAR ALL, if you choose any of the functions in the Thor menus or use one of the hot keys you’ve assigned in Thor, it works. How is that possible?

The secret is that _SCREEN and _VFP are the only objects that survive CLEAR ALL. Object members of those objects don’t survive but non-object members retain their values. When Thor starts up, it creates a new property of _SCREEN called cThorDispatcher and puts some code into that property. Near the start of that code is the following:

If PemStatus(_Screen, 'oThor', 5) = .F. or Vartype(_Screen.oThor) # 'O'

   _Screen.AddProperty('oThor', Newobject ('oThor', 'Thor.vcx', lcThorApp, lcThorFolder))

EndIf

So, if there’s no oThor member of _SCREEN or it doesn’t contain an object, that property is created and the main Thor class is instantiated into it.

How does that help? It turns out that most places that call Thor functionality don’t execute code like _SCREEN.oThor.SomeMethod(). Instead, they use code like this:

loThor = execscript(_screen.cThorDispatcher, 'Thor Engine=')

loThor.SomeMethod()

Of course, Thor had to be designed to support that: every place that calls Thor methods has to go through the Thor dispatcher rather than calling them directly.

Ingenious!