0% found this document useful (0 votes)
104 views

2004 Vol.2 Issue1

Programación visual Foxpro

Uploaded by

Oreste Hernandez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
104 views

2004 Vol.2 Issue1

Programación visual Foxpro

Uploaded by

Oreste Hernandez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 68

CoDe_Focus_Fox Pro 09 30.11.

2004 12:41 Uhr Seite 1


CoDe_Focus_Fox Pro 09 30.11.2004 12:41 Uhr Seite 2
CoDe_Focus_Fox Pro 09 30.11.2004 12:41 Uhr Seite 3
CoDe_Focus_Fox Pro 09 30.11.2004 12:41 Uhr Seite 4

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

The new productivity tools help you build interesting and


useful applications with just a few carefully chosen bits of
code.
Claudio Lassala
Departments
6 CoDe Compilers
41 Advertisers Index

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.

Subscribe to Code Component Developer Magazine

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.

Subscribe online at www.code-magazine.com

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.

4 Table of Contents www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:41 Uhr Seite 5
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 6

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]

Circulation & Distribution


General Circulation: EPS Software Corp.
Subscriptions
CoDe Focus Magazine is a supplement of Code Com-
ponent Developer Magazine. Code Focus reports in-
depth on newly released specific technologies. The
supplement is available to CoDe Component Develop-
er Magazine subscribers that have noted interest
in the specific technologies covered in the Code Focus
supplements.
Subscriptions Manager
Cleo Gaither
832-717-4445 ext 10
[email protected]
Subscribe to CoDe Component Developer Magazine
US subscriptions are US $29.99 for one year; Canada,
Mexico & US territories are US $44.99; Europe is US
$49.99; other countries are US $59.99. Payments
should be made in US dollars drawn on a US bank.
American Express, MasterCard, Visa, and Discover
credit cards 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.
Subscribe online at
www.code-magazine.com
CoDe Component Developer Magazine
EPS Software Corporation / Publishing Division
6605 Cypresswood Drive, Ste 300,
Spring, Texas 77379
Phone: 832-717-4445
Fax: 832-717-4460
6
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 7
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 8

QUICK ID 0404012

Walking on Cloud 9.0


of Visual FoxPro
The Visual FoxPro Team at Microsoft is enthused [sic] to announce Visual FoxPro 9.0
We’d like to include some details as an overview to the more detailed articles in this special CoDe Focus
issue devoted to Visual FoxPro 9.0.

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.

You can create and access COM components


and XML Web services that are compatible
with .NET technology. Visual FoxPro 9.0
allows you to build end-to-end solutions,
from data entry forms to complex report
outputs.

Reporting System Features


To Visual FoxPro’s already strong reporting
system, we’ve added an extensible new
output architecture that provides precision
control of report data output and formatting.

There’s multiple-detail band support for data


with multiple one-to-many relationships.

You can customize the Print Preview


window with improved display quality and
multiple page support. Our new output
reports support XML, HTML, image
formats, and customizable multi-page print
preview windows. The enhanced report
writer is backward compatible with existing
Visual FoxPro reports. And flexible report
Figure 1: Pictured here are some of the Visual FoxPro team members (from left to right): Ken Levy, John chaining allows for more complex print
Koziol, Yair Alan Griver, Calvin Hsia, Randy Brown, Richard Stanton, and Mike Stewart. jobs.

8 Walking on Cloud 9.0 of Visual FoxPro www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 9
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 10

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

10 Walking on Cloud 9.0 of Visual FoxPro www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 11
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 12

QUICK ID 0404022

What's New with Data


in Visual FoxPro 9.0?
The Microsoft Visual FoxPro team has a great reputation for
responding to community requests and the next version is no
exception. Most evident in several changes to the data engine, Visual FoxPro
9.0 includes many enhancements for data access and database application
development.
David T. Anderson
David is currently serving as a
contract tester with the Visual
FoxPro team at Microsoft, SQL Enhancements
V
isual FoxPro 9.0 contains more functional
testing the data enhancements enhancements to the data engine than any
made to Visual FoxPro 9.0 and release since 3.0. From the new and extended Certainly the best word to describe changes to the
implementing performance functionality in SQL to new data types and a binary SQL sub-language is MORE! There are no longer
benchmarks such as the Trans- index, this release demonstrates the power of a hard-coded limits to the number of elements in an
action Processing Council's mature development platform SQL statement. A single SQL
TPC-H. for data-centric solutions. Fast Facts SELECT statement can contain
more tables, more JOINs, more
With 22 years of application Changes to the data engine can Changes to the data engine in sub-queries, more nested sub-
development experience in the be summarized in five major Visual FoxPro 9.0 provide queries and more UNIONs
PC industry for government, areas: developers with enhanced power, than in previous versions.
military, educational institu- flexibility, and performance.
tions, and private industry, · SQL Enhancements: Removal There are also no hard-coded
From the greatly expanded SQL
David uses his experience of most hard-coded limits, limits on the number of items
relating Enterprise Architecture enhanced sub-query and
sub-language to new data types and in an SQL IN list. In versions
and Organizational Maturity to correlation support, support Rushmore optimizations, this prior to Visual FoxPro 9.0,
assist organizations in deter- for more complex expres- release demonstrates the FoxPro SQL IN was mapped to the
mining the most appropriate sions, and enhanced UNION team’s commitment to producing INLIST() function; that depen-
software processes for their support. a world-class data-centric dency has been removed. This
needs. · Performance: A new index development language. change allows an increase in
type, enhanced performance the number of arguments for
You can reach David at of filtered indexes and IN and for better optimization.
[email protected] improved SQL performance with TOP n, Visual FoxPro 9.0 stops evaluating expressions
MIN()/MAX(), and LIKE. from the list as soon as the match is found. This is
· Commands and Functions: Greater ability to helpful if the IN condition is not Rushmore-opti-
fine-tune how data is accessed and committed, mized, as performance can be improved by placing
functions to supplement SQL showplan, and the most-likely-to-match values at the beginning of
easier immediate expression nesting with the list. The total number of items is still indirectly
ICASE(). limited by the SYS(3055) function, which controls
· New Data Types: Support for VarChar, buffer memory size, so the higher the setting, the
VarBinary, and BLOB data types, a new CAST() more items are supported via IN. (See the
function, and enhancements to existing functions Common Error Messages sidebar for more infor-
to control and convert data types. mation.)
· Remote Data: Enhanced control over transac-
tions, better visibility regarding fetched records, No Limits?
rowsets returned from the provider, and
CursorAdapter enhancements that bring behavior No hard-coded limits does not mean limitless.
in line with remote views. Issues such as available memory and expression
complexity can still have an impact on whether or
Many of these changes improve the Visual FoxPro not a very long and complex statement can be run,
9.0 client/server story by providing stronger inter- but you'll have to work hard to find many real-
operability with SQL Server. With support for new world limitations.
data types and removing many limits from the SQL
language, it's now easier to develop a single code Enhanced Sub-Query Support
base that works with the Visual FoxPro 9.0 native
data engine and SQL Server. Sub-queries have always been powerful in the SQL
language. They can be used as filters by placing
Enough overview, let's dig in! them on the right side of a comparison in the

12 What's New with Data in Visual FoxPro 9.0 www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 13

WHERE clause. In Visual FoxPro 9, sub-queries


can also be used as part of the SELECT list (called
a projection) and in the FROM clause (often called A single SQL SELECT
a derived table).
statement can contain more tables,
When used as a projection, if the sub-query doesn't more JOINs, more sub-queries,
return any records, a NULL value is returned.
Correlation is supported with projection (more on more nested sub-queries, and more
this in a minute). UNIONs than ever before.
A SQL statement that uses projection looks like this:

SELECT ; Consider the following example:


C.CustomerID, ;
C.CompanyName, ; SELECT ;
C.customerid, ;
Common Error
(SELECT YTD_Sales FROM Sales_02 WHERE ;
P.product_count AS p_count;
Messages
C.CustomerID = Sales_02.CustomerID) AS Y02,;
(SELECT YTD_Sales FROM Sales_03 WHERE ; FROM Customers C, ;
As your SQL statements get
C.CustomerID = Sales_03.CustomerID) AS Y03,; (SELECT c2.customerid, ;
longer and more complex, you
(SELECT YTD_Sales FROM Sales_04 WHERE ; COUNT(DISTINCT D.productID) AS p_count ; will become familiar with the
C.CustomerID = Sales_04.CustomerID) AS Y04 ; FROM Customers C2 ; following errors:
FROM Customers C INNER JOIN Orders O ;
ON C2.customerid = O.customerid ; Error # 18: Line is too long
This SELECT statement returns the customer ID INNER JOIN OrderDetails D ;
and company name along with year-to-date sales
ON O.orderid = D.orderid ;
Error # 1812: SQL: Statement
from warehoused tables for the last three fiscal is too long
GROUP BY c2.customerid) AS P ;
years.
WHERE C.customerID = p.customerID ; Error# 1814:Queries of this
A restriction on a projection is that the sub-query AND P.p_count >= ; type are not supported.
should return only one column and no more than (SELECT (COUNT(*)*.50) FROM Products) ;
one record for each record in the containing ORDER BY p.product_count DESC Error# 1845: Too Complex
SELECT.
Error# 2189: SQL: Too many
Another valuable use of a projection is when it’s This SELECT statement returns customer ID and fields in final or intermediate
used as part of an expression. product count for all customers who have result have the same name.
purchased at least 50% of the product line.
SELECT ; If you dynamically build SQL,
C.customerID, ; Notice that the derived table has an alias of "P" you may want to consider
C.companyname, ; that is designated the same way you would alias adding traps for these errors so
a column, using the AS clause (required). It's that you can isolate them for
SUM(D.quantity*D.unitprice) AS CustTotal ,;
also important to note that the sub-query can be analysis.
(SUM(D.quantity*D.unitprice) / ;
complex (in this case, joining to two other
(SELECT SUM((quantity*unitprice)-discount) ; tables) and that the results from the derived SYS(3055)
FROM OrderDetails D2) ; table can be used as a condition of the WHERE
)*100 AS PctTotal ; clause and in the ORDER BY of the top-most If you are not bound by a low
FROM Customers C ; SELECT. memory environment, consider
INNER JOIN Orders O ; using SYS(3055) to set the
ON C.customerID = O.customerID ;
Unlike a projection, the derived sub-query can complexity level of the FOR and
return more than one column and more than one WHERE clauses to its
INNER JOIN OrderDetails D ;
record. It cannot be correlated. All sub-selects are maximum value of 2040 when
ON O.orderid = D.orderid ; executed before the top-most SELECT is evalu- you set up the environment for
GROUP BY C.customerID, C.companyname, O.orderID ; ated. your applications. This allows
ORDER BY pctTotal DESC more complex SQL statements
Sub-queries are also supported in the SET list of a and more values with IN. See
This SELECT statement returns customer ID, SQL UPDATE statement. Only one sub-query is the Help files for a list of other
company name, total sales, and a percent of total allowed in a SET clause and if there is a sub-query commands and functions that
sales against all customer sales. in the SET clause, a sub-query in the WHERE are affected by this setting.
clause is not allowed.
Note that the sub-query in the SELECT list is part
of a complex expression that includes an aggregate Better Correlation Support
function. Now that's flexibility!
The SQL UPDATE and SQL DELETE commands
A derived table as sub-query allows you to treat the now support correlation. A correlated statement
results of a sub-query as though it were its own includes a FROM clause to relate the records being
table. affected to another table.

www.code-magazine.com What's New with Data in Visual FoxPro 9.0 13


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 14

Also, with the hard-coded limits of SQL IN


