The Happy Project Hooker

Doug Hennig

Project objects and ProjectHooks are new in VFP 6. Together, they provide the ability to add to or change the behavior of the Project Manager. Doug's article presents tools that allow you to have project-specific field mappings, perform a text search on all files in a project, log activities, and have a toolbar of useful project functions.

Until VFP 6, the only "official" way to work with a project was through the Project Manager. While the Project Manager is a fine tool, it has a fixed feature set and user interface. Developers often wanted more functionality and had to resort to hacking the PJX file to get it. Here are some typical examples:


VFP 6 changes our approach to projects. There's no longer a need to hack the PJX file, because VFP 6 provides a new interface to projects: Whenever a project is opened, a Project object is now instantiated. Interestingly, Project objects are Automation -- not native VFP -- objects. This has several consequences:


There are two ways you can work with a Project object: through the Application (or _VFP) Projects collection or with Application.ActiveProject. Similar to VFP's Forms collection and ActiveForm property, there's an object reference to every open project in the Projects collection and a reference to the active project in the ActiveProject property. Like ActiveForm, ActiveProject is undefined (the TYPE function returns "U") when there's no open project.

As if Project objects weren't enough, VFP 6 also gives us ProjectHook objects. A ProjectHook object may be automatically instantiated when a project is opened (you have complete control over whether ProjectHooks are used or not), and its events are fired whenever something is done to the project: adding or removing files, modifying or running files, or building the project. ProjectHook is a new VFP base class, so we can create our own ProjectHook classes and put any code into them we want. Thus, we have a hook into the operation of the Project Manager, and we can even completely manipulate projects without using the Project Manager at all.

Because you'll need some background into Project objects and ProjectHooks before you can build some tools using them, this article will have more background than is usual for my articles. Please bear with me; I'll get to the good stuff soon.

Project object model
The object model for the Projects collection and Project objects is shown in Figure 1. As you can see, a Project object contains a reference to a ProjectHook object and has both Files and Servers collections. We'll look at these objects and collections, as well as their properties, events, and methods.

Projects collection
The Projects collection only has one property, Count (the number of Project objects in the collection), and one method, Item (which returns a reference to the specified project). Here are some examples:

? Application.Projects.Count
? Application.Projects.Item[1].Name


Like other collections, you can specify an index to the collection itself rather than having to use the Item method:

? Application.Projects[1].Name


One really cool thing about this collection (and other new collections in VFP) is that you can reference a project by index number or name. Thus, the following code works just fine as long as there's an open project called SOURCE (you must specify the extension or you'll get an error, but you don't have to specify the path):

? Application.Projects['source.pjx'].BuildDateTime


Project object
The properties of Project objects are listed in Table 1; properties common to all VFP base classes are omitted. You'll recognize many of these properties from the Project Info and EXE Version dialog boxes available from the Project Manager. In this table, "Access" is either read-only (R/O) or read-write (R/W), and "Type" is the data type of the property ("L" for logical, "C" for character, "O" for object, and so forth, plus "Coll" for collection).

Property Access Type Description
AutoIncrement R/W L .T. to increment the VersionNumber property when an EXE or DLL is built.
BuildDateTime R/O T The date and time of the last build.
Debug R/W L .T. to include debugging information for each compiled file.
Encrypted R/W L .T. to encrypt files as they're compiled.
Files R/O Coll A collection of File objects.
HomeDir R/W C The home directory of the project.
Icon R/W C The icon used when building an EXE.
MainClass R/O C The name of the ActiveDoc class used as the main program (only used when MainFile contains the name of the VCX where this class is defined).
MainFile R/O C The main program in the project, set using the SetMain method.
Name R/O C The name of the project, including the fully qualified path.
ProjectHook R/W O A reference to the ProjectHook object associated with the project.
ProjectHookClass R/W C The name of the class from which the ProjectHook object is instantiated.
ProjectHookLibrary R/W C The class library in which the ProjectHook class is defined.
SCCProvider R/O C The name of the source code control provider if the project is under source code control.
ServerHelpFile R/W C The name of the Help file for the typelib used for server classes.
ServerProject R/W C The first part of the ProgID for the Automation server created by the project; the default is the same as the Name property.
Servers R/O Coll A collection of Server objects.
TypeLibCLSID R/O C The typelib Registry CLSID.
TypeLibDesc R/W C The typelib description. The default is the name of the project + "Type Library".
TypeLibName R/O C The fully qualified path to the typelib for the project.
VersionComments R/W C Version comments.
VersionCompany R/W C Version company name.
VersionCopyright R/W C Version copyright.
VersionDescription R/W C Version description.
VersionNumber R/W C Version number in Major.Minor.Revision format.
VersionProduct R/W C Version product name.
VersionTrademarks R/W C Version trademarks.
Visible R/W L .T. (the default) to display the Project Manager.

Table 1: Project object properties.

Project objects have the following methods (see the VFP documentation for syntax):


