"Unbreakable" Objects (Part II)

Version: 1.00.01 - last update: Saturday, September 26, 2009, 16:40:00

Previous ChapterNeat Solutions Home (TOC)Next Chapter


This is all about how to create a CLEAR ALL resistant class to speed-up things while developing.

Intro

In part one of this multi-part blog we talked about the pieces our puzzle is made of. Finally we created a first VFP-Form that successfully refused being released. In this blog entry we’ll talk about how we can apply our findings. First of all: It is always good to have an idea of what one wants to achieve! Okay, let me tell you what I wanted to create when I was starting my development on this. I thought about the need for having something like a global resource management utility. That’s why I found the working title “Global Resource Manager” pretty well suited. Let me enumerate responsibilities some clever “Resource Manager” should be able to cover (this list is not exhaustive!)

  • 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!)

All these “Keep-track”-requirements have one thing in common: If you successfully set them up (executing some VFP code), there always is the latent chance they get killed by a simple CLEAR ALL (or some other related commands). We all know that every now and then there is no other way to escape. So there is only one thing we have to reassure: everything must get back into place afterwards automatically! How to do that is another story – back to the thread!

There is one thing you have to keep in mind! VFP’s _SHELL variable itself is a global resource! What if every vendor you’ve bought another super-cool tool from would try to utilize it for just this restarting purpose we’re just talking about? This would mean that only the last _SHELL-Writer (the luckiest) would win! Got the clue? What’s the general indicator for something called to be a “global resource” within VFP? A global resource is a singular something that is to be shared amongst many! Nobody can rely on being the only one using it!

BTW: SYS(988) and SYS(959), we’ve talked about in part one, are also accessing some global resources, don’t they?

Final Implementation

Our Form gets launched from our global startup program when VFP starts. To keep things simple our Form is stored in VFP’s HOME() directory. Our startup.prg could look like the following:

DO Form (HOME()+”RESI.SCX”) NAME _oResource LINKED WITH "START" NOSHOW 

This is our Form’s INIT event code:

LPARAMETERS tcMode AS String
WITH THIS
    *\\ check out: Is this a new VFP session?
    .lNewVFPSession = NOT SYS(988)
    *\\ finally set undocumented memory cell TRUE
    = SYS(988, .T.)
    *//
    DO CASE
        *\\ set start-mode token
        CASE PCOUNT() = 0
            .cStartMode = IIF(.lNewVFPSession,;
                        "STARTUP_VFP",;
                        "STARTUP")
        CASE NOT VARTYPE(m.tcMode) == "C"
            .cStartMode = IIF(.lNewVFPSession,;
                        "STARTUP_VFP",;
                        "")
        OTHERWISE
            .cStartMode = IIF(.lNewVFPSession,;
                        "STARTUP_VFP",;
                        UPPER(ALLTRIM(m.tcMode)))
    ENDCASE
ENDWITH
IF NOT TYPE("_oResource") == "O" OR ;
    TYPE("_oResource") == "O" AND ISNULL(_oResource)
    *\\ reassure we've got our public variable
    RELEASE _oResource
    PUBLIC _oResource
    _oResource = THIS
ENDIF
_SHELL = "_oResource.Start()"

We use SYS(988) to check if we’ve just started a new VFP session. In this case SYS(988) returns .F. (the boot default). After that we set it to TRUE, which will flag a running VFP session as long as we are working within VFP’s IDE. We could have passed the special “START_VFP” literal from within our startup.prg but that’s not bullet proof enough, coz someone might re-execute our starup.prg later in the game. There maybe some setup tasks we want to run only once while starting VFP. That’s why using a pretty unknown memory function like SYS(988) is a much more secure way to achieve that. At the end of our Form’s INIT event method we stuff a Start() command into VFP’s _SHELL. Doing so has some advantages:

  1. There might be some other code in our startup.prg we want to execute before running our Form’s Start() method.
  2. We can be sure VFP is fully initialized when getting back program control.

What you want to put into your Form’s Start() method is only limited by your imagination!


Previous ChapterNeat Solutions Home (TOC)Next Chapter

No comments:

Post a Comment