removed, the Designers no longer convert IN to
Many of these changes improve INLIST(). The INLIST() function still has a limit of
FoxPro's client/server 24 elements.
capabilities by providing
Enhanced UNION Support
stronger interoperability with
SQL Server. In addition to having no hard-coded limits for the
number of UNIONs, you can now use a UNION
inside the result set that is used by an INSERT
INTO.
For example:
You can now also ORDER BY <fieldname> when
DELETE products ; using UNION. The referenced field must be present
FROM mfg ; in the SELECT list for the last SELECT in the
John Koziol UNION.
WHERE mfg.productID = products.productID;
Test Engineer,
AND mfg.discontinued = .t.
Visual FoxPro Team
Microsoft Performance
This DELETE statement deletes all products
An overall area of enhance- marked as discontinued from a table provided by Regardless of whether you are doing remote data
ments for Visual FoxPro 9.0 the manufacturer. access or relying on the powerful native data
includes more event hooks and engine, performance has always been a priority for
fewer capacity limitations. You A correlated UPDATE looks similar: Visual FoxPro. Visual FoxPro 9.0 enhances the data
can now hook into Windows engine even further.
API events with the BINDE- UPDATE products ;
VENTS() function. Now only SET unitprice = mfg.msrp *.90 ; Binary Indexes
limited to available memory, FROM mfg ;
you can create arrays larger This new index type is a specialized index, designed
WHERE mfg.productID = products.productID
than 64K and nest DOs deeper for one thing:
than 128 levels. Also, many of
the limits on clauses in SQL This UPDATE statement sets the unit price for a INDEX ON DELETED() TAG DELETED BINARY
statements have been product at 90% of the manufacturer’s suggested
extended. You can write your retail price. The new index type can be used with any NOT
own report handlers and NULL logical expression. Other restrictions
enhance the Visual FoxPro You may be tempted to use a correlated sub-query preclude the use of a FOR expression and
interface via MemberData. as this is also supported. Just be aware that when ASCENDING, DESCENDING, UNIQUE, and
Visual FoxPro 9.0 is a great using a sub-query it's like doing an outer join. For CANDIDATE keywords.
upgrade for Visual FoxPro every record that is not found in the sub-query, the
developers who want to have value returned is NULL. This may not give the SET ORDER TO is not supported and the INDEX
fewer limits in building applica- desired results. ON command sets the current order to 0. Also, you
tions! cannot use a Binary index with any Seek operation.
UPDATE products ;
SET unitprice = ; The big advantage of a Binary index is its size. A
(SELECT ( msrp *.90 ) ; Binary index for a table with 8,000,000 records is
approximately 30 times smaller (1.1MB versus
FROM mfg ;
31.5MB). Smaller means faster I/O and faster
WHERE mfg.productID = products.productID)
APPEND and REPLACE, all with the same Rush-
more optimization as a non-binary index on the
This UPDATE statement sets the unit price for a same expression.
product at 90% of the manufacturer’s suggested
retail price for every product found in the Manufac- There is a trade-off to consider. Rushmore opti-
turers table. The price for products not found in the mization is faster if the amount of records returned
Manufacturers table is set to NULL. is more than 3% of the total records (about 92%
faster when all records match the condition).
Note that this statement operates on every record in However, Rushmore optimization is slower if the
the Products table; in the previous statement, only amount of records returned is less than 3% (about
updated records that matched in the Manufacturers two times slower when 0 records match the condi-
table were involved. tion). It is likely that the 3% threshold will become
smaller as the number of records in the table
View and Query Designers increases.

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

14 What's New with Data in Visual FoxPro 9.0 www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 15
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 16

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

16 What's New with Data in Visual FoxPro 9.0 www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 17

causes the current record to be committed before


the statement is executed.
Regardless of whether
you are doing remote data access The SET SQLBUFFERING command is scoped to
the current data session. When the WITH
or relying on the powerful BUFFERING clause is used, it overrides the SET
native data engine, performance statement.
has always been a priority.
CAST()
The new CAST() function is modeled after the SQL
writes data to the disk but the operating system Server function by the same name. It is useful both
keeps the writes cached. in and out of SQL. Used inside a SQL statement,
you can write SQL code that is more TSQL
When you use the FORCE keyword, Visual FoxPro compliant. As you might expect, this function
9.0 includes a call to the Windows API FlushFile- converts a data expression to another data type. Calvin Hsia
Buffers function. This ensures that even operating
system buffers are written to disk. Used within a SQL statement, the CAST() function Lead Developer,
looks like this: Visual FoxPro Team
Some examples of using the enhanced FLUSH Microsoft
command include: SELECT CustomerID, ;
CAST(nAmount*nRate AS N(8,2)) ; One of the many cool things
FLUSH "c:\data\customers.dbf" FROM SALES VFP 9.0 allows you to create is
FLUSH "c:\data\customers.dbf" FORCE better photo database applica-
FLUSH IN 1 FORCE tions without using the general
SELECT CustomerID, ;
field using the new BLOB data
FLUSH IN customer FORCE CAST(nAmount*nRate AS B NOT NULL) ; type and enhancements to
FLUSH "c:\test.txt" FORCE FROM SALES image properties. There are
FLUSH FORCE many new features in the
SELECT CustomerID, ; Property Sheet including
In versions prior to Visual FoxPro 9.0, using a SQL CAST(nAmount*nRate AS C(10)) ; custom font and color control
SELECT statement meant that the results were
FROM SALES
as well as a custom Favorites
always pulled from disk. This meant that if you tab for categorizing properties
wanted to query uncommitted changes from a and methods. There are new
buffered table, you were forced to use procedural SELECT foo.*, ; functions and events in VFP 9.0
commands. Now it's possible to specify for each CAST(NULL as I) AS IntegerField ; specifically designed for
table in a SELECT statement whether to read from FROM foo building even more advanced
the disk or from the local buffer using SET Tablet PC based applications.
SQLBUFFERING and SELECT … WITH Notice that there is the ability to specify whether
(Buffering = <lexpr>). NULLs are acceptable. If not specified, CAST()
inherits NULL behavior from the expression, if
Some examples of how to use WITH (BUFFERING possible.
…) include:
ICASE()
SELECT * FROM Customer WITH (BUFFERING = .t.)
Another function, ICASE() emulates TSQL’s CASE
SELECT * FROM Orders WITH (BUFFERING = lUseBuffer) branching construct. This function is similar to
IIF(), the immediate IF function. The value of
ICASE() is that it doesn't require the kind of ugly
SELECT DISTINCT c.city, o.shipcity ;
and verbose nesting syntax of IIF().
FROM customers C WITH (BUFFERING=.T.) ;
JOIN orders O WITH (BUFFERING=.T.) ; ICASE() works by requiring condition/result para-
ON c.customerID = o.customerID meter pairings. The first parameter is the condition
expression to evaluate, and the second parameter is
Notice that each table referenced has its own WITH the result if the condition provided in the first para-
BUFFERING clause. If no BUFFERING clause is meter evaluates to True. If the condition evaluates to
used, Visual FoxPro 9.0 respects the SET False, the second parameter is skipped and the next
SQLBUFFERING value (whose default is .f.). condition/result parameter pair is evaluated. This
continues for each parameter pairing. If the parame-
Support for BUFFERING is only available on local ters are not passed in pairs, Error # 11 is thrown.
Visual FoxPro 9.0 data. It is not supported on data
from back-end databases, so it should not be used Just like the CASE/ENDCASE syntax, there is an
with SQL Pass Through. Otherwise option that can be passed as the last
parameter to the function. If this parameter is not
When working with a table that is involved in ROW passed and all other condition parameters evaluate
buffering, using the WITH BUFFERING command to False, ICASE() returns a NULL.

www.code-magazine.com What's New with Data in Visual FoxPro 9.0 17


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 18

CLOSE DATA ALL


MODIFY FILE Showplan.txt NOWAIT

If you don't include a variable name as the third


parameter for SYS(3054), results are echoed to the
current window.

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.

In addition, if spaces are included with the original


Here is an example of ICASE() used outside of a value, they are not trimmed.
SQL statement:
It's important to note that when using expressions
nHour = HOUR(DATETIME()) combining VarChar with Character data types, the
? ICASE( nHour = 8, "breakfast" , ; result is always of the type VarChar.
nHour = 10, "caffeine" , ;
Because a VarChar is a fixed length field in Visual
nHour = 12, "lunch" , ;
FoxPro 9.0, the maximum field length is 255 char-
nHour = 15, "caffeine" , ;
acters. In SQL Server, it is possible for a single
nHour = 18, "dinner" , ; VarChar field to have a length <= 8060 bytes.
"snack" ;
)
VarBinary
Up to 100 condition/result parameter pairs can be The VarBinary data type is similar to VarChar in
passed to the ICASE(). that values assigned to VarBinary fields are not
padded. The only real difference between the two is
SYS(3092) Output to a File that FoxPro does not perform any code page trans-
lation for VarBinary types. (See Figure 1 for a
This new SYS() function works in conjunction with comparison of VarChar and VarBinary datatypes.)
SYS(3054), the SQL Showplan function. With
SYS(3092), you can specify a filename to which the BLOB
results of SYS(3054) output are sent.
The BLOB (Binary Large OBject) data type is not a
An example of how to use these functions together fixed length type, like a Memo. Its information is
is listed here: stored in an .FPT file that is external to but refer-
enced by the .DBF file. BLOBs have the same limi-
SYS(3054,12,"dummyVar") tations and issues as Memo fields and do not
SYS(3092,"ShowPlan.txt") support indexes.
OPEN DATABASE HOME(2)+"Northwind\Northwind"

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,"")

18 What's New with Data in Visual FoxPro 9.0 www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 19
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 20

9.0. Tables that include these new types cannot be


read by prior versions.
Many of the changes
made to the CursorAdapter were Remote Data
done to bring behavior
in line with remote views. Visual FoxPro has always had a strong remote data
story, and Visual FoxPro 9.0 adds even more
control over how remote data is manipulated and
retrieved.
Like the VarBinary type, Visual FoxPro 9.0 does not
perform any code page translation and its content is Transactions and Connections
treated as binary content.
A new property, DisconnectRollBack has been
The BLOB datatype is an ideal candidate to replace added to control whether pending transactions
the legacy General field. Pictures and other media should be rolled back when the connection is
can be stored in a BLOB and then rendered using disconnected. This property is available through the
the Image control PictureVal property. SQLSetProp, SQLGetProp, DBSetProp, and
DBGetProp functions.
MODIFY MEMO of a BLOB displays a HEX dump
of the binary data. SQLIdleDisconnect() is a new function that can be
used to temporarily disconnect a connection. In
SET EXACT & Binary Comparison most cases, this is controlled through the Idle-
TimeOut property of a connection. But in multi-
With Binary data types comes a difference in threaded run-time (MTDLL), idle tasks are disabled.
behavior with SET EXACT and SET COLLATE. Calling this function releases the connection until
the next command requiring a connection is issued.
SET EXACT ON specifies that expressions must
match exactly to be equal. However, with VarBinary Fetching and Processing Information
types whose values are padded with CHR(0), the
trailing bytes are ignored for the comparison. The CursorGetProp() receives two new properties,
shorter of the two expressions is padded on the RecordsFetched and FetchIsComplete. These prop-
right with CHR(0) bytes to match the length of the erties allow you to determine the number of records
longer expression. fetched and when a fetch is completed during the
execution of SQL Pass Through statements.
SET EXACT OFF specifies that expressions must
match up exactly to the length of the expression on The RecordsFetched value might not reflect the
the right side of the comparison. number of records in the cursor in the event that
some records in the cursor were locally appended
The == operator requires that both sides of the or deleted. The number of records reported does not
expression contain exactly the same number of respect filters that may be on the cursor.
bytes, including CHR(0) bytes.
The number of records affected by the SQL Pass
Further, because Binary data is case-sensitive, Through can be determined using the additional
comparisons are always case-sensitive regardless of parameter aCountInfo available with the
SET COLLATE. This is different than a comparison
with a Character type, which is case-insensitive if
SET COLLATE is set to GENERAL. Data Type Long Name Initial
Character Char, Character C
Learn to Type Date Date D
DateTime Datetime T
Prior to version 9.0, Visual FoxPro allowed a SQL Numeric Num, Number N
CREATE TABLE statement to include a long type- Floating Float F
name, although only the first letter of the type- Integer Int, Integer I
name was respected. This resulted in issues with Double Double B
data types such as Character and Currency. There Currency Currency Y
is now full support for long typenames with both Logical Logical L
CREATE and ALTER TABLE/CURSOR as well as Memo Memo M
the new CAST() function. Table 1 provides a list of General General G
FoxPro data types with their long name, single Picture Picture P
letter, and, in some cases, abbreviations, VarChar Varchar V
supported. VarBinary Varbinary Q
BLOB Blob W
Just like with the new Binary index datatype, using
these new datatypes requires that all clients Table 1: Here are some FoxPro data types with their sup-
accessing the data be upgraded to Visual FoxPro ported long names and initials.

20 What's New with Data in Visual FoxPro 9.0 www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 21

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.

www.code-magazine.com What's New with Data in Visual FoxPro 9.0 21


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 22

QUICK ID 0404042

The Visual FoxPro 9.0


