Understanding COM+ with VFP, Part 1
This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Understanding COM+ with VFP, Part 1
Craig Berntson
When COM+ debuted in Windows 2000, it introduced many new capabilities to
enhance n-tier applications. Now with VFP 7, you can use these enhancements to
make your applications more robust. In this first installment of a series, Craig
Berntson reviews COM and MTS, and then introduces COM+.
For many years, we've heard about the importance of breaking applications
into multiple tiers or services. By splitting the user interface, business
rules, and database access, we can easily modify or completely replace one
service without affecting the others.
Historically, Visual FoxPro applications have been single-tier solutions,
even if the data resides on the server. This is because developers have mixed
the user interface, business rules, and data access into one application or even
the same form.
With the use of SQL Server, we move to a two-tier scenario. The data is
normally accessed via ODBC by the use of Remote Views or SQL pass through.
Stored procedures are often called on the server, and the SQL SELECT statement
is resolved before sending any data across the wire. It's the splitting of the
processing onto the server and the workstation that makes this design two-tier.
In a three-tier solution, the user interface only displays data and accepts
input from the user. There might be some minor data validation, such as ensuring
that the required fields are populated or limiting the user's selection via a
list or combo box. However, all of the actual processing of the data takes place
in a separate component that holds all of the business rules. Calculations of
totals or taxes, validation of data, or the generating of report data are
examples of things that occur in the middle-tier business logic. Finally, the
data tier is responsible for the reading and writing of data into the data
store. The user interface should never directly access the data services, but
should go through the business services layer to get at the data.
This separating of multiple tiers is what Microsoft calls the Distributed
interNetworking Architecture, or DNA. The different components of each service
can reside on the same computer, making a logical separation of each service—or,
on multiple computers, providing a physical separation of the tiers. Typically,
the user interface resides on the client computer, while the business and data
components reside on an application server with the data store on a second
server. When access is via a Web browser, an additional server for IIS is often
added to the mix.
COMmon knowledge
The way to access these components is via the Component Object Model.
COM is a specification that allows components written in different languages to
interact with each other. Therefore, we can create a component in VFP that can
be accessed from a VB or Delphi application, or even from Word or Excel. ActiveX
controls are another example of COM objects. When you control Word or Excel from
your VFP application, it's done via COM.
The first thing to consider when creating a COM component is how it will fit
in with the other pieces of your application. In other words, you need to
determine whether it should run in-process or out-of-process.
An in-process component is compiled as a DLL and must be hosted by an
executable program. It runs in its host's memory space—hence the name
in-process—which makes instantiating (running) the component fast. Data is
marshaled (passed) across the COM boundary. Because the component runs in the
same memory space as the application, if the component crashes, it most likely
will cause the application to crash. One other thing to keep in mind: In-process
servers written in VFP can't have any user interface exposed.
An out-of-process server is compiled as an EXE and runs in its own memory
space. When it's instantiated, there's some overhead required such as allocation
of memory, process id, and so on. This all takes time, which makes instantiating
an out-of-process server slower than an in-process server. In addition, it takes
longer to marshal data across the process boundaries from the application to the
component, so it runs slower. However, because the COM server is running in a
different memory space than the client application, if the component crashes,
the application will quite possibly keep running.
Creating a COM component in VFP is quite easy. The OLEPUBLIC keyword tells
VFP to compile the code with the proper COM information needed for access from
other applications:
DEFINE CLASS Math AS SESSION OLEPUBLIC
FUNCTION Multiply(tnNum1, tnNum2)
LOCAL lnResult
lnResult = tnNum1 * tnNum2
RETURN lnResult
ENDFUNC
ENDDEFINE
When you build the component (see
Figure 1), you
can choose "Win32 executable/COM server (exe)" to create an
out-of-process server. To build an in-process server, select either
"Single-threaded COM server (dll)" or "Multi-threaded COM server
(dll)." I'll talk more about the difference between the two types of DLLs
later. Building the component will automatically register it on the development
computer. You then instantiate it using the CreateObject() function:
ox = CREATEOBJECT("MyProject.Math")
? ox.Multiply(3, 4) && returns 12
ox = NULL
Many of the rules and intricacies of COM are automatically handled for us by
VFP. However, we have to manually follow one rule. That rule states that we
should never change the interface of a component. If we do, we need to create a
new ID for the component. By interface, I don't mean user interface, but the
public methods and parameters of the component. Let's look at the preceding
example. If we add a third parameter to the Multiply method, we change the
interface and need to create a new component ID. This is done on the Build
dialog box. The last option on the dialog box is "Regenerate Component
IDs." Check the option to create a new GUID for the component.
When you start deploying your COM components on remote servers, you'll access
them via Distributed COM (DCOM). Historically, under DCOM, you distribute an
out-of-process server and set up the calling information on the client computer.
Chapter 16 of the VFP Programmer's Guide goes into detail about how to do
this. When you install the component on a remote server, the code runs on the
server, not on the client workstation. Don't have any UI in your server because
it will display on the server, not the client workstation.
MTS to the rescue
Microsoft saw the need for a better way for remote components to run,
so they created Microsoft Transaction Server (MTS). Originally available for NT
and Windows 9x through the NT 4.0 Option Pack, MTS solved a number of problems
by providing a host for COM DLLs. It also provided a wizard that set up all of
the DCOM calls on the client station for you. Some other features of MTS
include:
- Just-in-Time Activation: A component is kept on disk and then
brought into memory (activated) only when needed.
- Object Request Broker (ORB): MTS will handle multiple calls to
the same component from multiple clients.
- Transaction Services: Commits and aborts are handled by the
Distributed Transaction Coordinator (DTC) instead of the application. This
makes it possible to have a transaction that spans multiple databases.
- Role-based Security: The security scheme allows you to determine
who can access your components based on NT logins and groups. If a user
doesn't have authorization to access a component, an error message is returned
to the client indicating that the component can't be instantiated.
- Connection Pooling: Typically, an application will make a
connection to the data store, and then hold that connection during the life of
the application. MTS allows multiple clients to use the same connection.
Creating components for use under MTS requires that you think differently
about your application design. First, your application should be stateless. This
means that your client program should instantiate the component, make calls to a
method, and then release the component. The connection to the component should
be as short a time as possible. You should avoid setting properties and pass all
of the needed information as parameters. Note that COM doesn't allow parameters
to be passed to the Init method.
You also need to think about threading. We typically think of threading as
single or multi-threading. VFP creates single-threaded applications. That is, it
can only do one thing at a time. This is like going to the grocery store and
only having one checkout stand open. All customers must go through the same
line. Only one customer at a time can be helped. The others wait in the queue
for their items to be processed.
Multi-threading allows your application to split processing into different
pieces, all running simultaneously. Using the grocery store example, you can
unload parts of your shopping cart into different lines and have all of your
groceries rung up at the same time.
MTS uses a third type of threading, apartment model. Again using our grocery
store example, customers may choose any open checkout stand, but once you've
chosen one, you always have to use the same one. Luckily, MTS will open a new
line for us when all are used.
So, how do we make use of MTS in our VFP components? First, we have to add
some code. Let's modify our Multiply example to handle MTS.
DEFINE CLASS Math AS SESSION OLEPUBLIC
FUNCTION Multiple(tnNum1, tnNum2)
LOCAL lnResult, loMtx, loContext
* Create a reference to the MTS object
loMtx = CREATEOBJECT("MTXAS.APPSERVER.1")
* Create a reference to the Context object
loContext = loMtx.GetObjectContext()
lnResult = tnNum1 * tnNum2
* Commit the transaction if there is one and
* tell MTS that we're done using the component
loContext.SetComplete()
RETURN lnResult
ENDFUNC
ENDDEFINE
The Context object contains information about our particular instance of the
COM component. Also, note the call to SetComplete(). This will commit any open
transactions. If we need to abort the transaction, we would call SetAbort()
instead.
When we build our component, we can't use "Win32 executable/COM server
(exe)." MTS requires that components be DLLs. That leaves us with two
choices: single or multi-threaded.
The single-threaded DLL is a good choice when the method call will be very
fast or there's the possibility that only one user will hit it.
The multi-threaded DLL isn't truly multi-threaded. It's apartment-model
threaded. Make this choice when the method call is slow or many users will
simultaneously call your component.
Once you've built your component, you install it on the server with the
appropriate VFP runtime libraries. Then, you create an MTS package and import
your component using the MTS Explorer. Using MTS Explorer, you can set security
and transactional support, and export a client setup program.
You can get more information on MTS from Randy Brown's article,
"Microsoft Transaction Server for Visual FoxPro Developers,".
Windows 2000
When Microsoft introduced Windows 2000, it came with several new
services. One of those is COM+. Basically, COM+ is the marrying of COM and MTS,
but new COM+ features were also introduced. Under Windows NT, MTS ran on top of
the operating system. Under Windows 2000, it's integrated into the OS. COM+ is
only available in Windows 2000. However, Windows 95, 98, Me, and NT users can
use COM+ components running on a Windows 2000 server. COM+ not only includes
(and enhances) the features of MTS, but also introduces new services: Queued
Components (QC), Loosely Coupled Events (LCE), Object Pooling, and Dynamic Load
Balancing. In the next installment of this series, we'll begin to delve into
these services in detail.
COM+ Applications are administered through the Component Services Manager
(see
Figure 2). You'll find it in the Administrative
Tools group in the Windows Control Panel. Let's walk through registering the
component that we saw earlier.
- Expand the tree under Component Services until COM+ Applications is
available.
- Click on COM+ Applications to make it the currently selected node, and
then right-click on COM+ Applications.
- From the context menu, select "New Application" to launch the
COM Application Wizard. Then click Next.
- Click "Create an empty application" (see
Figure 3).
- Enter the name for your application. In the example, I've called it
"MyFirstCOMApp." Then select the Activation Type. Normally, you'll
select Server application because your component will run on a server. If you
install the component on a workstation and want it to run in your
application's memory space, then select Library application (see
Figure 4). Click Next.
- Select the User ID that the component will run under. When installing on
a server, it's a good idea to set up a user specifically for your component.
Be sure to assign the proper rights to the user so that the component will
have access to all of the drives, directories, and resources that will be
needed (see
Figure 5). Click Next, then Finish.
We now have the application set up, but it doesn't contain any components. We
have to add the component to the application:
- Click the plus sign ("+") next to our new COM+ Application to
expand the tree.
- Click on Components, and then right-click on Components. Select New
Component from the context menu to launch the Component Install Wizard. Click
Next.
- The wizard gives you three options: Install new component, Import
component(s) that are already registered, or Install new event class(es).
We'll use the third option when I talk about Loosely Coupled Events. The
second option, Import component(s) that are already registered, is used when
you've previously installed the component on the computer. However, at the
time this was written, there was a bug in Windows 2000 that caused this option
to not work correctly. That leaves option 1. Click the button next to this
option (see
Figure 6).
- You'll next be prompted to select the DLLs to install. If you don't have
the proper VFP runtime files installed, you won't be able to select and
install your component (see
Figure 7). Once you've
selected your components, click Next, then Finish.
Now that your component is installed, how do you access it? The same way as
before. Just use CREATEOBJECT() to instantiate the component and you're ready to
go.
Summary
We've covered quite a bit of ground in this article, but most of it
should be review. You might be wondering whether all of this COM stuff is still
useful in a .NET world. The answer is Yes! COM still exists in .NET. In
fact, .NET was originally called COM+ 2.0. In upcoming articles in this series,
I'll discuss security, distribution, loosely coupled events, transactions,
queued components, and other COM+ features.
Sidebar: It's GUID for Me, is it GUID for You?
A GUID (pronounced GOO-id) is a Globally Unique Identifier. It's a
128-bit Integer and looks something like {1EF10DF8-8BF9-4CD7-860A-8DCD84EA3197}.
The GUID is generated using a combination of the current date and time, a
counter, and the IEEE machine identifier from the network card. The chances of
two GUIDs being the same are extremely remote.
So how is this GUID used? When you build a component, three files are
produced. The first is the DLL, and the second is a Type Library (TLB). The TLB
is a binary file that lists all of the public classes, properties, methods, and
events in your automation server. The third file is a Registry file (VBR). This
lists the GUIDs for your server and is used to register your component.
When you register the component, the VBR file is used to make Registry
entries about your component. Things like the directory location of the DLL, its
threading model, and its public interfaces are placed in the Registry. When you
instantiate the component, the server name—for example, Excel.Application—is
looked up in the Registry. The GUID will then be used to get additional
information about the component, such as the directory location and public
interfaces.
To find out more about FoxTalk and Pinnacle Publishing, visit their website at
http://www.pinpub.com/html/main.isx?sub=57
Note: This is not a Microsoft Corporation website. Microsoft is not responsible for its content.
This article is reproduced from the May 2001 issue of FoxTalk. Copyright 2001, by Pinnacle Publishing, Inc., unless otherwise noted. All rights are reserved. FoxTalk is an independently produced publication of Pinnacle Publishing, Inc. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of Pinnacle Publishing, Inc. To contact Pinnacle Publishing, Inc., please call 1-800-493-4867 x4209.
© Microsoft Corporation. All rights reserved.