.NET for Visual FoxPro Developers Chapter
15 Microsoft has provided a two-way street for interoperability
between .NET and “other” software such as Visual FoxPro. They have made it extremely
easy to access your Most likely you have thousands of lines of Visual
FoxPro code you’ve spent countless hours creating, debugging, tweaking, and
enhancing until it suits your needs and those of your end users. Now with the
arrival of .NET do you have to throw all this code away? Definitely not! Fortunately, Microsoft is in the same boat as you. Think of
all the software applications Microsoft produced without using .NET. Although
Microsoft will rewrite some applications, rewriting all their applications in
.NET would be a colossal undertaking without enough benefits to make it
worthwhile. Based on this, Microsoft made it very easy to interoperate
with (I hate to use the word) “legacy” software so you can protect your code
investment. Here are some examples of situations where you may need to interop
with Visual FoxPro code from .NET: ·
.NET Web Forms applications accessing Visual
FoxPro business objects stored in a component library. ·
.NET Windows Forms applications accessing
middle-tier business objects stored in a component library. ·
.NET XML Web Services accessing Visual FoxPro
business objects stored in a component library. ·
.NET Windows Forms applications accessing a
Visual FoxPro Windows desktop application as an automation server (similar to
how you access Microsoft Office applications from VFP). Two technologies make this possible, COM (Component Object
Model) and XML. Interoperability via COM Once upon a time there was COM. Microsoft created COM
to provide interoperability between software applications and components
written in diverse languages such as C++, Visual FoxPro, and Visual Basic. Even
non-Microsoft languages such as COM lets you instantiate objects written in other languages,
call their methods, access their properties, and respond to their events
without knowing the language used to create COM moves into the 21st century by creating a
bridge between .NET and the rest of the world. If you need to access your
Visual FoxPro applications from .NET, you must compile your FoxPro code into a COM server. Types of COM servers There are two main types of COM servers—in-process
servers (DLLs) and out-of-process servers (EXEs). Important differences exist
between these two types of servers dictating which you should use in different
situations. In-Process servers An in-process server is a DLL loaded and run within the
same Windows process as the client. This provides fast access to objects
contained in the server because there is no cross-process communication
necessary. One limitation of in-process servers is they cannot interact with
the user interface (you can’t show forms, display messages, and so on). Typically, in-process servers contain multiple business
objects instantiated by clients that call their methods to perform a variety of
functions. This model covers the first three scenarios discussed earlier in
this chapter and is the most common way to access VFP code. Out-Of-Process servers An out-of-process server is an EXE running in its own
Windows Process apart from the client. This model incurs a slight performance
hit because of the extra work the operating system performs to pass calls from
one process to another. However, out-of-process servers do have the
ability to interact with the user interface. This means you can start an out-of-process server, such as a
Visual FoxPro desktop application, from within a .NET application and access
its functionality programmatically—much the same way you access Microsoft
Office applications from within Visual FoxPro. Visual FoxPro’s COM capabilities Fortunately, the Microsoft Fox team continued to
enhance Visual FoxPro’s COM capabilities with each new version. These
enhancements are critical in using newer technologies such as COM+ and .NET. For more information on
Visual FoxPro and COM, check out the book “What’s New in Visual FoxPro 7” from
Hentzenwerke Publishing. Interoperability via XML Although COM gives you the ability to instantiate a
Visual FoxPro object from .NET, you Again, the Fox team comes to the rescue by providing built-in
XML functionality starting with version 7.0 of VFP. The CursorToXml,
XmlToCursor, and XmlUpdateGram functions convert between Visual FoxPro’s native
cursor format and XML, a key .NET data format. You’ll be looking closer at these functions in the next
section as you build a Visual FoxPro component accessible from .NET. Creating a Visual FoxPro COM server In this section you’ll create an in-process Visual
FoxPro COM server to demonstrate how easy it is to access your VFP code from
.NET. The first step in building a COM server is creating a new
Visual FoxPro project. Create a new, empty VFP project named comdemo.pjx in the
bin\debug directory of this book’s sample code. (Below the HW .NET Book
Samples_CSharp directory if you’re working with C#, or the HW .NET Book
Samples_Visual Basic directory if you’re working with VB .NET). After creating
the new project, add a PRG file to the project and place the following class
definition code in the PRG: DEFINE CLASS Employee AS Session OLEPUBLIC cStartPath = "" PROCEDURE INIT *--- Issue SET
commands appropriate for COM servers SET RESOURCE OFF SET EXCLUSIVE OFF SET REPROCESS TO 2
SECONDS SET CPDIALOG OFF SET DELETED ON SET EXACT OFF SET SAFETY OFF *--- Save the server
startup path This.cStartPath =
ADDBS(JUSTPATH(Application.ServerName)) SET PATH TO
(This.cStartPath) ENDPROC *--- Get all Employees PROCEDURE
GetAllEmployees() AS String ; HELPSTRING
"Returns an XML string containing all employees" LOCAL lcXML SELECT * FROM
Employees INTO CURSOR Employee CURSORTOXML("Employee",
"lcXML", 0, 0, 0, "1") USE IN Employee RETURN lcXML ENDPROC *--- Get the specified
employee PROCEDURE
GetEmployeeByID(empID AS Integer) AS String ; HELPSTRING "Returns
an XML string containing the specified employee" LOCAL lcXML SELECT * FROM
Employees WHERE ; EmployeeID = empID INTO CURSOR Employee CURSORTOXML("Employee",
"lcXML", 0, 0, 0, "1") USE IN Employee RETURN lcXML ENDPROC ENDDEFINE This code defines a class named Employee subclassed from
Visual FoxPro’s Session class. The Session class is used because it ensures all
business objects have their own private data session. The OLEPUBLIC keyword
tells the Visual FoxPro compiler to make the class public to users of the COM
server. Only classes marked as OLEPUBLIC are visible and accessible to the
outside world. The Employee class contains three methods—Init,
GetAllEmployees, and GetEmployeeByID. The Init method issues SET commands appropriate
for COM servers. It also saves the DLL startup path and issues a SET PATH to
this directory. This allows the other COM server methods to find the data they
need. The other two methods make use of the strong-typing AS clause
introduced in Visual FoxPro 7.0. This clause specifies the type of method
parameters and their return values. Both methods declare a String return value,
which in this case is an XML string. The GetEmployeeByID method also uses the
AS clause to declare a single integer parameter. The HELPSTRING keyword
specifies the method description stored to the type library. Visual FoxPro’s strong-typing features are only used for
IntelliSense and to create type libraries for COM servers. The compiler does
not enforce them! Testing the Employee class Before compiling the comdemo project into a COM server,
it’s best to test the business object classes within Visual FoxPro first. This
is important because it’s very difficult to debug VFP COM servers! To test the Employee class, enter the following code in the
VFP Command Window: SET PROCEDURE TO business.prg EmployeeObj = CREATEOBJECT("Employee") ?EmployeeObj.GetAllEmployees() When you run the GetAllEmployees method, the resulting XML
string containing all employees is displayed in the Visual FoxPro desktop. You can test the GetEmployeeByID method by entering the
following command in the Visual FoxPro Command Window. This time you’ll use the
STRTOFILE command to write the resulting XML string to a file, and then examine
the file contents: STRTOFILE(EmployeeObj.GetEmployeebyID(1),
"Employee.xml") MODIFY FILE Employee.xml When you run the MODIFY FILE command, it displays the
contents of the Employee.xml file that looks like this (I’ve left the schema
information out for the sake of space): <?xml
version = "1.0" encoding="Windows-1252"
standalone="yes"?> <VFPData> <xsd:schema id="VFPData"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <!-- Left out the schema information to
save space--> </xsd:schema> <employee> <employeeid>1</employeeid> <lastname>Davolio</lastname> <firstname> <title>Sales
Representative</title> <titleofcourtesy>Ms.</titleofcourtesy> <birthdate>1948-12-08T00: <hiredate>1992-05-01T00: <address> <city> <region>WA</region> <postalcode>98122</postalcode> <country> <homephone>(206)
555-9857</homephone> <extension>5467</extension> <notes>Education includes a BA in
psychology from <reportsto>2</reportsto> <photopath/> </employee> </VFPData> As you can see, Visual FoxPro does all of the heavy lifting
for you by converting the cursor into an XML string and automatically
generating a schema to go with it! Compiling the COM server Now it’s time to compile the COM server. To do this,
click the Project Manager’s Build
button to launch the Build Options
dialog (Figure 1). Select Multi-threaded
COM server (dll) under Build
Action, select Recompile
All Files, and Display
Errors under Options.
When you’re done, click the OK
button to build the COM server. The build process creates three output files: ·
comdemo.dll –COM server ·
comdemo.tlb –Type Library ·
comdemo.vbr –Registry file The comdemo COM Server The comdemo.dll file is the COM server and is the main
output file. This file contains the compiled code for the Employee business
object class, although in most cases COM servers contain multiple business
object classes. When you compile a COM server, all OLEPUBLIC classes in the
server are automatically registered in the build machine’s Windows Registry.
You view these entries in the Registry using the Windows Registry Editor tool. To
launch the Registry Editor,
click the Windows Start
button and select Run.
In the Run dialog, enter
“RegEdit” in the Open
box, and then click OK.
When the Registry
Editor dialog appears (Figure 2), in the left pane select
the HKEY_CLASSES_ROOT
node of the tree view. This is the node where your COM server’s classes are registered.
From the Registry Editor’s Edit
menu, select Find to launch the
Find dialog (Figure 3).
In the Find what box,
enter “comdemo” and click the Find
Next button. After several seconds, the Registry
Editor should find your comdemo.Employee class. This is indicated
by the appearance of an expanded node in the tree view located in the left
pane, and the string “comdemo.Employee” in the right pane under the Data column. The node text in the left pane contains a series of
alpha-numeric characters (Figure 4). This is the Employee object’s
Globally Unique Identifier (GUID). This GUID is an identifier generated during
the compile process guaranteed to uniquely identify your COM object. If you expand this node, you see sub-nodes containing
additional information about your COM object. The comdemo type library Another by-product of the COM server build process is
the comdemo.tlb file. This is your COM server’s type library. A type library is
a binary file describing the public classes in your COM server. To view the contents of your server’s type library, launch
Visual FoxPro’s Object
Browser by selecting Tools
| Object Browser from the main Visual FoxPro menu. Next, click
the Open Type
Library button
(the button farthest left at the top of the Object
Browser window). This launches the Open
dialog (Figure 5). Select the COM
Libraries tab. It may take a few seconds before the tab gets
focus as the Windows Registry searches for all COM libraries. Click the Browse button to launch
the Open dialog (Figure
6). Navigate to the folder containing your comdemo type library. Notice in Figure 6 the default file type is “*.dll”. Isn’t
the type library stored in a TLB file? The answer is it can be stored in both,
depending on the operating system used to create the COM server. If you build a
Visual FoxPro COM server on a Windows NT, 2000, or XP machine, the type library
is placed in the external TLB file and is also embedded within the DLL.
If you build a VFP COM server on a Windows 98 machine, the type library is only
found in the TLB file, not in the DLL. If you’ve created the COM Server on Windows 98, in the Files of type combo box,
select “*.tlb”, select comdemo.tlb, and click OK.
If you’ve created the server on a newer platform, just select comdemo.dll and
click OK. When you click OK,
focus returns to the Object
Browser (Figure 7) dialog. Expand the comdemo type library node
shown in the left pane of the Object
Browser, then expand the Classes
node and select the Employee
class beneath it. Next, in the right pane expand the Methods
node and select the GetEmployeeByID
method. In the description pane at the bottom of the dialog, there is
a description of the GetEmployeeByID method as shown in Figure 7. The
description says the GetEmployeeByID method accepts a single numeric parameter
and returns a string value. It also displays the method description you
specified in the HELPSTRING attribute. The comdemo Windows Registry file The last of the three files generated by building your
COM server is the comdemo.vbr Windows Registry file. This file contains the
GUIDs for the classes in your COM server. If you open the comdemo.vbr file with
a text editor you’ll see something like this: VB5SERVERINFO VERSION=1.0.0 HKEY_CLASSES_ROOT\comdemo.Employee = comdemo.Employee HKEY_CLASSES_ROOT\comdemo.Employee\NotInsertable HKEY_CLASSES_ROOT\comdemo.Employee\CLSID =
{832DEF00-4A39-48DE-831A-B7A3AECAD9BD} HKEY_CLASSES_ROOT\CLSID\{832DEF00-4A39-48DE-831A-B7A3AECAD9BD} =
comdemo.Employee HKEY_CLASSES_ROOT\CLSID\{832DEF00-4A39-48DE-831A-B7A3AECAD9BD}\ProgId
= comdemo.Employee HKEY_CLASSES_ROOT\CLSID\{832DEF00-4A39-48DE-831A-B7A3AECAD9BD}\VersionIndependentProgId
= comdemo.Employee HKEY_CLASSES_ROOT\CLSID\{832DEF00-4A39-48DE-831A-B7A3AECAD9BD}\InProcServer32
= comdemo.dll HKEY_CLASSES_ROOT\CLSID\{832DEF00-4A39-48DE-831A-B7A3AECAD9BD}\InProcServer32\"ThreadingModel"
= Apartment HKEY_CLASSES_ROOT\CLSID\{832DEF00-4A39-48DE-831A-B7A3AECAD9BD}\TypeLib
= {97FD3B3E-2115-4DEE-B50B-B8761A45C358} HKEY_CLASSES_ROOT\CLSID\{832DEF00-4A39-48DE-831A-B7A3AECAD9BD}\Version
= 1.0 HKEY_CLASSES_ROOT\CLSID\{832DEF00-4A39-48DE-831A-B7A3AECAD9BD}\Foxruntime
= VFP7T.DLL HKEY_CLASSES_ROOT\INTERFACE\{17BE97B1-AAD2-4604-9253-DAB268C1E2F4}
= Employee HKEY_CLASSES_ROOT\INTERFACE\{17BE97B1-AAD2-4604-9253-DAB268C1E2F4}\ProxyStubClsid
= {00020424-0000-0000-C000-000000000046} HKEY_CLASSES_ROOT\INTERFACE\{17BE97B1-AAD2-4604-9253-DAB268C1E2F4}\ProxyStubClsid32
= {00020424-0000-0000-C000-000000000046} HKEY_CLASSES_ROOT\INTERFACE\{17BE97B1-AAD2-4604-9253-DAB268C1E2F4}\TypeLib
= {97FD3B3E-2115-4DEE-B50B-B8761A45C358} HKEY_CLASSES_ROOT\INTERFACE\{17BE97B1-AAD2-4604-9253-DAB268C1E2F4}\TypeLib\"Version"
= 1.0 ; TypeLibrary registration HKEY_CLASSES_ROOT\TypeLib\{97FD3B3E-2115-4DEE-B50B-B8761A45C358} HKEY_CLASSES_ROOT\TypeLib\{97FD3B3E-2115-4DEE-B50B-B8761A45C358}\1.0
= comdemo Type Library HKEY_CLASSES_ROOT\TypeLib\{97FD3B3E-2115-4DEE-B50B-B8761A45C358}\1.0\0\win32
= comdemo.dll HKEY_CLASSES_ROOT\TypeLib\{97FD3B3E-2115-4DEE-B50B-B8761A45C358}\1.0\FLAGS
= 0 As already mentioned, when you build a COM server, Visual
FoxPro automatically registers the COM server in the Windows Registry of the
build machine. If you want to move your COM server to a different machine, the
VBR file allows you to register the class definitions in the Windows Registry
of the target machine. For details on using the VBR file to register a Visual FoxPro
COM server, see the VFP Help topics “CliReg32.exe Remote Automation Utility”
and “Using Remote Automation”. Testing the COM server from Visual
FoxPro Before accessing the comdemo server from .NET, it’s a
“best practice” to test it from Visual FoxPro first. To do this, enter the
following commands in the VFP Command Window: EmployeeObj = CREATEOBJECT("comdemo.Employee") ?EmployeeObj.GetAllEmployees() This time you didn’t have to issue a SET PROCEDURE command.
Instead, you specified the name of the COM server (“comdemo”) and the name of
the business object (“Employee”) in the CREATEOBJECT command. Visual FoxPro
searches the Windows Registry for this COM object and instantiates it for you. You test the GetEmployeeByID method by issuing the same
command as you did earlier: STRTOFILE(EmployeeObj.GetEmployeebyID(1),
"Employee.xml") MODIFY FILE Employee.xml Now, knowing your COM server is working properly, it’s time
to access it from .NET. Creating a .NET test project Now you will make a very simple .NET Windows
Application with a single form containing a DataGrid for testing the VFP COM
server. From the Visual Studio .NET Start
Page, click the New
Project button. In the left pane of the New Project dialog (Figure
8), select Visual C#
Projects or Visual
Basic Projects depending on the language you want to use for this
project. In the Templates
pane on the right, select Windows
Application. In the Name
box, change the name of the application to “COM Interop Test Project” and click
OK. When VS .NET finishes
creating your new project, it displays a form named “Form1” in the IDE.
Normally, you would use this form to be your main application desktop window,
but for this simple example you’ll use it to host a DataGrid instead. First, make the form big enough to hold a DataGrid with several
columns. To do this, you simply resize the form by dragging its bottom right
corner or you can select the Properties Window and change the form’s Size property to
something around 640,340. Also change the form’s Text
property to “COM Interop Test” and its Name
property to “InteropTestForm”. If you’re using C#, there is one additional step. In the
Solution Explorer, right-click on Form1.cs and select View Code from the
shortcut menu. Next, in the Main method of the form change the “Form1” reference
to “InteropTestForm”: static void { Application.Run(new
InteropTestForm()); } If you’re using Visual Basic .NET, there’s also an additional
step you need to take. In the Solution Explorer, right-click on the project and
select Properties from
the shortcut menu. In the left pane of the Property
Pages dialog, beneath the Common
Properties node, select General.
In the right side of the dialog, in the Startup
object combo box, select “InteropTest Form”. Click OK to save changes and
close the dialog. Afterwards, view the form in design mode by clicking on the Form1.cs [Design] tab in
the VS .NET IDE. Now drag a DataGrid control from the VS .NET Toolbox and drop it on
the form. You make the Toolbox
visible by hovering your mouse pointer over the Toolbox tab. If you don’t see
the Toolbox tab, select View |
Toolbox from the main menu. After dropping the DataGrid on the
form, resize it to fill up most of the form. For example, you can set its Location property to
40,30, and its Size
property to 550,220. Also change its Name
property to grdEmployees. Now drag and drop a Button control from the Toolbox onto the bottom
of the form under the DataGrid. For example, set its Location
property to 280,270. Change the button’s Name
property to btnGetData and its Text property to “Get Data”. When you’re done,
your form should look like the form shown in Figure 9. Click the Save All button at the top of the Visual Studio
.NET IDE to save all changes you have made so far. Referencing the Visual FoxPro COM server Now you’re ready to add a reference to the Visual
FoxPro COM server to your new project. To do this, go in the Solution Explorer,
right-click the Reference
node beneath your project, and select Add
Reference from the shortcut menu (Figure 10). This launches the Add
Reference dialog. Select the COM
tab (Figure 11), click the Browse
button, and navigate to your comdemo project’s directory. If you generated the COM server on a Windows 98 machine,
select the comdemo.tlb file. If you generated the COM server on a newer
operating system, select the comdemo.dll file and click the Open button. This takes
you back to the Add Reference
dialog, with the comdemo file shown in the Selected
Components list at the bottom of the dialog. Click OK to add a reference to
the COM server to your .NET project. You should now see a comdemo
node in the Solution Explorer beneath the References
node (Figure 12). If you select the comdemo
node in the Solution Explorer and look at the Path
property in the Properties Window, you will see it does not reference
comdemo.dll. Rather, it refers to a .NET assembly named “Interop.comdemo.dll”.
This is a Runtime Callable Wrapper (RCW) automatically created by Visual
Studio .NET when you added a reference to comdemo.dll. This RCW acts as an
intermediary between .NET and the Visual FoxPro comdemo.dll (Figure 13).
A wrapper class is created in the RCW for each class in your COM server. Rather
than calling methods on a COM object directly, .NET calls methods on a wrapper
class in the RCW that in turn calls the corresponding method on the VFP COM
object. Take a closer look at this Runtime Callable Wrapper. Open the
VS .NET Object Browser by
selecting View | Other Windows | Object
Browser from the shortcut menu. In the Object
Browser, you should see a node named “interop.comdemo” (Figure
14). Expand the comdemo
node, and if you’re using C#, you will see three items listed: Employee, EmployeeClass, and IEmployee (I’ll look at
VB .NET in a moment). Both Employee
and IEmployee are
interfaces and EmployeeClass
is the concrete class you need to instantiate from within .NET. As you can see,
VS .NET takes the original class name and appends the suffix “Class”. If you
select the EmployeeClass
node, three methods appear in the right pane—your two original methods, GetAllEmployees and GetEmployeeByID, and a
new method called EmployeeClass,
which is the .NET constructor method. If you select the GetEmployeeByID
method, details of the method display at the bottom of the Object Browser (Figure
14). As you can see, the GetEmployeeByID method returns a string value
(System.String) and accepts a single integer parameter (System.Int32). If you’re using Visual Basic .NET, you should see a node
named Interop.comdemo in
the Object Browser (Figure
15). If you expand the comdemo
node, you only see one class named Employee
and no interfaces. This is a bit different than what you saw in C#, where there
was one class named “EmployeeClass” and two interfaces. If you click on the Employee class, in the
right pane you see all the same methods as in C#, except for the constructor
method. If you right-click on either pane of the Object Browser and select
Show Hidden Members from
the shortcut menu, the Iemployee
interface is displayed (Figure 16), although the Employee interface shown
in C# is not. Regarding the difference in the class name, if you select the
Employee class in the Using the COM server Employee object Now it’s time to add code to the Windows Form to
instantiate the Employee business object and call its methods. Select Form1 in design mode and double-click the Get Data button. This
automatically adds a new btnGetData_Click event handler method to the form.
Before adding code to this method, add a reference to the interop.comdemo
namespace at the top of the code file (VS .NET assigns classes in your COM
server to a namespace with the same name as your DLL). You should also add a
reference to the System.IO namespace, which you’ll need soon. In C#: using comdemo; using System.IO; In Visual Basic .NET: Imports comdemo Imports System.IO Now, in the btnGetData_Click event handler method at the
bottom of the code window, add the following code. In C#: private void
btnGetData_Click(object sender, System.EventArgs e) { // Instantiate the Employee class EmployeeClass Employee = new EmployeeClass(); // Get an XML string containing all Employees string EmployeesXml = Employee.GetAllEmployees(); // Create a new DataSet and fill it from the XML string DataSet dsEmployees = new DataSet(); dsEmployees.ReadXml( new StringReader(EmployeesXml)); // Clear and then set the DataBindings of the grid this.grdEmployees.DataBindings.Clear(); this.grdEmployees.SetDataBinding(dsEmployees, dsEmployees.Tables[0].TableName); } In Visual Basic .NET: Private Sub btnGetData_Click(ByVal sender As
System.Object, _ ByVal e As System.EventArgs)
Handles btnGetData.Click ' Instantiate the
Employee class Dim Employee As New
EmployeeClass() ' Get an XML string
containing all Employees Dim EmployeesXml As
String = Employee.GetAllEmployees() ' Create a new DataSet
and fill it from the XML string Dim dsEmployees As New
DataSet() dsEmployees.ReadXml(New
StringReader(EmployeesXml)) ' Clear and then set
the DataBindings of the grid
Me.grdEmployees.DataBindings.Clear()
Me.grdEmployees.SetDataBinding(dsEmployees, _
dsEmployees.Tables(0).TableName) End Sub This code instantiates the EmployeeClass Runtime Callable
Wrapper and calls its GetAllEmployees method. Behind the scenes, the RCW in
turn calls the GetAllEmployees method on the Visual FoxPro Employees COM
object, which returns an XML string containing all employees. The RCW takes the
return value and returns it as a .NET string type. Another feature worth noting is you get IntelliSense on
methods of the RCW (Figure 17) because it is consuming the interface of
your COM object and re-exposing it as a .NET interface. Running the Interop sample Now it’s time to compile and run the Interop sample
application. To do this, you can simply press F5. When the form is first
displayed, the grid is empty. If you click the Get
Data button, it runs code retrieving XML data from the Visual
FoxPro Employee COM object and binding the DataGrid to the data. The data is
then displayed in the DataGrid (Figure 18). To close the sample form, click the close button [X] in the
upper right corner of the form. Using Visual FoxPro COM objects from ASP.NET Although using Visual FoxPro COM objects from ASP.NET
is similar to using them from a .NET Windows application, there are enough nuances
to warrant creating a simple ASP.NET Web Forms application to demonstrate the
differences. Creating a Web Forms test application From the Visual Studio .NET Start
Page, click the New
Project button. In the left pane of the New Project dialog, select
Visual C# Projects or Visual Basic Projects
depending on the language you want to use for this project. In the Templates
pane on the right, select ASP.NET
Web Application. In the Location
box, change the name of the application to “Web COM Interop Test Project”, and
then click the OK
button. When VS .NET finishes creating your new Web project, it displays a form
named WebForm1 in the IDE. You’ll use this form to host a DataGrid containing
records retrieved from the Visual FoxPro Employees COM object. To do this, drag and drop a DataGrid from the Visual Studio Toolbox onto the upper
left corner of the Web form. Next, change the appearance of the DataGrid
similar to what you did on the Windows form. Go to the Properties Window,
change the ID property to
“grdEmployees”, and the Width
to 600px. When you’re done, your grid should look like Figure 19. Now go one step further with the DataGrid to make it look
just a bit more attractive. With the DataGrid selected in design mode, click
the Auto Format
hyperlink at the bottom left of the Properties Window. This launches the Auto Format dialog (Figure
20). You can choose any style you wish, but for this example, I’ve chosen
“Colorful 1”. Next, you need to specify the columns for the DataGrid.
Unlike the Windows Forms DataGrid, which looks passable without specifying any
column information, the Web Forms DataGrid needs a little more coaxing. To
specify columns for the DataGrid, select the DataGrid on the Web Form, and then
click the Property Builder
hyperlink at the bottom left corner of the Properties Window. This launches the
DataGrid Properties
dialog (Figure 21). Select the Columns
item in the left pane and a columns mover control is displayed as
shown in Figure 21. Next, clear
the Create columns automatically at
run time check box. Afterwards, select Bound
Column in the Available
Columns list and click the mover button (>) to add the bound
column to the Selected
columns list. In the Header
Text box, enter “Last Name” and in the Data
Field box enter “LastName”. Add three more bound columns to the DataGrid with Header Text and Data Field properties
shown in Table 1. When you have
added all of the columns to the DataGrid, click the OK
button to close the dialog. Header Text Data Field First Name First Name Title TitleOfCourtesy Home Phone HomePhone When you’re done, your DataGrid should look like the one
shown in Figure 22. Setting the aspCompat attribute When you use a COM component from an ASP.NET page, you
should set the page’s aspCompat
property to true. Do this now, and then I’ll explain the importance of this
setting. Click on the Web Form design surface and go to the Properties
Window. Select the aspCompat
property, open its associated combo box, and select “True” (Figure 23). Normally, ASP.NET runs in multi-threaded apartment (MTA)
mode. However, Visual FoxPro COM components are single-threaded apartment (STA)
objects. The aspCompat property
tells ASP.NET to execute in STA mode. Although you won’t get an error if you
don’t change this setting, your application runs slowly and may experience
deadlocks. For more information, see the .NET Help topic “COM Component
Compatibility”. Referencing the Visual FoxPro COM server Before going further, you need to add a reference to
the Visual FoxPro COM server in your Web Forms project. To do this, in the
Solution Explorer, right-click the References
node and select Add Reference
from the shortcut menu to launch the Add
Reference dialog. Select the dialog’s COM
tab and click the Browse
button. In the Select
Component dialog, navigate to the folder containing comdemo.dll,
select the file, and then click the Open
button (If you’re on a Windows 98 machine, select comdemo.tlb). This brings you
back to the Add Reference
dialog with “comdemo.dll” displayed in the Selected
Components list. Click the OK
button and VS .NET adds a Runtime Callable Wrapper assembly named “comdemo”
under the References node of
your project (Figure 24). Using the COM Server Employee object Now it’s time to add code to retrieve XML data from the
Visual FoxPro Employees COM object and display it in the DataGrid. To do this,
double-click the form’s design surface. VS .NET displays the Web Form’s
code-behind file, adding a new event handler method called Page_Load. Before
placing code in this method, add the following namespace references at the top
of the code-behind file. In C#: using comdemo; using System.IO; And in Visual Basic .NET: Imports comdemo Imports System.IO Next, add the following code to the Page_Load method. In C#: private void Page_Load(object sender, System.EventArgs
e) { // Instantiate the
Employee class EmployeeClass Employee =
new EmployeeClass(); // Get an XML string
containing all employees string EmployeesXml =
Employee.GetAllEmployees(); // Create a new DataSet and
fill it from the XML string DataSet dsEmployees = new
DataSet(); dsEmployees.ReadXml( new
StringReader(EmployeesXml)); // Data bind the grid to
the DataSet this.grdEmployees.DataSource
= dsEmployees; this.grdEmployees.DataBind(); } And in Visual Basic .NET: Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As
System.EventArgs) Handles MyBase.Load ' Instantiate the
Employee class Dim Employee As New
EmployeeClass() ' Get an XML string
containing all employees Dim EmployeesXml As
String = Employee.GetAllEmployees() ' Create a new DataSet
and fill it from the XML string Dim dsEmployees As New
DataSet() dsEmployees.ReadXml(New
StringReader(EmployeesXml)) ' Data bind the grid to
the DataSet Me.grdEmployees.DataSource
= dsEmployees
Me.grdEmployees.DataBind() End Sub This code instantiates the EmployeeClass Runtime Callable
Wrapper and calls the object’s GetAllEmployees method, which returns an XML
string containing all employees. It then fills a DataSet from the XML string
and binds the grid to the DataSet. Running the Web Interop sample Now you’re ready to run the Web Interop sample. To do
this, press the F5 key to compile and run the project. When your Web browser appears,
you should see a DataGrid containing data as shown in Figure 25. Other resources There are some great on-line articles available
regarding COM Interop with Visual FoxPro. The first is Rick Strahl’s on-line
article “.NET Interop for Visual FoxPro Applications” found at the following
URL: http://www.west-wind.com/presentations/VfpDotNetInterop/vfpDotNetInterop.htm Rick’s article covers information not discussed in this
chapter, such as returning Visual FoxPro objects from COM server methods for
use in .NET. It also includes some interesting speed comparisons using classic
ASP vs. ASP.NET to access Visual FoxPro COM objects. Another great resource is Cathi Gero’s on-line article “Using
ASP.NET in Visual Studio .NET with Visual FoxPro 7.0”. You can view this article at the following
URL: http://msdn.microsoft.com/library/?url=/library/en-us/dnfoxgen7/html/usingaspnetwithvfp7.asp Cathi’s article demonstrates the following four scenarios: ·
Accessing Visual FoxPro Data Using OLE DB ·
Accessing a Visual FoxPro COM component ·
Accessing a Visual FoxPro 7.0 XML Web Service ·
Accessing Visual FoxPro Data from an ASP.NET Web
Service You can also periodically check the Visual FoxPro
“Got-Dot-Net” Web site for new information on this topic: http://www.gotdotnet.com/team/vfp/.
Conclusion Microsoft has done a great job making it very easy to
access “legacy” code from .NET and allowing you to save your investment in your
existing Visual FoxPro applications. However, if you’ve placed most of your
application logic within methods and events of your Visual FoxPro user
interface, you need to migrate this code into business objects that can be
instantiated and accessed from .NET Windows Forms applications, Web Forms
applications, and Web Services.
Interoperability with Visual FoxPro
Visual FoxPro code from .NET and also access the functionality of .NET from
Visual FoxPro. This chapter shows you how easy it is to bridge the divide
between .NET and Visual FoxPro.
the component.
still need a mechanism for passing data between .NET and Visual FoxPro. The
mechanism
is XML.
Object Browser, the
description pane at the bottom of the browser shows the class refers to
comdemo.EmployeeClass. Because you need to instantiate the EmployeeClass in
.NET
(not the “Employee” class) I think the Runtime Callable Wrapper created by C#
is
more informative.