Report Writer
Microsoft has significantly improved the Report Writer in
Visual FoxPro 9.0. They also recognized the significant investment in existing
FRX-based reports and designed the new Visual FoxPro 9.0 Report Writer to be
compatible with previous versions of Visual FoxPro Reports. This makes it a great
blend of the old and the new. In this article, you'll learn about some of the new
Cathy Pountney features, including the new reusable data environments, report protection, and
Cathy Pountney is a Microsoft
Visual FoxPro MVP and has
several user interface enhancements. You’ll also learn about enhancements to
been developing software for layout objects and data groups. Finally, you’ll learn about one of the best
over 22 years, thirteen of which improvements to the Visual FoxPro 9.0 Report Writer: multiple detail bands.
were as an independent
consultant specializing in
FoxPro. In 2001 she had the
privilege of spending six
months as a contractor onsite

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.

22 The Visual FoxPro 9.0 Report Writer www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 23

must click Yes to continue. This helps remind you


that anything you have defined in the Data Envi-
ronment of the current report is about to be over-
written. If you click No, changes are not made and
the process is aborted. When you click Yes, the
Data Environment is copied and you are notified by
another dialog box.

You are now finished copying the Data Environ-


ment. You may manipulate the Data Environment
as needed. However, remember that any changes
made to the original report's Data Environment
after this point are not propagated to this new
report.
Figure 2: Use the Data Environment tab of the Report Prop-
erties dialog box to choose which report you want to copy a From a DE Class
Data Environment from.
When loading the Data Environment from a class,
code is added to the Data Environment of the new
group is the only option button-enabled when report to bind to the original DataEnvironment
saving a Data Environment of a report. class and instantiate it at runtime. This means that
future changes made to the DataEnvironment class
Enter a name for the class in the Name textbox. will propagate into any reports using the DataEnvi-
Next, enter the name of the class library you want ronment class.
the new class saved in. If you enter the name of a
class library that does not exist, the new class library Using the Report Properties dialog box, shown in
is created for you. You can also use the ellipse Figure 2, click the Link to a visual DE class button.
button to brows for the location of an existing class Next, click the Select… button to invoke the Open
library. Finally, you may optionally enter a descrip- dialog box that you can use to choose which class
tion of the new class. library and which class to use. After confirming
your intentions, the Data Environment is updated
Loading a DE and you are notified of its completion.

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.

When loading the Data Environment from another


report, all the code and members of the original Data
Environment are copied into the new report. This
means any changes made to the original report's
Just like the Report Designer,
Data Environment after the fact are not propagated you can control whether the new or
into reports created from the original report. old output engine is used.
The Report Properties dialog box, as shown in
Figure 2, appears after selecting Load Data Envi-
ronment… from the Report menu. Use this menu to
select the report from which you wish to copy the Protection
Data Environment.
In Visual FoxPro 9.0, you can create protection for
Select the Copy from another report file option one or more layout objects when using Report
button and then click the Select… button. This Designer or Label Designer. This lets your user
invokes the Open dialog box so you can choose modify a report, yet keeps them from making
which report to copy from. Once you chose a certain changes.
report, a confirmation dialog box appears.
Layout objects have five protection modes you can
Visual FoxPro 9.0 is about to copy the Data Envi- set, and Field objects have an additional protection
ronment from another report to the current report. option. Bands have two protection modes you can
Visual FoxPro 9.0 notifies you that it's about to set. The report itself has a variety of different protec-
overwrite the current Data Environment, and you tion modes you can set.

www.code-magazine.com The Visual FoxPro 9.0 Report Writer 23


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 24

option on the Report menu, from the right-click


menu of the band, or by double-clicking the gray
bar of the band. Figure 4 shows the Protection tab
of the Properties dialog box for a band. You can set
the following two protection modes for bands:

· Band cannot be edited prevents the Band Proper-


ties dialog box from being accessible to the user.
· Band cannot be resized prevents the user from
resizing the band.

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.

The Design-time caption portion of this dialog box


only applies to Field objects. The literal string
entered into this textbox is displayed in the Report
Designer, instead of the Expression. This gives you
the opportunity to display something that is user-
friendly instead of a complicated expression.

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.

24 The Visual FoxPro 9.0 Report Writer www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 25
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 26

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.

UI Enhancements When the _REPORTBUILDER system variable is


set to ReportBuilder.app, the behavior of the
Many changes have been made to the user interface Expression Builder dialog box is quite different.
to make designing reports easier and more intuitive. First of all, the Expression Builder defined in
Menus have been overhauled, context menus have _GETEXPR is invoked instead of the native Expres-
been changed, and new options have been added to sion Builder.
the Report Designer toolbar. The Expression
Builder dialog box and Expression Builder Options This Expression Builder dialog box has a combo
dialog box have new behaviors, and a few other box for choosing which table should be used
miscellaneous user interface enhancements have when listing fields in the Fields list box. Only
been added to the Visual FoxPro 9.0 Report Writer. tables that are currently in use are listed in the
Yair Alan Griver combo box. This is an important point to
Menus remember because tables defined in the Data
Group Manager, Environment are not automatically opened by the
Visual Studio Data Team Report Designer, and do not automatically appear
Microsoft The report menu system has been overhauled in in the combo box.
Visual FoxPro 9.0 to accommodate new options. In
The new data enhancements— addition, some options have been relabeled for This gives you the ability to control which tables are
particularly those that target clarity and some options have been repeated on available to end-users when you allow them to
SQL Server—are among my several menus to allow easier access. modify reports within your application. You may
favorite new capabilities in have defined some tables in the Data Environment
Visual FoxPro 9.0. I really like · The new Save As Class… option appears on the that you need, but to which you don't want user
being able to use CAST(), opti- File menu. access. Because you have to specifically open the
mized LIKE, and some of the · A new option has been added for the Report tables you want users to access, you can omit any
new features that give me Designer Toolbar and horizontal lines have been tables you want to keep from them.
better control over SQL added to separate the Grid Lines and Show Posi-
handles. I especially love the tion options from the other options. Expression Builder Options Dialog Box
enhanced SQL syntax. Being · Many changes appear on the Report menu,
able to more closely model including relabeled options, new options, and the The Field aliases option group is now enabled in
Visual FoxPro and SQL Server addition of the Print Preview option. the Expression Builder Options dialog box. This
statements is an awesome option group allows you to indicate whether or not
capability! Context Menus you want the table alias added to the report expres-
sion when picking fields from the Expression
Existing context menus have been improved with Builder dialog box.
additional items and are now more consistent with
the dialog boxes they invoke. Items in the Report The Always add alias and Never add alias option
Designer that previously didn't have context menus buttons cause Visual FoxPro 9.0 to automatically
now do. add the table alias, or to not add the table alias, for
all fields. The behavior of the Add non-selected
· The Global Context menu has new options and alias only option button depends on the value
one relabeled option. of the _REPORTBUILDER system variable. If the
· Invoke the new Band Context menu by right- _REPORTBUILDER system variable is empty, any
clicking on the gray bar of any band. field chosen from a table that is not the InitialSe-
· Invoke the new Layout Object context menu by lectedAlias is prefixed with the table alias. Fields
right-clicking on any layout object. from the InitialSelectedAlias table are not prefixed
with the table alias.
Toolbar
If the _REPORTBUILDER system variable is set to
The improved Report Designer toolbar, shown in ReportBuilder.app, the Add non-selected alias only
Figure 6, has two new buttons: The Page Setup option uses slightly different logic. The currently
button and the Font Properties button. selected alias is used instead of the InitialSe-
lectedAlias for determining whether or not to prefix
Figure 6: New options for Page Expression Builder Dialog Box the field with the table alias.
Setup and Font Properties have
been added to the Report Design- A few changes have been made to the Report In addition to selecting a field from the Expression
er toolbar. Expression dialog box, including a taller Expression Builder dialog box, dragging a field from the Data
for Field editing box, which allows more room for Environment to the Report Designer surface
entering a report expression. honors the setting of the Field aliases option
group. Also, a new option exists on the Report tab
When the _REPORTBUILDER system variable is of the Options dialog box to determine what the
empty, the native behavior of the Expression default Field aliases setting is for all newly created
Builder dialog box is specific. Only tables defined in reports.

26 The Visual FoxPro 9.0 Report Writer www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 27

Mouse Cursor example, when the Format expression is "999-999",


and the data contains "123456", the report shows
The mouse cursor now changes to provide a visual "123-56". Notice that the "4" is replaced by the dash
cue when an object can be resized (see Figure 7). in the format expression.

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.

www.code-magazine.com The Visual FoxPro 9.0 Report Writer 27


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 28

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.

28 The Visual FoxPro 9.0 Report Writer www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 29
CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 30

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.

30 The Visual FoxPro 9.0 Report Writer www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 31

When creating Multiple-Detail band reports, it's


important to prefix field names with the applicable
alias name. This prevents any confusion as to which
table a field comes from.

Headers and Footers


Another enhancement of the Multiple-Detail band
is the ability to add Headers and Footers to each
Detail band. These are similar to Group Headers
and Footers in some ways, yet different in others.
For each parent record that is processed, the
following occurs:

• The Detail 1 Header band is processed.


• The Detail 1 band is processed once for each
child record in the associated target alias.
• The Detail 1 Footer band is processed.
• The Detail 2 Header band is processed.
• The Detail 2 band is processed once for each
child record in the associated target alias.
• The Detail 2 Footer band is processed.
Figure 15: This sample Multiple-Detail band report has three • The Detail 3 Header band is processed.
separate detail bands for each customer. • The Detail 3 band is processed once for each
child record in the associated target alias.
• The Detail 3 Footer band is processed.
Defining Multiple-Detail Bands
• And so on …
By default, new reports are created with one Detail
band. Additional Detail bands are added through To turn on Detail Headers and Footers, place a
the Optional Bands dialog box. To invoke this check mark in the selection box for Detail
dialog box, select Optional Bands… from the Header/Footer in the Detail dialog box for each of
Report menu. This is the same dialog box that was the Detail bands. To help sort out the Detail bands
formerly named Title/Summary. from other bands, the triangle preceding the band
name is solid and the other triangles are clear.
Click the Add button to add another Detail band to
the report. You may define up to 20 Detail bands It's important to note that even if no detail records
for each report. exist for a particular Detail band, the associated
Detail Header and Detail Footer bands still print.
Defining the Target Alias If you do not want the Detail Header and Detail
Footer bands under this condition, you may use
The target alias is assigned to a Detail band the following Print when logic in each layout
through the Detail dialog box. This dialog box can object defined in the bands to suppress their
be invoked by selecting Edit Bands… from the printing.
Report menu and selecting the applicable Detail
band. You can also invoke this dialog box by NOT EOF(<target alias>)
double-clicking the gray bar of the applicable
Detail band.

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

*-- Open the parent table


In addition to manually SELECT 0
defining the Data Environment for a USE customer ORDER CustomerPK
new report, you have the *-- Set the relations between the parent and children
option to load the Data Environment SET RELATION TO CustomerPK INTO Members
from an existing report SET RELATION TO CustomerPK INTO Vehicles ADDITIVE
SET RELATION TO CustomerPK INTO Homes ADDITIVE
or from a saved
DataEnvironment class. *-- Run the report
REPORT FORM Insurance PREVIEW

www.code-magazine.com The Visual FoxPro 9.0 Report Writer 31


CoDe_Focus_Fox Pro 09 30.11.2004 12:42 Uhr Seite 32

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-

32 The Visual FoxPro 9.0 Report Writer www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 33

Figure 16: Use a Multiple-Detail report to print group subto-


