Where the log information goes: the Coverage workfiles
The Coverage engine organizes the information in the source log within several workfiles. Since the engine is based on the formset VFP baseclass, it is able to keep these workfiles well away from your other work in VFP in a private datasession. However, since this tool exists within the standard VFP interface, you can examine these workfiles easily, by turning your attention to the Coverage datasession. Understanding the structures of these workfiles, and then calling engine methods to act on various cursors of the proper workfile structures, is key to extending and manipulating the Coverage engine.
In the figure below I've used the default public variable reference in the Command window to access the Coverage data session. (You can do this directly from the Data Session window's drop down at any time.) I've opened the full set of Coverage workfiles.
The main workfiles are shown here as " Fromlog" , which represents the lines from the source log, and " MarkedCode" , which holds a list of all the source code items that the engine has identified within the log. Each MarkedCode record has fields to contain the source code in its original state, marked versions for both Profile and Coverage Mode, and statistics for that source code item.
A list of " SkippedFiles" is available to show you which items in the log were not identified (perhaps because you only have the compiled version of the source code or declined to give the engine a path for this file). A list of " IgnoredFiles" , which includes the Coverage engine's own source files by default, helps you to exclude files you do not wish to analyze. A list of " PJXFiles" shows project file statistics.
Not all the cursors you see here are always open. You only get a table with project files if you choose a project to analyze from the Statistics dialog, and you don't get a cursor with files that have been skipped unless you choose to see these files from the same dialog.
When you extend the Coverage engine, you'll probably work most often with the " FromLog" and " MarkedCode" cursors. You can think of them as the Coverage " source" and " target" workfiles. In fact, most engine methods that use these cursors refer to them in arguments as " tcSource" and " tcTarget" . When you call the engine methods that manipulate workfiles, you can usually call the methods with specific aliases to represent each file.
With the data session set to Coverage's own, you can investigate all the Coverage workfiles.
Why pass cursor aliases to the engine methods, rather than the engine maintaining information about these aliases? The aliases you see in the figure, and that I have used above to describe the cursors, are the default aliases for all the workfiles. The engine does maintain information about each default alias, but it allows any alias to be used for any of its workfile types, at any time. This allows the engine to analyze many sets of workfiles at once. It is often useful to compare the results of two coverage log runs against each other.
The engine properties that represent the current default values for the source and target tables are called cSourceAlias and cTargetAlias. You can think of this pair of tables as the workfiles that currently " have the focus" in the Coverage interface.
Among your sample AddIn there is one called ADD_LOGS.PRG which adds two additional sets of workfiles into the standard Coverage Profiler interface (see figure).
Using ADD_LOGS.PRG, a Coverage AddIn, you can see that the Coverage Profiler can host more than one log analysis at once, in different styles.
In this AddIn, each log is displayed using a different interface from the standard main dialog. One of the new interfaces is radically different from the original main dialog, and the other is quite similar. I added these different interfaces to underscore the fact that you can display and manipulate your workfiles anyway you want (also, the standard Coverage engine UI subclass is not designed to manage multiple pairs of main and zoom dialogs).
If you prefer, in your Coverage engine subclass, you could have many copies of the same interface, handling separate logs. Each interface would maintain knowledge about its specific set of workfile aliases, and call engine methods accordingly. The formset's Forms( ) collection will give you considerable help in this sort of design.
Using one engine object to handle multiple workfile sets is a much better use of resources than instantiating separate engine objects for each log you wish to analyze and compare. To encourage appropriate resource use, the Coverage engine behaves as a " singleton" ; it will not instantiate two objects of the same Coverage engine class at once. (You can still have different Coverage engine subclasses and instantiate them both at the same time if you wish.) If you DO (_COVERAGE) a second time or otherwise try to instantiate the class again, it will attempt to bring its original instance forward within the interface.