Inside the Visual FoxPro 8.0 Toolbox
Beth Massi, www.BethMassi.com
May 2003
Applies to:
Visual FoxPro 8.0
Summary: Learn how the Visual FoxPro 8.0 Toolbox works and see how to customize it to fit your work style and your projects. Create and distribute tool sets to your development teams and create create tool set installation packages. Learn the Toolbox architecture and how to extend the Toolbox easily by creating powerful add-in behaviors. Override existing behaviors and add your own new tool and category types.
Contents
Introduction
Tool Sets
Third-Party Tool Sets
Toolbox Architecture
Creating Add-In Behaviors
Overriding Behaviors and Supporting New Tool Types
Supporting New Category Types
Conclusion
Introduction
The Visual FoxPro Toolbox is a new enhancement to the Visual FoxPro Integrated Development Environment (IDE), which aids in the Visual FoxPro Development experience. The Toolbox displays by category user-customizable tool sets that the developer deems important for the creation of their applications. Tool sets typically contain classes and components but can also hold references to common file-based resources such as forms, programs, tables, reports, images, and so forth. They can also contain other types, such as ActiveX controls, builders and wizards, or XML Web service items. Items in the tool set can be dragged onto the workspace, clicked to run other default actions, or contain other behaviors accessible from the item shortcut menus.
Because you have complete control over the Toolbox, it becomes an essential part of the IDE. And like practically every feature in the Visual FoxPro IDE, the Toolbox is extensible. So if a type of tool or behavior is not currently supported, you can add new behaviors and tool types without having to recompile the Toolbox application. The individual tool sets are loaded into the Toolbox whose architecture also supports add-in behaviors, tools, and categories. This way third-party vendors or enterprise architects can easily provide their own specialized dynamic tool sets to achieve the ultimate in rapid application development.
In this article, you'll learn how you can create and distribute tool sets to your development teams and how third-party vendors can create tool set installation packages. You will gain an understanding of the Toolbox architecture and how to extend the Toolbox easily by creating powerful add-in behaviors. You will also learn how to override existing behaviors and add your own new tool and category types.
For more information on how to use the Visual FoxPro Toolbox and a complete discussion on the supported tool and category types, see the article in the February issue of Universal Thread Magazine.
Tool Sets
A tool set is a group of tool items contained in a category in the Toolbox. The items inside the tool set can represent many different types of objects. These objects can be classes from Visual FoxPro class libraries that are dragged onto the workspaces just as you can currently do with the form and class toolbars. But while Visual FoxPro toolbars expose all the classes in a library, the Toolbox can expose only the classes you want. The Toolbox also supports items that represent builders or wizards, ActiveX controls, XML Web services, and text scraps. In addition to these items, the Toolbox can represent file-based resources such as databases, tables, images, reports, labels, menus, forms, applications, programs and projects.
When developing systems with a team, it is typical for an architect or a group of senior developers to create a framework of Visual FoxPro classes and possibly builders or other resources to use on the project. The files are then distributed to the development team. However, because all the classes in a class library are exposed when loaded onto the Visual FoxPro class toolbar, members of the development team must invest time in learning which classes are abstract framework classes and which ones should be used in their development. To help your developers access the classes you want them to use, you can set up Toolbox tool sets and distribute them to your development team. These tool sets are not limited to classes. They can contain any type of item, such as links to other applications or resources. You can also set up dynamic folder categories that display items from a network file system folder so that developers can access shared resources easily.
The Toolbox stores all its content in a Visual FoxPro data table (.dbf) specific to each user. The Visual FoxPro Toolbox ships with default content contained in this table that is created the first time the Toolbox is opened. When you customize the Toolbox, you are modifying the content in this table. By default, the names of the content table files are Toolbox.dbf, Toolbox.fpt, and Toolbox.cdx. They are stored in your HOME(7) folder: \Documents and Settings\UserName\Application Data\Microsoft\Visual FoxPro 8\Toolbox\.
To create tool sets for your developers, customize your Toolbox to populate categories with framework classes, builders, and other tools that your developers should use on the project. You can even set up dynamic categories and category filters. Then all you have to do is distribute your Toolbox content table to the development team along with the actual framework class libraries and files.
When the Toolbox opens for the first time, it prompts for the Toolbox content table. The developer can then choose to load the content you supplied by selecting the appropriate option and locating the .dbf file. After the Toolbox has loaded once, the developer can switch between content tables using the Customize Toolbox > Options page by right-clicking the Toolbox and selecting Customize Toolbox on the shortcut menu. On the Customize Toolbox form, click General and then click Options from the tree view on the left. This displays all the Toolbox options. The path and name of the Toolbox content table is displayed in the middle of this form (Figure 1). Enter the new path and name or click the ellipsis (...) button to locate the .dbf file.
Figure 1 Alternate Toolbox content tables can be specified from Customize Toolbox > Options.The actual class libraries should be distributed into the same relative folders on the development computers for ease of use. However, if the developer uses a tool item and the Toolbox cannot locate the associated class, it prompts the developer to locate the class library and updates the tool item's data with this information. For example, if you create a tool item that refers to a class called MyClass in a library located in C:\MyFramework\MyClasses.vcx, you should distribute the class library MyClasses.vcx into the same folder on the developer's computer. If you do not do this, the developer is prompted for the location when the tool is used.
Before you set up enterprise tool sets in your Toolbox, you probably do not want to distribute any personal content you have set up. For instance, you may have created categories and filters that you do not want to distribute. What you need to do is back up your content and then restore the Toolbox to its original content. You can do this easily from the Customize Toolbox > Options page. You can restore the Toolbox content by clicking the Reset Toolbox to Default button. You will be prompted: "Do you want to maintain new categories and Toolbox items that were added by you or a third-party vendor?" If you click No, the entire Toolbox table is restored to the default installation, removing all user customizations, and a backup copy is made in the same directory. (The backup files are cumulative; for example, the first backup created is called ToolboxBackup, the second is ToolboxBackup_1, the third is ToolboxBackup_2, and so forth.)
Now you can customize your Toolbox by creating tool items, categories, and filters. When you are done, distribute the Toolbox content table and any required class libraries or files to your developers. If you made many additions and deletions to the content, you can clean up the Toolbox table before distributing it to your team. Select the Clean Up Toolbox button on the Options page to perform a PACK on the Toolbox content table. This permanently removes all deleted records and reduces table size. You can then switch back to your personal content by selecting the backup copy of your Toolbox table on the Options page.
Third-Party Tool Sets
Third-party tool sets are created in the same manner as enterprise tool sets except that they also have the additional requirement of installing directly into the developer's content table. Instead of the developer's switching between Toolbox content tables from the Toolbox Options page, the tool sets should be available from the developer's Toolbox along with the customized content. This can also be a requirement for an enterprise tool set. It involves adding and possibly updating records in the Toolbox data table.
Creating Tool Sets
When you create tool, category, and filter items in the Toolbox, records are added to the Toolbox content table. By default, the unique IDs for these items take the form of User.Sys(2015). The Visual FoxPro function SYS(2015) returns a unique 10-character name. If you add an item to the Toolbox, the unique ID is similar to User._0VC0UV6D2. This is important when creating third-party tool sets. After you are finished creating your tool set, you need to rename the items to be unique to your company or product, for example, CompanyName.Sys(2015). This way, you can create installation and upgrade scripts that affect only these items.
To create a simple third party-tool set from scratch, first restore the Toolbox content table by clicking the Reset Toolbox to Default button on the Customize Toolbox > Options page. When prompted to maintain user-added items, click No. This backs up your content table and removes all customizations. Now add a category to the Toolbox. You can do this directly from the Toolbox shortcut menu or by selecting a category in the tree view on the Customize Toolbox form and then selecting Add Category button on the category toolbar. For this example, create a general category called "Cool Tools."
Now add a class library by selecting the Add Item button and selecting Class in the Add Item dialog box and then picking a class library. Suppose you have a class library called CoolTools.vcx in a subdirectory of the Visual FoxPro home directory called CoolTools\ that contains three classes: CoolBaseControl, CoolControl, and CoolForm. After you select this class library, the tool items are displayed in the item grid and are all selected by default. Developers shouldn't use the CoolBaseControl directly because this is an abstract class, so you need to clear that item in the grid (Figure 2). You can also edit the tools names directly in the grid. If you are going to distribute a Help file for your tools, that file can be entered on the item properties sheet by clicking the Item Properties button on the item toolbar.
Figure 2 The Toolbox can be set to display only the classes you want to expose.
Now take a look at the records that were created in the content table. Close the Toolbox and browse the Toolbox table:
USE HOME(7)+"Toolbox" EXCLUSIVE GO BOTTOM BROWSE
This assumes your Toolbox table is installed in the default location. You will see a record for the category you added and a record for each item in the class library. In this case, there are only three classes, and one of them is inactive. So you should see something similar to the Table 1.
Table 1 Toolbox table for Cool Tools
| UniqueID | Showtype | ToolTypeID | ParentID | ToolName | Inactive |
|---|---|---|---|---|---|
| user._0VK0ZMPDL | C | CATEGORY.GENERAL | Cool Tools | .F. | |
| user._0VK0ZQV7H | T | CLASS | user._0VK0ZMPDL | coolbasecontrol (COOLTOOLS) | .T. |
| user._0VK0ZQV8V | T | CLASS | user._0VK0ZMPDL | Cool Control | .F. |
| user._0VK0ZQVAJ | T | CLASS | user._0VK0ZMPDL | Cool Form | .F. |
The Toolbox table structure is explained in detail in the next section, but for now take a look at the UniqueID, ToolTypeID, ShowType, and ParentID fields. The ShowType and ToolTypeID fields indicate which type of Toolbox item to display. You should also notice that the ParentID on the tool item is set to the category UniqueID. These four records make up your tool set data. Before you start writing the installation script, rename the UniqueIDs to include your company name. This makes it easier if the tool set needs to be redistributed because of an upgrade. You can write code to do this automatically. However, for this example, it is easy to do manually right in the browse window. The tool set records should now look similar to Table 2.
Table 2 The Toolbox table once you rename the UniqueIDs
| UniqueID | Showtype | ToolTypeID | ParentID | ToolName | Inactive |
|---|---|---|---|---|---|
| MASSI.COOLCAT | C | CATEGORY.GENERAL | Cool Tools | .F. | |
| MASSI.COOLBASE | T | CLASS | MASSI.COOLCAT | coolbasecontrol (COOLTOOLS) | .T. |
| MASSI.COOLCTRL | T | CLASS | MASSI.COOLCAT | Cool Control | .F. |
| MASSI.COOLFORM | T | CLASS | MASSI.COOLCAT | Cool Form | .F. |
The next step is to take these records and put them into a table of their own so you can include it in the installation package. For this example, create a table called CoolToolbox.dbf and append just these records into that table.
CD HOME()+"CoolTools" USE HOME(7)+"toolbox.dbf" IN 0 ALIAS Toolbox SELECT Toolbox COPY TO CoolToolbox FOR LEFT(uniqueid,6) = "MASSI." AND NOT DELETED()
Creating Installation Scripts
Now that you have your tool set records set up properly in their own table, you are ready to write an installation script that appends these records into the developer's Toolbox content table and copy the CoolTools class library into the proper folder. This example installs the tool set only if it does not already exist in the Toolbox. Typically, you handle upgrading your tool sets and creating new ones. However, this just involves standard FoxPro data manipulation of the Toolbox content.
Create a program called Setup.prg and put it in the same folder as the tool set and class library files—in this case, \Microsoft Visual FoxPro 8\CoolTools\. The code is very basic and does not have a user interface, but you can just as easily create your setup to be a form instead of a program. The trick in this setup code is that it uses the _oToolbox global variable to get to the location of the Toolbox table and closes the Toolbox before installation begins. Then the class library is copied from the current folder into the target folder, and your tool set records are appended to the Toolbox content table. There are obviously many ways you can write your setup scripts, but this code does a nice job for this example.
LOCAL lQuit, cToolboxTable, cSourceFolder, ;
cTargetFolder, oExc, cSetDeleted, nPrevArea
lQuit = .F.
cSourceFolder = ADDBS(JUSTPATH(SYS(16)))
cTargetFolder = HOME()+"CoolTools\"
cSetDeleted = SET("Deleted")
nPrevArea = SELECT()
SET DELETED ON
*-- Get the location of the Toolbox table, then close the Toolbox.
TRY
IF VARTYPE(_oToolbox)<>"O"
DO (_TOOLBOX)
ENDIF
cToolboxTable = _oToolbox.ToolboxTable
_oToolbox.Release
CATCH TO oExc
MESSAGEBOX(oExc.Message)
lQuit = .T.
ENDTRY
IF lQuit
RETURN
ENDIF
TRY
*-- Open the user's Toolbox content table and see if
*-- your tools are already there
USE (cToolboxTable) IN 0 ALIAS ToolboxTable
SELECT ToolboxTable
LOCATE FOR LEFT(UniqueID,10)=="MASSI.COOL"
*-- If our tool set is not found, create the library folder,
*-- copy the class library, and append this tool set
*-- records into the Toolbox content table.
IF NOT FOUND()
TRY
MD (cTargetFolder)
CATCH
ENDTRY
COPY FILE cSourceFolder+"CoolTools.vc*" TO cTargetFolder+"CoolTools.vc*"
APPEND FROM (cSourceFolder+"CoolToolbox.DBF")
ENDIF
CATCH TO oExc
MESSAGEBOX(oExc.Message)
lQuit = .T.
FINALLY
IF USED("ToolboxTable")
USE IN ToolboxTable
ENDIF
ENDTRY
IF lQuit
RETURN
ENDIF
*-- Re-open the Toolbox with the installed tool set displayed.
DO (_TOOLBOX) WITH "MASSI.COOLCAT"
MESSAGEBOX("Your Cool Tools are now installed.")
SET DELETED &cSetDeleted
SELECT (nPrevArea)
Now your Cool Tools tool set is ready for distribution. The files you need to distribute are contained in the Microsoft Visual FoxPro 8\CoolTools folder and are listed in Table 3.
Table 3 Files needed for your Cool Tools tool set distribution
| File Name | Description |
|---|---|
| CoolToolbox.dbf CoolToolbox.fpt | These files contain the tool set data to be loaded into the Toolbox. |
| CoolTools.vcx CoolTools.vct | These files contain the actual cool classes for developers to use. |
| Setup.prg | This is the installation script. |
Packaging and Distributing Tool Sets
There are many ways to create your distribution package, from simple ZIP files all the way to a complete Microsoft Installer package (MSI). However, there is an even better way to distribute and install these third-party tool sets by creating a task pane in the Task Pane Manager. The Task Pane Manager is another new feature of the Visual FoxPro 8.0 IDE. You use it to create task panes that users can install. After the user installs the pane, you can provide a link there to kick off the setup script for your tool set. By creating a task pane, you can also provide dynamic content to broadcast any updates, Help, or other information that relates to the Cool Tools tool set. The panes can consist of XML/XSLT, HTML, display entire Web pages on the Internet, call XML Web services, or contain Visual FoxPro controls. The best part is that the Task Pane Manager automatically packages all dependent files into one file for distribution.
For this example you can create an HTML pane that pulls dynamic content from an XML file on your local computer. In reality, the content on the pane should come from your company's Web server on an intranet or the Internet. In addition to HTML, XML, and XSLT, task panes can also run rich Visual FoxPro code from a class library or program file. If you are not familiar with mark-up languages, you can just as easily create panes written in Visual FoxPro.
Creating a Task Pane
First, open the Task Pane Manager, and click the Options button to open the Task Pane Options dialog box. On the tree view on the left, select Task Pane Manager - Customize, and then click the Customize Panes button. This opens the Pane Customization form. Click the New button (ALT+N) to create a new pane. You are prompted for your vendor name and a unique ID. You should follow the same naming convention as described earlier when creating a tool set. In the Name box, type Cool Tools, and select HTML as the Pane Type (Figure 3).