tals at the beginning of the group.
Figure 17: Use a Multiple-Detail report to print percentages Randy Brown
along with each detail line.
lation is applied. Next, the calculation is applied for Lead Program Manager,
each record in the target alias of the first Detail band. Visual FoxPro Team
Then the calculation is applied for each record in the and set the Reset based on to Detail1. Microsoft
target alias of the second Detail band, and so on. 6. Define the Detail #2 band: Double-click the
gray bar of the Detail 2 band to invoke the With Visual FoxPro 9.0,
Properties dialog box. Set the target alias to the Fox team brings you the
Tricks with Multiple-Detail Bands "Vehicles", remembering to use the quotes. best desktop database applica-
Check the Associated header and footer bands tion software on the market.
The previous section showed how to print data checkbox. Add any other objects needed in As one who has always appre-
from three different child tables on the same report. Detail 2 band. ciated all the great extensibility
But a multiple detail band report doesn't necessarily hooks that Fox has to offer,
have to have multiple child tables. The same child The above report definition tells the Visual FoxPro I am very excited about some
table can be used in more than one detail band. 9.0 Report Writer to process the Vehicles table of the new capabilities in
twice for each customer in the Customer table. The VFP 9.0 such as the ability to
Group Totals first time, it calculates the total records and dollar hook in your own custom
amount for the customer and then prints them. Menu Designer. You can now
Prior to Visual FoxPro 9.0, printing subtotals in the The second pass of the Vehicles table prints the extend your classes with
Data Group Header band (shown in Figure 16) was details. This process repeats for each customer in MemberData for class
very difficult. The data had to be preprocessed to the Customer table. members that offer capabilities
calculate the totals prior to running the report. With such as custom property
Visual FoxPro 9.0, no preprocessing is required. Percentages editors, display in a Favorites
Follow these steps to create this report: tab and even XML docs
Another reporting concept is to show percentages support. And the new open
1. Create the Data Environment: Add the of totals of each detail line, as the detail line prints. architecture for Visual FoxPro
Customer and Vehicles tables. Set the InitialSe- This can also be handled with Multiple-Detail 9.0 Reporting blows the doors
lectedAlias property to the Customer table. bands, as shown in Figure 17. Follow these steps to off of anything available in the
2. Create a Data Group: Set the Data Group create this report: market today.
expression to the Customer PK. Do not place any
objects in the Data Group Header or the Data 1. Define the Data Environment: Add the
Group Footer bands. Customer and Vehicles tables. Set the InitialSe-
3. Create the multiple detail bands: Select lectedAlias property to the Customer.
Optional Bands… from the Report menu. Click 2. Create a Data Group: Set the Data Group
the Add button to add one more detail band to expression to the Customer PK. Add the
the report. Click OK to exit the dialog box. Customer Name and Address objects to the Data
4. Define the Detail #1 band: Double-click the gray Group Header band.
bar of the Detail #1 band to invoke the Properties 3. Create the multiple detail bands: Select
dialog box. Set the target alias to "Vehicles", Optional Bands… from the Report menu. Click
remembering to use the quotes. Check the Asso- the Add button to add one more detail band to
ciated header and footer bands checkbox. Do the report.
not place any objects in the Detail 1 band.
5. Define the Detail #1 Footer band: Add the
Customer Name and Address objects to the band.
Add the total vehicles and total premiums Label The Visual FoxPro 9.0 Report Writer
objects to the band. Add a Field object for the total
vehicles; set the expression to vehicles.premium, includes one of the
set the Calculation type to Count, and set the most often requested features:
Reset based on to Detail1. Add a Field object for
the total premiums; set the expression to vehi-
Multiple Detail Bands.
cles.premium, set the Calculation type to Sum,

www.code-magazine.com The Visual FoxPro 9.0 Report Writer 33


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 34

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

34 The Visual FoxPro 9.0 Report Writer www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 35
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 36

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]

Claudio Lassala is a Senior

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

Visual FoxPro 9.0 goes a step further and intro-


duces the docking capability to user-defined forms This.cboEmployees.RowSource =;
as well. That enables creating dockable Forms on "Thisform.colEmployees, FirstName, EmployeeId"

36 Controls, Events, Commands, and More www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 37

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.

If the default value 0 is used, the scrollbar is always


visible. Value 1 determines that the scrollbar is only
The AppStates property indicates
visible when the ListBox is full. This makes a lot of whether the application has focus
sense, as a scrollbar is of no use when all the items (value 1), or not (value 0).
on the ListBox fit in a single pane. Value 2 deter-
mines that the scrollbar is never visible. If there are

Listing 1: Docking User-Defined Windows

Local loMainForm as Form Read Events


Local loCustomerForm1 as Form
Local loCustomerForm2 as Form Define CLASS CustomerForm as Form
Local loCustomerForm3 as Form
*-- The value of one indicates this form
loMainForm = CreateObject("MainForm") *-- "Supports dock and is dockable"
loCustomerForm1 = CreateObject("CustomerForm") Dockable = 1
loCustomerForm2 = CreateObject("CustomerForm")
loCustomerForm3 = CreateObject("CustomerForm") EndDefine

loCustomerForm1.Caption = "Customer 1" Define CLASS MainForm as Form


loCustomerForm2.Caption = "Customer 2"
loCustomerForm3.Caption = "Customer 3" Dockable = 1

loCustomerForm1.Dock(3, loMainForm) Procedure Destroy()


loCustomerForm2.Dock(2, loCustomerForm1) Clear Events
loCustomerForm3.Dock(2, loCustomerForm2) EndProc

loMainForm.Show() EndDefine

www.code-magazine.com Controls, Events, Commands, and More 37


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 38

When the following code snippet runs, you’ll notice


that the Customer table doesn’t open by the Init
method: The new Report Engine in Visual
FoxPro can leverage the power of
loCustomer = NewObject("CustomerBizObj",;
"NewObjectSample.prg", 0) GDI+, so if you’re planning on doing
AMembers(laMembers, loCustomer, 1) powerful work with reports, take a
Display Memory like laMembers serious look at the GDI+ FFC
Define Class CustomerBizObj As Session
classes.
CustomerID = ""
CustomerName = ""
expressions, the harder it is to read the code, as
Procedure Init multiple IIF calls are needed. The ICASE (imme-
Aleksey Tsingauz diate case) function solves that problem. The
Use Home(1)+"\samples\northwind\Customers"
Developer, Visual FoxPro Team following code snippet shows an example written
EndProc
Microsoft using both the IIF and the ICASE functions:

Visual FoxPro 9.0 significantly Procedure GetCustomersByPk(lcPK As String) Local lcAnswer


extends SQL capabilities. Some EndProc lcAnswer = "YES"
hard-coded limits on the EndDefine
amount of tables, the amount
? Iif(lcAnswer = "YES", "answered 'yes'",;
of JOIN operators, the amount
of sub-queries, and the amount Set Path Command Enhancements Iif(lcAnswer = "NO", "answered 'no'",;
of UNION operators used in a 'unanswered'))
single SELECT command are An Additive clause was added to the Set Path
removed. Also, now you can command. When that clause is used, the path being ? ICASE(lcAnswer = "YES", "answered 'yes'",;
enjoy multiple sub-query specified is added to the path setting, if it isn’t there lcAnswer = "NO", "answered 'no'",;
nesting, sub-queries in the SET already. Besides that, the Set Path command’s
"unanswered")
and SELECT list, and sub- maximum character limit has been increased to
queries in the FROM clause 4095 characters.
(derived tables). In addition, TTOC() Converts DateTime
Visual FoxPro 9.0 supports the
FROM clause for UPDATE and AppState Property Detects an Expressions to XML DateTime Format
DELETE commands, which Application Losing or Receiving Focus Visual FoxPro 9.0 joins the ranks of great software
allows you to easily modify a XML adopters. The TTOC function has been
table based on data stored in The _Screen object has a new property called improved and receives a value 3 as the second para-
other tables. The new SET AppState. This property is only available read-only meter, indicating that the resulting string must be
SQLBUFFERING command and at runtime, and it indicates whether the Visual formatted as an XML DataTime format.
WITH (BUFFERING = ...) clause FoxPro application has focus (value 1), or not
allows you to query table (value 0). The value changes automatically when- ? Ttoc(Datetime(),3)
buffered data along with those ever the application loses or receives focus, such as
already committed. All these, when the user uses Alt+Tab. A Timer object, or The settings Set Century, Set Hours, or Set Seconds
and other SQL enhancements, event handler (using the BindEvent function) can don’t affect the result of the TTOC function when
allow you to efficiently perform be used to query this property and execute code the parameter 3 is passed.
very complex queries or modi- whenever its value changes.
fications using a single SQL
command. Log Execution Plan’s Output from
Specify Where Focus is SYS(3054) Using SYS(3092)
Assigned in the Valid Event
The SYS(3054) function is very helpful for opti-
It’s always been a pain when something happens mizing SQL queries, as it produces an execution
inside a Valid event and you want the focus to go to plan of which indexes, if any, are in use, and
another control, as calling SetFocus from within a enabling optimization of queries by creating new
Valid event is not allowed. That’s been solved in indexes or fine-tuning the way the queries are
Visual FoxPro 9.0 by allowing you to return the execu- written. The new SYS(3092) function provides the
tion to a specified object from within the Valid event: ability to write the output of SYS(3054) directly to a
file on disk.
Return Thisform.txtCity
*-- Turn on execution plan.
Sys(3054, 12)
ICASE() Function
*-- Set up output file.
The IIF() (immediate if) function has always been a
Sys(3092, "c:\ExecutionPlan.txt", .T.)
very useful function, but the more complex the

38 Controls, Events, Commands, and More www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 39

Populate an Array with


*-- Run Query. Aliases Used by a Specified Table
Select * ;
The AUsed function improved to allow passing a
from Home(1)+"\samples\northwind\Customers" ;
third parameter, one that indicates that the array
into cursor curCustomers created by this function should only look for aliases
of a specific table. The following code snippet shows
*-- Turn off output and close file. a simple example:
Sys(3092, "")
Select * ;
*-- Let's see the log. from Home(1)+"\samples\northwind\Customers" ;
Modify File "c:\ExecutionPlan.txt" into cursor curCustomers

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.

SET COVERAGE TO C:\MyApp.log


Retrieving Active SQL
The Set Coverage command creates a log file for the Connection Statement Handles
code being executed. The Coverage Profiler tool
(available on the Visual FoxPro IDE under the The new ASQLHandles function creates an array
Tools menu) can then be used to analyze this log with the handles for all active SQL connections.
file. The Coverage Profiler tool shows the code’s Those handles can then be used with other func-
coverage, indicating which lines are being executed, tions such as SQLExec and SQLDisconnect.
and which ones never get executed; it also shows
statistics, such as how many times a line is executed, lnConn1 = SQLStringConnect(;
and how long that takes, helping you find code "driver=sql server;server=(local); "+;
bottlenecks. "database=northwind;")

This new ability of enabling coverage during


lnConn2 = SQLStringConnect(;
runtime is also useful for debugging errors that
occur during runtime, but that never happen in "driver=sql server;server=(local); "+;
interactive mode (through the Visual FoxPro "database=pubs;")
IDE).

www.code-magazine.com Controls, Events, Commands, and More 39


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 40

ASQLHandles(laHandles)

Display Memory like laHandles


The SQLExec function makes it
possible to get cursor and count
Get Cursor and Count Records Affected
records affected by the SQL Pass-
by SQL Pass-Through Execution Through command
The SQLExec function has been improved in order
to make it possible to immediately get cursor and
count records affected by the SQL Pass-Through By using GDI+, you can manipulate graphics and
command. A parameter is passed determining the images, so this is a really powerful feature. Entire
name of the created array with a list of aliases and a articles could be devoted to this topic, exploring the
record count produced by the SQL commands. different classes, how to use them, and when to use
them, but it’s beyond the scope of this article. I’ll
This code snippet demonstrates this enhancement, just mention these classes here so that you don’t
producing multiple result-sets: overlook this new feature when you are all excited
by the other new features.
lnConn = SQLStringConnect("driver=sql server;"+;
"server=(local);database=northwind;") One simple example of image manipulation is a
small program that takes an existent bitmap file on
disk, and creates a new JPEG out of the original
SQLExec(lnConn, ;
one, as shown in the following code snippet imple-
"Select * from Customers; "+;
mentation:
"Select * from Employees", "", aCount)
*-- Create an Image object.
Display Memory like aCount Local oLogoImage As GpImage ;
Of Home(1)+"ffc/_gdiplus.vcx"
oLogoImage = ;
Newobject('GpImage',Home(1)+'ffc/_gdiplus.vcx')
View Classes Inside a Program File
(.prg) with the Class Browser
The Class Browser now has the ability to manage
program-based (PRG) classes. In previous versions,
only Visual Class Library-based (VCX) classes could
be viewed. For developers who write several PRG-
based classes (like me!), this is definitely a very-
welcome feature.

GDI+ FFC classes


Visual FoxPro 9.0 has a new FFC (FoxPro Founda- Figure 3: The
tion Class) library for the Graphics Device Interface image can be
(GDI) called _GDIPlus.vcx. This library has many drawn on a form
classes working as wrappers around the GDI+ API. using GDI+.

Listing 2: An image can be drawn on a form using GDI+.

Public oForm As Form *-- Get the Form's (Window's) handle.


