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.

  1. Expand the tree under Component Services until COM+ Applications is available.
  2. Click on COM+ Applications to make it the currently selected node, and then right-click on COM+ Applications.
  3. From the context menu, select "New Application" to launch the COM Application Wizard. Then click Next.
  4. Click "Create an empty application" (see Figure 3).
  5. 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.
  6. 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:

  1. Click the plus sign ("+") next to our new COM+ Application to expand the tree.
  2. Click on Components, and then right-click on Components. Select New Component from the context menu to launch the Component Install Wizard. Click Next.
  3. 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).
  4. 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.

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.