Files collection
The Files collection is a collection of File objects, one for each file in a project. It has one property, Count (the number of files in the collection), and two methods, Item (which returns a reference to the specified file) and Add (which adds a file to the project and returns an object reference to it). Here are some examples:

oProject = Application.ActiveProject
? oProject.Files.Count
? oProject.Files[1].Name
? oProject.Files['myclasses.vcx'].Description
oFile = oProject.Files.Add('myprogram.prg')


File object
The properties of File objects are listed in Table 2; properties common to all VFP base classes are omitted.

Property Access Type Description
CodePage R/O N The code page for the file.
Description R/W C The description shown in the Project Manager.
Exclude R/W L .T. if the file is excluded from the project.
FileClass R/O C The class a form is based on.
FileClassLibrary R/O C The library the form's class is defined in.
LastModified R/O T The date and time the file was last modified.
Name R/O C The name of the file, including the fully qualified path.
ReadOnly R/O L .T. if the file is read-only.
SCCStatus R/O N The source code control status of the file. "0" means the file isn't source controlled; see the VFP documentation for other values (such as checked out or not).
Type R/O C The file type: V for VCX, P for program, R for report, B for label, K for form, Q for query, L for API library, D for table, d for database, Z for APP, M for menu, T for text, and x for other.

Table 2: File object properties.


File objects have the following methods (see the VFP documentation for syntax):


Servers collection
The Servers collection is a collection of Server objects, one for each Automation server in a project. It has one property, Count (the number of files in the collection), and one method, Item (which returns a reference to the specified server).

Server object
The properties of Server objects are listed in Table 3; properties common to all VFP base classes are omitted.

Property Access Type Description
CLSID R/O C The Registry CLSID for the server.
Description R/W C The server's description in the Registry.
HelpContextID R/W N The help context ID for the typelib.
Instancing R/W N Specifies how the server is instantiated: 1 (the default) for single use, 2 for not creatable outside of VFP, or 3 for multi-instance.
ProgID R/O C The Registry ProgID for the server.
ServerClass R/O C The class name of the server.
ServerClassLibrary R/O C The library the server class is defined in.

Table 3: Server object properties.


ProjectHooks
As I mentioned earlier, VFP has a new ProjectHook base class. A ProjectHook object may be automatically instantiated when a project is opened (you have complete control over whether ProjectHooks are used or not), and its events are fired whenever something is done to the project: adding or removing files, modifying or running files, or building the project. Like Project objects, ProjectHooks are actually ActiveX objects, not native VFP objects.

You can set a ProjectHook for individual projects or globally. To specify which ProjectHook class to use for an individual project, choose the Project page of the Project Info dialog box, and choose the desired class for the Project Class. You can also set the ProjectHookClass and ProjectHookLibrary properties of the Project object, although this won't instantiate the ProjectHook class until the project is closed and reopened. To set a ProjectHook for all projects that don't have individually specified ProjectHooks, use the Projects page of the Tools Options dialog box. You can also instantiate a ProjectHook object and store a reference to it in a Project object's ProjectHook property, but this provides a non-persistent hook to the project.

Once a ProjectHook class has been specified for a project, the ProjectHook object is automatically instantiated whenever the project is opened, and it's destroyed when the project is closed. If you want to open a project but not instantiate the ProjectHook, use the new NOPROJECTHOOK clause of the MODIFY PROJECT command. You can also use NOPROJECTHOOK with CREATE PROJECT to create a project without the global ProjectHook. These two commands have another new clause, NOSHOW, that instantiates the Project and ProjectHook objects but doesn't display the Project Manager, so you can manipulate a project without any user interface at all.

ProjectHook events
ProjectHook objects don't have any properties beyond those of other VFP base classes, but they have several specific events that automatically fire when something is done to the project (see the VFP documentation for parameters these events receive):


Extending functionality
Because a ProjectHook object is automatically instantiated when a project is opened from a user-defined class, and its events are automatically called when something is done with the project, you have the ability to define what happens when the user works with a project. I'm sure you can think of all kinds of things you could do with this capability; I'll discuss some of the ideas I've come up with.

Before I discuss what types of tools you can build, however, keep one thing in mind: Avoid the temptation to build a ProjectHook with everything in it, including the kitchen sink. There are a number of good reasons for making your ProjectHook classes granular:


There are several ways you can build modular ProjectHook classes and use dynamic composition to put them together:

Conclusion

Thanks to the new Project objects and ProjectHooks in VFP 6, we can now add to or change the behavior of the Project Manager. This allows us to create tools that give us more capabilities or more productivity than we get with the Project Manager. I expect we'll be seeing a lot of such tools in the months ahead.



Doug Hennig is a partner with Stonefield Systems Group Inc. in Regina, Saskatchewan, Canada. He is the author of Stonefield's add-on tools for FoxPro developers, including Stonefield Database Toolkit and Stonefield Query. 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 and 1998 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). 75156.2326@compuserve.com, dhennig@stonefield.com.