oForm = Createobject("MyFoxForm") oGr.CreateFromHWND(Thisform.HWnd)
oForm.Show()
*-- Create an Image object.
Define Class MyFoxForm As Form Local oLogoImage As GpImage Of Home(1)+"ffc/_gdiplus.vcx"
oLogoImage = Newobject('GpImage',Home(1)+'ffc/_gdiplus.vcx')
DoCreate = .T.
Name = "Form1" *-- Load a bitmap file in memory.
oLogoImage.CreateFromFile("c:\Fox.bmp")
Procedure Paint
*-- Create Graphics object. *-- Draw Image object on Graphic's surface (here, the Form).
Local oGr As GpGraphics Of Home(1)+"ffc/_gdiplus.vcx" oGr.DrawImageAt(oLogoImage,0,0)
oGr = Newobject('GpGraphics',Home(1)+'ffc/_gdiplus.vcx') EndProc
EndDefine

40 Controls, Events, Commands, and More www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 41

*-- Load an image file in memory.


oLogoImage.CreateFromFile("c:\Fox.bmp")

*-- Save the image to a JPG file on disk.


oLogoImage.SaveToFile("c:\Fox.jpg",;
oLogoImage.GetEncoderCLSID("image/jpeg"))

Another example is the ability to manipulate images


and draw them on a device such as a form. Listing 2
shows off an implementation of it, and Figure 3
show the result. Notice that the image shown on the
form was really drawn right into it, instead of having
been added using the Visual FoxPro Image object.

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

dFPUG c/o ISYS GmbH , Germany West Wind Technologies


www.visualextend.com 25 www.west-wind.com 15, 34

EPS Software Corp.


www.eps-software.com 19, 29, 42-43, 62-63

F1 Technologies This listing is provided as a courtesy to


www.f1tech.com 67 our readers and advertisers.

Micromega Systems The publisher assumes no responsibility


www.micromegasystems.com 5 for errors or omissions. Advertising Sales:
Vice President,
Microsoft Sales and Marketing
msdn.microsoft.com/visual/think 2-3 Michelle Yates
703-328-0333
ProLib Software [email protected]
www.AFPages.com 11

Southwest Fox Conference Sales Managers


www.southwestfox.com 9 Erna Egger
+43 (664) 151 0861
Stonefield Systems Group [email protected]
www.stonefieldquery.com 7
Tammy Ferguson
Take Note Technologies 832-717-4445 ext 26
www.takenote.com 32 [email protected]

www.code-magazine.com Controls, Events, Commands, and More 41


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 42
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 43
CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 44

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

44 Extending the Visual FoxPro 9.0 Reporting System www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 45

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:

The defined types are 0 for outputting to a printer, 1 loListener = createobject('ListenerA')


for previewing, 2 for page-at-a-time mode but not to loListener.Successor = createobject('ListenerB')
send the output to a printer, 3 for all-pages-at-once report form MyReport object loListener
mode but not invoke the preview window, 4 for
XML output, and 5 for HTML output. Other, user-
defined, types can also be used. The report engine only communicates with the
listener specified in the REPORT or LABEL
When you run a report this way, the application command, called the lead listener. As the report
specified in the new _REPORTOUTPUT system engine raises report events, the lead listener calls
variable (ReportOutput.APP in the Visual FoxPro the appropriate methods of its successor, the SET REPORTBEHAVIOR
home directory by default) is called to determine successor calls the appropriate methods of its Instead of modifying the
which listener class to instantiate for the specified successor, and so on down the chain. This type of REPORT commands in your
type. It does this by looking for the listener type in a architecture is known as a chain of responsibility, application to use the OBJECT
listener registry table built into the APP (although as any listener in the chain can decide to take some clause, you can use SET
you can also tell it to use an external table). If it action or pass the message on to the next item in REPORTBEHAVIOR 90 to turn
finds the desired class, it instantiates the class and the chain. on object-assisted reporting by
gives a reference to the listener object to the default. This means the
reporting engine. Thus, using OBJECT TYPE Some- Another interesting capability of _ReportListener REPORT command behaves as
Type in the REPORT command is essentially the is chaining reports. The AddReport method adds a if you’ve specified OBJECT
same as: report to the custom ReportFileNames collection. TYPE 0 when you use the TO
You pass this method the name of a report and PRINT clause or OBJECT TYPE
loListener = .NULL. optional report clauses to use (such as the 1 when you use the PREVIEW
do (_ReportOutput) with SomeType, loListener RANGE clause) and a reference to another clause. SET REPORTBEHAVIOR
report form MyReport object loListener listener object. The RemoveReports method 80 reverts to behavior from
removes all reports from the collection. RunRe- Visual FoxPro 8.0 and earlier.
ports runs the reports; pass it .T. for the first para-
ReportListener meter to remove reports from the collection after

During the run of a report, Visual FoxPro exposes


reporting events to objects based on the ReportLis- Property Description
tener base class as they happen. The Visual FoxPro CurrentDataSession The data session ID for the report’s data
Help file has complete documentation on the proper- FRXDataSession The data session ID for the FRX cursor
ties, events, and methods (PEMs) of ReportListener, GDIPlusGraphics The handle for the GDI+ graphics object used for
so I’ll only discuss the most useful ones in this article. rendering
ListenerType The type of report output the listener produces. The
Table 1 lists the most commonly used properties of default is -1, which specifies no output, so you’ll need to
ReportListener. change this to a more reasonable value. The values are
the same as those specified in the OBJECT TYPE clause
Table 2 lists the most commonly used events and of the REPORT command.
methods of ReportListener. OutputPageCount The number of pages rendered
QuietMode .T. (the default is .F.) to suppress progress information

_ReportListener Table 1: Some useful properties of the ReportListener class.

The FFC (FoxPro Foundation Classes) subdirectory


of the Visual FoxPro home directory includes Event/Method Description
_ReportListener.VCX, which contains some LoadReport Fires before the FRX is loaded and the printer spool is
subclasses of ReportListener that have more func- opened
tionality than the base class. The most useful of UnloadReport Fires after the report has been run
these is _ReportListener. BeforeReport Fires after the FRX has been loaded but before the
report has been run
One of the most important features of _ReportLis- AfterReport Fires after the report has been run
tener is support for successors. It’s possible you may BeforeBand Fires before a band is processed
want to use more than one report listener when AfterBand Fires after a band is processed
running a report. For example, if you want to both EvaluateContents Fires before a field is rendered
preview a report and output it to HTML at the same Render Fires as an object is being rendered
time, more than one report listener must be OutputPage Outputs the specified rendered page to the specified
involved. _ReportListener allows chaining of device
listeners by providing a Successor property that can
contain an object reference to another listener. Table 2: Some useful events and methods of the ReportListener class.

www.code-magazine.com Extending the Visual FoxPro 9.0 Reporting System 45


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 46

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

46 Extending the Visual FoxPro 9.0 Reporting System www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 47

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

oEffectHandlers = .NULL. * Do the normal behavior.


&& a collection of effect handlers
dimension aRecords[1] Handling
dodefault(tnFRXRecno, toObjProperties)
&& an array of information for each record in the FRX endfunc Datasessions
* Create a collection of effect handler objects and fill it with * Go through each effect handler to see There are three
if it'll datasessions
handle the current
* the handlers we know about. A subclass or instance could be involvedof
* report object. If so, add it to a collection during a report
handlers forrun.
the
* filled with additional ones. * object, and return that collection. The first is the datasession in
which the ReportListener is
function Init instantiated. This is often the
function SetupEffectsForObject(tnFRXRecno)
dodefault() local loFRX, ; default datasession. The
with This loHandlers, ; second is the datasession in
.oEffectHandlers = createobject('Collection') loObject which Visual FoxPro creates a
.oEffectHandlers.Add(createobject('DynamicForeColorEffect')) with This copy of the FRX file into a
.oEffectHandlers.Add(createobject('DynamicStyleEffect')) .SetFRXDataSession() cursor called FRX (this copy
endwith go tnFRXRecno can be used by a listener). The
endfunc scatter memo name loFRX FRXDataSession property
.ResetDataSession() contains the datasession ID for
* Dimension aRecords to as many records as there are in the FRX so this cursor, so use SET
loHandlers = createobject('Collection')
* we don't have to redimension it as the report runs. The first DATASESSION TO
for each loEffectHandler in .oEffectHandlers
* column indicates if we've processed that record in the FRX yet This.FRXDataSession if you
loObject = loEffectHandler.GetEffect(loFRX)
* and the second column contains a collection of effect handlers if vartype(loObject) = 'O' need access to the FRX. The
* used to process the record. loHandlers.Add(loObject) third datasession is the one in
endif vartype(loObject) = 'O' which the report’s data resides.
function BeforeReport next loEffectHandler If the report has a private
dodefault() endwith datasession, it is a unique
with This return loHandlers datasession; otherwise, the
.SetFRXDataSession() endfunc report resides in the default
dimension .aRecords[reccount(), 2] enddefine datasession. The Current-
.ResetDataSession() DataSession property tells you
endwith * Create a class that holds a reference which
to an datasession
effect handlerto use.
and
endfunc Remember
* the expression the effect handler is supposed totoact
save
on the
for a
* particular record in the FRX. ReportListener’s datasession
* Apply any effects that were requested to the field about to be and switch back to it after
* rendered. define class EffectObject as Custom selecting either the FRX or
oEffectHandler = .NULL. report data datasession.
function EvaluateContents(tnFRXRecno, toObjProperties) cExpression = ''
local loEffectObject, ; enddefine
loEffectHandler, ;
lcExpression * Define an abstract class for effect handler objects.
with This
define class EffectHandler as Custom
* If we haven't already checked if this field needs any effects, do
* so and flag that we have checked it so we don't do it again. * Execute is called by the EvaluateContents method of
* EffectsListener to perform an effect.
if not .aRecords[tnFRXRecno, 1]
.aRecords[tnFRXRecno, 1] = .T. function Execute(toObjProperties, toFRX)
.aRecords[tnFRXRecno, 2] = ; endfunc
.SetupEffectsForObject(tnFRXRecno)
endif not .aRecords[tnFRXRecno, 1] * GetEffects is called to return an object containing a reference
* to the handler and the expression it's supposed to work on if the

www.code-magazine.com Extending the Visual FoxPro 9.0 Reporting System 47


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 48

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

48 Extending the Visual FoxPro 9.0 Reporting System www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 49

Figure 2: This is
the TestColumn-
Chart.FRX as it
looks at design
time.

Figure 1: The code in Listing 1 produced this report, which


shows dynamic formatting for the Shipped Date and Ship
Via columns.

and then sets the first column of the array to .T. so


the FRX record isn’t examined again.

After determining whether there are any effects to


be applied to the field, EvaluateContents then goes
through the collection of effect handlers for the
field, calling the Execute method of each one to
have it do whatever is necessary.

DynamicForeColorEffect is one of the effect


handlers. It looks for a directive in the USER memo Figure 3: The code in Listing 2 produced this report, which
of a field in the report with the following format: creates a column chart rather than traditional output.

*:EFFECTS FORECOLOR = expression


The Execute method of DynamicForeColorEffect
changes the color of the field by setting the
(You can access the USER memo of an object in a PenRed, PenGreen, and PenBlue properties of the
report from the Other page of the properties dialog field properties object that was passed to Evaluate-
box for that object.) Contents to the appropriate colors and sets Reload
to .T., which tells the report engine that changes
The ORDERDATE field of the TestDynamicFor- were made.
matting report used in Listing 1 has the directive in
the following snippet in its USER memo; it tells DynamicStyleEffect uses a similar directive to
EffectsListener that the DynamicForeColorEffect change the font style. The style to use must be a
object should adjust the color of the field so it numeric value: 0 is normal, 1 is bold, 2 is italics, and
displays in red if the date shipped is more than 10 3 is bold and italics. The SHIPVIA field in the Test-
days after it was ordered or black if not: DynamicFormatting report has the following direc-
tive in USER, which causes the field to display in
*:EFFECTS FORECOLOR = iif(SHIPPEDDATE > ORDERDATE bold if SHIPVIA is 3 (which, because of the expres-
+ 10, rgb(255, 0, 0), rgb(0, 0, 0)) sion for the field, actually displays as Mail) or
normal if not:

*:EFFECTS STYLE = iif(SHIPVIA = 3, 1, 0)

The reporting engine in DynamicStyleEffect works the same as Dynamic-


Visual FoxPro 9.0 splits ForeColorEffect, but changes the Style property of
the field properties object.
responsibility for reporting between
the report engine, which now just Running TestDynamicFormatting.PRG results in the
output shown in Figure 1.
deals with data handling and
object positioning,
Custom Rendering
and a new object known as a
report listener, which handles You aren’t limited to changing the appearance of a
rendering and output. field—you can do just about anything you like in a
report listener. The Render method of ReportListener

www.code-magazine.com Extending the Visual FoxPro 9.0 Reporting System 49


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 50

