Manage Your Applications Doug Hennig

Similar documents
Zip it, Zip it Good Doug Hennig

Splitting Up is Hard to Do Doug Hennig

May I See Your License? Doug Hennig

A File Open Dialog Doug Hennig

The Mother of All TreeViews, Part 2 Doug Hennig

IntelliSense at Runtime Doug Hennig

uilding Your Own Builders with BuilderB Doug Hennig and Yuanitta Morhart

Role-Based Security, Part III Doug Hennig

A New Beginning Doug Hennig

Data-Drive Your Applications Doug Hennig

Data Handling Issues, Part I Doug Hennig

Taking Control Doug Hennig

CATCH Me if You Can Doug Hennig

Extending the VFP 9 IDE Doug Hennig

A New IDE Add-on: FoxTabs Doug Hennig

I Got Rendered Where? Part II Doug Hennig

pdating an Application over the Internet, Part II Doug Hennig

Putting Parameters in Perspective Doug Hennig

Christmas Stocking Stuffers Doug Hennig

A Generic Import Utility, Part 2

anguage Enhancements in VFP 7, Part V Doug Hennig

Base Classes Revisited Doug Hennig

Much ADO About Something Doug Hennig

Windows Event Binding Made Easy Doug Hennig

Access and Assign Methods in VFP

A File Open Dialog Box Doug Hennig

The Best of Both Worlds

Report Objects Doug Hennig

Cool Tools by Craig Boyd, Part II Doug Hennig

Speed in Object Creation and. Destruction. March 2016 Number 49. Tamar E. Granor, Ph.D.

Data Handling Issues, Part II Doug Hennig

## Version: FoxPro 7.0 ## Figures: ## File for Subscriber Downloads: Publishing Your First Web Service Whil Hentzen

Web Page Components Doug Hennig

anguage Enhancements in VFP 7, Part I Doug Hennig

More Flexible Reporting With XFRX Doug Hennig

Advisor Answers. January, Visual FoxPro 3.0 and 5.0

Advanced Uses for Dynamic Form

Custom UI Controls: Splitter

Part 1: Understanding Windows XP Basics

Splitting a Procedure File

Word: Print Address Labels Using Mail Merge

Midterm Exam, October 24th, 2000 Tuesday, October 24th, Human-Computer Interaction IT 113, 2 credits First trimester, both modules 2000/2001

Session V-STON Stonefield Query: The Next Generation of Reporting

Keep Track of Your Passwords Easily

XP: Backup Your Important Files for Safety

COPYRIGHTED MATERIAL. Starting Strong with Visual C# 2005 Express Edition

Clean & Speed Up Windows with AWO


Burning CDs in Windows XP

Startup Notes for Standard CMD 2015.x Setup

CHAPTER 1 COPYRIGHTED MATERIAL. Finding Your Way in the Inventor Interface

It s possible to get your inbox to zero and keep it there, even if you get hundreds of s a day.

Multi-User and Data Buffering Issues

FoxTalk. GOING through the classes provided in the FoxPro. More Gems in the FFC. Doug Hennig 6.0

How to Rescue a Deleted File Using the Free Undelete 360 Program

Excel Basics: Working with Spreadsheets

Chapter 1 Introduction

Taskbar: Working with Several Windows at Once

Extending the Unit Converter

Taking Control of Your . Terry Stewart Lowell Williamson AHS Computing Monday, March 20, 2006

Speed Up Windows by Disabling Startup Programs

How To Get Your Word Document. Ready For Your Editor

Manual Vba Access 2010 Close Form Without Saving Record

How To Upload Your Newsletter

Making the Most of the Toolbox

EE261 Computer Project 1: Using Mentor Graphics for Digital Simulation

Strategic Series-7001 Introduction to Custom Screens Version 9.0

MAPLOGIC CORPORATION. GIS Software Solutions. Getting Started. With MapLogic Layout Manager

Printing Envelopes in Microsoft Word

Instructions for Using the Databases

Term Definition Introduced in: This option, located within the View tab, provides a variety of options to choose when sorting and grouping Arrangement

Installing Dolphin on Your PC

Rescuing Lost Files from CDs and DVDs

Getting Started with Amicus Document Assembly

Online Demo Guide. Barracuda PST Enterprise. Introduction (Start of Demo) Logging into the PST Enterprise

Getting Started. Excerpted from Hello World! Computer Programming for Kids and Other Beginners

Intro. Scheme Basics. scm> 5 5. scm>