Figure 3 Set up an HTML task pane by specifying your Vendor name and Unique ID.
A Cool Tools node is created in the pane content tree view on the right, and the General tab is displayed. This node is referred to as the root content. You can select an image to display on the Task Pane Manager by clicking the Select Image button (Figure 4); otherwise, a default image is provided for you.
Figure 4 Content sections you create are displayed in the pane content tree on the Pane Customization form.
Adding Pane Content
Click the Add button (ALT+D) to add a content subsection. By default, it creates a section called New Content. On the General tab, type the name Install. This section will be a static link that runs some handler code that calls an installation script (Setup.prg). Open the Data tab, and select Static Text for the Source, and type the following HTML:
<a href="vfps:runinstaller" class="button">Install Tool Set</a>
The special href syntax vfps: calls the handler code, passing the action runinstaller. Open the Handler Code tab and enter the following Visual FoxPro code:
LPARAMETERS cAction, oParameters, oBrowser, oContent
TRY
DO CASE
CASE cAction == "runinstaller"
DO (oContent.CacheDir+"setup.prg")
ENDCASE
ENDTRY
The CacheDir property of the content object returns the full path to the folder where your task pane is installed. This is where the tool set files will also be installed (more on this later). When you click the Install Tool Set link in the task pane, this code runs the Setup.prg.
Next, you create the dynamic content section. If you do not want to broadcast dynamic content in your task pane, you can skip the next section.
Adding Dynamic Pane Content
To set up a dynamic content subsection, click the Add button (ALT+D), and type What's New in the Name box. This subsection content displays data from an XML file. So that this section appears at the top, click the move up arrow located above the pane content tree. Then open the Data tab, and select URL for the Source and type the following in the text box:
file://c:/coolinfo.xml
In reality, this should be an http: address for a file located on the Internet. However, for this example, it will pull from a local file. Keep in mind, though, this file is not distributed with the task pane, so specifying a local file here would not work on another computer. However, this technique is great for testing.
Now you create the Coolinfo.xml file, and place it on your C drive. The schema of the XML is totally up to you. In a moment, you will specify a style sheet, so you have total flexibility in the way you structure your data. In fact, there are so many ways the task panes can be created that the content file does not even have to be XML. For this example, the XML content is very simple.
<?xml version='1.0' encoding='windows-1252' standalone='no'?>
<VFPData>
<content>
<name>Cool Tools Home Page</name>
<link>
<![CDATA[vfps:linkto?url=http://www.massitools.com/default.htm]]>
</link>
<desc>Take a tour of all the Cool Tool products!</desc>
</content>
<content>
<name>Cool Tools Reference</name>
<link>
<![CDATA[vfps:linkto?url=http://www.massitools.com/help.htm]]>
</link>
<desc>Access the Cool Tools Help file.</desc>
</content>
<content>
<name>Cool Tools News</name>
<link>
<![CDATA[vfps:linkto?url=http://www.massitools.com/news.htm]]>
</link>
<desc>Get the most up-to-date information on Cool Tools.</desc>
</content>
</VFPData>
There are three content nodes defined in the XML file that contain brief descriptions and URLs to Web pages on the Internet (though the URLs in this example do not really exist). Now you specify the transformation of this data. Click the Transform Data tab, select XSL as the Type, Static Text as the Source, and enter the following XSL transformation:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="VFPData">
<table border="0" width="100%" cellpadding="2" cellspacing="0" >
<xsl:apply-templates />
</table>
</xsl:template>
<xsl:template match="content" name="contents">
<xsl:variable name="linkvar" select="link"/>
<tr>
<td>
<a href="{$linkvar}"><xsl:value-of select="name"/></a>
</td>
</tr>
<tr>
<td class="description">
<xsl:text>- </xsl:text><xsl:value-of select="desc"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
This transforms your XML into an HTML table that will be used on the final transformation of the root content. Now the XML content contained in the Coolinfo.xml file is downloaded from the specified location and cached according to the Task Pane Manager settings. If the connection cannot be established later, the cached copy is used. If the URL cannot be reached the first time you open the pane, you can specify default XML data to display on the Default Data tab.
Merging Content Subsections
Now that you have created the subsection content, you need to pull them together into the root content section, which is the information displayed in the task pane. Select the root content Cool Tools from the Pane content tree. Click the Data tab, and select Static Text as the Source. Enter the following into the edit box:
<VFPData> <!-- XMLCONTENT --> </VFPData>
The XML comment specifies that internal XML content is going to be the data source for this pane. When the Task Pane Manager renders this pane, it replaces the comment <!-- XMLCONTENT --> with the content data from all the subsections before it runs its own final transformation. You specify the final transformation into an HTML document on the Transform Data tab. On this tab, select XSL as the Type and Static Text as the Source. Then enter the following XSL transformation:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<xsl:template match="VFPData">
<html>
<head>
<title>Cool Tools</title>
<style>
BODY {
font-family:verdana;
font-size:9pt;
margin-top:0px;
margin-left:2px;
margin-right:2px;
margin-bottom:2px;
}
H3 {margin-bottom:0px; margin-top:0px; font-weight: bold}
A:link {color: #0033CC;text-decoration: none}
A:visited {text-decoration: none}
A:hover {color: #CC0000;text-decoration: underline}
A {text-decoration: underline; color: #0066FF}
TD {font-size:9pt}
TD.TableTitle { padding:2px;background-color:#0000FF;color:#FFFFFF; }
H3 {margin-bottom:0px;margin-top:0px; font-weight: bold}
TD.Description {font-size:8pt; }
A.button {
background:#E0DFE3;
font-weight:bold;
padding:2px;
margin-left:0px;
margin-right:2px;
border-top:1px solid #E5E4E8;
border-left:1px solid #E5E4E8;
border-bottom:1px solid #6699CC;
border-right:1px solid #6699CC;
color: #0033CC
font-size:10pt;
line-height:2em;
text-align:center;
}
</style>
</head>
<body>
<table cellSpacing="0" cellPadding="0" width="100%">
<tr>
<td class="TableTitle" width="100%" nowrap="nowrap">
<h3>Cool Tools</h3>
</td>
</tr>
<tr>
<td></td>
</tr>
<xsl:for-each select="PaneContent">
<tr>
<td height="10"></td>
</tr>
<tr>
<td >
<xsl:value-of select="HTMLText" disable-output-escaping="yes"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
This style sheet converts XML into the final HTML document that is displayed in the pane. It first specifies the styles for formatting the HTML in standard cascading style sheet syntax. The important code, however, is located between the <body></body> tags. This specifies that for each pane content subsection, output the data contained in the <HTMLText> node. As mentioned previously, the Task Pane Manager creates XML internally that contains all the subsection content's transformed data. It has a <PaneContent> node for each subsection you create that contains information on the subsection content. It is in the <HTMLText> node that the transformed data from the subsection resides. So in the preceding XSLT, all you are really doing is outputting the content in all the subsections and formatting it in a well-formed HTML document. You can take a look at some of the existing task panes, such as Start and XML Web Services, to see more examples of this technique.
When you click the Apply button at the bottom of the Pane Customization form, the Task Pane Manager displays the Cool Tools pane (Figure 5).

Figure 5 You can easily create a task pane to distribute your tool set and display dynamic content from the Internet.
You will see the XML content displayed at the top section of the pane. If you modify the Coolinfo.xml file and click the Refresh button in the Task Pane Manager, the content section updates. This is one way you can easily push dynamic content to your users' desktops.
Packaging Dependent Files
Now that you have set up the Cool Tools task pane, it is time to add the setup script and tool set files to the task pane package. Select View Files in the upper-right of the Pane Customization form. This changes the display so that you can manage the files in your distribution package. Click the Add (ALT+A) button, and select Setup.prg, CoolTools.vcx, and CoolToolbox.dbf. (Selecting both VCX and DBF files also pull in the VCT and FPT files automatically.) Then click Apply at the bottom of the form to save your changes. The Task Pane Manager can now package these files into an XML distribution file. It will be installed in the pane cache on users' computers when they install the task pane. Remember, when the Setup.prg runs, the tool set is installed, and the CoolTools library is copied to a folder under the Visual FoxPro home directory.
Creating, Distributing, and Installing the Package
To create the task pane installation package, select the Cool Tools task pane in the Pane Customization form, and click Publish (ALT+P). You are prompted for the type of package to create. Select Publish all content in pane, make sure the Publish files associated with the pane is also selected, and then click OK. Select the directory, type a name for the XML package file (it defaults to cool_tools.xml), and then click Save. This process wraps up all pane information and any files you added to the package in the Files section. All you have to distribute is one single XML file. When the pane is installed, the Task Pane Manager unwraps all the files and places them in the pane cache.
You can test the installation of your task pane and tool set by first deleting the Cool Tools pane. Select the pane, click Delete, and then click Save on the Pane Customization form. In the Task Pane Manager Options dialog box, select Task Pane Manager > Customize from the tree view and click the Install Pane button. Navigate to the cool_tools.xml pane package and click OK. The Cool Tools pane appears at the bottom of the list. To test the installation of the tool set properly, first make sure you delete the Cool Tools category from your Toolbox if it is still there. Then rename the \CoolTools folder under the Visual FoxPro home directory. The setup program creates this directory and copies the CoolTools class library from your pane cache folder. Click the Install Tool Set link to run the installation, and then look in the Toolbox to see the Cool Tools category appear.
When installing XML pane packages you download from the Internet, make sure you trust the provider absolutely. After a task pane is installed, it can run Visual FoxPro code in your security context—so be careful! However, if you are a tools vendor, you probably already have a trusted site and digitally sign your downloads. Distributing panes within the developer community is no more or less dangerous than exchanging any other code—just be aware of who is giving it to you.
Now that you understand how to create simple tool sets and how to distribute them through a dynamic task pane, you should also know how to extend the behaviors of the items in Toolbox. You can create simple custom behaviors called add-ins without having to know too much about the Toolbox architecture. However, to create really useful add-ins, you need to be aware of the architecture, data tables, and item classes first so you can take full advantage of the power the Toolbox provides.
Toolbox Architecture
The Toolbox application resides in the Visual FoxPro home directory (HOME()) and is called Toolbox.app. As you have already seen, user-specific content is stored in the Toolbox.dbf file that the Toolbox reads to load tools, categories, and filters the user has created. The location of the Toolbox content table is stored in the Foxuser resource file and defaults to the HOME(7) folder.
The Toolbox application also reads a table called Tooltype that stores information about category and tool types the Toolbox supports. This table directs the Toolbox application in loading the tool classes from the _toolbox.vcx class library. This class library contains the class implementation for all the supported tool and category types. The _toolbox.vcx class library and the Tooltype table are stored in a \Toolbox folder under the Visual FoxPro home directory. Having this metadata and class library stored outside the Toolbox.app allows for the creation and distribution of new tool and category types that developers may need in the future. This means the Toolbox can evolve as fast as the developer community that supports it.
The Toolbox engine is responsible for loading the Toolbox form, reading the data tables and loading the correct tool classes into the Toolbox at run time. This way you can change the implementation of tool item classes without having to recompile Toolbox.app. When you look at examples of how to create new tools and categories, you will really understand how valuable this feature can be.
The Toolbox system variable _TOOLBOX specifies the path and file name for the Visual FoxPro Toolbox. By default, this path is the Visual FoxPro home directory, and the file name is Toolbox.app. However, you can specify a path and file name for _TOOLBOX on the File Locations tab in the Visual FoxPro Options dialog box. You can pass a string parameter that is the category Unique ID into the Toolbox application that specifies the category to display when it opens.
DO (_TOOLBOX) WITH "MASSI.COOLCAT"
Additionally, when the Toolbox form is open in the Visual FoxPro IDE, the global variable _oToolbox is exposed. As you have already seen, this can be handy when installing tool sets so that the Toolbox can be closed while the installation script runs. You can also switch or create Toolbox content tables programmatically using the _oToolbox.ToolboxTable property. Other useful read/write properties are _oToolbox.FilterName and _oToolbox.Category, which can be the unique ID or the name of the filter or category you want to apply to the Toolbox.
All the source code for the Toolbox application is included in the Xsource.zip file contained in the \Tools\XSource\ folder under the Visual FoxPro home directory.
Toolbox Content Table
As mentioned previously, the Toolbox content table is stored by default in your \Documents and Settings\UserName\Application Data\Microsoft\Visual FoxPro 8\Toolbox\ folder and is called Toolbox.dbf. The name and location can be changed in the Customize Toolbox > Options dialog box. This table stores all items, categories, filters, and add-ins for each user. Becoming familiar with the structure of this table is important if you want to create custom behaviors or define specialized tool sets. Table 4 describes the structure and the description of each field in the Toolbox content table.
Table 4 Fields in the Toolbox content table
| Field name | Type | Description |
|---|---|---|
| UniqueID | C(25), Indexed | A unique ID for the record created. This should be in the format of CompanyName.Uniqueid For example: microsoft.textscraps |
| ShowType | C(1), Indexed | Indicates the type of Toolbox item:
'C' = category 'F' = favorites category 'S' = filter set 'T' = tool item 'I' = filter item 'A' = add-in behavior 'M' = passes a context menu as the second parameter that can be used to create a menu rather than invoke an add-in behavior directly. |
| ToolTypeID | C(25), Indexed | References the tool type as defined in ToolType.dbf, and is copied directly from the ToolType.UniqueID field when the record is created. |
| ToolType | M | The friendly name of the tool type. This is copied directly from the ToolType.ToolType field when the record is created. |
| ParentID | C(25) | For tool and filter items (ShowType="T" OR "I"), references the Toolbox.UniqueID of the parent category or filter set in which they belong. For add-ins (ShowType="A"), this references the Toolbox.UniqueID of the parent menu option in which the add-in belongs. |
| ToolName | C(100) | Friendly name of the tool item, category, or filter set. |
| ImageFile | M | The image to display for a tool item. |
| ClassType | C(10) | Designates the behavior class type. This corresponds to the ClassType property on the item classes. |
| SetID | M | Designates the class library file for class tools (for example, the VCX or PRG file name that a class tool item is defined in). |
| ClassName | M | Toolbox item class name. If not specified, a default is used based upon the ShowType field, for example, _classtool. |
| ClassLib | M | Toolbox item class library where the class is contained. If not specified, defaults to _toolbox.vcx. |
| ToolTip | M | Text that is displayed on ToolTips and in the Help text section of the Toolbox. |
| HelpFile | M | Help file to use when F1 is pressed or Help is selected from context menu. |
| HelpID | N(10,0) | Help context ID to use when F1 is pressed or Help is selected from context menu. |
| ToolData | M | Stores data specific to the item. This is information on the item and category properties dialog box. For example, for a class item it would specify the base class, object name, and additional properties in this format:
<baseclass>Editbox</baseclass> <objectname>Editbox</objectname> <properties></properties> |
| DisplayOrd | I | Indicates the order the item appears in its container. |
| LockAdd | L | If the record is a category or a favorites category, set to TRUE to prevent adding new items. |
| LockDelete | L | Set to TRUE to prevent deleting this tool item or category. |
| LockRename | L | Set to TRUE to prevent renaming this item or category. |
| Inactive | L | Set to TRUE to mark the item as inactive to prevent it from appearing in the Toolbox. |
| User | M | User-defined. |
| Modified | T | Last modified date/time. |
Tooltype Table
Besides the Toolbox content table, there is also a Tooltype table that is located in the \Toolbox\ subdirectory of the Toolbox application (\Program Files\Microsoft Visual FoxPro 8\Toolbox\). If this table cannot be found when the Toolbox starts, an included version that is compiled into Toolbox.app is used. The Tooltype table stores information about category and tool types the Toolbox supports. Each row represents a type of supported category or tool item. When tool items and categories are created in the Toolbox, information on the type of item being created is copied from the appropriate row in this table into the Toolbox content table. If you want to support new Toolbox item and/or category types, you add rows to this table. Table 5 describes the structure and the description of each field in the Tooltype table.
Table 5 Fields in the Tooltype table
| Field name | Type | Description |
|---|---|---|
| UniqueID | C(25) | A unique ID for the record created. Entries you create should be in the format of CompanyName.Uniqueid. |
| ShowType | C(1) | The type of toolbox item this type represents:
'C' = category 'T' = toolbox item |
| ToolType | C(50) | The friendly name of the tool type. |
| ClassName | M | Toolbox item class name. If not specified, a default is used based upon the ShowType field. For example, _classtool. |
| ClassLib | M | Toolbox item class library where the class is contained. If not specified, defaults to _toolbox.vcx. |
| FileType | M | A comma-delimited list of file types to which this Tooltype applies. It is used to determine the type of item to create when you drag a file from Explorer to the Toolbox. |
| DataValues | M | Currently unused. In the future, this will represent default ToolData when creating an item of this type. |
| ShowNew | L | Set to TRUE to show in the list box of available item types when adding a new item to the Toolbox. |
| PropSheet | L | Set to TRUE to display the properties dialog box immediately after creating an item/category of this type. |
| DefaultID | C(25) | For category types (ShowType = 'C'), refers to the ToolType.UniqueID for the default items this category should contain. |
| DisplayOrd | I | Indicates the order the item appears in its container. |
| ToolTip | M | Text that is displayed on ToolTips and in the help text section of the Toolbox. |
| Inactive | L | Set to TRUE to mark the item as inactive to prevent it from appearing in the Toolbox. |
| User | M | User-defined. |
| Modified | T | Last modified date/time. |
Toolbox Class Library
The Toolbox class library contains the class hierarchy for all tool items and categories supported in the Toolbox (Figure 6). By default, each type of supported tool contained in the Tooltype table corresponds to classes in this library. You inherit from these classes to override behaviors or to support new types. You can also modify this class library directly to change the behavior of the supported classes. If you just want to add a new shortcut menu behavior to an item, you can do that through an add-in. It is helpful but not critical to understand the general characteristics of the classes in this library while creating your add-ins. However, it will be necessary when you create your own tool and category types. In this section, you will take a look at some of the more important methods and properties of these classes. You will be concentrating on the common methods that you typically override to support your own tools.

Figure 6 The class hierarchy of the Toolbox item classes.
The class hierarchy of the Toolbox classes starts at the _root class. All tool items and categories inherit from this class. This is where common methods that are used to control the behavior are defined: OnClick, OnDblClick, OnKeyPress, OnOleSetData, OnStartDrag, and OnCompleteDrag. These methods provide the fine-grained control of the click and drag-and-drop behaviors of all tools and categories in the Toolbox. The following are the more important properties and methods of the Toolbox classes.
Common Properties and Methods
ShowAsLink—This property is set to .T. if the item needs to be shown in a hyperlink style when mouse hovers over it. This applies to non-category items only. For example, file tools have this property set to true.
oEngine—This property contains a reference to the Toolbox engine and is used to call engine methods. (You will see examples of using this property when you create add-ins and a dynamic category type.)
OnDblClick()—This method is called when the item is double-clicked with the mouse. It is also executed for a single-click if the Double-click to open an item option in the Toolbox Options dialog box is not selected.
OnClick()—This method is called when the item is clicked with the mouse.
OnKeyPress(nKeyCode, nShiftAltCtrl)—This method is called when the object has the focus and a key is pressed.
OnRenderCategory(oToolCollection)—This method is available for classes that inherit from the _category class. This method executes when the category is opened to populate the category with tool items. (You will see an example of using this method when you create a dynamic category later.)
CreateContextMenu(oContextMenu)—This method is called when the shortcut menu for an item is activated. It is where tool-specific context menu options are added. The oContextMenu parameter is the menu object that can be manipulated using its AddMenu method, for example:
LPARAMETERS oContextMenu
LOCAL oMenuBar
oMenuBar = oContextMenu.Addmenu("Run", "oRef.RunItem()")
oMenuBar.Bold = .T.
The first parameter to the AddMenu method of the context menu is the caption of the menu option. The second parameter is a string that contains the code to run when the menu item is selected, in this case, oRef.RunItem(). The oRef variable evaluates at run time to the tool object instance when the user chooses the menu selection. In this example, the object's RunItem method is called. However, a wizard or other external program can also be run. The AddMenu method of the context menu class returns a menu bar object so you can set the properties as shown in Table 6.
Table 6 Menu bar properties
| Property | Type | Default | Description |
|---|---|---|---|
| Caption | String | Caption to display on the menu bar | |
| ActionCode | String | Code to evaluate and execute when the menu bar is selected | |
| Picture | String | Name of a picture to display | |
| Checked | Logical | .F. | Indicates whether the menu bar is selected |
| IsEnabled | Logical | .T. | Indicates whether the menu bar is enabled |
| Bold | Logical | .F. | Indicates whether the menu bar is in a bold font |
These properties can also be passed into the AddMenu method as parameters in the order shown.
oContextMenu.Addmenu("Run", "oRef.RunItem()", "Picture.bmp", .F., .T., .T.)
OnCreateDataValues()—Some items in the Toolbox specify additional information on its property sheet. For instance, file-based tool items have a file name property. The OnCreateDataValues method is called when the item is instantiated and populates a collection of properties for the particular instance. It does this by calling the AddDataValue method that inserts a new property into the oDataCollection collection. This effectively adds options to the item's property sheet.
LOCAL cName, xDefaultValue, cCaption, cToolTip, lReadOnly, ; cClassName, cClassLibrary cName = "filename" xDefaultValue = "" cCaption = "File name" cToolTip = "Specify a file which this tool represents" lReadOnly = .F. cClassName = "cfoxfilename" cClassLibrary = "" DODEFAULT() THIS.AddDataValue(cName, xDefaultValue, cCaption, cTooltip, lReadOnly, ; cClassName, cClassLibrary)
Table 7 Parameters of the AddDataValue method
| Parameter | Type | Description |
|---|---|---|
| cName | String | Name of the option. |
| xDefaultValue | Any | Default value. |
| cCaption | String | Caption to display on property sheet. |
| cTooltip | String | ToolTip text. |
| lReadOnly | Logical | Indicates that the control is read-only. |
| cClassName | String | Class name of the control used to collect this property value. |
| cClassLibrary | String | Class library where the control to display is defined. If this parameter is not specified or empty, it defaults to ToolboxCtrls.vcx that is compiled into the Toolbox application. |
The last two parameters of this method specify the class name and location of the controls to display on the property sheet. If a class library is not specified, the property sheet control classes contained in the compiled ToolboxCtrls.vcx class library are used. Common classes in this class library are listed in Table 8.
Table 8 Common classes in the class library
| Property sheet control class | Base class |
|---|---|
| cFoxCheckbox | Checkbox |
| cFoxEditbox | EditBox |
| cFoxSpinner | Spinner |
| cFoxTextBox | TextBox |
| cFoxDirectory | Container – (Displays the GETDIR() dialog box) |
| cFoxFileName | Container – (Displays the GETFILE() dialog box) |
Additionally, the GetDataValue method retrieves the value of the property from the collection and SetDataValue sets a value of an existing property in the collection. You can also use the EvalText method to evaluate the value of the property. If the value is surrounded by parenthesis, EvalText returns the evaluated version of the value; otherwise, it treats the value as a literal. This is useful if the property contains script code, functions, or variables.
cFileName = THIS.EvalText(NVL(THIS.GetDataValue("filename"), ''))
The contents of this collection are saved as XML in the item's ToolData field in the Toolbox content table.
OLE Drag-and-Drop Methods
Tool classes are based on the Visual FoxPro Custom class and do not inherently support the Visual FoxPro OLE drag-and-drop methods you are familiar with. Therefore, the tool classes are forwarded OLE drag-and-drop method calls from the Toolbox buttons that contain them. For instance, the OLEStartDrag method of the toolboxbutton class calls the OnStartDrag method of the tool item class when the drag operation begins. For more information on OLE drag-and-drop, see OLE Drag-and-Drop Overview in the Visual FoxPro documentation.
OnOleSetData(oDataObject, eFormat, oDropTarget, nMouseXPos, nMouseYPos)—This method sets the drag and-drop data. You can place data in the oDataObject in the specified format with the SetData method.
#include "foxpro.h"
LPARAMETERS oDataObject, eFormat, oDropTarget, nMouseXPos, nMouseYPos
LOCAL cText
IF VARTYPE(eFormat) == 'N' AND eFormat == CF_TEXT AND ;
VARTYPE(oDropTarget) <> 'O'
cText = NVL(THIS.GetDataValue("filename"), '')
oDataObject.SetData(cText, eFormat)
ENDIF
OnStartDrag(oDataObject, nEffect)—This is called when a drag operation begins.
OnCompleteDrag(nEffect, oDropTarget, nMouseXPos, nMouseYPos)—This is called when the Toolbox item is dropped on the drop target.
LPARAMETERS nEffect, oDropTarget, nMouseXPos, nMouseYPos LOCAL lcSCXName = "" THIS.DropOnContainer(oDropTarget, lcSCXName, nMouseXPos, nMouseYPos) RETURN
DropOnContainer(oDropTarget, cSCXName, nXPos, nYPos)—Tools that inherit from the _baseclasstool have this method, which is called from the OnCompleteDrag method. Code is run that sets up the proper data to pass to the DropOnObject method. The object can then be dropped onto designer workspaces and editor windows.
Creating Add-In Behaviors
Use add-ins to extend the behavior of a particular type of item or category by calling custom code you place in the Toolbox content table. You can easily create add-ins that appear on the item shortcut menus to run custom actions. You do not need to know all the details of the Toolbox application architecture to create an add-in. If you skipped the architecture discussion, you can still create add-in behaviors and distribute your tool sets to other developers. However, to create some really useful add-ins, the following examples access properties and methods of the tool classes discussed earlier.
Tool Item Add-in Behaviors
The Toolbox already supports many types of items and their behaviors. They are described in Table 9.
Table 9 Toolbox items and their behaviors
| Tool Type | Behavior |
|---|---|
| Class Library-Based Class | These items represent classes that can be designed in the class designer (Checkbox, Label, TextBox, Form, and so forth). These classes are defined in a class library file (.vcx). You can drag and drop this type of item to class and form designer workspaces to drop an object instance. You can also drag and drop to the text editor or command windows to create object instantiation calls. Modify and Create subclass are also available on the shortcut menu. Selecting Modify opens the class designer for that class. Click Create subclass to open the Visual FoxPro New Class dialog box (CREATE CLASS). The form class items also have Create form available on the shortcut menu. Selecting this menu item creates a new form (.scx) that inherits from the form class. |
| Program-Based Class | These items represent classes that are defined in a program file (.prg). Drag and drop works the same as the class library-based class items. Modify is also available from the shortcut menu. Click Modify to open the program file containing the class definition. |
| Base Class | These items represent Visual FoxPro base classes that are contained in the Visual FoxPro Base Classes category. Drag and drop works the same as the class library-based class items. Click Create subclass on the shortcut menu to open the Visual FoxPro New Class dialog (CREATE CLASS). |
| Class Library File | These items represent the class library files themselves (.vcx). Drag and drop a class library item to an editor or command window to drop the file path and name as text. Click the item to open the Modify Class dialog box, which is the same as clicking Modify on the shortcut menu. |
| Program | These items represent program files (.prg, .mpr). Drag and drop a program item to an editor or command window to drop the file path and name as text. Click the item to open the file in the editor, which is the same as selecting Modify on the shortcut menu. You can also click Run on the shortcut menu to run the program. |
| Form | These items represent Visual FoxPro form files (.scx). Drag and drop a form item to an editor or command window to drop the file path and name as text. Click the item to open the form in the form designer, which is the same as clicking Modify on the shortcut menu. You can also click Run on the shortcut menu to run the form. |
| Menu | These items represent Visual FoxPro menu files (.mnx) Drag and drop a menu item to an editor or command window to drop the file path and name as text. Click the item to open the menu in the menu designer, which is the same as clicking Modify on the shortcut menu. |
| Report | These items represent Visual FoxPro report files (.frx). Drag and drop a report item to an editor or command window to drop the file path and name as text. Click the item to open the report in the report designer, which is the same as clicking Modify on the shortcut menu. You can also click Run on the shortcut menu to run the report. |
| Project | These items represent Visual FoxPro project files (.pjx). Drag and drop a project item to an editor or command window to drop the file path and name as text. Click the item to open the project manager, which is the same as clicking Modify on the shortcut menu. |
| Database | These items represent Visual FoxPro database files (.dbc). Drag and drop a database item to an editor or command window to drop the OPEN DATABASE command with the file path and name. You can also click Open on the shortcut menu to open the database. Click the item to open the database in the database designer, which is the same as clicking Modify on the shortcut menu. |
| Table | These items represent Visual FoxPro table files (.dbf). Drag and drop a table item to an editor or command window to drop the USE command with the file path and name. You can also click Open on the shortcut menu to open the table. Drag and drop a table item to the form designer, or double-click when a designer is open to add a grid to the form and the table to the data environment. By default, it drops the Visual FoxPro base class Grid. You can change this class in the Visual FoxPro Options dialog box Field Mappings tab accessed from the Tools menu. Select the Multiple type and click Modify to change the class and class library information. If no designers are open, double-click the table item to browse to the table, which is the same as clicking Browse on the shortcut menu. You can also select Modify on the shortcut menu to open the table designer. |
| Image | These items represent image files (.ani, .bmp, .cur, .dib, .gif, .ico, .jpg). Drag and drop an image item to the designers or double-click when a designer is open to drop an image control with the picture property set. You can also click Open on the shortcut menu to open the image in your default image editor. This is controlled by the Windows operating system (ShellExecute) and has the same effect as double-clicking the image file in Windows Explorer. |
| Application | These items represent Visual FoxPro application files (.app). Drag and drop an application item to an editor or command window to drop the file path and name as text. Click the item to run the application, which is the same as clicking Run on the shortcut menu. |
| Text File | These items represent text files (.txt). Drag and drop a text file item to an editor or command window to drop the file path and name as text. Click the item to open the file in the editor, which is the same as clicking Modify on the shortcut menu. |
| Text Scrap | These items are pieces of text. Select and drag text to the Text Scrap category to create a text scrap item. Drag and drop a text scrap to an editor window, command window, or other Windows application that supports drag-and-drop text. Text scrap items can also be evaluated using the Visual FoxPro text-merging feature so that code can be embedded in the text scrap and is evaluated when it is dropped. Drag and drop a text scrap to the designers to drop label controls for each line in the scrap. Click Copy to clipboard on the shortcut menu to copy the contents of the text scrap to the Windows Clipboard. |
| ActiveX Control | These items represent loaded ActiveX components. You can drag and drop this type of item to class and form designer workspaces to drop an OleControl. Or, drag and drop to a text editor or command window to create object instantiation calls. You can also click Open in object browser on the shortcut menu to browse the component's properties, events, and methods. |
| XML Web Service | These items represent registered XML Web services. You can drag and drop this type of item to class and form designer workspaces to drop a Web service proxy class you specify. By default the WSHandler class in the _ws3client FoxPro foundation class library is used. Drag and drop XML Web service items to text editor windows to generate proxy code automatically. |
| Other Windows File Types | Items based on any Windows file type that does not have specific behaviors supported by the Toolbox can still be kept in the categories as a generic file type. Click these items or click Open on the shortcut menu to launch the default Windows editor. This is controlled by the Windows operating system (ShellExecute) and has the same effect as double-clicking the file in Windows Explorer. |
You can create your own add-in behaviors in addition to these behaviors by adding records to the Toolbox content table. These add-ins appear as shortcut menu options for an item type. For instance, you can create an add-in for project tools that builds the project into an application. You want a Build Application option to appear on the shortcut menu for all project tool items in the Toolbox. When selected, it builds the project into an .app file. These types of simple add-ins only require you to enter records into the content table.
Open your Toolbox table, and add a new record by entering the information in Table 10.
Table 10 Information needed to add a Build Application shortcut menu option
| Field | Value |
|---|---|
| UNIQUEID | MASSI.BUILDAPP |
| SHOWTYPE | A |
| TOOLTYPEID | PJX |
| TOOLNAME | Build Application |
| INACTIVE | .F. |
The A in the Showtype field and PJX in TooltypeID indicate to the Toolbox that this is an add-in for project tool items. So a Build Application option appears on the shortcut menu for all project tools in the Toolbox. Specify the code to run in the Tooldata field.
LPARAMETERS oToolItem
LOCAL cFilename
cFilename = oToolItem.GetDataValue("filename")
IF FILE(cFilename)
BUILD APP (FORCEEXT(cFilename, "APP")) FROM (cFilename)
ENDIF
Add-ins are passed a parameter, oToolItem, that is a reference to the tool object where the add-in was activated. You can access any property or method of the item and run any code. This particular add-in builds the project into a .app file. Close the Toolbox table and restart the Toolbox. Build Application appears on the shortcut menu for all the project tools in the Toolbox (Figure 7).

Figure 7 Add-ins can appear as shortcut menu options for a particular item type.
Another example is to create a menu selection for class items called Rename Class. When selected, this command opens a dialog box where you enter a new name for the class in the class library. It then renames the class in the class library and refreshes the category. Open your Toolbox table and add a new record by entering the information in Table 11.
Table 11 Information needed to add a Rename Class shortcut menu option
| Field | Value |
|---|---|
| UNIQUEID | MASSI.RENAMECLASS |
| SHOWTYPE | A |
| TOOLTYPEID | CLASS |
| TOOLNAME | Rename Class |
| INACTIVE | .F. |
Then specify the following code in the Tooldata field:
LPARAMETERS oToolItem
LOCAL cClassName, cClassLib, cNewName, oException
cClassName = oToolItem.GetDataValue("classname")
cClassLib = oToolItem.GetDataValue("classlib")
cNewName = INPUTBOX("New name for class:", "Rename Class", cClassName)
cNewName = LOWER(ALLTRIM(cNewName))
IF !EMPTY(cNewName) AND !(cNewName == LOWER(cClassName))
TRY
RENAME CLASS (cClassName) OF (cClassLib) TO (cNewName)
oToolItem.oEngine.RefreshCategory()
CATCH TO oException
MessageBox(oException.Message)
ENDTRY
ENDIF
This particular add-in renames the class in the class library and then refreshes the category that removes the tool item with the old class reference. The add-in then creates a new item with a reference to the new name. You call the RefreshCategory() method on the Toolbox engine to accomplish this.
Suppose you want to add another behavior called Copy Class. When selected, this opens a dialog box where you enter the name for the new class. It then creates a copy of the tool item's class in the class library and refreshes the category to display this new class as a tool item. Open your Toolbox table, and then add a new record and enter the information in Table 12.
Table 12 Information needed to add a Copy Class shortcut menu option
| Field | Value |
|---|---|
| UNIQUEID | MASSI.COPYCLASS |
| SHOWTYPE | A |
| TOOLTYPEID | CLASS |
| TOOLNAME | Copy Class |
| INACTIVE | .F. |
Then specify the code to run in the Tooldata field:
LPARAMETERS oToolItem
LOCAL cClassName, cClassLib, cTempClassLib, oException, cNewName
cClassName= oToolItem.GetDataValue("classname")
cClassLib = oToolItem.GetDataValue("classlib")
cNewName = INPUTBOX("Name for the new class:", "Copy Class", cClassName)
cNewName = LOWER(ALLTRIM(cNewName))
IF !EMPTY(cNewName) AND !(cNewName == LOWER(cClassName))
cTempClassLib = ADDBS(SYS(2023)) + SYS(2015)
TRY
ADD CLASS (cClassName) OF (cClassLib) TO (cTempClassLib)
RENAME CLASS (cClassName) OF (cTempClassLib) TO (cNewName)
ADD CLASS (cNewName) OF (cTempClassLib) TO (cClassLib)
oToolItem.oEngine.RefreshCategory()
CATCH TO oException
MessageBox(oException.Message)
ENDTRY
ERASE (cTempClassLib + ".vcx")
ERASE (cTempClassLib + ".vct")
ENDIF
Close the Toolbox table and restart the Toolbox. Copy Class and Rename Class appear on the shortcut menu for all class tools.
Instead of cluttering up the main shortcut menu with these two add-ins, you can specify that Rename Class and Copy Class appear on a separate submenu called Class Stuff. You can easily do this by adding the information in Table 13 to a new record in the Toolbox content table.
Table 13 Information needed to add a Class Stuff submenu
| Field | Value |
|---|---|
| UNIQUEID | MASSI.CLASSSTUFF |
| SHOWTYPE | A |
| TOOLTYPEID | CLASS |
| TOOLNAME | Class Stuff |
| INACTIVE | .F. |
Then update the ParentID fields of the Rename Class and Copy Class add-ins with the UniqueID of the Class Stuff add-in — MASSI.CLASSSTUFF. No code is necessary in the Class Stuff add-in record because the Toolbox automatically renders the hierarchy of the add-in menus by looking at the ParentID fields (Figure 8).

Figure 8 You can easily have add-ins appear on their own submenus.
As you can see, add-ins can be very powerful and also very easy to create. Up to now, all you have been creating are static menu options. What if you want to create an add-in submenu dynamically? For instance, suppose you want to add a behavior to a class library (.vcx) tool that displays its class members on an add-in menu. When selected, this add-in menu would open the Class Designer. Depending on the class library tool you select, this menu can contain different items. Fortunately, the Toolbox provides the flexibility to manually create the add-in menu if you type M in the Showtype field when you define an add-in record (Table 14).
Table 14 The M in ShowType lets you specify the menu contents in your code.
| Field | Value |
|---|---|
| UNIQUEID | MASSI.MODICLASSLIB |
| SHOWTYPE | M |
| TOOLTYPEID | VCX |
| TOOLNAME | Modify Class |
| INACTIVE | .F. |
In the ToolData field for this menu add-in, the following code creates the menu items dynamically based on the class names contained in the VCX. It does this by manipulating the oContextMenu object manually with the AddMenu method. When the class name is selected on the menu, it invokes another add-in that is marked inactive with the UniqueID = MASSI.MODICLASS. It is the tool item method InvokeAddIn that calls the MODICLASS add-in and opens the Class Designer for the selected class.
*-- Add-Ins with ShowType == 'M' pass the context menu as the 2nd
*-- parameter which we can use to create a dynamic menu.
LPARAMETERS oToolItem, oContextMenu
LOCAL cFilename
LOCAL nClassCnt
LOCAL i
LOCAL ARRAY aClassList[1]
cFilename = oToolItem.GetDataValue("filename")
nClassCnt = AVCXCLASSES(aClassList, cFileName)
*-- Create the menu items dynamically
FOR i = 1 TO nClassCnt
*-- When the menu item is selected we will invoke the MODICLASS add-in
*-- record passing it the name of the class that was selected.
oContextMenu.AddMenu(aClassList[i, 1], ;
[oRef.InvokeAddIn("MASSI.MODICLASS", "] + aClassList[i, 1] + [")])
ENDFOR
Now to set up the MODICLASS add-in, add a record using the information in Table 15.
Table 15 Information needed to set up the MODICLASS add-in
| Field | Value |
|---|---|
| UNIQUEID | MASSI.MODICLASS |
| SHOWTYPE | A |
| TOOLTYPEID | VCX |
| INACTIVE | .T. |
Notice that the Inactive field is set to true (.T.) to prevent this add-in from being visible in the Toolbox. However, this does not prevent it from being called manually using the InvokeAddin method.
The ToolData code is as follows:
LPARAMETERS oToolItem, cClassName
LOCAL cFilename
cFilename = oToolItem.GetDataValue("filename")
MODIFY CLASS (cClassName) OF (cFilename) NOWAIT
Close the table and restart the Toolbox. When you activate the shortcut menu for a class library item, you see that a Modify Class add-in menu option and its submenu contains the class names contained in the library (Figure 9). Selecting one opens it in the Class Designer.

Figure 9 You can create add-ins menus that are dynamically created at run time.
Category Add-in Behaviors
Add-in behaviors can also be created for category types as well. Table 16 lists the currently supported category types and their behaviors.
Table 16 Currently supported category types and their add-in behaviors
| Category Type | Behavior |
|---|---|
| General category | This category does not have any special behavior. It is a static category that can contain any type of tool item. |
| Dynamic folder category | You specify a file system folder and file types for this type of category to read. When the category is opened, the tool set contents are dynamically filled based on the contents of the file system folder. Open is available on the shortcut menu that opens Windows Explorer to the system folder. |
| Text scraps | This type of category creates scrap tools when text is selected and dropped to this category. You can also select text from other Windows applications, such as Word, and drag it to the Text scrap category to create a text scrap automatically. Drag the text scrap from the Toolbox into editor windows or other Windows applications to drop the text. Text scraps can also be created using the Visual FoxPro text merge features so that code can be embedded in the scrap and evaluated when it is dropped. |
| Registered ActiveX controls | This type displays all ActiveX controls that are loaded in Visual FoxPro. You load these controls on the Visual FoxPro Tools menu. Click Options and then select the Controls tab. |
| XML Web services | This type of category displays all the Visual FoxPro registered XML Web services specified in the Visual FoxPro IntelliSense manager. |
You can also create your own category add-in behaviors in addition to these behaviors by adding records to the Toolbox content table. The only difference is that the ToolTypeID field indicates a category type instead of a tool type. For instance, to create an add-in for general categories, enter CATEGORY.GENERAL for the value of the ToolTypeID.
Other Add-ins
You can also create add-ins that are available on all the shortcut menus for all the items in the Toolbox. This is useful if you have a behavior that is not specific to any type of tool. For example, you want to add Dock to the shortcut menu for all items in the Toolbox. When selected, this command docks the Toolbox to the right side of the desktop. You can do this by adding a record with the information in Table 17.
Table 17 Information for adding the Dock shortcut menu option
| Field | Value |
|---|---|
| UNIQUEID | MASSI.DOCK |
| SHOWTYPE | A |
| TOOLTYPEID | |
| TOOLNAME | Dock |
| INACTIVE | .F. |
Notice that the ToolTypeID field is empty. This tells the Toolbox to put this add-in on all the context menus. The code in the ToolData field is self-explanatory:
LPARAMETERS oToolItem *-- 0 = dock left, 1 = dock right _oToolbox.DockIt(1)
Instead of creating add-ins that appear on the shortcut menus, you can create a behavior that runs when a category, item, or the Toolbox is opened. In this case, the ClassType field for the add-in is set to ONLOAD. For example, enter a new add-in record with the information in Table 18.
Table 18 Information for adding the ONLOAD behavior
| Field | Value |
|---|---|
| UNIQUEID | MASSI.ONLOADEXAMPLE |
| SHOWTYPE | A |
| CLASSTYPE | ONLOAD |
| INACTIVE | .F. |
In the ToolData field, a simple message box is displayed for this example. However, notice that a reference to the toolbox engine is passed into the code:
LPARAMETERS oToolboxEngine
Messagebox("Reading Toolbox Table " + oToolboxEngine.ToolboxTable)
When you restart the Toolbox, this code runs before the Toolbox form is displayed.
Keep in mind that all of these add-in records can be distributed in the same manner as described earlier. That way, you can easily exchange with other developers add-in behaviors as part of your tool sets. If you are creating third-party tools, follow the same naming conventions as other tools in the set by including your vendor or product name along with the unique IDs so they can be included in the installation and upgrade processes.
Overriding Behaviors and Supporting New Tool Types
As discussed in the preceding sections, add-ins are an easy way to add custom behaviors to the currently supported set of Toolbox types and are easily distributed as part of a tool set. In addition to add-in behaviors, the Toolbox can be extended so that you can override existing behaviors or support your own new tool and category types. For most situations, add-ins accomplish what you need; however, there are cases when you need to create your own tool class implementations.
You can extend or change current behaviors by inheriting your own tool item from a supported item type or by changing the behavior code directly in the tool item class. For instance, you can create a subclass of the _dbftool called mydbftool to support a different drag-and-drop behavior for table items. Or you can edit the _dbftool class directly in the _toolbox.vcx class library. You can also create new item types by inheriting from the appropriate parent classes, such as _filetool or _tool, depending on the type of tool you need to support or the level of control you want. As a rule, all toolbox items you create should inherit from the _tool class. All categories you create should inherit from _category, and dynamic categories should inherit from _dynamiccategory.
The first example describes how to override a behavior for all tools of a certain type. There are two ways to accomplish this: either modify the appropriate tool class directly in the _toolbox.vcx class library or create a subclass of the appropriate tool class and direct the Toolbox to use this class instead. If you modify the _toolbox.vcx directly, all items of that type pick up the new behavior. This involves editing the appropriate behavior methods directly in the _toolbox.vcx for the class tool you want to modify. When you restart the Toolbox, it reads the new code you entered.
For example, suppose you want to modify the drag-and-drop behavior of the _dbftool. Currently, when you drop a table item to a form, it drops a grid object based on a registry setting you can set in the Visual FoxPro Options dialog box Field Mappings tab under the Multiple type. If this isn't set, it drops the Visual FoxPro base class Grid. This means that every table item you drop uses this setting. To set this information per table item in addition to this global approach, one option is to modify the _dbftool class to look for the grid class name and library specified in the item properties dialog box (Figure 10). You can then specify a particular class to drop for each table item in the Toolbox.

Figure 10 The _dbftool can be modified to read the item properties for class library and name to determine which grid object to drop to the designers.
The first approach to modifying this behavior is to edit the _dbftool class directly in the _toolbox.vcx class library. It's a good idea to back up the _toolbox.vcx and _toolbox.vct files before you start. Now open the _dbftool in the class designer, and open the DropOnContainer method. You should see the following code:
#include "foxpro.h"
#include "toolbox.h"
LPARAMETERS oDropTarget, cSCXName, nXPos, nYPos
LOCAL cClassLib
LOCAL cClassName
LOCAL cPropertyList
LOCAL cOriginalObjName
LOCAL cFilename
*-- Look up the registry values for class name and location to use.
cClassLib = THIS.GetRegistryValue("ClassLocation", INTELLIDROP_KEY + "Multiple")
cClassName = THIS.GetRegistryValue("ClassName", INTELLIDROP_KEY + "Multiple")
*-- Obtain the item property value 'filename' for this item.
*-- Ex. 'C:\MYDATA\TABLE1.DBF'
cFilename = NVL(THIS.GetDataValue("filename"), '')
*-- If the registry value isn't set, use the VFP base class Grid
IF EMPTY(cClassName) OR !FILE(cClassLib)
cClassLib = ''
cClassName = "Grid"
ENDIF
*-- Obtain the item property value 'objectname' for this item.
*-- Ex. 'MyGrid'
cOriginalObjName = NVL(THIS.GetDataValue("objectname"), '')
IF EMPTY(cOriginalObjName)
cOriginalObjName = "grd" + JUSTSTEM(cFilename)
ENDIF
*-- Create the list of properties specified in the properties dialog.
*-- Any writable properties will be set when the object is dropped.
cPropertyList = TEXTMERGE( ;
[RecordSourceType=1] + CHR(10) + ;
[RecordSource=<<JUSTSTEM(cFilename)>>] + CHR(10), ;
.F., "<<", ">>") + ;
CHR(10) + THIS.EvalText(NVL(THIS.GetDataValue("properties"), ''))
*-- Drop the object to the designer
THIS.DropObject(oDropTarget, cSCXName, nXPos, nYPos, cClassName, ;
cClassLib, '', cOriginalObjName, cPropertyList, '', '', cFilename)
It is important to understand that this method is reading the registry for the class name and location so it can specify that information in the parameters cClassName and cClassLib to the DropObject method. So all you need to do is set those two variables with the corresponding property information. You can do this with string parsing. The properties of an item can be obtained by calling the GetDataValue method and passing it the name of the value to retrieve, in this case, properties. This returns a string that contains a carriage return delimited list of item properties in the form of PropertyName=Value. All you need to do is search for Class= and ClassLibrary= to retrieve the values.
#include "foxpro.h"
#include "toolbox.h"
LPARAMETERS oDropTarget, cSCXName, nXPos, nYPos
LOCAL cClassLib
LOCAL cClassName
LOCAL cPropertyList
LOCAL cOriginalObjName
LOCAL cFilename
m.cFilename = NVL(THIS.GetDataValue("filename"), '')
LOCAL lcProps
lcProps = THIS.GetDataValue("properties")
*-- Were both the properties specified?
IF "class=" $ LOWER(lcProps) AND "classlibrary=" $ LOWER(lcProps)
*-- Split the properties into an array for easy searching
LOCAL ARRAY laProps[1]
ALINES(laProps,LOWER(lcProps))
*-- Find the class property and get the value
m.cClassName = THIS.EvalText( ;
SUBSTR(laProps[ASCAN(laProps, "class=")],LEN("class=")+1))
*-- Find the classlibrary property and get the value
m.cClassLib = THIS.EvalText( ;
SUBSTR(laProps[ASCAN(laProps, "classlibrary=")],LEN("classlibrary=")+1))
ELSE
*-- If we didn't specify item properties, use the 'Multiple' registry setting
m.cClassLib = ;
THIS.GetRegistryValue("ClassLocation", INTELLIDROP_KEY + "Multiple")
m.cClassName = ;
THIS.GetRegistryValue("ClassName", INTELLIDROP_KEY + "Multiple")
ENDIF
IF EMPTY(m.cClassName) OR !FILE(m.cClassLib)
m.cClassLib = ''
m.cClassName = "Grid"
ENDIF
.
.
.
This code searches for the Class and ClassLibrary properties first. If these properties are found, it sets the appropriate variables that are then passed to the DropObject method. The EvalText method evaluates the value of the property so that you can include functions and variables in the item property values. For instance, you can specify the location of the class library in the item properties dialog box as: (HOME()+"FFC\_BASE.VCX") to use the FoxPro Foundation classes. You can test your changes by closing the class library and opening the Toolbox. Specify a grid class for one of your table tools in the item properties and then drop the item to a form. You will see the grid object that is dropped is now based on the class you specified.
Instead of modifying the _toolbox.vcx class library, you can create a subclass of the _dbftool in a new class library. You then modify the Tooltype table fields Class and Classlib to specify new class information for the Table tool type. If you do it this way, only new items of that type that are added to the Toolbox pick up the new behavior. When you create items in the Toolbox, the Class and Classlib fields in the Tooltype table are copied to the Toolbox content table for that item. So any existing items still refer to the parent class. Any new items you create, however, refer to your subclass. You can create tool sets in which individual tools can have overriding behaviors. This is especially handy if third-party vendors want tools in their tool set to exhibit a special behavior but do not want to override the default behavior for all tools of that type. In this case, you do not need to touch the Tooltype table. You just have to enter the Class and Classlib information manually in the Toolbox content table for that particular item and then distribute the class library.
Restore the _toolbox.vcx class library and create a new tool class called mydbftool and base it on the _dbftool. Create this class in a new class library called MyToolbox.vcx and store it in the same folder as the _toolbox.vcx.
CREATE CLASS mydbftool OF MyToolbox.vcx AS _dbftool FROM _toolbox.vcx
Edit the DropOnContainer method to include the code changes, and save and close the class. Next, browse the Tooltype table, and locate the record where the Tooltype field equals Table (the Uniqueid is DBF). Set the Classname field to mydbftool and the Classlib field to the name and location of MyToolbox.vcx class library, that is, C:\Program Files\Microsoft Visual FoxPro 8\Toolbox\MyToolbox.vcx. Close the Tooltype table and restart the Toolbox. In the Customize Toolbox form, add an item, select File as the type, and locate a table (.dbf file). Open the item properties, specify the Class and ClassLibrary of a grid to drop, and then drag and drop the item to a form. The grid is based on the class you specified. However, if you have any existing table items in your Toolbox, the behavior of those items does not change. You can see this by opening your Toolbox content table and looking at the values of the Classname and Classlib fields.
This same method is used to add a new tool type to the Toolbox. First, create your tool class by inheriting from an appropriate tool in the hierarchy. If the type you are adding is based on a particular file type that is not supported, inherit from the _filetool class. Then write the appropriate code for your new tool class. Finally, add your new tool type to the Tooltype table, making sure you specify a unique ID for your tool. It is recommended that you follow the format CompanyName.Toolname.
For the mydbftool class, in the Tooltype table create your own type called Extended Table, instead of specifying it as the Table type's class. Add a record to the Tooltype table as shown in Table 19, and enter the relevant field values. (You can refer to the Tooltype table discussed earlier in this article for details on all the fields in this table.)
Table 19 Information to create youw own Extended Table type
| Field | Value |
|---|---|
| UNIQUEID | MASSI.TABLEEX |
| SHOWTYPE | T |
| TOOLTYPE | Extended Table |
| CLASSNAME | mydbftool |
| CLASSLIB | C:\Program Files\Microsoft Visual FoxPro 8\Toolbox\MyToolbox.vcx |
| SHOWNEW | .T. |
| PROPSHEET | .T. |
| INACTIVE | .F. |
Close the table and restart the Toolbox. Because the Shownew field is set to true, when you select Add Item from the Customize Toolbox dialog box, you see the new tool type listed (Figure 11).

Figure 11 New tool types you create can be displayed in the Add Item dialog box.
After you select the Extended Table type, the item properties sheet opens so you can enter all the required fields for the item, such as Item name, Object name, and File name. In addition, you can enter the ClassLibrary and Class properties into the property editor. The property sheet displays immediately because the Propsheet field is set to True. When you drag and drop the Extended Table item to the designer, a grid based on the class you specified is dropped. However, any Table items you add to the Toolbox exhibit the default behavior.
Supporting New Category Types
Creating new category types is the same process as creating new tool types. You create the category class and add a record to the Tooltype table. Typically, you add a new category type because you need to perform actions when the category is opened. Some of the built-in category types already do this; for instance, a dynamic folder category creates tool items on the fly when it opens. A dynamic category has some special characteristics that you will explore.
When you create dynamic categories, the items in the category are not represented physically in the Toolbox content table. Instead, they are stored in memory in a cursor. So if you look in your Toolbox content table for items displayed in a dynamic folder-based category, you do not see these records. This is also why dynamic categories display the message "Dynamic Category - click on Category Properties to modify" in the Customize Toolbox item grid. To create and manipulate these virtual tool items, you look to the Toolbox engine for some special methods that save and restore virtual items.
For example, you can create an environment category that displays as tool items all your environment sets and projects stored in the Visual FoxPro Environment Manager. The Environment Manager is a new tool in Visual FoxPro 8.0. It manages groups of environment settings so you can quickly and easily change environment settings and run script to set up projects. You can also associate projects with environment sets. It is typically accessed from the Task Pane Manager, but you can also run the EnvMgr.app as a stand-alone application. In fact, you can pass it the name of the environment set to run automatically and specify whether to run in quiet mode. You can also pass it the name of a specific project to open so that it will apply the environment settings and then open the project manager. If you run in quiet mode, the Environment Manager does not display a message box when it runs the environment set.
DO (HOME()+"ENVMGR.APP") WITH "Environment Set 1", .T.
You want each item in the category to be created dynamically and display the environment set name and any project names by reading the Environment Manager table (EnvMgr.dbf). When the item is clicked, the Environment Manager is called, passing it the ID of the set or project. You can also set up two options on the category: the location of Environment Manager table and whether to run in quiet mode. The location of the table that contains the environment sets defaults to \Documents and Settings\UserName\Application Data\Microsoft\Visual FoxPro 8\EnvMgr.DBF, or HOME(7)+"EnvMgr.dbf". If this option is blank, the default location is assumed.
The first thing to do is create an environment manager category class that is subclassed from _dynamiccategory.
CREATE CLASS EnvMgrCategory OF MyToolbox.vcx AS _DynamicCategory FROM _toolbox.vcx
When creating your own dynamic category types, there are usually just two methods to override: OnCreateDataValues and OnRenderCategory. It is in OnCreateDataValues where you specify the options this category should provide. This information is displayed on the category properties sheet. You can specify an option to run in quiet mode and an option to specify the Environment Manager table to use. Ideally, you can use the Visual FoxPro resource table to get this information. However, for this example, if the property is blank, the default location is assumed. You should recall that to create these options, all you do is call the AddDataValue method. The OnCreatDataValues method code should look like the following:
*-- Add all the default properties of a dynamic category
DODEFAULT()
*-- Add our additional properties
THIS.AddDataValue("quietmode", .F., "Run quietly", '', .F., "cfoxcheckbox")
THIS.AddDataValue("envfile", '', "Env. Manager Table", '', .F., "cfoxfilename")
Next, you write code in the OnRenderCategory method to create each tool in the category. You first query the environment manager table for all environment sets and projects. For each set or project found, you create a tool object that is displayed in the category. When a tool in this category is clicked, you run EnvMgr.app, passing it the UniqueID of the item and a second parameter to indicate whether to run in quiet mode. To facilitate this behavior, tool items you create dynamically are an instance of the application tool class indicated in the ToolType table where ToolType.UniqueID = "APP". This tool type currently references the _apptool class in the _toolbox.vcx class library. Because the application tool type already has the behavior to run an application when clicked, all you do is set the file name property to run the Environment Manager application. You can add parentheses around the file name property so that it can be evaluated at run time. You can then easily call the Environment Manager application with parameters. For example, to run an environment set in quiet mode, manually create an application item and set the filename property as follows:
(DO (HOME() + "ENVMGR.APP") WITH "_0VK0QENFH", .T.)
However, when you create this application item manually, it creates a physical record in the Toolbox content table. This category needs to create virtual application tools that are displayed dynamically when the category is opened. You can manage your environment sets in one place, the Environment Manager, and the category picks up the changes automatically. To create virtual tool items, you use two methods of the Toolbox engine: GetVirtualToolObject and SaveVirtual. These methods manipulate an internal cursor of virtual tools called VirtualCursor. A reference to the engine can be obtained through the oEngine property of the tool class. These tools then must be added to the oToolCollection collection that is passed into the OnRenderCategory method.
The OnRenderCategory method code looks like the following:
*-- Load the passed oToolCollection with the tool objects
*-- in this category -- in this case a Tool object for
*-- each environment set or project defined in the EnvMgr.dbf table.
LPARAMETERS oToolCollection
LOCAL oToolObject, cEnvFile, nCnt, i, oToolType, lQuietMode
LOCAL cToolTypeID, cToolCaption, cToolTip, cFileName
LOCAL ARRAY aEnvList[1]
DODEFAULT(oToolCollection)
*-- Get the value of the quietmode property
lQuietMode = NVL(THIS.GetDataValue("quietmode"), .F.)
*-- Get the value of the envfile property
cEnvFile = THIS.EvalText(NVL(THIS.GetDataValue("envfile"), ''))
IF EMPTY(cEnvFile)
cEnvFile = HOME(7) + "envmgr.dbf"
ENDIF
IF FILE(cEnvFile)
*-- Grab all Environment Sets ('E') and Projects ('P') from the
*-- environment manager table
SELECT UniqueID, EnvType, SetName ;
FROM (cEnvFile) ;
WHERE (EnvType == 'E' OR EnvType == 'P') ;
ORDER BY SetName ;
INTO ARRAY aEnvList
nCnt = _TALLY
cToolTypeID = "APP"
FOR i = 1 TO nCnt
*-- Create a virtual tool object that is identified in ToolType.dbf as "APP".
*-- (Remember, Tooltype is where the class and class library is specified.)
*-- The second parameter is the caption for the tool object and the
*-- third parameter specifies the tool tip.
cToolCaption = RTRIM(aEnvList[i, 3])
cToolTip = cToolCaption
oToolObject = THIS.oEngine.GetVirtualToolObject(cToolTypeID, ;
cToolCaption, cToolTip )
IF !ISNULL(oToolObject)
IF lQuietMode
*-- To run in quiet mode, pass .T. as the second parameter to EnvMgr.App
cFileName = [(DO "] + HOME() + ;
[EnvMgr.app" WITH "] + aEnvList[i, 1] + [", .T.)]
ELSE
cFileName = [(DO "] + HOME() + ;
[EnvMgr.app" WITH "] + aEnvList[i, 1] + [")]
ENDIF
*-- Set the filename property on our virtual application tool
oToolObject.SetDataValue("filename", cFileName )
*-- Save the virtual tool object in the VirtualCursor
THIS.oEngine.SaveVirtual( oToolObject)
*-- Add the tool to the collection so it will display in the category.
oToolCollection.Add( oToolObject)
ENDIF
ENDFOR
ENDIF
RETURN
Notice how the QuietMode property of the category is queried so you can set the filename property on the tool object appropriately. You can also create your own tool type by subclassing the _apptool and put the code to do some of this in the tool object itself.
The final step is to add the new category type to the ToolType table. Add a record to the Tooltype table and enter the relevant field values as given in Table 20.
Table 20 Information for adding the new category type for Environment Manager
| Field | Value |
|---|---|
| UNIQUEID | MASSI.ENVMGR |
| SHOWTYPE | C |
| TOOLTYPE | Environment Manager |
| CLASSNAME | EnvmgrCategory |
| CLASSLIB | C:\Program Files\Microsoft Visual FoxPro 8\Toolbox\MyToolbox.vcx |
| SHOWNEW | .T. |
| PROPSHEET | .T. |
| INACTIVE | .F. |
Now reopen the Toolbox, and add an Environment Manager category by selecting Environment Manager, which is now listed as an available selection in the list of category types. Type a category name and click OK. The category property sheet appears so that you can select the Environment Manager table location and specify whether to run in quiet mode (Figure 12).

Figure 12 The new category type you created displays your custom properties in the Category Properties dialog box.
Open the category, and you can see application tool items for each environment set and project in the Environment Manager (Figure 13). Click an application tool to set the environment.

Figure 13 The Environment Manager category type you created displays your environment sets and projects as virtual application tools.
Conclusion
In this article, you learned how to create and distribute tool sets to your development teams and how to create tool set installation packages. You also learned about the Toolbox architecture and how easy it is to extend the Toolbox by creating powerful add-in behaviors. In addition, you discovered how to override existing behaviors and add your own new tool and category types.