Listing 2: TestColumnChart.PRG shows how you can do custom rendering in a report to produce a column chart.

* Define some constants we'll use. .aColumnColors[5] = .CreateColor(rgb(255, 255, 0))


&& Yellow
#define FRX_OBJCOD_TITLE 0 && OBJCODE for title band .aColumnColors[6] = .CreateColor(rgb( 0, 255, 255))
#define FRX_OBJCOD_PAGEHEADER 1 && OBJCODE for page header band && Cyan
#define GDIPLUS_FontStyle_Regular 0 && GDI+ font style: regular .aColumnColors[7] = .CreateColor(rgb(255, 128, 0))
#define GDIPLUS_Unit_Point 3 && GDI+ units: points && Orange
.aColumnColors[8] = .CreateColor(rgb(128, 0, 255))
* Open the data for the report. && Purple
endwith
close databases all dodefault()
open database _samples + 'Northwind\Northwind' endfunc
use Category_Sales_For_1997
* Do some setup tasks before the report starts.
* Create the listener and run the report.
function BeforeReport
loListener = createobject('ColumnChartListener') dodefault()
loListener.OutputType = 1 with This
report form TestColumnChart object loListener
* Create a GPGraphics object so we can do GDI+ drawing.
* The ColumnChartListener class.
.oGDIGraphics = newobject('GPGraphics', ;
define class ColumnChartListener as _ReportListener of ; home() + 'ffc\_GDIPlus.vcx')
home() + 'ffc\_ReportListener.vcx'
* Dimension aRecords to as many records as there are in the FRX so
oGDIGraphics = .NULL. * we don't have to redimension it as the report runs. The first
&& reference to GPGraphics _GDIPlus object * column indicates if we've processed that record in the FRX yet,
dimension aRecords[1] * the second column is .T. for a Column chart object, the third
&& array of flags for each FRX record * column is .T. for a field containing values for chart labels, and
dimension aValues[1] * the fourth column is .T. for a field containing values for the
&& array of labels and values to chart * chart data.
nCurrentRow = 0
&& current row being processed in aValues .SetFRXDataSession()
dimension aColumnColors[1] dimension .aRecords[reccount(), 4]
&& array of column colors .ResetDataSession()
endwith
nSpacing = 100 endfunc
&& space between columns
nLegendSpacing = 300 * Because the GDI+ plus handle changes on every page, we need to
&& spacing between the chart and its legend * set our SharedGDIPlusGraphics property appropriately and set the
nLegendBoxSize = 200 * handle for our GPGraphics object.
&& the size of a legend box
nLegendBoxSpacing = 100 function BeforeBand(tnBandObjCode, tnFRXRecNo)
&& the spacing between items in the legend with This
nLegendTextSpacing = 50 if inlist(tnBandObjCode, FRX_OBJCOD_PAGEHEADER, ;
&& the spacing between boxes and text in the legend FRX_OBJCOD_TITLE)
cLegendFontName = 'Arial' if not .IsSuccessor
&& font name for legend text .SharedGDIPlusGraphics = .GDIPlusGraphics
nLegendFontSize = 10 endif not .IsSuccessor
&& font size for legend text .oGDIGraphics.SetHandle(.SharedGDIPlusGraphics)
endif inlist(tnBandObjCode ...
* Set the colors for the various columns. dodefault(tnBandObjCode, tnFRXRecNo)
endwith
function Init endfunc
with This
dimension .aColumnColors[8] * Return a SCATTER NAME object for the specified record in the FRX.
.aColumnColors[1] = .CreateColor(rgb( 0, 0, 255))
&& Blue procedure GetReportObject(tnFRXRecno)
.aColumnColors[2] = .CreateColor(rgb( 0, 255, 0)) local loObject
&& Green This.SetFRXDataSession()
.aColumnColors[3] = .CreateColor(rgb(255, 0, 0)) go tnFRXRecno
&& Red scatter memo name loObject
.aColumnColors[4] = .CreateColor(rgb(255, 0, 255)) This.ResetDataSession()
&& Magenta return loObject

50 Extending the Visual FoxPro 9.0 Reporting System www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 51

Listing 2: Continued

endproc endif lnRow = 0


.nCurrentRow = lnRow
* Handle a shape to see if it's a column chart.
* If this is a data value, add it to the current total.
procedure AdjustObjectSize(tnFRXRecno, toObjProperties)
local loObject case .aRecords[tnFRXRecno, 4]
with This .aValues[.nCurrentRow, 2] = .aValues[.nCurrentRow, 2] + ;
val(lcText)
* If we haven't already checked if this object is a column chart, endcase
* find its record in the FRX and see if its USER memo contains endwith
* "COLUMNCHART". Then flag that we have checked it so we don't do endproc
* it again.
* If we're supposed to draw a column chart, do so. Otherwise do the
if not .aRecords[tnFRXRecno, 1] * normal rendering.
loObject = .GetReportObject(tnFRXRecno)
.aRecords[tnFRXRecno, 1] = .T. procedure Render(tnFRXRecno, tnLeft, tnTop, tnWidth, tnHeight, ;
.aRecords[tnFRXRecno, 2] = atc('COLUMNCHART', ; tnObjectContinuationType, tcContentsToBeRendered, ;
loObject.User) > 0 tiGDIPlusImage)
endif not .aRecords[tnFRXRecno, 1] with This
if .aRecords[tnFRXRecno, 2]
* If this is supposed to be a column chart, make its width the same .DrawColumnChart(tnLeft, tnTop, tnWidth, tnHeight)
* as its height. nodefault
endif .aRecords[tnFRXRecno, 2]
if .aRecords[tnFRXRecno, 2] endwith
toObjProperties.Height = toObjProperties.Width endproc
toObjProperties.Reload = .T.
endif .aRecords[tnFRXRecno, 2] procedure DrawColumnChart(tnLeft, tnTop, tnWidth, tnHeight)
endwith local lnMax, lnColumns, lnI, lnColumnWidth, loColumnBrush, ;
endproc loPen, loFont, loStringFormat, loPoint, loTextBrush, ;
lnColors, lnColor, lnLeft, lnHeight, lnTop
* Handle a field to see if it's involved in the column chart. with This

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

if not .aRecords[tnFRXRecno, 1] * Create _GDIPlus objects we'll need for drawing.


loObject = .GetReportObject(tnFRXRecno)
.aRecords[tnFRXRecno, 1] = .T. loColumnBrush = newobject('GPSolidBrush', ;
.aRecords[tnFRXRecno, 3] = atc('LABEL', loObject.User) > 0 home() + 'ffc\_GDIPlus.vcx')
.aRecords[tnFRXRecno, 4] = atc('DATA', loObject.User) > 0 loPen = newobject('GPPen', ;
endif not .aRecords[tnFRXRecno, 1] home() + 'ffc\_GDIPlus.vcx')
loFont = newobject('GPFont', ;
* Get the value for the field, then decide what to do with it. home() + 'ffc\_GDIPlus.vcx')
loStringFormat = newobject('GPStringFormat', ;
lcText = toObjProperties.Text home() + 'ffc\_GDIPlus.vcx')
do case loPoint = newobject('GPPoint', ;
home() + 'ffc\_GDIPlus.vcx')
* If this is a label, ensure it's in our array. loTextBrush = newobject('GPSolidBrush', ;
home() + 'ffc\_GDIPlus.vcx')
case .aRecords[tnFRXRecno, 3] loPen.Create(.CreateColor(0)) && Black
lnRow = ascan(.aValues, lcText, -1, -1, 1) loFont.Create(.cLegendFontName, .nLegendFontSize, ;
if lnRow = 0 GDIPLUS_FontStyle_Regular, GDIPLUS_Unit_Point)
lnRow = iif(empty(.aValues[1]), 1, ;
alen(.aValues, 1) + 1) * Draw the border for the column chart.
dimension .aValues[lnRow, 2]
.aValues[lnRow, 1] = lcText .oGDIGraphics.DrawLine(loPen, tnLeft, tnTop, tnLeft, ;
.aValues[lnRow, 2] = 0 tnTop + tnHeight)

www.code-magazine.com Extending the Visual FoxPro 9.0 Reporting System 51


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 52

Listing 2: Continued

.oGDIGraphics.DrawLine(loPen, tnLeft, tnTop + tnHeight, ; .oGDIGraphics.FillRectangle(loColumnBrush, lnLeft, lnTop, ;


tnLeft + tnWidth, tnTop + tnHeight) .nLegendBoxSize, .nLegendBoxSize)
lnLeft = lnLeft + .nLegendBoxSize + .nLegendTextSpacing
* Draw the column. loPoint.Create(lnLeft, lnTop)
loTextBrush.Create(.CreateColor(0)) && Black
lnColors = alen(.aColumnColors) .oGDIGraphics.DrawStringA(.aValues[lnI, 1], loFont, ;
for lnI = 1 to lnColumns loPoint, loStringFormat, loTextBrush)
lnColor = (lnI - 1) % lnColors + 1 next lnI
loColumnBrush.Create(.aColumnColors[lnColor]) endwith
lnLeft = tnLeft + lnI * .nSpacing + ; endproc
(lnI - 1) * lnColumnWidth
lnHeight = tnHeight/lnMax * .aValues[lnI, 2] * GDI+ colors are represented by a number as 0xAARRGGBB, where AA
lnTop = tnTop + tnHeight - lnHeight * is the alpha, RR is the red, GG is the green, and BB is the blue.
.oGDIGraphics.DrawRectangle(loPen, lnLeft, lnTop, ; * Unfortunately, the VFP RGB() function gives us 0xBBGGRR, so we
lnColumnWidth, lnHeight) * need to add the alpha component and reverse the red and blue
.oGDIGraphics.FillRectangle(loColumnBrush, lnLeft, lnTop, ; * component positions.
lnColumnWidth, lnHeight)
procedure CreateColor(tnRGB, tnAlpha)
* Draw the legend for the column. local lnAlpha
lnAlpha = iif(pcount() = 1, 255, tnAlpha)
lnLeft = tnLeft + tnWidth + .nLegendSpacing return bitlshift(lnAlpha, 24) + bitand(tnRGB, 0x00FF00) + ;
lnTop = tnTop + (lnI - 1) * (.nLegendBoxSize + ; bitlshift(tnRGB, 16) + bitrshift(tnRGB, 16)
.nLegendBoxSpacing) endproc
.oGDIGraphics.DrawRectangle(loPen, lnLeft, lnTop, ; enddefine
.nLegendBoxSize, .nLegendBoxSize)

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.

52 Extending the Visual FoxPro 9.0 Reporting System www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 53

the columns, and then it creates some objects from


The key to changing the _GDIPlus classes needed to perform the drawing. It
calls the DrawLine method to draw the vertical and
way a field appears in horizontal borders for the chart, and then goes
a report is the through the aValues array, drawing a column for
each value using DrawRectangle and filling it with
EvaluateContents method. the appropriate color via FillRectangle. Draw-
ColumnChart adds a box and label to the legend for
the chart using the same DrawRectangle and Fill-
GPGraphics needs a handle to the GDI+ surface Rectangle methods for the box and DrawStringA for
being rendered to. Fortunately, the listener already the label.
has such a handle in its GDIPlusGraphics property.
The only complication is that the handle changes Some drawing attributes come from values in
on every page, so the BeforeBand method, which custom properties, making charting more flexible.
fires just before a band is processed, calls the For example, cLegendFontName and nLegendFont-
SetHandle method of the GPGraphics object to give Size specify the font and size to use for the legend
it the handle when the title or page header bands label, and nLegendBoxSize specifies the size of box
are processed. to draw. See the comments for these properties near
the start of the Listing 2.
As the report is processed, the listener needs to
determine where the labels and values for the chart
come from. It does that in the EvaluateContents
method by looking at each field as it’s about to be A listener that performs
rendered. If the USER memo for the field’s record custom rendering will almost
in the FRX contains LABEL (as it does for the Cate-
goryName field), that indicates that this field should certainly have to use
be used for the labels for the column chart. DATA GDI+ functions to do so.
in the USER memo (as is the case for the Catego-
rySales field) indicates that the field is used as the
values for the chart. As with the EffectListener class
I discussed earlier, there isn’t a need to check the Summary
USER memo more than once, so the same type of
mechanism—storing a flag in an array property to Microsoft has blown the lid off the Visual FoxPro
indicate whether the field was processed—is used in reporting system! By passing report events to
this class. ReportListener objects, they’ve allowed us to react
to these events to do just about anything we wish,
If the listener hasn’t checked the USER memo for from providing different types of output to dynami-
the field being rendered yet, EvaluateContents does cally changing the way objects are rendered. I can
that, setting flags in the array indicating whether the hardly wait to see the type of things the Visual
field is used for labels or values, and setting the first FoxPro community does with these new features.
column of the array to .T. so the FRX record isn’t
examined again. If the field is used for either labels Doug Hennig
or fields, EvaluateContents updates the aValues
array accordingly.