Hello World! Computer Programming for Kids and Other Beginners. Chapter 1. by Warren Sande and Carter Sande. Copyright 2009 Manning Publications

What you need to know about Windows Security

Mastering the Actuarial Tool Kit

In This Chapter Listening Through the Original Tracks 9 The Alt and Shift Key Secret 11 The Fat Finger Secret 14 Drum Editing Prep 14 Creating an

Financial Statements Using Crystal Reports

Sisulizer Three simple steps to localize

Handling crosstabs and other wide data in VFP reports

FoxTalk. LET S face it. You re going to have to learn Visual. Visual Basic for Dataheads: A New Beginning. Whil Hentzen

The name of our class will be Yo. Type that in where it says Class Name. Don t hit the OK button yet.

Download Free Pictures & Wallpaper from the Internet

Using Microsoft Excel

One of the fundamental kinds of websites that SharePoint 2010 allows

The first thing we ll need is some numbers. I m going to use the set of times and drug concentration levels in a patient s bloodstream given below.

This document explains how to obtain a direct link from within an existing Facebook page to the hotel s booking

Navigating and Managing Files and Folders in Windows XP

How to Get Your Inbox to Zero Every Day

T H E I N T E R A C T I V E S H E L L

Tutorial #5: Color Policy

Creating a new form with check boxes, drop-down list boxes, and text box fill-ins. Customizing each of the three form fields.

Give users a control that makes entering dates as easy as it is in Intuit Quicken.

getting STARTed Virtual Coin Cabinet 2v9 beta COIN database SOFTWARe STePHeN HUSTON FileMaker Pro developer .A FIleMAKeR PRO 10 RUNTIMe SOlUTION

Startup Notes for CMD 2015.x with Remote Database Server Software for CMD 2015, 2014, and 2013 Users

Chapter The Juice: A Podcast Aggregator

Transcription:

Manage Your Applications Doug Hennig This month s article presents a simple yet useful tool, and discusses several reusable techniques used in this tool. If you re like me, your hard drive (or your server s hard drive) is littered with project directories: finished applications, in-progress client work, R & D stuff, etc. Managing and switching between all these directories can be a drag ( was that project in T:\Apps\Clients\ACME Rentals\SalesApp or in F:\Projects\Current\SalesApp? ). Recently, I had to do some remedial work on some FoxPro 2.6 applications (I bet we ve all been doing some of that in the last year or so <g>), and was reacquainted with an old friend: an application manager I d written years ago and forgotten about. It installed in the FoxPro system menu, and was a single keystroke away. This application manager was very simple: it just listed, by a descriptive name, each application I d registered with it, and had functions to select an application, add or edit information about an application, or remove an application from the list. When you selected an application, the application manager made that application s directory the current one and automatically opened the project file. Switching between applications was a piece of cake: Ctrl-L (to invoke the application manager), End (to highlight the last application in the list, for example), and Enter (to make that application s directory the current one and open its project file). (Other developers take similar approaches that are implemented a little differently. For example, FoxTalk Editor Whil Hentzen adds a new pad to the end of the VFP system menu that lists all of his projects as items in the menu). Once I started using my FoxPro 2.6 application manager again, I just had to use something similar in VFP. So, this month s article is about my shiny new application manager. That sounds like kind of a simple topic, you may be thinking. Perhaps, but it s a useful tool and we ll encounter some interesting and useful techniques along the way. The Application Manager Table and Form Figure 1 shows the application manager form when it s running. It has a list of applications registered with the manager and buttons to select, add, edit, and remove an application. Double-clicking or pressing Enter in the list acts like clicking on the Select button. Figure 1. The Application Manager.

