"It Was Automation, You Know"
Besides black art, there is only automation and mechanization.
Federico Garc�a Lorca, 1936
Have you ever been working in one application and really needed some capability from another? Say you were creating a report in FoxPro, but really needed Word's formatting prowess? Or maybe you needed to do calculations on a few items of data contained in a set of spreadsheets? We sure have, more times than we can count. In the real world, many of the things people want to do aren't segregated into discrete kinds of tasks. Sure, sometimes all you want to do is write a letter or total some numbers. But more often, you want to create a complex report with pictures and maybe some spreadsheet data and so forth. (Heck, even our kids do this sort of thing starting in middle school these days.)Finding a way to handle interaction among applications has been computing's equivalent of searching for the Rosetta Stone since not too long after the PC was introduced. Various approaches have been tried over the years. First, we had applications that could read data in other formats or write their own data out in a format another application could understand. That helped, but it didn't solve the problem.Next up, we got the integrated applications, like Framework, Q&A, ClarisWorks and Microsoft Works. These tried to throw all the apps you might need into a single package. The price was that none of the apps inside was particularly powerful, and they could only talk to each other through common file formats, though they knew something about each other's formats.Until the Windows world, that was pretty much it. Windows brought us Dynamic Data Exchange (DDE), which let one application order another around. Progress, but it was awfully hard to use. Windows also introduced Object Linking and Embedding (OLE). That gave us a way to combine data from different applications into a single document, but still didn't quite solve the problem.Then along came Automation (called OLE Automation at the time, until Microsoft decided that the term "OLE" wasn't snazzy enough for them, so they dropped it). Automation lets one application speak directly to another in a simple object-based way, and makes it easy to work with data from multiple applications at the same time. We love Automation! In fact, this book was assembled using Automation. We wrote it using Word (a word processor did seem like the most appropriate choice). Each chapter, as well as each entry in the Reference section, was stored in a separate document. (That's 900-odd documents, if you're counting.) Of course, being FoxPro programmers, we tracked the progress of each document using a set of VFP tables.Eventually, we finished, though not by the time that we're writing this. (That was a sentence only Raymond Smullyan could love.) But how do you turn over 900 documents into a book and a CHM file? Automation to the rescue. Focusing on the hairiest part of the book, the Reference section (which is not in the printed book, so go download it from www.hentzenwerke.com if you haven't already), we told Word to open each of the documents, convert them to HTML, and put them in the proper location for the CHM file. We used Automation for the previous editions of this book, too, and were amazed how easily, accurately and quickly an error-prone, tedious operation was completed.As Automation itself has become more common, Microsoft has morphed OLE into ActiveX and, more recently, ActiveX into COM (Component Object Model). COM gives us the ability to talk not just to other applications, but to an assortment of operating system objects as well. Clearly, Automation brings us much closer to the lingua franca. But how do you use it?Putting Automation to Work
Far and away the best prize that life offers is the chance to work hard at work worth doing.
Theodore Roosevelt, 1903
The good news is that if you're comfortable with VFP's object-oriented syntax, where one object calls another's methods, and you can manipulate behavior by changing properties, Automation is easy. It's just another set of objects, each with its own properties and methods. The bad news is that, for each application you want to talk to, you have to learn a new object model. Each one has its own objects in their own hierarchy, and some of it is pretty obscure (not to mention underdocumented).You may have already won a million dollars. No, wait a minute! That's Ed McMahon's line. Let's try again. You may have already worked with some Automation objects. The Project object introduced in VFP 6 is an Automation object, as are the DataObjects used in OLE drag and drop, and the Objects collection found in the VFP container classes.Most Automation objects, though, don't make themselves available quite so transparently. You have to go out and grab the object you want (using CreateObject(), GetObject(), or CreateObjectEx()). Once you have a reference to it, though, you can do all kinds of things, from opening documents with the application to saving them to sending data from VFP to the other application to bringing the other application's data into VFP.But Where Did Automation Come From?
Automation offers the opportunity to start moving our applications away from the one-app-does-it-all method of writing huge applications, toward an application design where more of the components are pulled off the shelf and the job of the application developer becomes one of identifying the correct components and providing the glue to bring them together. Much of the productivity gain of the Industrial Age came from the availability of cheap, interchangeable parts available in large quantities from many vendors. Automation may lead to a similar availability of component parts for our applications.Automation is similar in many ways to the DDE (Dynamic Data Exchange) protocol it's eclipsing. Both require applications on each end to carry on a conversation. Both require one of the applications to initiate the conversation (the client), and one to respond (the server). (This is an unfortunate choice of terms, as client-server means something completely different in the world of database management systems.) There are also differences—Automation is implemented by a new engine, and in a different way, than DDE is. Automation has the opportunity of being a visible as well as invisible participant in the ongoing events. Automation is a replacement for DDE, but a far richer and more visual replacement. In exchange, it also tends to be far more resource-intensive. Automation allows direct dialogue between applications, giving the programmer the opportunity to take advantage of the strengths of the different applications making up the total client solution. In this way, Automation can be thought of as an inter-application or Windows batch language.Automation was introduced in the OLE 2.0 standard. The Microsoft Office Development Kit for Office 95 states that "Different applications expose different objects in different ways." This is an understatement. Every application we've worked with has its own unique implementation of Automation. We are seeing improvement, however: Microsoft has standardized on VBA for their Office applications, and is trying to bring similar object models to other applications as well. VBA has been licensed by a number of third-party vendors, too. But many tools, both within and outside Microsoft, lag behind, with weird implementations, actions that fire on setting property values, strange callback schemes, and hard-to-decipher error messages. Nonetheless, despite the frustrations of having to learn to speak a new language with each application, the power of Automation promises to bring new levels of functionality and features to our applications.I'd Rather Fight Than Switch
So is DDE dead? Nope, not by a long shot. While Automation has supplanted DDE in many applications and has become the more stable and reliable of the two, many third-party applications are just now getting on board the Automation bandwagon. Other applications may never need to make the switch, so the older DDE means of communication will still be needed for some time. If you have an application running satisfactorily using DDE, we can't recommend that you switch. On the other hand, if you have a DDE link to an application that keeps failing or crashing or just not working, press the vendor for an Automation solution (or shop for a vendor offering one) and see if that makes for a more solid solution.Using FoxPro as a Client
Visual FoxPro works quite well as the client in an Automation conversation, directing the work of other Automation servers. It's quite impressive to see the database-processing power of Visual FoxPro augmented by the features of Word, Excel or Visio (or whatever Automation server you need to use). There are four commands to initiate Automation: CreateObject(), NewObject(), GetObject() and CreateObjectEx(). CreateObject() is used to create new objects (surprising, huh?) based on either Visual FoxPro class definitions (base classes or class definitions in programs, procedures or VCXs) or from OLE objects defined in the Windows Registry.oObjectHandle = CreateObject(cClassName)NewObject() sure sounds similar to CreateObject(), doesn't it? It does essentially the same thing for COM objects. Its main advantage for VFP-coded classes is that the class library can be specified as part of the NewObject() call.
oObjectHandle = NewObject(cClassName, cClassLibrary)GetObject() is used to access a pre-existing object, and is used only for Automation, unlike the overloaded CreateObject() above.
oObjectHandle = GetObject(cFileName, OLEClassName)In most cases, only the file name must be supplied—COM matches the file up to its appropriate server. In the case where a file might have more than one server that could work with it, or where the file has a non-standard extension that doesn't specify the server, cClassName should be used to indicate which class to use.Finally, CreateObjectEx() is the extended version of CreateObject(), though used only for COM objects. You give it the class name, and optionally the name of a remote computer, and you can take advantage of Distributed COM (DCOM) objects. A feature new to VFP 7 is that you can also optionally specify the interface for early binding (see the Reference section).Once you've instantiated an object, you can manipulate it by using the properties and methods it "exposes" through COM. The next section illustrates the kind of interfaces that may be presented.In addition to manipulating the properties and methods, you may want to respond to events raised by that control. It wasn't until VFP 6 that you could use VFPCOM, a separate free utility from Microsoft, to react to events in another COM object. While it generally worked well, it was a separate DLL that needed to be shipped and installed with your application. VFP 7 has incorporated event binding right into the product with the EventHandler() function. One note on the syntax you'll encounter below. Some commands and property references use the Object property. This isn't really a Visual FoxPro property; it's a means of clarifying that you want to speak to the server contained within an OLE control, rather than the OLE control itself. This syntax is required only when an OLE server object and the OLE control have a property or method with the same name—use Object to make it clear that you mean the contained OLE server's property or method, and not that of the container.
Automation with the Office Applications
When I give a man an office, I watch him carefully to see whether he is swelling or growing.
Woodrow Wilson, 1916
Word 97 changed everything from the challenges we described in our original Hacker's Guide. Where Word 6.0 exposed only a single "Word.Basic" object and you had to manipulate all of the Word features through a difficult interface, Word 97 introduced a rich object model that made it easy to work with just the feature set you need.We've heard many complaints that every example of Automation anyone can find uses the same example: Open Word, load and print a document, and close Word. It's not only boring, it's trivial and useless. So we've got a better solution: We won't show you an example at all. The easy examples are, well, easy, and the tough ones are way too specific. Here's a little bit of advice instead.First, take advantage of the Help provided with the product. Search for "Visual Basic" in your version of Word for instructions on installing and running the help for VBA. Other Office products have similar topics. These are your best friends as you stick your toes into the waters of automating the Office applications. If you're going to get into Office Automation in a big way, get the best references out there. In our opinion, there's no better reference than the Hentzenwerke book, Microsoft Office Automation with Visual FoxPro (we should know, as Tamar and Della wrote it, and Ted edited it). See www.hentzenwerke.com for more information about the book. In addition, Microsoft publishes a monstrous set of books detailing every nook and cranny of the interface. Start slowly, and build your way up. A number of other authors have written killer books on using the Office tools. Our litmus test is pretty easy: Recall a problem you encountered in automating Office that took a while to resolve. Go to your local bookstore and check the indexes and tables of contents of the books to see if you can solve the problem. Read the section involved. If you understand the solution and like the writing style, buy the book. If they can't solve a problem you've already run into, what are the chances they'll solve any others? Take a pass.Our favorite way to start an Automation programming session is to start in the tool we want to automate and record the sequence of actions. The easiest way to learn to program Word, Excel or PowerPoint is to record a macro of the steps you need to take, and then translate it into matching VFP code. Unfortunately, there isn't a one-to-one correspondence from the VBA code into the code VFP uses via Automation because VBA allows the use of named arguments. However, the translation isn't that difficult. Here's the trick.In languages that support only positional arguments (like FoxPro), parameters are passed to a function in a specific order, and elements not needed for that call are left empty or placeholders are supplied, as in this example:Do MyFunc with "One","Two","Three", , , , "Seven"But in languages that support named arguments, you can pass only those parameters that are needed, by preceding each with the parameter name, like this:
MailMerge CheckErrors = 0, Destination = 3, MergeRecords = 0While somewhat more self-documenting, this notation is wordier and is more difficult to work with using Automation, which supports only the positional form. Versions of Office prior to Office 97 didn't always document the correct positional form, and additional documentation needed to be dug out of the Microsoft documentation dungeons. With the later versions, they seem to have done a much better job of covering the language.
Digging Into Other Servers
You will no doubt be called upon to automate other servers. The good news is that, even if the books supplied with a server seem lacking in essential details, most of what you need to know to automate a server is built in to the server and its supporting files. With Visual FoxPro 7 and later, IntelliSense should automatically provide much of this information to you. In earlier versions, using the Class Browser, Office's Object Browser, or another OLE-snooping tool (see below), you should be able to determine the interface of the server, the constants it uses, and the parameters it requires in its method calls. Type Libraries, typically with extensions of TLB and OLB, are the files an application uses to register itself on your machine. The libraries contain the definitions of method names, parameters and constants added to the Registry and made available to calling programs to validate their method calls. You, too, can access this information, with a variety of tools. The first tool in your Automation toolbox is the IntelliSense feature in VFP 7. Provided that you've used early binding when you declare your variable (the AS clause in the LOCAL command, below), IntelliSense can prompt you for the members in the object. Imagine you are typing in the following code:LOCAL oWord AS Word.Application oWord = CreateObject("Word.Application") oWord.Just after you hit that period on the last line, a popup appears, showing you the list of available members. You can scroll down the list to find the Visible property, or the Documents collection. You won't find the Font object, as it's not a member of the Application object. Since many of the resources available list the PEMs in alphabetical order, IntelliSense is a wonderful tool for making sense out of what you're actually able to use for the object. See "Intellisense and Sensibility" for more information on IntelliSense.Should you need a little more help than IntelliSense provides, your second tool is VFP 7's Object Browser. This cool tool is even an improvement on the Object Browsers provided with VBA, as it sorts the members into categories, such as properties, events, methods and constants. Click the Open icon, and you're presented with a dialog listing all the registered COM objects. Choose the appropriate one, and the list of members (PEMs, constants, interfaces, etc.) is displayed. You can examine constant values, see the syntax to the methods, and determine which objects the method or property belongs to. The Object Browser also provides an easy way to solve the constants problem: Just drag the Constants node into a program file, and VFP #DEFINE's are created for all the constants. If you haven't upgraded to VFP 7 (what are you waiting for?), you can view type libraries with the Class Browser. It can open and examine Type Libraries. Click the Open icon, and drop down the listing of file types—note that both TLB and OLB files are listed. You can also use the Visual Basic or VBA Object Browsers. (In Word, Tools | Macro | VB Editor gets you to the Visual Basic editor. Select Tools | References, pick the COM component you want to examine, and then press F2 to bring up the Object Browser). If these tools aren't enough, you can really get down and dirty with the OLE View tool that comes with Visual Studio (assuming you have access to Visual Studio). It's normally installed as part of the standard Visual Studio install. It lets you examine OLE interfaces in some detail, down to the GUID numbers and the Access and Assign interfaces for each exposed member. Several third-party tools are available that expand on the Microsoft tool; you'll easily find a wide variety of free and inexpensive utilities by searching the Internet.
Turning the Tables
It is not real work unless you would rather be doing something else.
J. M. Barrie, 1922
Like so much else these days, Automation looks at the world in terms of clients and servers. The application that starts the conversation and says, "Hey, you! I want to talk to you!" is the client. The application on the other end of the line, the one saying "Yeah? What's up, man?" is the server. In our various examples above, VFP was always the client, telling Word to assemble our book or telling Excel to hand over some data so it could be stored in a table for further processing. And, in fact, in VFP 3, that was your only choice. FoxPro could be an Automation client only. In VFP 5, Microsoft added an interesting capability. They allowed VFP to be used as an Automation server. So, other applications can call on VFP to hand over some data or whatever's called for. You can even call on the VFP Automation server from inside VFP, using the built-in Application object (or the system variable that references it, _VFP). The application object's DoCmd, Eval and SetVar methods let you execute a VFP command, evaluate an expression, and assign a value to a variable, creating it if necessary, respectively.For fun, call on VFP 7 from VFP 3 by issuing:oVFP = CreateObject("VFP.Application")Then, use the oVFP reference and its methods to execute VFP 7 code in VFP 3. Well, it's not really in VFP 3, any more than a command you send to Word through Automation is executing in VFP. But it is fun. However, there's not much practical use for this particular ability, because you have to have VFP 7 to do it. Why would you bother with VFP 3 when VFP 7 is available?More importantly, because VFP is an Automation server, other applications can call up and say, "Run this query and hand me the results" or "Here's some new data for you. Please store it where it belongs." We're also fairly certain that, without the ability to act as an Automation server, VFP couldn't play with OLE drag and drop, one of the coolest additions back in VFP 6.
Would You Care for a Custom Server?
He serves his party best who serves his country best.
Rutherford B. Hayes, Inaugural Address, 1877
However, working with VFP through its Application interface can get a little tedious. You can manipulate properties and even objects in an OOP way, but to execute any custom code, you're stuck with the DoCmd, Eval and SetVar methods. While you can do just about anything, it doesn't take too long to get tedious this way.If the goal is to have access to a fixed set of operations, there's another way to go. Instead of working with the whole VFP Automation object, use VFP to build a custom class with methods for the things you want to do. Have VFP build it into a server for you (by declaring it OLEPublic). Then, you can instantiate your server object from other applications, and call on its methods to do what needs to be done.An Automation server is a DLL or EXE created in FoxPro. It presents COM interfaces that can be manipulated by other programs. So how do you create those interfaces? How do you create the DLL or EXE? How do you choose between DLL or EXE, for that matter? And finally, once you've solved all that, how do you distribute your Automation server to the world?All objects you want to make accessible through COM must be created as part of a VFP project. The process of building a project into an EXE or DLL creates the appropriate Registry entries and the additional files needed to turn a VFP program or class into a COM object.COM interfaces are nothing more than method calls, just like the ones we're used to making. It's the packaging that's different. All classes containing interfaces you want to make public must be declared with the keyword OLEPUBLIC. For classes defined in code, this keyword is used in the DEFINE CLASS statement; for visually designed classes, the OLE Public check box must be checked in the Class Info dialog. Once you've defined a class as OLE Public, you'll probably want to tweak the class definition a bit so only those PEMs you want accessible to the outside world are visible via COM. In the Class Designer, check Protected on the Members tab for all those PEMs you want to keep internal to the object. Public members are exposed as part of the COM interface. If you're defining the class in code, use the Protected keyword for the properties and methods to hide. For greater control of the visibility of PEMS, you could use the Session object, which exposes only custom PEMs. Still greater control is obtained by using VFP 7's new _COMATTRIB flags on the DEFINE CLASS command. These flags follow the method definition, and designate whether the method is restricted, hidden or non-browsable—these are varying forms of hiding the method from other developers looking at it through property and object browsers. The _COMATTRIB flags can also be used to make properties read-only and write-only. See DEFINE CLASS in the Reference section for details on how to use these features.In your method, it's pretty much business as usual. You define the parameters for the method to receive, perform the processing code, and return a result. Essentially, there's no difference in the behavior of FoxPro code within a COM server; it's just running in the runtime as far as it is concerned. Since you're running as a COM object, however, there are a few additional considerations you need to keep in mind. First, most developers who use COM objects are used to seeing a brief description of what the method does, what parameter and expected data types are passed to the method, and what is returned from the method. VFP 7 offers some new enhancements to the DEFINE CLASS command to help out developers who use your COM objects. The HELPSTRING keyword sets the help string displayed in an object browser. For example:PROCEDURE GetCustomerName(tcCustID) ; HELPSTRING "Accepts the customer ID and returns the customer name." ENDPROCDEFINE CLASS now has strong typing, too. Visual FoxPro has notoriously been a weakly typed language, meaning that all variables are seen as variant types. You don't have to explain to FoxPro what the variable contains, nor does it always have to contain a certain type of data. Weak typing can have its place, but not in writing COM objects. The DECLARE CLASS command has an AS clause that can be added after each parameter. Likewise, you can add the AS clause after the parameter list, to assign a type to the return value. It looks like this:
PROCEDURE GetCustomerName(tcCustId AS String) AS StringSee the DEFINE CLASS topic for more information on these new features.Another thing to consider when creating COM servers is to make sure that your code doesn't attempt to interact with the user. Since a COM object is instantiated invisibly, there is nowhere to ask the user "Are you sure?" questions. Make sure your code doesn't call any dialogs. You also need to turn off the implicit ones. Remember to SET SAFETY OFF if you're deleting or overwriting files. Scan your code carefully. Some statements will surprise you. SET HELP TO, for example, will probably work fine on your development system but hang on your client's workstation. Why? SET HELP TO tries to set help to the default FoxHelp.CHM—what you probably mean to do is SET HELP OFF. Visual FoxPro 6.0 introduced a new function, SYS(2335), which prevents your server from invisibly hanging when a dialog appears. Instead, it generates an error, which your error handler should be able to record. Then, you can safely and cleanly terminate your server, if appropriate.
Face to Face with COM Interfaces
But wait, didn't we just say that you shouldn't call any dialogs in your COM objects? Isn't that an interface? Yes, that's a user interface; but here we're talking about COM interfaces. A COM interface is how the client talks to the COM server. It's just a bunch of methods. Of course, it's not quite that simple, because the interface must meet a stringent binary definition. Visual FoxPro automatically creates a default COM interface for you, so this business of dealing with interfaces can be simple.Of course, interfaces can get more complex, too. First of all, once you've published your COM component, you cannot change its interface, because this breaks all of the code based on this component. Instead of changing an interface, COM, and now VFP 7, supports multiple interfaces, meaning that you can add interfaces to your control to keep existing applications happy while providing new features to future applications. (Of course, you can also regenerate the COM control with a different GUID, and change whatever you'd like, because it's no longer the same control. But that wouldn't lead us into a discussion of multiple interfaces.) Another example of multiple interfaces is to provide several different event interfaces that other applications (or different facets of the same application) can hook into.An interface is a related group of methods that define a behavior. There's always a default interface, which is named "I" plus the name of the class. So an Employee class has a default interface of IEmployee. Managers are a special kind of employee, so you might define an interface called IManager that adds or augments features of the IEmployee interface. Many different interfaces can be added; carrying this theme a little further, you might have IInfoTechs, IHumanResources, or IAccounting. Now, what if you want to implement the interface of a COM object? VFP has had implementation inheritance since it was released. That's where the PEMs in the class and the code behind them are inherited, and something we're quite fond of. However, when you DEFINE CLASS using the IMPLEMENTS keyword pointing to a COM object's interface, COM does not support implementation inheritance. What they do support is interface inheritance, meaning that the public methods are inherited, without any code behind them—you get the interface only, and you supply the code. So using IMPLEMENTS gets you interface inheritance, not implementation inheritance (is this OOP terminology overloaded, or what?).Without any code, what's the value of interface inheritance? Plenty! First is polymorphism—different objects responding differently to the same commands. Do you use abstract classes (classes that contain PEMs with no code behind them) as templates? That's like using interface inheritance. And interface inheritance is absolutely required if you want to venture into the COM+ world.This is actually quite a complex topic, and we recommend that you look at other sources. One that we know is a Hentzenwerke Publishing book, What's New in Visual FoxPro 7.0, by Tamar, Doug, and Kevin McNeish. There are five chapters devoted to creating COM components, understanding and implementing COM+, and understanding Web services.EXE or DLL? Only Your Hairdresser Knows for Sure.
I am not an adventurer by choice but by fate.
Vincent Van Gogh, 1886
The Build dialog in the Project Manager includes options for building both EXEs and DLLs. Both of these apply to COM. (Of course, BUILD EXE also applies to other applications.) An EXE, known as an Out-of-Process server, runs in its own memory space, while a DLL, or In-Process server, shares memory space with the application that instantiates it. You need to create your COM server as an EXE if you're going to make it available remotely. For other machines to invoke the COM server on a server machine, the COM server needs to run on that server machine in its own memory space. Another reason for choosing an EXE over a DLL is stability. If a COM server runs into problems and errors out, hangs, or just plain dies, an EXE usually crashes its own space, but causes an error only in the client calling it. A crash in a DLL-based server usually brings down the whole process—client, server and all. There's a down side to using EXEs, of course. Since the client application and the server are in different processes, there is a significant amount of overhead in the interprocess communication that takes place. Also, if the EXE needs to load from disk and start each time it is called, there can be a significant wait (called a "latency period") before the EXE is ready to serve. Under heavy loads, this latency can become a bottleneck.A DLL has the opposite benefits, with equivalent liabilities. Because a DLL is running in the same memory space, the communication carries far less overhead. But running a FoxPro DLL, especially inside a FoxPro application, does introduce some tricky issues. The Fox DLL shares the same VFP runtime with its hosting client, which means that they share the same DEFAULT, TALK and other global settings. Be very careful to preserve and restore any settings you change when crafting a FoxPro DLL. Like a guest in someone else's house, make sure you put back what you move and disturb as little as possible. (Of course, that's always good advice when programming.) Take advantage of scoping and privatizing your behavior, using private data sessions and minimal variable scope to minimize the effects on the host application.The other advantage of DLLs is that they can run within the Microsoft Transaction Services (MTS in NT 4.0) or Component Services (Windows 2000). These DLLs can be pooled, so that more of them are available to handle heavy bandwidth demands, and can be kept alive when not in use for rapid startup. This topic, too, tends to get beyond what we need to cover in a VFP-specific book, but check the documentation for your particular OS and Microsoft's online resources for a lot more information on this.Distributing Your COM Server
Our society distributes itself into Barbarians, Philistines and Populace; and America is just ourselves with the Barbarians quite left out, and the Populace nearly.
Matthew Arnold, Culture and Anarchy, 1869
If you're using VFP 6 or earlier, a COM server can be bundled up and shipped using the Setup Wizard, just like any other application. In the second step of the wizard, pick "COM Components" and follow the prompts to add your servers to the list displayed. In-Process (DLL) servers have no options, but with Out-of-Process (EXE) servers, you can specify several options as to how the install should proceed. Check the Help file for more details.VFP 7 replaces the Setup Wizard with a VFP-specific version of InstallShield Express. Check its Help file for more details on how to install your COM server.How to Troubleshoot
People struggled on for years with "troubles," but they almost always succumbed to "complications."
Edith Wharton, Ethan Frome, 1911
Troubleshooting COM components can be a bear because they don't have a visible interface you can use for direct debugging. A DLL produces a "Feature not available" error if you attempt to suspend or debug in the middle of one of its procedures, even if you've instantiated it in the FoxPro development environment. Our advice: Debug in advance as much as possible, and set up a robust error handler to dump all of the environmental information you can find into an error log when an error occurs. That way, even though live debugging is unavailable, you should have sufficient evidence to deduce the source of the problem. You should also consider adding a simple logging feature to your base COM classes (textmerge and the new file-handling functions are ideal for this), so you can log "Step 1 start", "Step 1 end" if you're in one of those sticky debugging situations where things just seem to stop.COM, DCOM, and COM+
DCOM, or Distributed COM, is simply a term meaning that the location of the COM server doesn't matter. Termed location transparency, this ability to access a COM server on your local machine, on another machine on your local network, or on some machine who-knows-where on the Internet, is what DCOM is. So, what does DCOM give us?Distributed COM is built into all versions of Windows, beginning with Windows NT 4.0 and Windows 98 (if you're still using Windows 95, there's a free download from the Microsoft site). DCOM allows you to call for a service, using the same terminology you would for any object invocation, but the service actually runs on another machine! This opens up some great possibilities for distributed computing—where a few fast, powerful machines, or machines with special resources, could provide their services to other clients. So what's COM+? Well, with the advent of DCOM, the developers had to roll their own solutions for a number of things, such as managing all the resources, data transactions and security. Microsoft created Microsoft Transaction Server as an add-on for Windows NT to provide developers some relief from writing these things themselves. In this latest incarnation of COM, COM+ merges COM and MTS, improves on them, and builds them right into the Windows 2000 and later operating systems.But What About .NET?
Microsoft is at it again, developing more acronyms for us to learn. The latest of these is .NET, the integrated development environment for creating Internet applications. Does it spell doomsday for COM/COM+? Of course not. Microsoft knows that software companies have a significant investment in COM/COM+, so they're not going to yank it out from under them in the near future. In fact, Microsoft's own .NET Enterprise servers, including SQL Server 2000 and BizTalk Server 2000, have COM/COM+ at their core. Instead of mandating a move to .NET, Microsoft has made it easy for the two technologies to co-exist.How does VFP play in the .NET arena? Pretty well, actually. Since .NET has XML Web Services at its core, VFP 7 has new features that allow developers to write and consume Web Services. Visual Studio .NET is Microsoft's premier toolbox for writing .NET applications, and much has been made of taking VFP out of the Visual Studio box. This is a Good Thing: We have the best of both worlds. We can write and consume Web Services, thereby playing in the future .NET arena, and we can write the "old-style" COM/COM+ objects (old? didn't we just learn how to write COM objects?), supporting the current software technologies. .NET has some cool features, one of which is the Common Language Runtime, or CLR, which replaces the separate C, C++, and VB runtimes. No, VFP won't take advantage of the CLR or other VS.NET features (which is another Good Thing, as we would have lost our local database engine and significant backwards compatibility—both hallmarks of the FoxPro product). So, we get to have our cake and eat it, too, taking advantage of .NET when it is available, but retaining the ability to develop independent, stand-alone applications. The Fox team has enabled us to be compatible with .NET without losing features we've come to love.Using VFP in an n-Tier Architecture
Microsoft's recent marketing pitch, COM+, is an application architecture that uses COM components and the COM interface for all layers of an n-tier application model. (See "n-Tiers of a Clown" in "Your Server Will Be With You in a Moment" for more on the n-tier model.) We welcome these developments, and feel that VFP has a place to play, both as a heavy-duty front-end tool and as a middle layer serving business rules between the client and the data services. However, we advise caution before leaping into this new solution.Before you dive in head-first, you want to make sure that your application really needs the power of an n-tier solution. While the architecture seems attractive, we've discovered that the complexity of design, management and testing of our applications is proportionate to the number of interfaces we need to support. As more components are introduced into the mix, it becomes more complex to anticipate and properly code the ability to handle failures of single components, error passing between layers, and many other issues.Once you've determined that your application needs the n-tier model, Visual FoxPro provides a rich array of tools to help you create your COM components.