AdjustObjectSize is similar to EvaluateContents


except it fires for shapes rather than fields. Adjus-
tObjectSize checks the USER memo of the FRX
record of the current shape for the presence of
COLUMNCHART, indicating that this shape is to
be replaced by a column chart. As with Evaluate-
Contents, the listener only needs to check once, so
it uses similar logic.

The Render method is responsible for drawing an


object on the report. If the object about to be drawn
is a shape to be replaced with a column chart, it
calls the custom DrawColumnChart method
followed by NODEFAULT to prevent the shape
from being drawn. Otherwise, the object is drawn
normally. (Notice that there’s no DEDEFAULT();
the native behavior is to draw the object, so it isn’t
required).

DrawColumnChart figures out the maximum of the


values being charted so it knows how big to draw

www.code-magazine.com Extending the Visual FoxPro 9.0 Reporting System 53


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 54

QUICK ID 0404062

Visual FoxPro 9.0 IDE


Enhancements
Every version of FoxPro has always included a number of
enhancements to the IDE, and Visual FoxPro 9.0 is no exception.
Visual FoxPro 9.0 includes a number of IDE enhancements that make its already
rich development environment considerably richer.
Rod Paddock
[email protected] Fonts and Colors Everywhere Microsoft didn’t stop with just the Project Manager,
of course. You can also specify the display font for
Rod Paddock is the editor of One major enhancement to the UI is the ability to the Properties sheet. In previous versions of Visual
CoDe Magazine. He has been a configure fonts that are used in many designers and FoxPro, you were limited to changing the font from
software developer for more dialog boxes. Visual FoxPro 9.0 allows you to small to medium or large. You now have full
than 12 years and has worked configure the font used to control over the font in the
with numerous tools including display items in the Project Fast Facts Properties sheet. You can right-
Visual Studio .NET, SQL Manager. To change the font click the Properties sheet and
Server, Visual Basic, Visual for your projects, right-click on Visual FoxPro 9.0 select Font… from the shortcut
FoxPro, Delphi, and many your open project and select has a number of IDE Changes menu to activate the Windows
others. Font… from the shortcut menu. that continue Font dialog box just like you
This activates the Windows Visual FoxPro’s trend of making did with the Project Manager.
Rod is president of Dash Point Font dialog box, from which
developers more productive.
Software, Inc. Dash Point is an you can specify the font, style, Another enhancement to the
award-winning software devel- and size you wish to use. Properties sheet is the ability to
opment firm that specializes in Figure 1 shows the Visual FoxPro Project Manager specify the colors for different categories of properties.
developing applications for with the Comic Sans font, 14pt, and Bold selected. You can specify colors for ActiveX properties, non-
small to large businesses. Dash default values, custom properties, and instance prop-
Point has delivered applications erties. To specify the colors for custom properties:
for several corporations
including: Six Flags, First 1. Right click on the Properties sheet.
Premier Bank, Intel, Microsoft, 2. Select Custom Properties Color… from the
and the US Coast Guard. shortcut menu.
3. Select the color from the Windows Color dialog box.
Rod is also VP of Development
for SQL Server tools maker, Figure 2 shows the Properties sheet with a custom
Red Matrix Technologies. property displayed in red.
(www.redmatrix.com)

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.

Figure 3: The new


Property dialog box
Figure 2: The Properties sheet with the Custom Property with the default value
color set to red. set to ADD,EDIT.

54 Visual FoxPro 9.0 IDE Enhancements www.code-magazine.com


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 55

Figure 4: This Properties sheet shows the default value for


the ceditmode property.

Figure 7: The Run Query dialog box shows the results of a


query.
Figure 5:
Here’s the feature called the Data Explorer. The Data Explorer is Mike Stewart
More Panes a new tool that is included in the Visual FoxPro Task Test Engineer,
dropdown Pane Manager. To activate the Data Explorer, open Visual FoxPro Team
list from the the Task Pane Manager from the Visual FoxPro Tools Microsoft
Task Pane menu and select Data Explorer from the Task Pane
Manager dia- Manager’s More Panes dropdown list (Figure 5). This The enhanced BINDEVENTS()
log box. activates the Data Explorer in the Task Pane Manager functionality brings new ways
window. for Visual FoxPro developers to
interact with the Windows
You can now add connections to external databases operating system. Prior to
or use Explorer for databases on your local Visual FoxPro 9.0, when events
computer. Figure 6 shows the Data Explorer such as a system-level color or
perusing the Master database. From the Data font changes occurred, it was
Explorer, you can query tables by right-clicking on a difficult or impossible for a
table and selecting Run Query from the shortcut Visual FoxPro developer to
Figure 6: menu. Selecting Run Query opens the Run Query execute code in response. In
Data Explorer dialog box (Figure 7), which allows you to execute Visual FoxPro 9.0, developers
shows the SQL code in your SQL Server database. can execute their own code
contents of when users insert a USB drive,
the Master The Data Explorer tool is something that has been connect to a network drive,
database. sorely missing from Visual FoxPro for some time. power down their computer, or
Thanks to Microsoft for adding this very necessary nearly any other event notifica-
2. Select Class then select New feature. tion. In addition, Visual FoxPro
Property from the Visual FoxPro menu. developers can now hook into
3. Specify the name of your property. Visual FoxPro's IDE windows
4. In the Default/Initial Value field, enter the new In The Background more easily than before. This
default value (as shown in Figure 3). brings with it possibilities for
5. Click Add. Visual FoxPro 9.0 also includes a major enhance- custom context menus and IDE
ment to the Program Editor. Visual FoxPro 9.0 has window hooks with just a small
You should now see the new default value for your background compilation of code. When FoxPro amount of native Visual FoxPro
property in the Properties sheet (see Figure 4). comes across a syntax error, it underlines it. This code.
gives you the ability to fix code immediately instead
of waiting for a compile to run.
Data Exploration
As you know, Visual FoxPro works very well with Visual FoxPro 9.0 IDE = More Produc-
data. Visual FoxPro 9.0 is especially well-suited to tivity
working in client/server development environments.
Visual FoxPro 9.0 includes tools to help facilitate Even though this list may be small, the IDE changes
development in a client/server world with a new in Visual FoxPro 9.0 pack a real punch. Back-
ground compilation prevents
bugs at the source, font changes
make it easier to see what you
Visual FoxPro 9.0 are looking for, and the Data You can specify colors
facilitates development in a Explorer makes dealing with for ActiveX properties,
client/server data that much
client/server world simpler. non-default values,
with a new feature called custom properties,
Rod Paddock
the Data Explorer. and instance properties.

www.code-magazine.com Visual FoxPro 9.0 IDE Enhancements 55


CoDe_Focus_Fox Pro 09 30.11.2004 12:43 Uhr Seite 56

QUICK ID 0404072

Interop: Making .NET and


VFP Talk to Each Other
Many companies have relied on COM components in the last
couple of years. That includes Microsoft. Using COM components made it
possible for different programming languages to reuse logic between them, by
agreeing to a standard defined by the COM specification.
Claudio Lassala
[email protected] Calling VFP Components
M
any developers wrote VFP applications
using COM components, usually for data from .NET
Cladio Lassala is a Senior access logic and business logic. As a VFP
Developer at EPS Software developer you’ll be relieved to know that you can In order for .NET to see COM components, you
Corp. and a part time Universal reuse those components in .NET, allowing you to must create a proxy (or wrapper). This proxy,
Thread Consultant. He has easily create a .NET User called Runtime Called
presented several lectures at Interface (a Web application, Fast Facts Wrapper (or just RCW), is an
Microsoft events as well as for instance) that uses those object that sits between COM
several conferences and user VFP components, instead of .NET is growing and .NET, and translates calls
groups in North America and throwing them away and more and more important, from .NET to COM. To the
Brazil. He is a Microsoft C# rewriting everything from making interoperability between .NET client, the proxy looks
MVP, MCSD for .NET, and also scratch. On the other hand, .NET and VFP a hot topic. like any other .NET compo-
a columnist at MSDN Brazil. He the .NET Framework comes nent, and the proxy takes care
There are a few
is the author of several training with many classes that VFP of interpreting the calls to
videos that can be found at the developer might want to use different approaches to COM. Creating the RCW is
Universal Thread, and he has in their applications, and that combining the two tools, not a daunting task, as you will
several articles published in is also possible. such as COM Interop, see in a minute.
various magazines including Web services,
MSDN Brazil Magazine and Whether you use a COM and interoperability on You first create a COM
FoxPro Advisor. A full-bio can component from .NET, or a the database level. component in VFP. The
be found at .NET component from a COM- following code creates a sort
www.lassala.net/bio. enabled environment (such as of business object class that
VFP), the mechanism that allows for that is called .NET will use. (We say sort of business object
COM Interop. because the data access code is there too, but
separating layers is not the point we’re trying to
make here):
Why COM Interop?
Define Class CustomerBizObj As Session OlePublic
COM-enabled languages can use COM compo- DataSession = 2 && Private Session
nents created in any language because those
components conform to the standards defined by
Procedure Init
COM. Most languages have different types, or treat
Use Home(2) + "\Northwind\Customers.dbf"
common types in a different way, and therefore, in
order to make components created in different EndProc
languages talk to each other, they have to be
compatible, and it is COM that determines the Procedure GetCustomerList() As String
common rules.
Local lcOut As String
.NET goes a step further trying to address issues
lcOut = ""
with the COM standards (such as DLL hell), and it
Cursortoxml("Customers","lcOut",1,0,0,"1")
uses different approaches that lead to a very
different set of standards. COM components and Return lcOut
.NET components are not compatible by default. EndProc
However, keeping in mind that many companies EndDefine
have put a lot of work into COM components,
Microsoft added a mechanism to .NET so that .NET
components can see COM components as if they The GetCustomerList method retrieves a list of
were .NET components, and COM components can customers, returning the results in an XML string.
see .NET components as if they were COM compo- Note that you must declare the return type, other-
nents. wise VFP will define the return type to be of type

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

"C:\Program Files\Microsoft Visual Studio .NET


2003\SDK\v1.1\Bin\. You can run the tool at
a DOS prompt like this: (We broke the lines
for better readability, but this is typed in one
line.)

tlbimp.exe
"C:\YourVFPProject\BizObjects.dll"
/out:
"C:\YourDotNetProject\bin\Proxy.BizObjects.dll"
/namespace:BizObjects

Notice that you specify the COM DLL, and then