Applications are registered with the manager by adding records to APPMGR.DBF. This simple table has two fields: NAME, the descriptive name of the application, and PROJECT, the path and name of the project file for the application. APPMGR.SCX is the application manager form. Its Load method checks for the existence of APPMGR.DBF, and creates it if necessary before opening it. local lcdirectory dodefault() lcdirectory = substr(sys(16), at(' ', sys(16), 2) + 1) lcdirectory = addbs(justpath(lcdirectory)) if not file(lcdirectory + 'APPMGR.DBF') create table (lcdirectory + 'APPMGR') (NAME C(60), ; PROJECT C(128)) index on upper(name) tag APPMGR endif not file(lcdirectory + 'APPMGR.DBF') use (lcdirectory + 'APPMGR') order APPMGR again shared How do we know where to look for APPMGR.DBF? We expect it s in the same directory as APPMGR.APP, so we can use SYS(16) to give us the name of the currently executing method and the file (including path) it s in. In this case, we ll get PROCEDURE FRMAPPMGR.LOAD <your path>appmgr.sct. So, to get the path, we can t just use JUSTPATH(), since that would give us PROCEDURE FRMAPPMGR.LOAD <your path>. Instead, we ll use JUSTPATH() on everything after the second space ( <your path>appmgr.sct ), and use ADDBS() to ensure there s a trailing backslash. The Init method calls the custom GetApps method, which does a SQL SELECT from APPMGR.DBF into the aapps array property of the form. The lstapps listbox on the form has this array as its RowSource so it lists the application descriptions. The DblClick method of the listbox and Click method of the Select button both call Thisform.SelectApp. This method tries to change the current directory to the one containing the project file for the selected application, and then open the project. It tries to handle potential problems, such as the directory not existing or the project file not found. For example, if the directory exists but the project file doesn t, it looks in the directory to see if there are any project files. If there are none, it gives an error message. If there s exactly one, it opens that one (on the assumption that the project file was renamed after it was registered with the application manager). If there s more than one, an Open File dialog is presented so you can pick the project file to open. The Click method of the Remove button calls Thisform.RemoveApp, which simply deletes the record for the selected application and calls GetApps again to refresh the array and listbox. The Click methods of the Add and Edit buttons both call Thisform.EditApp, Add passing it.t. to indicate that we re adding rather than editing. EditApp runs a form called EDITAPP.SCX to get the description of the application and its project file. However, notice that we ll need three return values from EDITAPP.SCX: the description, the project, and whether the user chose OK or Cancel. Since there can only be one return value, how do we handle this? My preferred mechanism is to use a parameter object, one whose sole purpose is to be moved between methods with a package of parameters in its properties. These parameters are two-way; either the caller or the method being called can examine or change them. Because both the caller and the method being called must know the names of the properties in the parameter object, you could create a class for the parameter object for this use. However, if you use this technique a lot, you d quickly find yourself creating a lot of these classes. Being a lazy, er, efficient programmer, I prefer to use a single generic class (SFParameter in SFCTRLS.VCX) for this. This class has a This_Access method that automatically fires whenever anything tries to access a property of the object. The code for that method is as follows: lparameters tcmember if not pemstatus(this, tcmember, 5) This.AddProperty(tcMember) endif not pemstatus(this, tcmember, 5) return This

This code does something pretty cool: if the property being accessed doesn t exist, it s created. This means that even though this object doesn t have, for example, a cmessage property, we can do the following: loproperties = createobject('sfparameter') loproperties.cmessage = 'Howdy' In other words, this class exposes a variable interface; it looks like anything anyone wants it to! OK, back to the EditApp method. The first task is to create an SFParameter object and fill its (created on the fly) properties with either the description and project file name for the selected application or empty values if we re adding an application. Next, if we re editing an application, we position the APPMGR table to the record for the application; this allows EDITAPP.SCX to ensure we don t enter a duplicate record. Then we call EDITAPP.SCX, passing it the parameter object. Upon return, we either do nothing if the user chose Cancel, or create or update the record in APPMGR and call GetApps to refresh the application array and listbox if the user chose OK. In the case of adding an application, we also ensure the new application is highlighted in the listbox. lparameters tladd local lcappname, ; lcproject, ; loproperties * Create a properties object and fill it with either the * name and project for the selected app or blanks for a * new app. lcappname = iif(tladd, '', ; trim(thisform.aapps[thisform.lstapps.listindex, 1])) lcproject = iif(tladd, '', ; trim(thisform.aapps[thisform.lstapps.listindex, 2])) loproperties = MakeObject('SFParameter', 'SFCtrls.vcx') loproperties.cappname = lcappname loproperties.cproject = lcproject loproperties.lnew = tladd loproperties.lsaved =.F. * If we're editing an app, position the APPMGR table to * the record for the selected app. if not tladd seek upper(loproperties.cappname) endif not tladd * Run the EditApp form. If the user saved their changes, * either add or edit the app information. do form EditApp with loproperties do case case not loproperties.lsaved case tladd insert into APPMGR values (loproperties.cappname, ; loproperties.cproject) This.GetApps() lnapp = ascan(this.aapps, loproperties.cappname) if lnapp > 0 This.lstApps.ListIndex = asubscript(this.aapps, ; lnapp, 1) endif lnapp > 0 otherwise replace NAME with loproperties.cappname, ; PROJECT with loproperties.cproject This.GetApps() endcase

