A Global Resource Manager for VFP (Part II)

Version: 1.02.00 - last update: Wednesday, September 07, 2009, 00:59:00

Previous ChapterNeat Solutions Home (TOC)Next Chapter   Latest Addition(s) Screen Cast showing 1st alpha release


This thread is all about how to gain full design-time control over VFP’s shared/public resources and more!

Intro

In OffSiteLink Part I of this thread we talked about all kinds of things our Global Resource Manager (GRM) should be up to handle, fast and reliably. There is one thing we didn’t mentioned yet. Okay, I talked about it once, but in a different context. It is the fact that our manager should behave like a “native” part of VFP’s IDE - like the project manager does, for example. In other words, no CLEAR ALL, no CLOSE ALL, no RELEASE ALL or any other VFP direct command should spoil our GRM instance. Our GRM reference variable should last like any VFP “_System” variable.

Utilizing an “Unbreakable” Form

You should read my thread OffSiteLink Unbreakable Objects to better grasp what I’m going to talk about now. Well, our GRM has to be based on a VFP FORM class. Even more, we do need a SCX-based form that is run using the DO FORM syntax. This form will act as our host container. As long as we can guarantee that this form isn’t released we have some kind of secure home for all of our global resources. Before we dive into making the implementation of our GRM bullet-proof, we have to think about how we will manage our global resources internally.

The MY Namespace Object

When I was thinking about how to implement the resource management internally, I remembered a Sedna add-on called “MY Library”. You can download the whole package here OffSiteLink Microsoft Visual FoxPro 9.0 "Sedna" Add-Ons. This download contains six components: VistaDialogs4COM, Upsizing Wizard, Data Explorer, NET4COM, MY for VFP and VS 2005 Extension for VFP. I must admit, I had installed the Sedna add-on long time ago, but never really used it. I don’t know why, maybe it seemed to be of no big help to me. Anyway, today I believe that combining the MY namespace for VFP with our unbreakable host form will bring it to another, much higher, level of usefulness!

Advantages of MY for VFP

The following list shows the most important points

  • Data-driven & fast
  • Extendable arbitrarily
  • Reliable & thoroughly tested
  • Easy to learn & to handle
  • Easy to integrate
  • Runtime- and Design-time support
  • Comprehensive documentation

As you can see, there are a lot of good reasons to utilize the MY namespace tool in our GRM project. While checking the My Namespace classes I came to the conclusion that it would be best to have a MY system variable referring our GRM’s internal engine. Wouldn’t it be nice to have an unbreakable global variable called MY that could be used in any IDE context?

The Global MY Variable

Let’s speculate – there is a native VFP namespace called MY (if you prefer, name it _MY to stay congruent with other system variables). Now, with the help of our unbreakable MY we are able to address e.g. our unbreakable forms collection like so:
My.Forms.Add(_oBrowser) && make current class browser instance unbreakable

Or, let’s add some Win-Api DECLAREs to our “CLEAR ALL protected” declarations like so:
My.WinApi.Add(m.DeclarationExpr) && make declaration CLEAR ALL resistant

If we need to protect a memory variable against a RELEASE ALL, we could do it this way:
My.Memory.Add(m.VarName, m.VarValue) && make variable CLEAR ALL/RELEASE ALL resistant

The cool thing about the MY namespace for VFP is its extendibility. Using the MyBuilder that ships with the project it’s a snap to add someone's own sub-namespace. The only important thing still to solve is how to make a global VFP variable unbreakable. Impossible?  Come on, lets do it…

Global Resource Manager 1st Implementation

To create a first implementation to proof technical feasibility, we have to record what we want to achieve:

  1. Unbreakable host form
  2. Unbreakable global MY reference variable

The 1st part isn’t that difficult (even the 2nd is not insolvable). All we have to do first is to gather all VFP commands that are capable to “kill” our form and/or MY variable. If one of these commands gets issued, we have to be noticed, somehow. Otherwise, our public MY variable might be gone unbeknownst to our GRM internally. The following list shows the most “dangerous” commands:

  • CLEAR ALL
  • CLEAR WINDOWS
  • RELEASE ALL (EXTENDED)
  • CLOSE ALL

As you should know by now, CLEAR ALL and CLEAR WINDOWS can be trapped by our host form. The number one question now is: How can we detect a RELEASE ALL?

Introducing the MY-Proxy

To put it bluntly, the answer is: There’s no way. At least, I didn’t find a native VFP way. Therefore, I came up with the following workaround. Instead of using a simple/single global variable, I’m using an object. I named it the “MY-proxy”. The global MY variable still exists. But, instead of holding a direct object reference to our GMR host form (more exact: a reference to our GRM’s internal MY-engine), our global MY variable stores a reference to an independent CUSTOM-based object (the MY-proxy)! The MY-proxy class implements a THIS_ACCESS method that redirects any access (to MY) directly to our GRM’s internal implementation. Thus, the MY variable looks like being a direct reference to the Global Resource Manager! Now, while doing a RELEASE MY, the proxy-object’s DESTROY()  gets raised. That’s of course THE EVENT we’ve bound to from within our GRM. In other words: As soon as our MY-proxy gets destroyed, our “monitor”-event is raised and we will create another new MY-Proxy instantaneously. That’s all we have to do to simulate some unbreakable global variable in VFP, right?

