Tuesday, June 16, 2009

Instrumenting Menus

A week or so ago I was asked about tracking menu hits in the Visual FoxPro application I am working on for a client. This application is vintage late 1990's so there is no single procedure/object to process menu hits. Each pad/bar has it's own little procedure that run some code. So, I did what I do anytime I am asked to implement something new... I googled it. I found a wonderful article titled Instrumenting FoxPro Applications by Rod Paddock. It was written in 1997. So, the article confirmed what I already knew, I was in trouble because there was not a central menu execution object in this application.

Next I stumbed across the Extending the VFP 9 IDE with MENUHIT and MENUCONTEXT article by Doug Hennig. Ok, so first of all, Intellisense is available at runtime now. I spoke on this a while back. Next, intellisense has exposed "generic" menu events. So, I should be able to use this to instrument my menu without adding code to each menu item. Yes I could! Here is how I did it:

  1. I opened my FoxCode table and copied it to the application's data directory and deleted all of the records.

  2. I added one new record to the application specific FoxCode table with the following field values:

    Type = 'S'
    Abbrev = 'MENUHIT'
    Data = The following program code.


    LPARAMETERS ;
    toParameter

    LOCAL ;
    loSelect AS Object, ;
    lcBar AS Character, ;
    lcPad AS Character

    loSelect = CREATEOBJECT('cSelect')
    lcBar = UPPER(ALLTRIM(toParameter.MenuItem))
    lcPad = UPPER(ALLTRIM(toParameter.UserTyped))

    *!* do not track use by developers
    IF VERSION(2) <> 0
    RETURN
    ENDIF

    SELECT 0
    USE MenuTrack
    LOCATE FOR UPPER(cBar) = lcBar AND UPPER(cPad) = lcPad

    IF NOT FOUND()
    APPEND BLANK
    REPLACE cBar with lcBar, cPad with lcPad
    ENDIF

    REPLACE nCount WITH nCount + 1, ;
    dLastHit WITH DATETIME()

    USE IN SELECT("MenuTrack")


  3. Then, in my main program I added the following lines of code:


    IF FILE(‘FOXCODE.DBF’)
    _FOXCODE = ‘foxcode.dbf’
    ENDIF



It works beautifully and now we are able to track which menu items are called and which ones are called most often. Thanks Rod and Doug!