Version: 1.01.10 - last update: Saturday, September 26, 2009, 17:30:00
This thread is all about how to gain full design-time control over VFP’s shared/public resources (and more)! Missed any prerequisites? Follow back-link below.
Intro
At the beginning of part II of my thread “Unbreakable” Objects I talked about what different tasks/responsibilities a global resource manager should have (IMHO). That’s about a year ago! Well, sometimes things evolve slowly. At that time, I defined the following list:
- Keep track of all global variables (name and content)
- Keep track of all loaded FLLs
- Keep track of all assigned ONKEY etc.
- Keep track of all of VFP’s system variables
- Keep track of all DECLAREd Win API functions (and their aliases)
- Keep track of any other global resource like mouse cursor, caret, states of CapsLock and others
- Keep track of VFP’s _SYSMENU additions
- Keep track of all DEFINEd popups, menus, windows etc. (plus their win-event bindings)
- Keep track of all tool instances currently running (plus their entire states)
- Keep track of all exclusive WIN event bindings (those to _VFP/_SCREEN)
- Keep track of all table related stuff (wow, there’s a lot!)
That listing was set up seen from the perspective what kind of resources should be made CLEAR ALL resistant. To this day, I added some more perspectives which seem as important as “CLEAR ALL resistance” to me.
Shared Items
When talking about VFP’s global resources we have to think about all kinds of items that have a unique identity within VFP’s environment. Sometimes, we even have to go “one level up” also taking those singletons into account, which belong to the hosting operation system, like mouse and clipboard does.
Shared Behaviour
Beneath settings, declarations and definitions there certainly is another important group called shared behaviour. A lot of VFP’s SET commands apply to shared behaviour, providing an opportunity to alter a specific behavioural aspect. In fact, most of VFP’s SET commands are globally scoped this way, expect for those scoped to a data session (Yes! I know you know that:-). Another interesting (coz not so easily controllable) part are VFP’s system/window events that lack a native xBase-syntax implementation.
Win-Events
Since VFP 9, we are enabled to handle Win-Events without tasking complicated Win-Api calls, using VFP’s Win-Event binding. Contrary to VFP’s object-event binding, VFP’s Win-Event binding does not permit to bind to more than one delegate. Basically, this is because binding to a “WIN-Window“ overwrites the entry-point of the main message loop of the window, redirecting message execution to someone’s own delegate implementation. “Sub-classing” a WIN-Window this way cannot be chained in VFP. Thus, every running top level window like VFP’s main window (_VFP.Whnd) or the _SCREEN (_SCREEN.Whnd) we want to bind our own main message loop handler to, can be regarded as a unique resource (seen from that point of view).
Win-Api Calls
VFP application development today comes with employment of Win-Api calls, right? Just think about utilizing all the nice effects provided by GDI+! VFP’s DECLARE command superseded Foxtools’ RegFn32() call, which still is available, though. Beside the fact, that all DECLAREd Win-Api calls are released by a CLEAR ALL, they belong to our public resources, as well. VFP doesn’t maintain any internal reference counter for each defined Api call, like it does for it’s own object references! Thus, releasing a declared Api call definition is always scoped to VFP’s entire session; code in all procedures/methods will loose access to that definition, immediately after releasing it.
The Declare Stumbling Block
There is another almost unknown latent jeopardy while working with Api call ALIAS names!
Let’s review the DECLARE DLL syntax shortly:
DECLARE [cFunctionType] FunctionName IN LibraryName [AS AliasName] …
I dropped the parameters portion which isn’t important at the moment. Therefore, I coloured the AS name part, that may cause you troubles if not handled the right way! Assigning an AS-Alias is a common practice to avoid name-clashes. Another reason is to create multiple declarations of the same Win-Api call using different parameter signatures. Now, look at the following code sequences that are using a simple declaration example, taken from VFP’s help file:
Scenario #1 (error-prone)
CLEAR ALL ? ADLLS(aD) && echos >>> 0, which is absolutely Okay! DECLARE INTEGER GetActiveWindow IN WIN32API AS MyGetActiveWindow DECLARE INTEGER GetActiveWindow IN WIN32API ? ADLLS(aD) && echos >>> 1, which should be 2! CLEAR DLLS GetActiveWindow && or CLEAR DLLS MyGetActiveWindow ? ADLLS(aD) && echos >>> 0, which is bad, coz the 2nd DEF was dropped, too!
Scenario #2 (fail-safe – at least partial)
CLEAR ALL
? ADLLS(aD) && echos >>> 0, which is absolutely Okay! DECLARE INTEGER GetActiveWindow IN WIN32API DECLARE INTEGER GetActiveWindow IN WIN32API AS MyGetActiveWindow ? ADLLS(aD) && echos >>> 2, that’s right now! CLEAR DLLS GetActiveWindow ? ADLLS(aD) && echos >>> 1, that’s right now! *\\ until now we are save - our aliased declaration *\\ still is active. But then: DECLARE INTEGER GetActiveWindow IN WIN32API ? ADLLS(aD) && echos >>> 1, which should be 2!
The bottom line is: If you need to declare an aliased Win-Api call for another reason than to avoid a name-clash, ALWAYS declare the un-aliased one, first! If you are sure, you can release your declaration, always release both parts! Or, maybe even better, always use aliased declarations, never use the original Win-names anywhere else but as the FunctionName parameter within the declaration itself. That approach will never lead you into troubles later on.
I’ve seen a lot of other developer’s code blocks defining a Win-Api call just before calling it. This is bad practice in terms of well behaved access to global resources! Therefore, wouldn’t it be great to have some central mechanism that would take care and control VFP’s “weird” DECLARE DLLs behaviour? Well, my Global Resource Manager will be able to do so!
Back to the thread
We learned that a global resource can be:
- A unique object
- A (set of) unique event(s) or routine(s)
- Some unique behaviour.
Global resources are not limited to VFP’s environment, but may belong to the enclosing operation systems (as well). There are two different scenarios where we need access to global resources:
- Design-time
- Run-time
Although both are different in general, they share some common aspects:
- At design-time, it would be very useful to have simplified access while coding classes and scripts – in other words, we need IntelliSense support. On the other hand, it would be great to have unified access to our global resources from within our tool apps we are running to facilitate our daily work.
- At run-time, the global resources should be available by using the same building blocks we’ve created and utilized at design-time, basically. In other words, our design-time Global Resource Manager should have a set of core functions encapsulated in some base classes that can be reused in our run-time applications.
- Design-time stresses high availability of global resources.
- Run-time stresses high-performance access to global resources.
How to achieve that, I will show you in my next blog entry.