How to Trap a CLOSE ALL

Object’s persistence isn’t threatened by a CLOSE ALL command, fortunately. But, CLOSE ALL is able to close tables, editor sessions, designer instances and more. So, if we want to keep any of these alive (protecting them against being closed by a CLOSE ALL) we have to get noticed when an interactive CLOSE event occurs, too.

I wrote a short article about how to monitor the life-cycle of any VFP class/form designer instance. You can read about that OffSiteLink here. Issuing a CLOSE ALL will certainly close all class designer sessions. Therefore, we can create one, make it “invisible” to VFP’s IDE and just start to monitor its existence. If if gets destroyed this can only be done by a CLOSE ALL – Voila, there it is, our CLOSE ALL “event”!

No idea how to make a class designer instance invisible/inaccessible to VFP’s IDE ? Read ahead…

How to Disguise a VFP Designer Session

Creating a form, using the form designer, fits best in our scenario (we don’t have to select a class library).

*\\ we need Foxtools.fll
LOCAL cFormName AS STRING, nHWND AS Integer
LOCAL ARRAY laSel[1]
*\\ we need the forms object reference later in the game to "bind" to.
PUBLIC goForm AS Form
*\\ make form name unique and remember it! 
cFormName = LOWER(SYS(2015))
*\\ create the form designer instance CREATE FORM (m.cFormName) NOWAIT *\\ get VFP’s internal Win-handle nHWND = _WFINDTITL("Form Designer - " + m.cFormName + ".scx") *\\ get VFP's object reference to the form inside the form designer = ASELOBJ(laSel, 3) goForm = laSel[1] *\\ Hide the whole designer session _WHIDE(m.nHWND) *\\ finally, drop VFP’s window menu entry by clearing *\\ our designer window’s caption! _WSetTitle(nHWND, "") *//

The above line containing the SYS(2015) was driving me nuts lately! During my interactive testing (using the command window only) I was using the fixed name “test” for my new form – always typing lower case letters. Then I wrote the little proggy above using SYS(2015) without  lowering its outcome. I never noticed that VFP always applies a LOWER() to the new form’s scx filename that gets appended to the designer caption after the leading “Form Designer – “ part. Did you? Because _WINDTITL() does a case sensitive search my program never found the newly created form designer window, which finally caused an exception doing the _WHIDE() and _WSETTITLE() Foxtools calls. Since I wrapped the SYS(2015) with a LOWER() the whole thing runs as expected.

In the little demo program I created a public <goForm> variable. In our GRM’s production environment we will take a local reference and store it to an _ASSIGN() decorated property instead – like described in my previous posting. Now, if someone issues a CLOSE ALL VFP will drop the “invisible” form designer without confirmation, which will cause storage of the NULL value to our property and firing our  _Assign() event!

VFP’s Start-Up Sequence

Finally we have to reassure that out GRM is the first object that gets instantiated. Therefore, its good to be aware of VFP’s start-up sequence so that we can hook in our little tool at the very first position!

While starting, VFP executes up to three different programs/commands in the following sequence :

  1. _Startup
  2. Command
  3. _Shell

We can pass in a CONFIG file reference during VFP’s start (or just have a default config.fpw file in VFP’s home directory). The  _STARTUP = <startup_program_file> entry inside the config.fpw is read by VFP and the startup program is executed. BTW: Be aware that there is another Startup entry in VFP’s options dialog that takes priority over the config.fpw entry!

Second script/command that gets executed by VFP can be assigned to the COMMAND entry (also located in the config.fpw configuration file). Use it like this: COMMAND = <command_or_program_file>

Finally you can put a _SHELL assignment into the config.fpw file. The command stored to VFP’s _SHELL variable gets executed last. Use something like this: _SHELL = <Command_or_Do_program_file>

Hooking on _STARTUP

The best thing you can do is to create a Startup.Prg and put a reference to it in VFP’s options dialog like shown below.

VFP's Option Dialogue has a Startup Program entry, too!

Next, you should put the DO FORM command for the Global Resource Manager launch on line #1 of your script! That’s all you have to do to make the GRM the top controlling form each time you start your VFP development environment.

 

Back to Top A Little Teaser

I recorded a short screen cast, showing the first alpha version of my Global Resource manager in action. What you will see are three events I have implemented so far (EvtClearAll, EvtCloseAll and EvtReleaseAll). When using the GRM you may like to bind to these events to get noticed when the user does a CLEAR ALL, a CLOSE ALL or a RELEASE ALL. The other feature is a simple way to make a form instance unbreakable by passing the form reference to an internal manager (referenced by My.UBForms) – have fun.

GRM4VFP Alpha Version 0.1

My Global Resource Manager for VFP

I highly recommend to watch the video on YouTube (in a new window) in HD!

Download Alpha Version

Download is coming soon!

Download will be enabled very soon – I just have to make some minor additions and corrections.

 


Previous ChapterNeat Solutions Home (TOC)Next Chapter