EDITAPP.SCX is a simple form: it just has a couple of textboxes so you can enter the application description and project filename. Its Init method accepts the parameter object passed in and stores a reference to it in This.oProperties. The Click method of the OK button (which is an instance of SFOKButton in SFBUTTON.VCX so it has a standard appearance) puts the description and project filename into the cappname and cproject properties of the parameter object, sets its lsaved property to.t. so the EditApp method will know the user chose OK, and then releases the form. There s no code in the Cancel button, since it s an instance of SFCancelButton (also in SFBUTTON.VCX), which has Thisform.Release() in its Click method. One useful thing in EDITAPP.SCX is a button that displays an Open File dialog (using GETFILE()) so the user can select a file. This button is an instance of SFGetFile (in SFBUTTON.VCX). Rather than having to remember all the parameters for GETFILE() and code what to do after the user selects a file, you simply drop this class on a form and set a few properties. The cextensions, ctext, copenbutton, nbuttontype, and ccaption properties represent the appropriate parameters for GETFILE(), cresult contains the name of the location to put the filename the user selected into, and cafterdone contains the name of a method or function to execute after the file dialog is closed. In the case of the instance used in EDITAPP.SCX, cextensions contains PJX (since we only want to select project files), cresult contains Thisform.txtProject.Value (since that s where the filename should be placed), and cafterdone contains Thisform.RefreshForm() (which, while refreshing the form, will enable the OK button if the application name was also entered). Main Program APPMGR.PRG is the main program for the application manager APP file. It consists of a main routine and a few subroutines. The purpose of the main routine is two-fold: to install the application manager in the VFP system menu, and to run the application manager (I prefer to have an APP be self-contained rather than having the installation and execution code in separate places). Which of these tasks is performed depends on how the program is called. If no parameters are passed, or if INSTALL is passed (in other words, you used DO APPMGR.APP or DO APPMGR.APP WITH INSTALL ), this routine will call the InstallAppMgr subroutine to install the application manager in the menu. If RUN is passed (which is what happens when you choose Application Manager from the menu, as we shall soon see), the RunAppMgr subroutine is called to run APPMGR.SCX. Here s the code for the main routine: lparameters tcaction, ; tcpopup local lccurrtalk, ; lcaction * Save the current TALK setting and set it off. if set('talk') = 'ON' set talk off lccurrtalk = 'ON' else lccurrtalk = 'OFF' endif set('talk') = 'ON' * Handle the action parameter: if it isn't passed, we'll * assume "INSTALL". lcaction = iif(vartype(tcaction) <> 'C' or ; empty(tcaction), 'INSTALL', upper(tcaction)) do case * If this is an "install" call, do the installation. case lcaction = 'INSTALL' do InstallAppMgr with tcpopup * Run the application manager. case lcaction = 'RUN' do RunAppMgr endcase

* Cleanup and return. if lccurrtalk = 'ON' set talk on endif lccurrtalk = 'ON' return Notice that this routine can accept two parameters: the action ( RUN, INSTALL, or nothing, which means INSTALL ) and the name of the menu popup into which to install the application manager. As we ll see in a moment, the default popup is _MSM_TOOLS, the popup for the Tools menu, but you can pass the name of another popup (note it must be the popup name, not the prompt that appears in the menu; see System Menu Names in the VFP help file for a list of the names) if you want it installed under a different menu item. There s another good reason for passing the popup, even _MSM_TOOLS, as I ll discuss shortly. The RunAppMgr subroutine, called when RUN is passed to APPMGR.APP, is very simple: it just consists of DO FORM APPMGR. I could ve placed this code directly into the main routine rather than calling a subroutine, but this approach is more modular. The main routine calls InstallAppMgr to add the application manager to the system menu. This routine defines a couple of constants that specify the prompt to appear in the menu (including the hot key for it) and the popup to install in if one isn t specified (_MSM_TOOLS). The first task of this routine is to determine what directory this program is running in. We need it so we can hard-code the path to find APPMGR.APP into the menu; after all, we don t want to have the directory in the VFP path and it certainly won t be in the current directory. This uses the same technique involving SYS(16) I discussed earlier. lparameters tcpopup local lcdirectory, ; lnbar, ; lcbar, ; llpopup, ; lcpad, ; lni #define ccmenu_bar_prompt 'Appl\<ication Manager' #define ccmenu_pad '_MSM_TOOLS' lcdirectory = substr(sys(16), at(' ', sys(16), 2) + 1) lcdirectory = addbs(justpath(lcdirectory)) The next thing to do is to see if an item for the application manager has already been added to the menu. This might happen if, for example, you run this program more than once. We wouldn t want to have two items for the application manager in the menu, so if we find one, we ll just reuse it. We ll use CNTBAR() to get the number of bars in the popup, then step backwards through them (since the application manager item is added at the bottom of the menu, this is faster than starting at the top and working down). GETBAR() gives us the number of a bar in a menu based on its position, and PRMBAR() gives us the prompt of the specified bar. Since PRMBAR() gives us the prompt without any hot key characters (\<), we ll compare the prompt against the desired prompt stripped of these characters. lnbar = 0 lcbar = strtran(ccmenu_bar_prompt, '\<') llpopup = vartype(tcpopup) = 'C' and not empty(tcpopup) lcpad = iif(llpopup, tcpopup, ccmenu_pad) for lni = cntbar(lcpad) to 1 step -1 if prmbar(lcpad, getbar(lcpad, lni)) = lcbar lnbar = lni exit endif prmbar(lcpad... next lni If we didn t find the application manager in the menu, we ll add a separator line and a new bar at the end of the menu. We ll then define what to do when the item is chosen. Notice that the directory is hardcoded into the menu using macro expansion; this is necessary because we can t use the lcdirectory variable when the menu item is chosen since that variable won t exist. We also use LOCFILE() if for some reason