Rod Paddock Figure 3: A .NET project set up for COM Interop. use the switch out in order to specify where you
[email protected] want to locate the proxy and what you want to
name it. Use the namespace switch to specify the
Rod Paddock is the editor of created automatically by the Visual Studio .NET name of the namespace the proxy class will be
CoDe Magazine. He has been a IDE as soon as a reference to the COM component contained on.
software developer for more was added to the .NET project. If you select the
than 12 years and has worked cominteropsample reference on the Solution At this point, you can remove the reference created
with numerous tools including Explorer window and look at its Path property, you previously in the .NET project for the COM compo-
Visual Studio .NET, SQL should see something like the following: nent. You can add a new reference pointing to the
Server, Visual Basic, Visual Proxy.BizObjects.dll you just created. (The RCW is
FoxPro, Delphi, and many C:\YourProject\obj\Interop.cominteropsample.dll already a .NET class so Visual Studio .NET won’t
others. try to create another proxy). You can rewrite the
YourProject should be whatever path you have to using statement at the top of the Web Form as
Rod is president of Dash Point the .NET project you’ve created. The important using BizObjects.
Software, Inc. Dash Point is an detail to notice here is that the path doesn’t point
award-winning software devel- directly to the cominteropsample.dll (created by
opment firm that specializes in Visual FoxPro). Instead, it points to an Calling .NET Components
developing applications for Interop.cominteropsample.dll. This DLL is the from Visual FoxPro
small to large businesses. Dash RCW created by .NET. This proxy will help .NET
Point has delivered applications to communicate with the COM component. It has There are many .NET classes that can be useful for
for several corporations a class with the same name as the one exposed by the Visual FoxPro developer, and you can use those
including: Six Flags, First the COM component, but with the class word classes through COM interop. For instance, you
Premier Bank, Intel, Microsoft, added to it (thus, the CustomerBizObjClass that’s might want to use the classes that provide GDI+
and the US Coast Guard. instantiated in the .NET sample). In other words, features. Listing 1 shows a class created in .NET
whenever your application instantiates that class in that wraps up some GDI+ functionality. We
Rod is also VP of Development .NET, the proxy will know how to instantiate the compiled the class into a class library project in
for SQL Server tools maker, COM component, and whenever a method is called .NET. The most important thing to note here is that
Red Matrix Technologies. in that class, the proxy will know how to translate the project has been marked as “Register for COM
(www.redmatrix.com) the .NET call into a COM call. Interop.” To do that, right-click on the project,
select Properties, select Configuration Properties –
Build, and then set the Register for COM Interop
The Type Library Importer Tool option to True to expose a .NET class as a COM
component (Figure 3).
When a reference to a COM component is added
to a .NET project by using the Visual Studio .NET After you compile the project you can immedi-
IDE, Visual Studio uses a tool called the Type ately use the class through COM from VFP.
Library Importer, accepting default values for it. However, in order to provide a better experience
Some of those defaults determine that the proxy for the user of such class, you might want to apply
will be named after the COM DLL, but preceded some attributes to the class. For instance, the class
by the word “interop” (such as in showed in Listing 1 has the following attributes
Interop.cominteropsample.dll), and the proxy applied:
class will be placed inside a namespace also
named after the .dll (such as cominteropsample). [ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("VFPAndDotNet.ImageHelper")]
Many developers want to have more control over
the process of creating the RCW. This means they
want to have more control over the namespace The ClassInterface attribute, set to ClassInter-
where the proxy is going to be placed, and where faceType.AutoDual, enables the IntelliSense
the proxy DLL is going to be created. Developers support in VFP. The ProgId attribute specifies the
can use the Type Library Importer tool ProgId that VFP uses when instantiating the .NET
(Tlbimp.exe) for that. This command-line tool component as a COM component. For example,
that comes with the .NET SDK is in the folder you can use the ImageHelper class in VFP like so:

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-

Listing 1: An ImageHelper class that wraps up GDI+ funcionalities

using System; bmpGraphics.InterpolationMode = InterpolationMode.High;


using System.Drawing; bmpGraphics.TextRenderingHint =
using System.Drawing.Imaging; TextRenderingHint.AntiAlias;
using System.Drawing.Drawing2D; bmpGraphics.SmoothingMode = SmoothingMode.HighQuality;
using System.Drawing.Text;
using System.Runtime.InteropServices; // Creates the rectangle where we'll draw the image.
Rectangle compressionRectangle =
namespace MiscClasses new Rectangle(0, 0,
{ SourceBitmap.Width, SourceBitmap.Height);
/// <summary>
/// The ImageHelper class wraps up some GDI+ functionalities. // Draw the original image on the graphic object.
/// </summary> bmpGraphics.DrawImage(SourceBitmap, compressionRectangle);
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("VFPAndDotNet.ImageHelper")] // Add logo.
public class ImageHelper Image imgPhoto = Image.FromFile(@"c:\MyCompanylogo.jpg");
{ Bitmap bmPhoto =
public ImageHelper() {} new Bitmap(imgPhoto.Width, imgPhoto.Height,
PixelFormat.Format24bppRgb);
private string strImageFile;
public string ImageFile // Draw logo on source image.
{ Graphics grPhoto = Graphics.FromImage(bmPhoto);
set { this.strImageFile = value; } bmpGraphics.DrawImage(imgPhoto,
get { return this.strImageFile; } TargetBitmap.Width - imgPhoto.Width, 1);
}
// Add copyright info.
private string strCopyright; bmpGraphics.DrawString(@"Copyright © 2004 - " +
public string Copyright this.Copyright, new Font("Arial Black",12),
{
new SolidBrush(
set { this.strCopyright = value; }
Color.FromArgb(153, 255, 255, 255)),3,
get { return this.strCopyright; }
SourceBitmap.Height - 24);
}
// Save image to disk.
private string strSaveFileAs;
public string SaveFileAs TargetBitmap.Save(this.SaveFileAs, ImageFormat.Jpeg);
{
set { this.strSaveFileAs = value; } // Create thumbnail.
get { return this.strSaveFileAs; } thumbnail = TargetBitmap.GetThumbnailImage(
} 72,98,null,IntPtr.Zero);
ImageFormat format = TargetBitmap.RawFormat;
public void ProcessImage() thumbnail.Save(this.SaveFileAs + "_thumbnail.jpg", format);
{ }
// Declare some variables. catch
Bitmap SourceBitmap = null; {
Bitmap TargetBitmap = null; throw;
Graphics bmpGraphics = null; }
Image thumbnail = null; finally
{
try // Dispose objects.
{ if (SourceBitmap != null)
// Create a bitmap representation of the source image. SourceBitmap.Dispose();
SourceBitmap = new Bitmap(this.ImageFile); if (TargetBitmap != null)
TargetBitmap.Dispose();
// Create an empty bitmap for the target image. if (bmpGraphics != null)
TargetBitmap = bmpGraphics.Dispose();
new Bitmap(SourceBitmap.Width, SourceBitmap.Height); if (thumbnail != null)
thumbnail.Dispose();
// Create a graphic object based on our target bitmap size. }
bmpGraphics = Graphics.FromImage(TargetBitmap); }
}
// set Drawing Quality for the image. }

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

Figure 4: Creating a new Web service project in Visual


Studio .NET.

form and language-neutral fashion. This means that


any language and operating system can call any
Web service no matter how the Web service was
created. This, of course, means that Visual FoxPro
can call Web services created in Visual Studio
.NET.

We’ll show you how to create a .NET Web service


before we call one. You can easily do this using the Figure 5: Testing our simple Web service using the provided test bench application through Internet
Visual Studio .NET IDE. (Note: If you do not have Explorer.
Visual Studio .NET installed, you can probably
follow the example by calling an existing Web
service such as one of the many Web services found You can start your Web service project (simply Recommended Links
listed on www.UDDI.org). press F5) to see a test bench interface in Internet to Interoperation
Explorer. In this example, the service is rather
If you’re following along, you have Visual Studio simple since it only has one exposed method. Click
Between VFP and
.NET loaded. First create a new ASP.NET Web the link to that method and then click the “Invoke” .NET:
service project. The language you choose to use button to run the service. (Note: If your method A lot of information related to
does not matter. This example will use Visual Basic accepted parameters, this interface provides this topic can be found on
.NET but if you are more familiar with C#, you textboxes to enter those parameters.) You can see www.VFPConversion.com. The
should have no difficulty following the examples. the result in Figure 5. The return value of the following is a list of detailed
Figure 4 shows the New Project dialog box. method is wrapped in XML, which is the key mech- reading recommendations:
anism that allows you to call this service from
When you create a new ASP.NET Web service Visual FoxPro. .NET Interop for Visual FoxPro
project, the Visual Studio .NET IDE automatically Applications:
includes all the required references and creates a You can register a Web service in VFP through the http://west-wind.com/presenta-
Web service source code file (Service1.asmx), with Task Pane Manager under its special “Web tions/VfpDotNetInterop/vfpDot-
a hello world method as a template. For our Services” tab. Click the first link provided in this NetInterop.htm
purposes, we’ll delete that method and instead window, Register an XML Web Service. In the
change the code to what you see in Listing 2. You Web Service Registration dialog box (Figure 6) Using Visual FoxPro to call
may have noticed that most of the code in Listing 2 you’ll specify a URL that describes the Web service .NET Web services:
is inside a “designer region,” which means that and tells VFP what methods as well as parameters
developers should never have to touch it. The and return values are supported by the service. http://www.eps-cs.com/VFPCon-
important part of Listing 2 is the following method: ASP.NET-based Web services provide a WSDL version/Article.aspx?quickid=03
(Web Service Description Language) URL that 0074
<WebMethod()> _ provides exactly that information. You can find the
Public Function GetCurrentTime() _ VFP COM interoperability with
As DateTime Visual Basic .NET:
Return DateTime.Now
http://www.eps-
End Function
cs.com/pdf/whitepaper_vfpcom-
interop.pdf
This method simply returns the current date and
time as a DateTime data type. The only unusual COM Interop in Visual Studio
aspect about this is the <WebMethod()> attribute. .NET:
This attribute tells the ASP.NET runtime that this http://www.eps-cs.com/VFPCon-
method is to be exposed through a Web service Figure 6: Adding a Web service reference using the Visual version/Article.aspx?quickid=02
according to the SOAP standard. FoxPro 9.0 Task Pane. 03031

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

Note that in a real-life scenario, you need


to replace “localhost” with the name of the
domain the Web service resides on (such as
www.codefocus.com).

After you register a Web service with the VFP Task


Pane, you can test it immediately through the Task
Pane Manager. Simply pick the service you would
like to test (“Service 1” in our example) and the
method you would like to call, and click on the
icon next to the method drop-down list. You can
see the result in Figure 7. You now know that the
Web service works in VFP and you can start using
it from within a VFP program. Doing this requires
a little bit of code. The good news is that the Task
Pane also provides sample code (the bottom left of
Figure 7 shows the start of the sample code) that
you can use directly by dragging and dropping that
code into a source code window. Listing 3 shows
code created based on the sample code provided
by the Task Pane. Note that Listing 3 contains a
lot of code that is not strictly required including
error handling. The important code is in this next
code snippet.
Figure 7: Our sample Web service is registered in the VFP Task Pane Manager and ready to be tested.

URL by launching the test bench in Visual Studio


.NET (click F5), to launch the service test bench Many companies have
start page. At the very top of the page there is a
link to the “Service Description” of the Web
relied on COM
service. In our example, the URL is similar to the components in the last
following: couple of years.
http://localhost/ExampleService/ That includes Microsoft.
Service1.asmx?WSDL

Listing 2: A first Web service created by ASP.NET and the Visual Studio .NET IDE

Imports System.Web.Services <System.Diagnostics.DebuggerStepThrough()> _


Private Sub InitializeComponent()
<System.Web.Services.WebService(Namespace := _ components = New _
"http://tempuri.org/ExampleService/Service1")> _ System.ComponentModel.Container()
Public Class Service1 End Sub
Inherits System.Web.Services.WebService
Protected Overloads Overrides Sub Dispose( _
#Region " Web Services Designer Generated Code " ByVal disposing As Boolean)
'CODEGEN: This procedure is required by
Public Sub New() 'the Web Services Designer
MyBase.New() 'Do not modify it using the code editor.
If disposing Then
'This call is required by the Designer.
If Not (components Is Nothing) Then
InitializeComponent()
components.Dispose()
End If
'Add your own initialization code after
End If
'the InitializeComponent() call
MyBase.Dispose(disposing)
End Sub End Sub

'Required by the Web Services Designer #End Region


Private components As _
System.ComponentModel.IContainer <WebMethod()> _
Public Function GetCurrentTime() As DateTime
'NOTE: The following procedure is required by the Return DateTime.Now
'Web Services Designer End Function
'It can be modified using the Designer.
'Do not modify it using the code editor. End Class

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

LOCAL loService1 AS "XML Web Service" CATCH TO loException


* LOCAL loService1 AS "MSSOAP.SoapClient30" lcErrorMsg="Error: "+;
* Do not remove or alter following line. It is used to TRANSFORM(loException.Errorno)+;
* support IntelliSense for your XML Web service. " - "+loException.Message
*__VFPWSDef__: loService1 =
DO CASE
http://megger05/ExampleService/Service1.asmx?WSDL , Service1 ,
CASE VARTYPE(loService1)#"O"
Service1Soap
* Handle SOAP error connecting
LOCAL loException, lcErrorMsg, loWSHandler * to web service
TRY CASE !EMPTY(loService1.FaultCode)
loWSHandler = NEWOBJECT("WSHandler",; * Handle SOAP error calling method
IIF(VERSION(2)=0,"",HOME()+"FFC\")+; lcErrorMsg=lcErrorMsg+CHR(13)+;
"_ws3client.vcx") loService1.Detail
loService1 = loWSHandler.SetupClient(; OTHERWISE
"http://megger05/Svc/Service1.asmx?WSDL", ;
* Handle other error
"Service1", "Service1Soap")
ENDCASE
LOCAL ldCurrentTime as Datetime * Use for debugging purposes
ldCurrentTime = loService1.GetCurrentTime() MESSAGEBOX(lcErrorMsg)
MESSAGEBOX(Transform(ldCurrentTime)) FINALLY
ENDTRY

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

Listing 4: Code to query Visual FoxPro data from ASP.NET

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

You might also like