2004 Vol.2 Issue1
2004 Vol.2 Issue1
TABLE OF CONTENTS
Features
8 Walking on Cloud 9.0 of Visual FoxPro 44 Extending the Visual FoxPro 9.0 Reporting
So just what was the Visual FoxPro team thinking when System
they planned Visual FoxPro 9.0? Here is what they want- The new reporting engine splits responsibility for report-
ed to accomplish—straight from the VFP team. ing between the report engine, which now deals only
Microsoft Visual FoxPro Development Team with data handling and object positioning, and a new ob-
ject known as a report listener, which handles rendering
and output.
12 What’s New with Data in Visual FoxPro 9.0 Doug Hennig
With support for new data types and removing many lim-
its from the SQL language, it's now easier to develop a
single code base that works with the Visual FoxPro 9.0 54 Visual FoxPro 9.0 IDE Enhancements
native data engine and SQL Server.
A little bit here and a little bit there make Visual FoxPro
David T. Anderson
9.0 even more productive. Rod provides an overview of
the latest IDE enhancements to your favorite tool.
Rod Paddock
22 The Visual FoxPro 9.0 Report Writer
56 Interop: Making .NET and
Explore the new features of the Report Writer, including
dealing with legacy data, report protection, user interface Visual FoxPro Talk to Each Other
enhancements, layout objects, and data groups, plus the There’s no doubt that many Visual FoxPro developers
great new multiple detail band feature. need to live in a world that supports older applications
Cathy Pountney and new development architectures. But why rewrite
business rules that already work? Our writers offer the
highlights to make it all work together.
36 Controls, Events, Commands, and More Claudio Lassala, Markus Egger, Rod Paddock
CoDe Focus Magazine is a supplement of Code Component Developer Magazine. Code Focus reports in-depth on newly released specific
technologies. The supplement is available to CoDe Component Developer Magazine subscribers that have noted interest in the specific
technologies covered in the Code Focus supplements.
US subscriptions are US $29.99 for one year; Canada, Mexico, and US territories are US $44.99; Europe is US $49.99; other countries, US
$59.99. Payments should be made in US dollars drawn on a US bank. American Express, MasterCard, Visa, and Discover credit cards are
accepted. Bill me option is $5 additional and available only for US subscriptions. Back issues are available. For subscription information,
email [email protected] or contact customer service at 832-717-4445 ext 10.
CoDe Component Developer Magazine (ISSN # 1547-5166) is published bimonthly by EPS Software Corporation, 6605 Cypresswood Drive.,
Suite 300, Spring, TX 77379. POSTMASTER: Send address changes to CoDe Component Developer Magazine, 6605 Cypresswood Drive.,
Suite 300, Spring, TX 77379.
CODE COMPILERS
Volume 2 Issue 1
Group Publisher
Markus Egger
Associate Publisher
Rick Strahl
Editor-in-Chief
Rod Paddock
Managing Editor
Ellen Whitney
Content Editor
Melanie Spiller
Writers In This Issue
David T. Anderson Markus Egger
Doug Hennig Claudio Lassala
Ken Levy Cathy Pountney
Rod Paddock
Technical Reviewers
Markus Egger
Rod Paddock
Art & Layout
King Laurin GmbH
[email protected]
Production
Franz Wimmer
King Laurin GmbH
39057 St. Michael/ Eppan, Italy
Printing
Fry Communications, Inc.
800 West Church Rd.
Mechanicsburg, PA 17055
Advertising Sales
Vice President, Sales and Marketing
Michelle Yates
703-328-0333
[email protected]
Sales Managers
Erna Egger
+43 (664) 151 0861
[email protected]
Tammy Ferguson
832-717-4445 ext 26
[email protected]
QUICK ID 0404012
Visual FoxPro 9.0 Overview Visual FoxPro 9.0 Goals with the flexibility to build all types of
database solutions, move on to reporting
Visual FoxPro 9.0 is fully compatible with Our goals for Visual FoxPro 9.0 were to: system enhancements, and finish up with
previous versions of Visual FoxPro. With its data handling and interoperability. But
local cursor engine, tight coupling between · Maintain backward compatibility these only touch on some the great new
language and data, and powerful features, · Enhance database language and types features you’ll want to explore on your
Visual FoxPro 9.0 is a great tool for building · Add end user UI features own.
database solutions of all sizes. · Increase developer productivity
· Improve the Report Writer significantly Flexibility to Build All Types of
Its data-centric, object-oriented language · Extend .NET and SQL Server interoper-
offers developers a robust set of tools for ability
Database Solutions
building database applications for the · Increase extensibility, including Xbase
desktop, client-server environments, or the source code Using Visual FoxPro 9.0, you can create
Web. Developers will have the necessary .NET-compatible solutions with hierarchical
tools to manage data—from organizing tables XML and XML Web services. You can also
of information, running queries, and creating Visual FoxPro 9.0 exchange data with SQL Server through
an integrated relational database manage- Product Highlights enhanced SQL language capabilities and
ment system (DBMS) to programming a newly supported data types.
fully-developed data management application There are so many new features that it’s
for end users. hard to limit the discussion. We’ll start You can build and deploy standalone and
remote applications for Windows-based
Tablet PCs.
The new ReportListener class provides access Common Questions download at http://msdn.com/vfoxpro. The beta
to report generation and rendering events at can be installed side by side with Visual
runtime. As for what will be added to Visual FoxPro FoxPro 9.0 or previous versions of Visual
after version 9.0 is released, it is too early to FoxPro. There is a time bomb built into the
Powerful design-time hooks with customiz- discuss this at the time of writing this article. beta that expires March 31st, 2005. Do not
able builders make your development experi- The Visual FoxPro team welcomes feedback contact technical support for questions, as
ence smoother. on how we can improve our developer tools the public beta is unsupported and is to be
in the future based on what is disclosed for used as is.
Data-Handling Visual FoxPro 9.0 and Visual Studio 2005.
Details of how we enhance Visual FoxPro, Visual FoxPro 9.0 is scheduled to be released
and Interoperability how it is packaged, what it is called, and to manufacturing near the end of 2004 and
when updates will be released probably will will be included in all levels of MSDN
Three new data types, VarChar, VarBinary, not be disclosed until the first half of 2005. Subscriptions (Universal, Enterprise, and
and BLOB, allow for improved interoper- Professional). For more information about
ability with SQL Server. There are extended A common question is how Visual FoxPro MSDN Subscriptions, refer to
SQL language enhancements as well, 9.0 relates to Visual Studio 2005 and SQL http://msdn.com/subscriptions/prodinfo/levels.asp.
including more capabilities with SELECT, Server 2005. We improved the XML support MSDN Subscription members will be first to
INSERT, UPDATE, and DELETE state- in Visual FoxPro 9.0 which will also improve obtain the released version of Visual FoxPro
ments. .NET interoperability. We also added some 9.0 (within a few business days of release to
new data types that will also help for use with manufacturing). The full product, upgrades,
A new function, CAST(), allows you to both SQL Server 2000 and SQL Server 2005. and academic editions will be available
convert different data types. You can use the approximately six to eight weeks after they
new binary index to improve performance Visual FoxPro 9.0 is scheduled to be released are released to manufacturing.
using the deleted tag, and the XMLAdapter in late 2004, and the schedule for Longhorn
provides improved nested hierarchical XML is not announced yet. We can only discuss Visual FoxPro 9.0 pricing will be the same as
and XSD schema support. how Visual FoxPro relates to Longhorn once it was for Visual FoxPro 8.0: the full product
Longhorn is nearly complete and close to is $649US, the upgrade is $349US, and the
There are many improvements to client UI being released. academic edition is $75US. For a limited
features. You can dock forms, anchor form time, a $50 rebate will be offered with Visual
elements to control movement on a form Although we will not be including native FoxPro 9.0 (for the upgrade version only, in
during resizing, and control the position of PDF support in Visual FoxPro 9.0, we are U.S. and Canada only) for licensed users of
images on a button using text alignment. working to make it very easy for third parties Visual FoxPro 8.0.
and FoxPro developers to create a variety of
There’s new word wrap support for checkbox solutions for add-on PDF output support. To obtain Visual FoxPro, MSDN Subscrip-
captions and rotating text for label captions. tions, FoxPro gear, and more, go to
Using shapes and lines, you can create poly- We do not have any plans to extend the 2GB http://FoxToolbox.com. Additional information
gons and Bezier curves. The property sheet database size limit in Visual FoxPro for many about Visual FoxPro 9.0 including white
provides support for new font and color reasons, including the 32-bit architecture that papers, samples, and links to third-party
display options, extended characters, and already exists within the product. Besides resources can be found at
long expressions. using SQL Server 2000, an additional option http://msdn.com/vfoxpro.
is upcoming: SQL Server 2005 Express
You can bind images to non file-based extends the 2GB limit of MSDE to 4GB total.
pictures. You can use List and Combo collec- Visual FoxPro 9.0 System
tions as databinding row sources. Although Visual FoxPro will remain 32-bit Requirements
and will not use 64-bit addressing natively, it
Member data extensibility adds the ability to will run in 32-bit compatibility mode. Visual To install Microsoft Visual FoxPro 9.0 Profes-
specify custom property editors and Studio 2005 will support creating native 64- sional, we recommend:
favorites. With the extended system capabil- bit applications.
ities, there are no limits beyond available • A PC with a Pentium-class processor
memory for arrays, procedure size, and It is up to developers and installing organiza- • Windows 2000 with Service Pack 2 or later
nesting levels. tions to decide which .NET language is best operating system
for them. C# is generally for developers who • 64MB of RAM; 128MB or higher recom-
Single line background compiling allows you like to write and control all of their code. It’s mended
to see whether or not your syntax is valid as very source code-centric. Visual Basic is for • 165MB of available hard disk space for a
you type command lines. RAD (rapid application development) and typical installation, 165MB maximum;
ease-of-use while providing access to the full 20MB of additional hard-disk space for
There are new and improved task panes such power of the .NET Framework. For a high- Microsoft Visual FoxPro 9.0 Prerequisites
as the Data Explorer pane. level overview of the language differences, • A CD-ROM or DVD-ROM drive
refer to the Visual Studio Roadmap at • A super VGA 800 X 600 resolution
There are new string functions and a new http://msdn.microsoft.com/vstudio/productinfo/roa monitor, or higher, with 256 colors
inline function—ICASE()—that is similar to dmap.aspx. • Microsoft Mouse or compatible pointing
DO CASE statements. device
Visual FoxPro 9.0 Availability
For international solutions we’ve added
greater support for using FontCharSets in Until March 31st, 2005, the free public beta
applications. of Visual FoxPro 9.0 will be available for
QUICK ID 0404022
Unfortunately, due to the complexity of the SQL Turning your DELETED indexes into Binary
statements you can write with these enhancements, indexes is an easy way to start taking immediate
the Query and View Designers do not support many advantage of Visual FoxPro 9.0 performance
of the sub-query changes to SQL. enhancements. Just be sure that all clients accessing
your data are upgraded, as this new index cannot be currently deploy. If you are unable to use a binary
read by prior versions. index, you may find that with these optimizations,
you can at least drop a few existing indexes.
Rushmore Optimizations
If only indexes filtered FOR NOT DELETED() were
There are a few new Rushmore optimizations that used for Rushmore optimization and SET
do not require changes to data and index structures. DELETED is ON, additional NOT DELETED()
optimization is unnecessary.
Top N [PERCENT], an optimization made to SQL,
provides improved performance. This operation
returns only the top number or percent of records in Commands and Functions
a result set as controlled in the ORDER BY clause.
This change in Visual FoxPro 9.0 eliminates records A few commands and functions have been extended
from the sort process that don't belong in TOP N as to provide greater control over how and when
early as possible, reducing comparison operations Visual FoxPro reads and writes data to disk.
and decreasing file I/O in low memory situations.
This also has the side-effect of only returning Fine-Tune How Data is
exactly N [PERCENT] records.
Accessed and Committed
In previous versions, if there was a tie for Nth place,
all records that matched the tie were included, It is now possible to specify fractions of a second for
resulting in getting back more than N records. the second parameter of the SET REFRESH
command. The second parameter is used to specify
If this change in behavior is not desired, consider the number of seconds between refreshing local
bracketing the SQL call with SET ENGINEBE- memory buffers with current data from disk. You
HAVIOR 80. can also specify a value of –1, which forces Visual
FoxPro to always read data from the hard drive. The
The only limitation to this optimization is that TOP lowest setting for the second parameter is .001.
N PERCENT cannot be used unless the entire result
set can be read into memory at once. Setting this value to a low number causes some
performance degradation as the number of requests
When appropriate, Visual FoxPro 9.0 uses filtered increase, especially across a network, so use it spar-
indexes to optimize MIN() and MAX() aggregate ingly.
functions in FOR DELETED() and FOR NOT
DELETED() only. This improves MIN()/MAX()
performance, if such an index exists.
A derived table,
The Like “sometext%” operator is now fully opti-
mizable when the string ends in a wildcard. (Note such as a sub-query, allows you
that this is not the case when the comparison value to treat the results
begins with a wildcard or when the wildcard is
embedded within the string.) This optimization
of a sub-query as though it
scenario works like WHERE field = “sometext”. were its own table.
More INDEX Smarts
Visual FoxPro 9.0 is even smarter in how it utilizes The SYS(1104) function purges memory cached by
existing indexes to achieve Rushmore optimization. programs and data, and it clears and refreshes
For example: buffers for open tables. In Visual FoxPro 9.0, a
second parameter scopes the operation to a specific
INDEX ON DELETED() TAG DELETED work area or alias. This is valuable because using
SYS(1104) when a large number of buffered tables
This index is used to optimize both NOT are open can result in slow performance while each
DELETED() and DELETED() conditions without buffered table refreshes.
the presence of a tag created by INDEX ON NOT
DELETED(). The FLUSH command is used to ensure that
changes made to tables, indexes, and files are saved
Just like the MIN()/MAX() optimization, Visual to the disk. In Visual FoxPro 9.0, the FLUSH
FoxPro 9.0 uses a FOR NOT DELETED() filter on command has been enhanced in two ways: speci-
an index to optimize a DELETED() or NOT fying FLUSH areas, and calling the FlushFileBuffers
DELETED() query. Whenever it is possible to deter- function.
mine that a condition should filter on DELETED()
or NOT DELETED(), a filtered index FOR You can now be specific about the filename, work
DELETED() or FOR NOT DELETED() is used in area, or alias to be FLUSHed. Although this extra
the event that no non-filtered indexes exist. Take granularity is handy, it's the FORCE keyword that is
this upgrade opportunity to review the indexes you very useful in scenarios where Visual FoxPro 9.0
New Datatypes
In an effort to provide better compatibility with
back-ends such as SQL Server, Visual FoxPro 9.0
has added three new data types, VarChar,
VarBinary, and BLOB. These data types can be
used as part of a local table, which is created by
using the CAST() function or mapped to when
retrieving results from remote data.
VarChar
The VarChar is a character data type that is not
padded with spaces to the length of the field.
This provides similar functionality as SET
Figure 1: Comparing Character and VarBinary data types looks like this. ANSI_PADDING ON in SQL Server.
SELECT * ;
FROM Customers INTO CURSOR temp1 When using expressions
that combine
SELECT * ;
FROM summary_of_sales_by_year ;
VarChar with Character
INTO CURSOR temp2 data types, the result is
always of the type VarChar.
SYS(3092,"")
SQLEXEC() and SQLMORERESULTS() functions. In addition, properties have been added to support
ACountInfo is a two column array containing the DEFAULT and CHECK constraints and for
alias and count. mapping remote data to the new VarChar and
VarBinary data types.
Rowsets from the Provider
XMLAdapter changes include support for:
Three functions have been added to support
returning result sets from stored procedures when · Hierarchical XML
accessed via the provider. · XPath expressions
· XML encoding and decoding enhancements
SetResultSet() is used to specify which work area in
the current DataSession is to be used as the result
set. Only one cursor in a DataSession can be Upgrading
marked.
Visual FoxPro 8.0 included changes to FoxPro's
GetResultSet() returns the work area for the cursor SQL commands, and brought it into greater compli- Ken Levy
marked by SetResultSet. ance with ANSI SQL standards. These changes may Product Manager,
have discouraged you from upgrading to version 8 Visual Studio Data Team
ClearResultSet() sets the marked result set to 0 and because of the impact on existing code. If you've Microsoft
returns the work area for the previously marked been putting off fixing some of those ambiguous
cursor. queries or at least bracketing them with SET With all the great new features
ENGINEBEHAVIOR, Visual FoxPro 9.0 provides included in Visual FoxPro 9.0,
Within a stored procedure, you create a cursor with many compelling reasons to make the investment to my favorite feature remains the
the results you want returned and use SetRe- upgrade. world-wide FoxPro community.
sultSet() to identify the work area for the cursor. There is a list of great Visual
When executed by the provider, return values are Fortunately, the kinds of changes made in Visual FoxPro community resources
not respected, but a rowset is created based on the FoxPro 9.0 won't require the kind of recoding you at http://msdn.com/vfoxpro
cursor you provided. may have found necessary for 8.0. community. Posting a question
on a community Web site is
As in prior versions, using the SET ENGINEBE- free and you usually get a quick
HAVIOR command allows you to isolate legacy response from somebody who
As in prior versions, code that may be problematic. knows the answer. Interacting
using the SET ENGINEBEHAVIOR within the FoxPro community
SET ENGINEBEHAVIOR 90 impacts the behavior is not only educational, but can
command allows of TOP N and the behavior of aggregate functions be fun and it can result in
you to isolate legacy code without a GROUP BY clause. In versions prior to 9, finding employees or
if such a statement resulted in no matching criteria, employers.
that may be problematic. 0 records were returned. To be more ANSI
compliant in version 9.0, FoxPro returns a single Information from the Visual
record resultset with NULL value(s) for aggregate FoxPro team is regularly
CursorAdapter and XMLAdapter columns. included in the monthly letters
Enhancements at
http://msdn.com/vfoxpro/letters.
Changes to the CursorAdapter and XMLAdapter Final Thoughts For even more up-to-date news
classes are worthy of another multi-page article. But for and information, refer to my
the purpose of this overview, it's important to briefly In this article, you’ve seen that the changes to the blog at
note some of the more significant enhancements. data engine in this release are substantial. A http://blogs.msdn.com/klevy,
commitment to backward compatibility and an easy Calvin Hsia's blog at
Many of the changes made to the CursorAdapter upgrade path has made these changes nearly trans- http://blogs.msdn.com/calvin_h
bring behavior in line with remote views. These parent when moving from 8 to 9. Once you've made sia, and the Visual Studio Data
enhancements include: the move, you can start taking advantage of these Team blog at
great enhancements—some without changing a http://blogs.msdn.com/vsdata.
· Support for Timestamp fields. This allows single line of code. Other enhancements ensure that All of this information Visual
UPDATE/DELETE commands to use Timestamp code based on the new features is more compatible, FoxPro 9.0 whitepapers and
fields as part of the WhereType method. powerful and maintainable than ever before. samples can be found on the
· Auto-Refresh support. Several new properties Visual FoxPro home page at
have been added so that remote data managed by David T. Anderson http://msdn.com/vfoxpro.
the CursorAdapter is automatically refreshed after
an INSERT or UPDATE operation. This is valu-
able for retrieving auto-incremented or default
field values and timestamps.
· On Demand Record Refresh support. More
properties and events have been added to
CursorAdapter to support the same kind of func-
tionality provided by the REFRESH() function for
local and remote views.
QUICK ID 0404042
B
efore I explain the new features, you need to
in Redmond with the Microsoft understand how to use the new Report Designer *-- Use the old output engine
Fox Team. Currently she works and how to run reports using the new output SET REPORTBEHAVIOR 80
for Optimal Solutions devel- engine.
oping Visual FoxPro applica-
tions for schools. Cathy has The Report Designer: By default, the new Visual The rest of this article assumes that the new Report
spoken at many FoxPro confer- FoxPro 9.0 Report Writer uses the new Xbase Designer and the new output engine are both in use.
ences and user groups across Report Designer. It provides
the U.S., written articles for newer dialog boxes and is easier Fast Facts
various magazines, and her to use than the old version. It Data Environments
book, The Visual FoxPro Report also provides access to many of The new
Writer: Pushing it to the Limit the new features that are not Visual FoxPro 9.0 Report Writer
and Beyond, is available from available through the old is compatible with previous The Visual FoxPro 9.0 Report
Hentzenwerke Publishing Report Designer. You can easily versions of Visual FoxPro, Writer can now share Data
(www.hentzenwerke.com). control which Report Designer making it a great blend of the old Environments with other
is used by changing the value of reports. Data Environments
and the new.
the new _REPORTBUILDER can also be saved as a class and
[email protected]
system variable. then loaded into reports as
www.frontier2000.com needed. This offers a great reuse scenario for
www.optimalinternet.com *-- Use the new Report Builder defining common reporting needs.
_REPORTBUILDER = HOME() + 'ReportBuilder.app'
Save As Class
*-- Use the old Report Builder
To save a Data Environment as a class, start by
_REPORTBUILDER = ''
defining the Data Environment in a report as usual.
While the Data Environment window is still active,
The Output Engine: Just as with the Report select the new
Designer, you can control whether the new or old Save As Class…
output engine is used. Unlike the Report Designer, option from the
which defaults to the new style out of the box, File menu.
Visual FoxPro 9.0 defaults to the older output
engine. The reason for this is that GDI+ is used in After selecting
the new engine, and renders slightly differently than the Save As
the GDI used by the old engine. Therefore, some of Class… option,
your existing reports could render differently in the Save As
Visual FoxPro 9.0, which means you'd have to Class dialog box
tweak them to make them appear correctly. You appears, as
can switch between the output engines with the shown in Figure
following command: 1. The DataEn- Figure 1: Use the Save As Class dialog
vironment box to declare the name of the new
*-- Use the new output engine button of the class and the class library for saving
SET REPORTBEHAVIOR 90 Save option the Data Environment of a report.
In addition to manually defining the Data Environ- At this point, code has been added to five Data
ment for a new report, Visual FoxPro 9.0 also gives Environment methods: Init(), BeforeOpenTables(),
you the option to load the Data Environment from AfterCloseTables(), Destroy(), and Error(). Some of
an existing report or from a saved DataEnvironment the methods have very simple code with nothing
class. The Load Data Environment… option on the more than a DODEFAULT() command. The reason
Report menu allows you to select which Data Envi- for this is that BindEvents() does not function
ronment to load. unless the method contains at least one line of code.
Look at the code in these methods to see what it
From a Report does, but I do not recommend that you change it.
Protecting a Report
To set overall report protection, select the Report
Properties dialog box. You can invoke this dialog
box by selecting Properties from the Report menu
Figure 4: Use the Protection tab of the Band or from the right-click menu of the report. Figure 5
Properties dialog box to set protection modes shows the Protection tab of the Report Properties
of the band. dialog box.
Figure 3: Use the Protection tab of the Properties di-
alog box to set protection modes of a layout object. The top portion of this dialog box allows you to
define which tabs of the Report Properties dialog
box are unavailable to the user. For each of the
Protecting an Object
selections made in this area, the applicable tab of
To protect a layout object in the Report Designer, the Report Properties dialog box is disabled. The
SUMMARY Issues select the Properties dialog box for the object. The Protection option is always checked and disabled.
Properties dialog box can be invoked from the The Ruler/Grid option is disabled because the tab
Using the SUMMARY clause of Report menu after selecting the object from the cannot be protected, although it appears on the
the REPORT FORM command right-click menu of the object, or by double-clicking dialog box so that the selections are consistent with
prevents the Detail band from the object. Figure 3 shows the Protection tab of the the tabs on the Report dialog box.
printing, yet all the Page Properties dialog box for a field object. You can set
Headers and Footers, Column the following five protection modes for layout The bottom portion of this dialog box allows you to
Headers and Footers, and objects: define which menu options are unavailable to the
Group Headers and Footers are user. For each of the selections in this area, the
printed. Any On Entry or On · Object cannot be moved or resized prevents users applicable menu option is disabled.
Exit expressions in a Detail from moving this layout object to a different posi-
band are not processed when tion on the design surface and prevents users from Honoring Protection Flags
the SUMMARY clause is used. resizing this object.
When issuing SUMMARY on a · Object cannot be edited prevents the user from To invoke protection during a Report Designer or
Multiple-Detail band report, the making changes to the properties of this layout Label Designer session, use the PROTECTED
Detail Headers, Detail Footers, object. keyword, as shown in the following examples.
and Detail bands are not · Object cannot be deleted prevents the user from
processed. deleting this object. CREATE REPORT MyReport PROTECTED
· Object cannot be selected prevents users from MODIFY REPORT MyReport PROTECTED
selecting this object. When this option is selected, CREATE LABEL MyLabel PROTECTED
the protection behaviors of Object cannot be
MODIFY LABEL MyLabel PROTECTED
moved or sized. Object cannot be edited and
Object cannot be deleted are also imposed.
· Object is not visible in Designer prevents this If the PROTECTED keyword is not used, the
object from appearing in the Report Designer in
protected mode. When this option is selected, the
protection behavior of the other four options is
also imposed.
Protecting a Band
To protect a band in the Report Designer, select the
Properties dialog box for the band. The Properties Figure 5: Use the Protection tab of the Report Properties di-
dialog box can be invoked from the Edit Bands… alog box to set overall protection modes of a report.
Report Designer functions as if no protection were the Data Environment are listed in the Fields list
applied to the layout objects. box. Tables opened outside of the Data Environ-
ment are not available in the list box.
Multiple Selection Dialog Box When the Interleave option is used, the special
character is inserted in between existing characters
Visual FoxPro 9.0 has a Multiple Selection dialog in the data. For example, when the Format expres-
box, which allows you to set the Protection and sion is "999-999", and the data contains "123456",
Print when properties for more than one layout the report shows "123-456". Notice that the dash is
object at a time. It also allows you to change any of inserted between the "3" and the "4".
the other properties of any individual layout object.
To use this new feature, select more than one layout Trim Mode for Character Expressions
object, and then double-click any one of the objects
to invoke the Multiple Selection dialog box, as Prior to Visual FoxPro 9.0, field objects were
shown in Figure 8. always trimmed to the nearest word when the text
was too long. In Visual FoxPro 9.0, a new option
The layout objects that were selected when this on the Field Properties dialog box allows you to
dialog box was invoked are listed in the first tab of determine how the text is trimmed. The six trim Figure 7: Use the new mouse cur-
this dialog box. To work with all layout objects options are: sor to know when an object can
defined in a report, use CTRL + A to select all be resized.
layout objects before invoking this dialog box. · Default trimming uses the default
behavior, which is the same as the
The Sort by option allows you to sort the list of Trim to nearest word, append
layout objects by Type or Location within the ellipsis option. This behavior is
report. The Remove from list button removes the similar to prior versions of Visual
selected layout objects from the list. Double-click on FoxPro, with the exception of
any item in the list and the applicable Properties appending the ellipsis.
dialog box for the individual object is invoked. The · Trim to nearest character trims text
Properties tab of the Multiple Selection dialog box, to the last full character that fits in
shown in Figure 9, is used to change the properties the defined area.
of all the items listed in the Selection tab. · Trim to nearest word trims text to
the last full word that fits in the
Select the Apply these protection settings to the defined area.
selected objects checkbox to enable the Protec- · Trim to nearest character, append
tion options. Select the Apply this condition to ellipsis trims text to the last full
the selected objects upon saving checkbox to character that fits in the defined
enable the Print when option. Change the Protec- area, after an ellipsis is added to the
tion and Print when settings as needed, and then text that prints.
select OK to close the dialog box and apply the · Trim to nearest word, append
changes to all the layout objects listed on the first ellipsis trims text to the last full Figure 8: Use the Selection tab of the Multiple Selec-
tab. word that fits in the defined area, tion dialog box to choose which layout objects you
after an ellipsis is added to the text want to work on.
More Zoom Levels that prints.
· Filespec: Show inner path as
The Preview window now has more Zoom levels, ellipsis replaces the inner directo-
ranging from 10% up to 500%. ries of a long path and filename
with an ellipsis when the full text
does not fit in the defined area.
Layout Object Enhancements
Size and Position
A few improvements have been added for layout
objects, including an option to control template Another new feature available on
characters, a trim mode for character expressions, Layout objects is better control of the
and relative and absolute positioning. size and position of the object. When
an object is added to the report, the
Template Characters values for From page top, From left,
Height, and Width are automatically
The Field Properties dialog box has a new section set. It's important to note that the
for Template characters. The two available options From page top property is relative to
are Overlay and Interleave. These determine how the top of the page in the Report
special characters are used in the format. Designer, which means it takes into
account the height of any gray bars Figure 9: Use the Properties tab of the Multiple Selec-
When the Overlay option is used, special characters above the object. Changing the From tion dialog box to change the Protection properties and
are treated as part of the data and overlay any other page top property may inadvertently the Print When logic of the selected layout objects all
specific character in a specified position. For move the object to another band. at once.
Figure 10: Prior versions of Visual FoxPro wasted a lot of Figure 11: Prior versions of Visual FoxPro reserved space
space when using horizontal columns with Data Groups. for Data Group Headers, even when none were defined.
Relative Positioning: The From page top property Data Group Enhancements
and the Height property work together to deter-
mine whether absolute positioning or relative posi- A few enhancements have been made to Data
tioning is used. When the From page top property Groups in the Visual FoxPro 9.0 Report Writer,
is set to a value that falls within the Report Designer including maximum Data Groups and horizontal
surface, and the value of the Height property is less columns.
than or equal to the height of the band in which the
object is located, relative positioning is used. Rela- Maximum Data Groups
tive positioning is needed for objects in bands other
than the Page Header and Page Footer. The maximum number of Data Groups has been
increased from 20 to 74. In actuality, the maximum
Absolute Positioning: When the From page top of 74 was always true, but the user interface only
property is set to a value that falls outside the allowed 20 Data Groups to be entered.
Report Designer surface, or
the value of the Height prop- Horizontal Columns
erty is greater than the height
of the band in which the Previously, reports with more than one column
object is located, absolute defined as horizontal with a Data Group wasted a
positioning is used. Absolute lot of space. The first position (row 1, column 1)
positioning means the object is was left blank and data began in column 2 of row 1.
printed in exactly the same Also, a blank band was wasted in between each set
location on each and every of Data Groups, as shown in Figure 10. Even if the
page. height of the Data Group Header band is zero,
Visual FoxPro still reserved the space, as shown in
Absolute Positioning can be Figure 11.
used to create a watermark on
a report. Place a graphic image In Visual FoxPro 9.0, the behavior of Data Groups
in the Page Header band, and and horizontal columns has been changed. When a
set it to Scale contents, retain new Data Group is encountered, it is printed in
shape. Change the From page column 1 of the next full row. The remainder of this
top property and the From left row is left blank and not used for printing details.
property to indicate the upper- The details belonging to the Data Group begin in
left corner of where you want column 1 of the row immediately after the row the
the watermark to begin. Data Group is printed in, as shown in Figure 12.
Change the Height and Width Also, no extra space is reserved if the height of the
properties to indicate the Data Group Header band is zero, as shown in
overall size of the watermark, Figure 13.
Figure 12: Visual FoxPro 9.0 does not waste as much space making sure not to extend
as prior versions when horizontal columns and Data Groups beyond the printable margins of The new behavior, although avoiding the previously
are used. the printer. described situation, may break some existing reports.
Figure 13: Visual FoxPro 9.0 does not reserve extra space Figure 14: In Visual FoxPro 9.0, you can expand the Data
when the Data Group Header band is 0" tall. Group Header band across multiple columns.
However, an added benefit of the new behavior is make sure the Customer table is the current work
that the Data Group band can be stretched across all area at the time the report runs.
the columns, as shown in Figure 14.
The Target Alias
Multiple-Detail Bands The target alias is the term used to describe which
table is the driving table for a particular detail band.
The new multiple-detail band feature is one of the In this example, the Members table is the target
biggest, and most often requested, improvements. It alias for Detail 1 band, the Vehicles table is the
allows you to process multiple child tables for each target alias for Detail 2 band, and the Homes table
record in a parent table. An example of this type of is the target alias for Detail 3 band.
report is shown in Figure 15.
If no target alias is defined for a Detail band, the
Tables and Relationships behavior it takes on is that of prior versions of
Visual FoxPro. In other words, one detail band is
Understanding how the parent and child tables processed per parent record. However, if you enter
work together are key to understanding how to use the name of the parent table as the target alias,
this new feature. As an example of a Multiple-Detail you'll get very different results. For each record in
scenario, assume you are writing the report shown the parent table, Visual FoxPro processes through
in Figure 15. The database for this scenario is: all records in the entire parent table, printing each
parent record in the Detail band. If you have a table
· The Customer table is the parent table and with 10 parent records, and you set the target alias
contains one record for each insurance customer. of a detail band to the parent table, the final report
· The Members table holds one record for each prints 10 sets of 10 records, or a total of 100
family member of the customer. The Members records.
table is a child table of the Customer table.
· The Vehicles table holds one record for each Relationships
vehicle insured by the customer. The Vehicles
table is a child table of the Customer table. Relationships play a big part in how multiple-detail
· The Homes table holds one record for each home bands operate. Visual FoxPro uses the relationships
insured by the customer. The Homes table is a between the parent table and the child tables to
child table of the Customer table. navigate through the records. You may use SET
RELATION or SET SKIP to define these relation-
Driving the Report ships. If you're opening the tables in the Data Envi-
ronment, and relationships are already defined in
One table is necessary to drive the report. In this the database, these relationships are honored.
example, the Customer table is the driving table. If
you use the report's Data Environment to define the If you're opening the tables in code, Listing 1 shows
tables, set the InitialSelectedAlias property to this how to set up the tables for the Insurance Customer
table. If you are using code to define the tables, Listing shown in Figure 15.
The Target alias is an expression and you must Listing 1: Setting the relationship between the parent and child tables.
wrap the table name in quotes. Once you have each
target alias defined, the gray bars representing the *-- Open the child tables
USE Members IN 0 ORDER CustomerFK
Detail bands show the target alias.
USE Vehicles IN 0 ORDER CustomerFK
USE Homes IN 0 ORDER CustomerFK
Be sure to place a check mark in the selection box Report Variables and Calculations
for Remove line if blank for these layout objects as
well. With the introduction of Multiple-Detail bands, report
variables and calculations have some new twists to
Similar to Group Headers and Footers, Detail them. You need to fully understand how they are
Headers and Footers have some of the same processed in order to use them effectively. Otherwise,
options. you may not get the results you're expecting.
• Start on a new column: Causes the Detail set to The Reset at prompt on the Report Variables dialog
start on a new column of the report. Note that this box has been renamed Reset based on. This more
option allows you to assign a Detail set to a clearly defines that the variable is reset based on the
specific column. If one Detail set has enough change in value of the selected option. In addition
information to overflow the column, it is to renaming the control, if more than one Detail
continued in the next column. band is defined in the report, each Detail band is
• Start on a new page: Makes the Detail set start on added to the drop-down list.
a new page.
• Reset page number to 1 for each detail set: With Selecting Detail n as the Reset based on value tells
the Start on a new page option, resets the page Visual FoxPro to only process this calculation when
number to 1 for each new Detail set. processing the detail records in the target alias of this
• Start detail set on new page when less than: Detail band. The report variable is not altered while
Helps prevent orphans. The detail set begins on a records in other target aliases are being processed.
new page if the indicated amount of space is not This allows you to tie a report variable to one partic-
available. ular Detail band. The value of the report variable is
• Detail Header/Footer: Adds a Detail Header and not cleared until the Detail Header band of this same
Detail Footer band around this Detail band. Detail set is processed for the next parent record.
• Reprint detail header on each page: With the
Detail Header/Footer option, makes the Detail If you chose a Reset based on value other than one
Header band reprint whenever the Detail set over- of the Detail bands, the calculation is processed in
flows to a new page. several places. First, for each parent record, the calcu-
4. Define the Detail #1 band: Double-click the Associated header and footer bands checkbox.
gray bar of the Detail #1 band to invoke the Add any objects needed in the Detail 2 band.
Properties dialog box. Set the target alias to Add the Percent object to the Detail 2 band with
"Vehicles", remembering to use the quotes. Check an expression of rnPercent.
the Associated header and footer bands 7. Define the Detail #2 Footer band: Add the total
checkbox. Do not place any objects in the Detail premium object, set the expression to
1 band. vehicles.premium, set the Calculation type to
5. Create some report variables: Create a variable Sum, and set the Reset based on to Detail 2. Add
named rnTotalPremium, set the Value to store to the total percent object, set the expression to
Vehicles.premium, set Calculation type to sum, rnPercent, set the Calculation type to Sum, and
and set the Reset based on to Detail 1. Create a set the Reset based on to Detail 2.
variable named rnPercent, set the Value to store
to ROUND(100 * vehicles.premium / rnTotal- The above report definition tells the Visual FoxPro
Premium, 2), and set the Calculation type to 9.0 Report Writer to process the Vehicles table
None. twice for each customer in the Customer table. The
6. Define the Detail #2 band: Double-click the first time totals the premium so it can be used in the
gray bar of the Detail 2 band to invoke the Prop- second pass. The second pass of the Vehicles table
erties dialog box. Set the target alias to "Vehi- prints the data for the customer, using the report
cles", remembering to use the quotes. Check the variable that was calculated during the first detail
band. This process repeats for each customer in the
Customer table.
A Lot to Learn
The Visual FoxPro 9.0 Report Writer has many new
features to help you create better reports. The new
reusable data environments allow you to share data
environments among reports. Various aspects of
reports, such as objects and bands, can be
protected. A better development experience has
been created through the new user interface. The
new object layout enhancements and data group
enhancements offer more options than previously
available. And finally, the new multiple-detail band
feature opens up many more reporting options.
Together, all these improvements and enhance-
ments give you the ability to create more complex
reports than ever before.
Cathy Pountney
QUICK ID 0404052
Controls, Events,
Commands, and More
Microsoft Visual FoxPro 9.0 is here and it brings lots of new
features. This entire issue of CoDe is dedicated to Visual FoxPro 9.0, providing
details and scenarios on how you can use the new features and enhancements. In
this article, I will discuss some of the new controls, events, and commands, and a
little more.
Claudio Lassala
[email protected]
I
’m sure you are as anxious as I am to explore new the IDE or on the application delivered to the
Developer at EPS Software properties, events, and methods, new or improved users.
Corp. and a part-time Universal commands, and FoxPro Foundation Classes
Thread Consultant. He has (FFCs). Let’s dive right in! In order to support this feature, new members were
presented several lectures at added to the Form class, such as the Dockable and
Microsoft events as well as at Docked properties, the Dock
several conferences and user Anchoring Controls Fast Facts and GetDockState methods,
groups in North America and and the AfterDock, Before-
Brazil. He is a Microsoft C# Before Visual FoxPro 8.0, many As is typical of every new Dock, and UnDock events.
MVP, and MCSD for .NET, and lines of code had to be written version of Visual FoxPro, Listing 1 shows a simple
also a columnist at MSDN in order to properly resize new commands, properties, example that produces the
Brazil. He is the author of onscreen controls whenever a methods, and events are introduced. result showed on Figure 1.
several training videos that can form was resized. In Visual
This article highlights
be found at Universal Thread, FoxPro 8.0, that task got slightly
and has had several articles easier with the introduction of some of these new features to make Collection Object
published in various maga- the BindEvent function. In the introductions, but you’ll Support in ComboBox
zines, such as MSDN Brazil Visual FoxPro 9.0, it gets way want to look at the
Magazine and FoxPro Advisor. easier with the introduction of ”What’s New” section on the Help
and ListBox Controls
A full-biography can be found anchors. Anchors allow a file, because there’s a lot The RowSourceType property
at www.lassala.net/bio. control to maintain its propor- more in there. on ComboBox and ListBox
tional relationship with other objects has a new option added
objects and controls within a to the list of possible sources:
form, no matter what size the form becomes. value 10, for the Collection object.
The Anchor property is obeyed when the control A Collection could be populated with Business
sits on containers such as Forms, CommandGroups, objects or objects holding some sort of data, and that
and Page objects. Whenever those containers get Collection can be used to populate ComboBoxes and
resized, the controls within it that have the Anchor ListBoxes. The following code snippet shows an
property set are resized and/or repositioned example of that, using a collection named colEm-
depending on the settings used. Make sure to check ployees contained in the form, and the ComboBox’s
out the Anchor Property topic on the Help file for RowSourceType property is set to 10.
available settings.
Select EmployeeId, FirstName;
from employees into cursor curTemp
Docking Forms
Scan
Docking allows toolbars and other controls to be
Local loEmployee as Object
“attached” to any user-chosen edge of a Form and
maintain that positioning despite resizing or Scatter NAME loEmployee Blank
scrolling. Visual FoxPro 8.0 introduced the ability to Scatter NAME loEmployee additive
dock objects, such as the Command, Document
View, and Properties windows, as well commands This.colEmployees.Add(loEmployee,;
and functions that handled docking programmati- Transform(loEmployee.EmployeeId))
cally.
EndScan
Figure 1: Docking user-defined windows is simple. Figure 2: The ListBox’s AutoHideScrollbar property provides
lots of options.
Converting Data
Rotating Label, Line, and Shape more items on the ListBox than what can be viewed Types with the Cast()
Controls in a single pane, up and down arrows appear on the Function
control. Figure 2 shows a snapshot of a form with
For long time now, Visual FoxPro developers have ListBoxes using the three available settings. The new Cast() function
been waiting for the ability to rotate labels. The converts expressions from one
option is now available through a new Rotation data type to another. Get used
property, which receives a number indicating the NewObject() Creates Objects without to writing SQL statements that
degrees the control will rotate. The Rotation prop- Raising Initialization Code are compatible with SQL
erty is also available for Line and Shape controls. Server.
The NewObject function now accepts 0 as the third
parameter in order to create the object without
ListBoxControls Can Hide ScrollBars raising code in the Init method. That’s useful when
the interface of an object must be analyzed (using
A new AutoHideScrollbar property was added to the AMember function, for example), where neither
the ListBox class. This property determines whether the code on the Init or Destroy methods should run.
or not the ScrollBar is shown on the ListBox, and
whether it is shown if the control only has a few
entries.
loMainForm.Show() EndDefine
Select * ;
Extended SQL Capabilities from Home(1)+"\samples\northwind\employees" ;
There are many improvements to the SQL subset in into cursor curEmployees
Visual FoxPro 9.0. With each new release, the Visual
FoxPro team moves Visual FoxPro’s SQL closer to ? AUSED(gaInuse, Set("Datasession"), "Employees")
T-SQL (SQL Server’s SQL implementation).
DISPLAY MEMORY LIKE gaInuse
Some of the most notable improvements are:
· The limit of nine join clauses and sub-queries was In the sample above, an array shows the aliases and
removed from the SQL Select statement, as were work area numbers for the Employees table avail-
the nine Union clauses limit, the 30 tables limit, able at the current data session.
and the referenced aliases limit.
· The level of nesting for sub-queries in a SQL Select
statement, formerly limited to only one level, is SQLIdleDisconnect() Temporarily
now unlimited. Disconnects SQL Pass-Through
· The list of fields and the FROM clause can now
have a sub-query. This works for the ON clause on
Connections
joins as well.
· The Like clause is now optimized. The new SQLIdleDisconnect function is a great
new addition to the SQL Pass-Through set of func-
Make sure to read the Data Features Enhance- tions. This function temporarily disconnects a
ments section under the What’s New in Visual connection handle passed to it (or it disconnects all
FoxPro on the Help file for more specific informa- connections, if a 0 is passed).
tion about all the improvements on these subjects.
That’s a great feature for disconnected scenarios,
where an application doesn’t have to hold a
Set Coverage Command connection to the database even when the user is
Available at Runtime reading retrieved data, rather than sending data
back and forth regularly. Plus, when the connection
The Set Coverage command is now available at run must be enabled again in order to process some-
time. Anywhere inside an application, the Set thing, it happens automatically, using the original
Coverage command can be called like this: connection string.
ASQLHandles(laHandles)
The important thing to notice is that before being Figure 4: New FFC classes for GDI+ are similar to the ones
drawn, the image can be manipulated, perhaps found in the .NET Framework.
adding a logo or watermark to it, or text can be
drawn over it. It’s also worth mentioning that the
new Report engine in Visual FoxPro can leverage
Conclusion
the power of GDI+, so if you’re planning on doing
powerful stuff with reports, take a serious look at There are many improvements and new features in
the GDI+ FFC classes. Visual FoxPro 9.0 that are both productivity tools
and exciting new ways of building interesting and
These classes (shown in Figure 4) map to the useful applications. I’ve only briefly covered some of
classes available on the .NET Framework. I strongly the developments you’ll find when you start playing
suggest that you read some articles about GDI+ with this new version. Make sure you take a close
with .NET Framework published in previous look into the “What’s New in Visual FoxPro”
editions of CoDe Magazine, so that you can under- section on the Help file, and have fun!
stand what sorts of things can be done with this
technology, and then you should be able to translate Claudio Lassala
most of the .NET code into Visual FoxPro using the
FFC classes.
ADVERTISING INDEX
CoDe Magazine Vision Data Solutions
www.code-magazine.com 6, 35, 60 www.visionds.com 68
QUICK ID 0404032
Extending the
Visual FoxPro 9.0
Reporting System
Among the new and improved features in Microsoft Visual
FoxPro 9.0, you’ll find the ability to extend the behavior of the
Doug Hennig reporting system when running reports. In this article, you’ll learn
[email protected]
about Visual FoxPro 9.0’s report listener concept, how it receives events as a
Doug Hennig is a partner with
report runs, and how you can create your own listeners to provide different types
Stonefield Software Inc. He is of output in addition to print and preview.
the author of the award-
winning Stonefield Database
Toolkit (SDT), the award-
winning Stonefield Query, and
the MemberData Editor, Anchor
T
here are incredible improvements in the Visual listener, which handles rendering and output.
Editor, and CursorAdapter and FoxPro 9.0 reporting system. Of several aspects, Because report listeners are classes, we can now
DataEnvironment builders that I’ll discuss just one in this article: the ability to interact with the reporting process in ways we could
come with Visual FoxPro. extend the behavior of the runtime reporting engine. only dream of before.
Doug is co-author of the The Visual FoxPro development team had several Report listeners produce output in two ways. Page-
“What’s New in Visual FoxPro” goals in mind when they worked on the runtime at-a-time mode renders a page and outputs it, then
series and “The Hacker’s Guide improvements, including: renders and outputs the next
to Visual FoxPro 7.0.” He was Fast Facts page, and so on. This mode is
the technical editor of “The · Handling more types of report used when a report is printed.
Hacker’s Guide to Visual output than just printing and The Visual FoxPro 9.0 In all-pages-at-once mode, the
FoxPro 6.0” and “The Funda- previewing reporting system raises events in a report listener renders all the
mentals.” All of these books · Using GDI+ for report output, new base class, called pages and caches them in
are from Hentzenwerke providing many significant ReportListener. ReportListener is memory. It then outputs these
Publishing. improvements, such as more rendered pages on demand.
the key to the different
accurate rendering, smooth This mode is used when a
Doug has spoken at every scaling up and down of types of provided report output, report is previewed.
Microsoft FoxPro Developers images and fonts, and addi- also giving us the ability
Conference (DevCon) since tional capabilities, such as text to change how a report is rendered.
1997 and at user groups and rotation. New Reporting Syntax
developer conferences all over · Providing a more flexible and
North America. He is a extendible reporting system Visual FoxPro 9.0 supports running reports using
Microsoft Most Valuable the old report engine; you use the REPORT
Professional (MVP). You have access to both the old report engine and command just as you did before (although, as you’ll
the new one, so you can run reports under either see in a moment, you can use a new command to
For more information about engine as you see fit. But once you see the benefits override the behavior of REPORT). To get new-style
Stonefield and its products, of the new report engine, you won’t want to go back reporting behavior, use the new OBJECT clause of
visit www.stonefield.com and to old-style reporting. the REPORT command. The OBJECT clause
www.stonefieldquery.com supports two ways of using it: by specifying a report
listener and by specifying a report type. Microsoft
Reporting System Architecture refers to this as object-assisted reporting.
Before Visual FoxPro 9.0, the report engine was A report listener is an object that provides new-style
monolithic; it handled everything and with a few reporting behavior. Report listeners are based on a
exceptions (user-defined function, expressions for new base class in Visual FoxPro 9.0 called ReportLis-
OnEntry and OnExit of bands, and so forth), you tener. To tell Visual FoxPro 9.0 to use a specific
couldn’t interact with it during a report run. listener for a report, instantiate the listener class and
then specify the object’s name in the OBJECT clause
The new reporting engine splits responsibility for of the REPORT command. Here’s an example:
reporting between the report engine, which now
deals only with data handling and object posi- loListener = createobject('MyReportListener')
tioning, and a new object known as a report report form MyReport object loListener
If you’d rather not instantiate a listener manually, For example, suppose ListenerA and ListenerB are
you can have Visual FoxPro do it for you automati- both subclasses of _ReportListener that each
cally by specifying a report type: perform some task, and you want to use both
listeners for a certain report. Here’s how these
report form MyReport object type 1 listeners can be chained together:
they’re run and .T. for the second parameter to Both of these listener classes have additional prop-
ignore any listeners specified in AddReport. erties you can use to further control the output. I
Here’s an example that runs two reports as if they recommend a look at the Visual FoxPro documen-
were a single one: tation for details. Also, as they are subclasses of
_ReportListener, listener classes support the capa-
loListener = newobject('_ReportListener', ; bilities of the _ReportListener class, including
home() + 'ffc\_ReportListener.vcx') chaining listeners and running multiple reports.
loListener.ListenerType = 1 Here’s an example that outputs to both XML and
HTML at the same time:
loListener.AddReport('MyReport1.frx', ;
'nopageeject')
use _samples + 'Northwind\Orders'
loListener.AddReport('MyReport2.frx')
loListener1 = .NULL.
loListener.RunReports()
do (_reportoutput) with 4, loListener1
loListener1.TargetFileName = 'MyReport.xml'
Richard Stanton HTML and XML Output loListener1.QuietMode = .T.
Developer, Visual FoxPro Team Because one of the design goals of the development loListener1.XMLMode = 0
Microsoft team was to provide additional types of report && 0 = data only, 1 = layout only, 2 = both
output, Visual FoxPro 9.0 includes two subclasses of loListener2 = .NULL.
The enhanced report engine _ReportListener, called the HTMLListener, and the do (_reportoutput) with 5, loListener2
emphasizes backward compati- XMLListener, providing HTML and XML output, loListener2.TargetFileName = 'MyReport.html'
bility, one of Visual FoxPro's respectively. These listeners are built into
loListener2.QuietMode = .T.
strongest aspects. Many of the ReportOutput.APP but are also available in
loListener1.Successor = loListener2
new reporting features are _ReportListener.VCX.
designed so that they are easy report form MyReport object loListener1
to integrate into existing appli- Listener type 5 specifies HTML output and type 4 is
cations. For example, you can for XML output, so you could just use the following
use the new SET REPORTBE- command to output to HTML:
Creating Your Own Listeners
HAVIOR command to quickly Because report listeners are a class, you can create
run and preview reports using report form MyReport object type 5 subclasses that alter the behavior of the reporting
the new reporting engine or the system when a report runs.
old engine. Visual FoxPro 9.0 However, this doesn’t give you any control over the
also includes features such as name of the file to create or other settings. Instead, For example, one thing I’ve always wanted is a way
object-assisted runtime report call ReportOutput.APP to give you a reference to to dynamically format a field at runtime. Under
processing using the new the desired listener, set some properties, and then some conditions, I may want a field to print with
custom ReportListener class, tell the REPORT command to use that listener. red text, and under others, I want it in black.
multiple-detail bands, report Perhaps a field should sometimes be bold and the
chaining, and many other The following code creates an HTML file called rest of the time not.
design time enhancements. MyReport.HTML from the MyReport report. When
You can add all these features you specify type 5, ReportOutput.APP uses its built- The key to changing the way a field appears in a
incrementally to existing in HTMLListener class to provide output. report is the EvaluateContents method. This
reports, making it easy to take method fires for each field object just before it’s
advantage of the functionality loListener = .NULL. rendered, and gives the listener the opportunity to
you want without major design do (_reportoutput) with 5, loListener change the appearance of the field. The first para-
changes. loListener.TargetFileName = 'MyReport.html' meter is the FRX record number for the field object
being processed and the second is an object
loListener.QuietMode = .T.
containing properties with information about the
report form MyReport object loListener
field object. (See the Visual FoxPro Help file for a
list of the properties this object contains.) You can
The following code creates an XML file, called change any of these properties to change the
MyReport.XML from the MyReport report, appearance of the field in the report. If you do so,
containing only the data. In this case, the XMLLis- set the Reload property of the object to .T. to notify
tener class (type 4) is used. the report engine that you’ve changed one or more
of the other properties.
loListener = .NULL.
do (_reportoutput) with 4, loListener Listing 1 shows some code (TestDynamicFormat-
loListener.TargetFileName = 'MyReport.xml' ting.PRG) defining a subclass of _ReportListener
called EffectsListener, that handles different types of
loListener.QuietMode = .T.
effects that may be applied to fields in a report.
loListener.XMLMode = 0
These effects are applied by effect handler objects,
&& 0 = data only, 1 = layout only, 2 = both which are stored in a collection in the oEffectsHan-
report form MyReport object loListener dlers property of EffectsListener. Each effect
handler object handles a single effect
HTML output actually uses the XML listener to
produce XML and then uses XSLT to produce the As the report is processed, the listener needs to deter-
HTML end-result. mine which fields will have effects applied to them. It
Listing 1: TestDynamicFormatting.PRG shows that the EvaluateContents method of ReportListener can change the way a field appears in a report.
use _samples + 'Northwind\Orders' * Go through the collection of effect handlers for the field (the
loListener = createobject('EffectsListener') * collection may be empty if the field doesn't need any effects),
loListener.OutputType = 1 * letting each one do its thing.
report form TestDynamicFormatting.FRX preview object loListener
for each loEffectObject in .aRecords[tnFRXRecno, 2]
* Define a class that knows how to apply effects to objects in a loEffectHandler = loEffectObject.oEffectHandler
* report. lcExpression = loEffectObject.cExpression
loEffectHandler.Execute(toObjProperties, lcExpression)
define class EffectsListener as _ReportListener of ; next loEffect
home() + 'ffc\_ReportListener.vcx' endwith
does that in the EvaluateContents method by looking However, EvaluateContents fires for every field in
at each field as it’s about to be rendered. Evaluate- every record, and there really isn’t a need to check
Contents calls SetupEffectsForObject, which calls the for the effects more than once for a particular
GetEffect method of each effect handler to let it field (doing so would slow down the performance
decide whether to apply an effect to the field. GetEf- of the report). So, BeforeReport creates an array
fect looks in the USER memo of the field’s record in with as many rows as there are records in the
the FRX for a directive indicating what type of effect FRX.
to apply. If a particular handler is needed for the
field, a reference to the handler is added to a collec- If the first column of the array is the default .F., the
tion of handlers that processes the field (as a field listener hasn’t checked for the effects of the field
may have more than one effect applied to it). being rendered yet, so EvaluateContents does that
Listing 1: Continued
* specified report object needs this effect, or return null if not. define class DynamicForeColorEffect as UserEffectHandler
cEffectName = 'FORECOLOR'
function GetEffect(toFRX)
local loObject * Evaluate the expression. If the result is a numeric value and
loObject = .NULL. * doesn't match the existing color of the object, change the
return loObject * object's color and set the Reload flag to .T.
endfunc
function Execute(toObjProperties, tcExpression, toFRX)
* EvaluateExprssion may be called by Execute to evaluate the local lnColor, ;
* specified expression. lnPenRed, ;
lnPenGreen, ;
function EvaluateExpression(tcExpression) lnPenBlue
return evaluate(tcExpression) lnColor = This.EvaluateExpression(tcExpression)
endfunc if vartype(lnColor) = 'N'
enddefine lnPenRed = bitand(lnColor, 0x0000FF)
lnPenGreen = bitrshift(bitand(lnColor, 0x00FF00), 8)
* Define an abstract class for effect handlers that look for lnPenBlue = bitrshift(bitand(lnColor, 0xFF0000), 16)
* "*:EFFECTS <effectname> = <effectexpression>" in the USER memo. if toObjProperties.PenRed <> lnPenRed or ;
toObjProperties.PenGreen <> lnPenGreen or ;
define class UserEffectHandler as EffectHandler toObjProperties.PenBlue <> lnPenBlue
cEffectsDirective = '*:EFFECTS' with toObjProperties
&& the directive that indicates an effect is needed .PenRed = lnPenRed
cEffectName = '' .PenGreen = lnPenGreen
&& the effect name to look for (filled in in a subclass) .PenBlue = lnPenBlue
.Reload = .T.
function GetEffect(toFRX) endwith
local lcEffect, ; endif toObjProperties.PenRed <> lnPenRed ...
laLines[1], ; endif vartype(lnColor) = 'N'
lnRow, ; endfunc
lcLine, ; enddefine
lnPos, ;
loObject * Define a class to provide dynamic style effects.
lcEffect = This.cEffectsDirective + ' ' + This.cEffectName
if atc(lcEffect, toFRX.User) > 0 define class DynamicStyleEffect as UserEffectHandler
alines(laLines, toFRX.User) cEffectName = 'STYLE'
lnRow = ascan(laLines, lcEffect, -1, -1, 1, 13)
lcLine = laLines[lnRow] * Evaluate the expression. If the result is a numeric value and
lnPos = at('=', lcLine) * doesn't match the existing style of the object, change the
loObject = createobject('EffectObject') * object's style and set the Reload flag to .T.
loObject.oEffectHandler = This
loObject.cExpression = alltrim(substr(lcLine, lnPos + 1)) function Execute(toObjProperties, tcExpression, toFRX)
else local lnStyle
loObject = .NULL. lnStyle = This.EvaluateExpression(tcExpression)
endif atc(lcEffect, toFRX.User) > 0 if vartype(lnStyle) = 'N' and ;
return loObject toObjProperties.FontStyle <> lnStyle
endfunc toObjProperties.FontStyle = lnStyle
enddefine toObjProperties.Reload = .T.
endif vartype(lnStyle) = 'N' ...
* Define a class to provide dynamic forecolor effects. endfunc
enddefine
Figure 2: This is
the TestColumn-
Chart.FRX as it
looks at design
time.
Listing 2: TestColumnChart.PRG shows how you can do custom rendering in a report to produce a column chart.
Listing 2: Continued
procedure EvaluateContents(tnFRXRecno, toObjProperties) * Figure out the highest value and the width of each column.
local loObject, lcText, lnRow
with This lnMax = 0
lnColumns = alen(.aValues, 1)
* If we haven't already checked if this object is involved in the for lnI = 1 to lnColumns
* column chart, find its record in the FRX and see if its USER memo lnMax = max(lnMax, .aValues[lnI, 2])
* contains "LABEL" or "VALUE". Then flag that we have checked it so next lnI
* we don't do it again. lnColumnWidth = (tnWidth - (lnColumns * .nSpacing))/lnColumns
Listing 2: Continued
is responsible for drawing each object on the report The code shown in Listing 2, taken from
page. You can override this method to perform TestColumnChart.PRG, runs the TestColumn-
various types of output. Chart.FRX report, shown in Figure 2, and creates
the output shown in Figure 3. Notice how
A listener that performs custom rendering will different the output looks than the report layout
almost certainly have to use GDI+ functions. suggests; the fields and shape don’t appear but a
GDI+ is a set of hundreds of Windows API func- column chart graphing the contents of the Cate-
tions that perform graphical manipulations and gory_Sales_For_1997 view in the sample North-
output. wind database does. That’s partly due to Print
When clauses on the fields that prevent them
from printing, but the biggest reason is that the
listener class used for this report, Column-
_ReportListener allows ChartListener, replaces the shape object in the
chaining listeners by providing a Summary band with a column chart. Let’s see
how this listener does that.
Successor property
that may contain an object The Init method of ColumnChartListener initial-
izes the aColumnColors array to the color to use
reference to another listener. for each column in the chart. Note that GDI+
colors are a little different than the values returned
by RGB(), so the CreateColor method is used to
do the necessary conversion. If you want to use a
To make it easier to work with GDI+ functions, different set of colors, you can subclass Column-
Visual FoxPro includes _GDIPlus.VCX in the FFC ChartListener or store a different set of colors in
directory. _GDIPlus, which was written by Walter the array after you instantiate ColumnChartLis-
Nicholls of Cornerstone Software in New Zealand, tener. Note that only eight colors are defined; if
consists of wrapper classes for GDI+ functions, there are more than eight columns in the chart, the
making them both easier to use and object-oriented. listener uses the same colors for more than one
The “GDI Plus API Wrapper Foundation Classes” bar.
topic in the Visual FoxPro Help file lists these
classes and provides a little background about them. The BeforeReport method instantiates a
This library is a great help in doing GDI+ rendering GPGraphics object into the custom oGDIGraphics
because you don’t have to know much about GDI+ property. GPGraphics is one of the classes in
to use them; I certainly don’t and yet was able to _GDIPlus.VCX. It and other _GDIPlus classes are
create the listener class discussed next in just a used in the DrawColumnChart method to draw the
couple of hours. components of the column chart.
QUICK ID 0404062
Class Upgrades
Visual FoxPro 9.0 added one much-desired feature
to its Class designer. You can now specify default
values for custom properties added to your classes.
To specify a default values for your custom property:
Figure 1: The Project Manager with the font set to
Comic Sans. 1. Open your custom class from the Project
Manager or type MODIFY CLASS in the
Command window.
QUICK ID 0404072
56 COM Interop: Making .NET and VFP Talk to Each Other www.code-magazine.com
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 57
Figure 1:
Adding a reference
to a .NET project.
Markus Egger
variant in the type library (a file that defines the [email protected]
methods and other things that are in a COM Figure 2: A .NET Web application that uses VFP compo-
component). A variant is really bad because .NET nents and data. Markus is an international
doesn’t support a variant type. On the .NET side, speaker who presents sessions
the developer must know in advance what data at numerous conferences
type is actually getting returned in order to be able The CustomerBizObj class created in VFP will be including a number of confer-
to use it. contained within a namespace called cominterop- ences in North America and
sample, so we added the line using cominterop- Europe. Markus has written
You declare the class using the OlePublic keyword, sample; at the top of the code-behind the Web numerous articles for publica-
marking it to be exposed as a COM component. For form. Inside that namespace you’ll find the class tions including CoDe Magazine,
this demo we created a project called COMInterop- named CustomerBizObjClass. This Web form Visual Studio Magazine,
Sample and added the CustomerBizObj.prg to the displays the list of Customers returned by the asp.netPro Magazine, FoxPro
project. We need to build the project as a Multi- GetCustomerList method on the business object. Advisor, Fuchs, FoxTalk and
threaded COM server (.dll). The following code snippet shows the Page_Load Microsoft Office & Database
method on the Web form, which runs every time Journal. Markus is the
You can use the following code to test the COM the page loads: publisher of CoDe Magazine.
component in VFP:
private void Page_Load(object sender, Markus is also the President
*-- Instantiate the object. System.EventArgs e) { and Chief Software Architect of
oCustomerBizObj=; EPS Software Corp., a custom
CreateObject("COMInteropSample.CustomerBizObj") software development and
CustomerBizObjClass customer =
consulting firm located in
new CustomerBizObjClass();
Houston, Texas. He specializes
*-- Call the method a save XML returned to file.
in consulting for object-
StrToFile(oCustomerBizObj.GetCustomerList(),; DataSet dsCustomers = new DataSet(); oriented development, Internet
"c:\CustomerList.xml") development, B2B and Web
dsCustomers.ReadXml( services. EPS does most of its
*-- Release the object. new StringReader( development using Microsoft
Release oCustomerBizObj customer.GetCustomerList()));
Visual Studio (.NET). EPS has
worked on numerous software
projects for Fortune 500
*-- Show XML. this.dgCustomerList.DataSource = dsCustomers; companies including Philip
Modify File c:\CustomerList.xml this.dgCustomerList.DataBind(); Morris, Qualcomm, Shell, and
} Microsoft. Markus has also
Next you can create any sort of .NET application. worked as a contractor for the
For this example we’ve created an ASP.NET Web As you can see, the code just instantiates the Microsoft Visual Studio team
application, and we chose to use C#, but the CustomerBizObjClass as well as a DataSet. The where he is mostly responsible
language really doesn’t matter. After we created the DataSet is then filled with data based on the XML for object modeling and other
project, we added a reference to the COM compo- returned from GetCustomerList. The DataSet’s object and component related
nent in the .NET project. You can do this by going ReadXml() method takes care of the transformation technologies.
to the Add Reference option on the Project menu, from XML to ADO.NET data. Finally, the DataSet
or by right-clicking the References node on the is bound to the DataGrid. Other than the specifics Markus also received the
project through the Solution Explorer window of using DataSets and StringReaders, using the VFP Microsoft MVP Award (96, 97,
(Figure 1 shows that). From the dialog box, click component is just a matter of instantiating objects 98, 99, 2000, 2001, 2002,
the Browse button, and navigate to the and calling methods, as the VFP developer is very 2003, and 2004) for his contri-
COMInteropSample.dll that was created when the used to doing in VFP. Figure 2 shows the results of butions to the developer
VFP project was compiled. running that page. community. Visual LandPro 98,
one of the applications Markus
Next we created a CustomerList.aspx Web Form, Remember what seemed to be a daunting task of was in charge of, was nomi-
and added a DataGrid control (named dgCus- creating the RCW (that proxy that intermediates nated for the Microsoft Excel-
tomers) to it. .NET calls to COM components)? That’s been lence Awards three times.
www.code-magazine.com COM Interop: Making .NET and VFP Talk to Each Other 57
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 58
tlbimp.exe
"C:\YourVFPProject\BizObjects.dll"
/out:
"C:\YourDotNetProject\bin\Proxy.BizObjects.dll"
/namespace:BizObjects
58 COM Interop: Making .NET and VFP Talk to Each Other www.code-magazine.com
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 59
*-- Instantiate the .NET class as a COM component. From the VFP side, there is no indication that the
oHelper = CreateObject("VFPAndDotNet.ImageHelper") object being used is a .NET object.
*-- Set some properties. Calling .NET Web Services from VFP
oHelper.Copyright = "Claudio Lassala"
oHelper.ImageFile = "C:\MyImage.BMP" The one .NET feature that was (and still is)
oHelper.SaveFileAs = "C:\CopyOfMyImage.jpg" mentioned more than any others is the ability to use
.NET to create XML Web services. Web services are
*-- Call a method on the class. methods of functions that are exposed to the Web
through a standardized protocol called SOAP.
oHelper.ProcessImage()
SOAP enables you access to components in a plat-
www.code-magazine.com COM Interop: Making .NET and VFP Talk to Each Other 59
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 60
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 61
www.code-magazine.com COM Interop: Making .NET and VFP Talk to Each Other 61
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 62
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 63
CoDe_Focus_Fox Pro 09 30.11.2004 12:44 Uhr Seite 64
Listing 2: A first Web service created by ASP.NET and the Visual Studio .NET IDE
64 COM Interop: Making .NET and VFP Talk to Each Other www.code-magazine.com
CoDe_Focus_Fox Pro 09 30.11.2004 12:44 Uhr Seite 65
loWSHandler = that you must parse before VFP can use it. In the
NEWOBJECT("WSHandler",; case of a DataSet, VFP has an XMLAdapter class.
(Note: For more information about the
IIF(VERSION(2)=0,"",;
XMLAdapter class, see the “What’s New with Data
HOME()+"FFC\")+"_ws3client.vcx")
in Visual FoxPro 9.0” article in this issue, or search
loSvc = for “XMLAdapter” on www.code-magazine.com.) For
loWSHandler.SetupClient(; other complex objects, parsing the XML may be a
"http://.../Svc.asmx?WSDL",; little more complex, but using tools like XMLDOM,
"Service1", "Service1Soap") it is never overly hard.
MessageBox(loSvc.GetCurrentTime(
)) Exposing VFP Objects as Web Services
Note: We shortened the URL to make it more read- Visual FoxPro does not support a native way to
able. Please replace the URL with the URL of the expose VFP objects as Web services, but there are
service you created. several other Microsoft tools and technologies that
you can use to accomplish this goal. In previous
The sample code instantiates the WSHandler object, versions of VFP, Microsoft recommended the SOAP
which is VFP’s connector to a Web service. This Toolkit (and in fact provided tools to automatically
object is then configured with the WSDL URL. publish VFP Web services using this toolkit). This
Subsequently, we call the GetCurrentTime() approach is now not recommended anymore,
method, which returns a .NET DateTime variable. mainly because the SOAP Toolkit uses either ASP
VFP automatically assigns the return value to a VFP or ISAPI “listeners” to react to incoming requests.
DataTime variable even though the two formats Neither technology is recommended at this point,
internally differ slightly. Since the value is returned and is only supported by Microsoft based on the
as a DateTime you can perform additional opera- standard Microsoft support policy. The better way
tions on it. For instance, you can retrieve the time to go at this point is to expose VFP objects through
portion using the following commands: modern ASP.NET Web services.
LOCAL ldCurrentDateTime The overall idea for this approach is simple: First,
ldCurrentDateTime = ; create a VFP object and expose it as a COM object.
loService1.GetCurrentTime() You can access this COM object from ASP.NET
using a simple wrapper service to expose individual
? TToC(ldCurrentDateTime,2)
methods. For instance, consider the following VFP
object:
Note that automatic type assignment does not
happen all the time. It is possible, some would even DEFINE CLASS TestClass AS Custom OLEPublic
say likely, that the Web service will return a data FUNCTION GetName() AS String
type that is not natively supported in Visual FoxPro. RETURN "John Smith"
This typically happens when the return value is a
ENDFUNC
complex object, such as an ADO.NET DataSet. In
ENDDEFINE
that case the return value would be complex XML,
Listing 3: Calling the ASP.NET Web service from within a VFP program
www.code-magazine.com COM Interop: Making .NET and VFP Talk to Each Other 65
CoDe_Focus_Fox Pro 09 30.11.2004 12:44 Uhr Seite 66
Public Sub GetFoxProData() '-- create the adapter class for filling
Dim cConnString As String '-- our dataset
cConnString = "Provider=vfpoledb.1;" Dim oAdapter As New OleDbDataAdapter
cConnString += Data Source=\\JAWATEST\NorthWind\NorthWind.dbc" oAdapter.SelectCommand = oCMD
cConnString += ";Exclusive=false;Nulls=false"
'-- go get the data
'-- connect to database Dim oDS As New DataSet
Dim oConn As New OleDbConnection oAdapter.Fill(oDS, "customers")
oConn.ConnectionString = cConnString
oConn.Open() '-- clean up
oConn.Close()
'-- create a command object to query
Dim oCMD As New OleDbCommand '-- view the data
oCMD.CommandText = "select * from customers" Me.DataGrid1.DataSource = oDS.Tables("customers")
oCMD.Connection = oConn Me.DataGrid1.DataBind()
End Sub
Here is the wrapper class used to expose this object Further details of accessing VFP data through OLE
through ASP.NET as a Web service: DB is beyond the scope of this article. The core
concept however is relatively simple and pretty
Imports System.Web.Services similar to accessing SQL Server data.
< WebService(Namespace := _
Conclusion
"http://MySvc.org/Service1")> _
Public Class TestService
COM Interop makes it easier for the developer to
Inherits WebService use VFP components in a .NET application,
preventing the developer from rewriting portions of
#Region " Designer Generated Code " logic such as data access and business rules when
time constraints and budget don’t allow for that.
<WebMethod()> _ The same mechanism also enables the developer to
use .NET classes from VFP, adding even more
Public Function GetName() _
power to existing VFP applications.
As String
Dim oVFPObject As New _
TestProject.TestClass()
Return oVFPObject.GetName()
End Function
XML Web services
have been promoted more
End Class than any other feature in
.NET, and they
For more details on how to use VFP COM objects are indeed very useful.
in .NET, please refer to the earlier section on COM
Interop.
Visual FoxPro and OLE DB Web services are a more open process and allow
your VFP application to work with environments
Another way to interact with Visual FoxPro data that do not support COM or .NET. Web services
from .NET is via the Visual FoxPro OLE DB work over the Internet, hence automatically adding
provider. Listing 4 demonstrates querying data from remote invocation as a free benefit.
the sample NorthWind.DBC file and displaying it
on an ASP.NET page. Interop on the database level is also a viable option.
This works both ways: .NET can access VFP data
You can simply call this method from an event in through OLE DB. VFP, on the other hand, can
an ASP.NET Web Form (such as the Load event). access many of the data sources .NET uses, such as
The code first opens an OLE DB connection to a SQL Server. (We skipped this topic because SQL
VFP database container. Next the code executes a Server data access with VFP has been discussed
SELECT statement and fills the results into an many times).
ADO.NET DataSet using a DataAdapter. You can
then use this DataSet like any other ADO.NET Claudio Lassala,
DataSet. In this example, we use it as the bound Markus Egger,
data source for a DataGrid. and Rod Paddock
66 COM Interop: Making .NET and VFP Talk to Each Other www.code-magazine.com
CoDe_Focus_Fox Pro 09 30.11.2004 12:44 Uhr Seite 67
CoDe_Focus_Fox Pro 09 30.11.2004 12:44 Uhr Seite 68