VFP can t find APPMGR.APP where it was originally located. APPMGR.APP will be passed RUN so the main routine in APPMGR.PRG knows to run the application manager rather than install it. if lnbar = 0 lnbar = cntbar(lcpad) + 1 define bar lnbar of &lcpad after _mlast prompt '\-' define bar lnbar + 1 of &lcpad after _mlast ; prompt ccmenu_bar_prompt else lnbar = lnbar - 1 endif lnbar = 0 on selection bar lnbar + 1 of &lcpad ; do locfile('&lcdirectory.appmgr.app', 'APP', ; 'Locate APPMGR.APP') with 'Run' if not llpopup set sysmenu save endif not llpopup return Notice something interesting at the end of this code: if no popup name is specified, we use SET SYSMENU SAVE to ensure that SET SYSMENU TO DEFAULT doesn t wipe out the application manager item in the menu. However, we don t do this if a popup name is passed as a parameter. The reason for doing this is something Toni Feltman of F1 Technologies pointed out to me: if you use more than one SET SYSMENU SAVE, your chance of getting a menu manager inconsistency error (which terminates VFP faster than you can say GPF ) at some point in your VFP session skyrockets. So, if you want to add several items to your VFP system menu, it s best to leave the SET SYSMENU SAVE command until after you ve added them all. Although I don t like to mention products I ve developed in my articles, a feature I recently added to Stonefield Database Toolkit (SDT) is pertinent here: SDT.APP (which adds two items to the Tools menu) accepts the action and popup name parameters using almost the same code as APPMGR.PRG (in fact, I shoplifted the code for APPMGR.PRG from SDT <s>). So, if you want to add both the application manager and SDT to your system menu, here s the best way to do that: do APPMGR.APP with 'Install', '_MSM_TOOLS' do SDT.APP with 'Install', '_MSM_TOOLS' set sysmenu save This defers SET SYSMENU SAVE until all the custom items have been added to the menu. An example of where you might do this is in some program automatically executed when you start VFP (for example, I have _STARTUP = VFPSTART.PRG in my CONFIG.FPW and have code I want executed every time VFP starts in this PRG). Conclusion Although this is a simple tool, I find myself using it at least a dozen times a day (am I the only one who s usually at about four levels of interrupt deep at any one time <g>?), so it saves me lots of time trying to remember the exact name of a directory, typing it correctly, and then remembering (and typing correctly) the name of the project file to open. In addition to a useful tool, I hope you also picked up a few useful techniques. Doug Hennig is a partner with Stonefield Systems Group Inc. in Regina, Saskatchewan, Canada. He is the author or co-author of Stonefield s add-on tools for FoxPro developers, including Stonefield Database Toolkit, Stonefield Query, and Stonefield Reports. He is also the author of The Visual FoxPro Data Dictionary in Pinnacle Publishing s The Pros Talk Visual FoxPro series. Doug has spoken at the 1997, 1998, and 1999 Microsoft FoxPro Developers Conferences (DevCon) as well as user groups and regional conferences all over North America. He is a Microsoft Most Valuable Professional (MVP) and Microsoft Certified Professional (MCP). He can be reached at dhennig@stonefield.com.