Chapter 16: Adding OLE

You can extend the power of your Visual FoxPro applications by employing the strengths of other Automation-enabled applications or ActiveX controls. In your applications’ forms or General fields, you can include specific functionality or data such as text, sound, pictures, and video from other applications. You can view or manipulate this data visibly by using the application that created it. Or, you can manipulate the data invisibly and automatically by controlling the application programmatically with Automation.

Other applications can also tap into the power of Visual FoxPro through Automation. You can even create Automation servers (COM components) in Visual FoxPro that your applications or other applications can access locally and remotely.

This chapter discusses:

Designing an OLE Application

Automation-enabled applications and COM components can act as Automation servers, clients, or both. Components that act as servers can provide objects to another application; components that act as clients can create objects.

You can easily incorporate the power and flexibility of applications, such as Microsoft Excel and Word, in your Visual FoxPro applications. Because Visual FoxPro also acts as a server, you can also provide functionality that can be integrated into solution packages based around Microsoft Office or other COM components.

Insertable OLE objects come from OLE-capable applications such as Microsoft Excel and Word. Such objects include Word documents and Excel worksheets. On forms, you can link or embed these objects using the OLE Container control, and you can store such objects in General fields of a table, displaying them in your forms with the OLE Bound control.

In a Visual FoxPro application, you can use OLE and ActiveX technology in many ways. Before you create an application, consider the ways you can use it.

Linking or Embedding OLE Objects

You can embed or link files from other Windows applications in your tables and forms. For example, you can embed or link a Word document in a General field of a table, and you can embed or link an Excel worksheet on a form.

The difference between embedding and linking lies in where the data is stored. Embedding stores the data in the table or form, whereas linking does not. For example, when you embed an Excel worksheet on a form, the form contains a copy of the worksheet. When you link, however, the form contains only a reference to the worksheet — not the worksheet itself.

Embedding and linking data

Both embedded and linked data start off with the original contents of the server file, as the illustration shows:

A spreadsheet embedded and linked in a form

But when the original file is changed, linked data is automatically updated to reflect the change, whereas embedded data is not:

Linked data updated in a form

Embedded data is not necessarily static, though. Both embedded and linked data can be displayed, changed, and manipulated interactively and programmatically in Visual FoxPro.

Adding Bound or Unbound OLE Objects

On a form or in a report, you can create objects that are bound to General fields in tables. Such objects are called bound OLE objects and you use them to display the contents of OLE objects in General fields. You create bound OLE objects by using the OLE Bound control on the Form Controls toolbar. Alternatively, you create unbound OLE objects by using the OLE Container control. An unbound OLE object is not connected to a General field in a table.

Adding OLE Objects to Your Applications

You can add OLE objects to tables and forms interactively or programmatically.

Adding OLE Objects to Tables

While you're designing tables for your application, consider whether you need OLE objects in the tables. For instance, suppose you have a product table and want to include Word documents containing nicely formatted descriptions of the products to be sent to potential customers. To include the Word documents, you must define a General field in the table. Then, you add the documents to the table by linking or embedding them in the General field.

To add an OLE object to a table

  1. Use the Table Designer to create a table with General field.

  2. Open the window for the General field by browsing the table and double-clicking the General field or by using the MODIFY GENERAL command.

  3. From the Edit menu, choose Insert Object.

    -or-

For more information about adding OLE objects with the Table Designer, see Chapter 10, Sharing Information with Other Applications, in the User’s Guide.

Appending OLE Objects to Tables

You can add OLE objects to tables programmatically with the APPEND GENERAL command. With this command, you can import an OLE object from a file and place it in a General field. If the field already contains an object, the new object replaces it.

Note   Unlike APPEND and APPEND BLANK, APPEND GENERAL does not add a new record to the table.

You can use APPEND GENERAL to embed OLE objects or link to OLE objects created by applications such as Microsoft Excel and Word. These applications support both linking and embedding. However, some applications such as Microsoft Graph only support embedding.

Suppose you have Microsoft Word files that you want to store in a Visual FoxPro table. If the table has a General field named WordDoc, you can embed the documents by using the following code:

CREATE TABLE oletable (name c(24), worddoc g)
CD GETDIR()

nFiles = ADIR(aWordFiles, "*.doc")
IF nFiles > 0
   FOR i = 1 to nFiles
      APPEND BLANK
      REPLACE Oletable.Name WITH aWordFiles(i,1)
      APPEND GENERAL WordDoc FROM aWordFiles(i,1)
   ENDFOR
ELSE
   MESSAGEBOX("No Word files found.")
ENDIF

Note   The preceding example looks only for files ending in .doc, the standard extension used by Word files. Because Microsoft Word and OLE are aware of this, the files are automatically associated with the Word server when you use APPEND GENERAL.

If you use a different extension from the one expected by the server, you must declare the class of the server, using the CLASS clause. For example, if you add the class for Word to the previous example, the code becomes:

APPEND GENERAL WordDoc FROM wordfiles(i,1) CLASS "Word.Document.6"

If you have files with common extensions (for example, .bmp) that other servers might use, you can use the CLASS clause to specify the particular server you want to use for those files. Alternatively, if you’d rather link than embed objects, use the LINK keyword.

APPEND GENERAL WordDoc FROM wordfiles(i,1) LINK CLASS "Word.Document.6"

In addition, you can replace data in an object by using the DATA keyword of APPEND GENERAL, as the following Microsoft Graph example illustrates.

Refreshing Microsoft Graph

Microsoft Graph is an embeddable application. The values in a Microsoft Graph chart are based on the values in the Microsoft Graph data sheet.

Microsoft Graph object in a general field

In order to programmatically change the data in a Microsoft Graph chart, you need to construct a string that contains the new data, including tabs, carriage returns, and line feeds, and pass this string to a Microsoft Graph object with the DATA clause of the APPEND GENERAL command.

The following example assumes you have a table, named stock, with, among other fields, date and close for the date and the closing price of the stock. The Microsoft Graph object is stored in the msgraph general field of a table named graph. The example refreshes a graph with stock closing prices from the previous 30 days.

Code Comments
#DEFINE CRLF CHR(13)+CHR(10)
#DEFINE TAB CHR(9)
LOCAL lcData
Define carriage return and tab characters.
SELECT date, close;
  FROM Stock WHERE BETWEEN(date, ;
  DATE(),DATE() - 30) ;
  ORDER BY date INTO CURSOR wtemp
Select the values that you want to update the graph with, in this case, the date and closing values for stocks for the last 30 days.
SELECT wtemp
lcData = " " + ;
  TAB + "Closing Price" + CRLF
SCAN 
  lcData = lcData + DTOC(date)
  lcData = lcData + TAB
  lcData = lcData + ;
  ALLTRIM(STR(close)) + CRLF
ENDSCAN
Build a character string (lcData) of data from the cursor to refresh the graph.

“Closing Price,” as the column header, is the text that will be displayed by default in the graph’s legend.

SELECT graph
APPEND GENERAL msgraph DATA lcData
Send the new values to the graph in the DATA clause of the APPEND GENERAL command.
USE IN wtemp
Close the cursor.

Note   You can also display OLE objects from General fields in your reports. For details about displaying OLE objects in reports, see “Adding a General Field” in Chapter 7, Designing Reports and Labels, in the User’s Guide.

Adding OLE Objects to Forms

Using the Form Designer, you can add insertable OLE objects to forms with the OLE Container control. In addition, you can display OLE objects from General fields by using the OLE Bound control.

To add an OLE object to a form

  1. In the Form Designer, add an OLE Container control to your form. The Insert Object dialog box opens.

  2. In the Insert Object dialog box, select Create New or Create from File.

    Insert Object dialog box

  3. Choose the appropriate OLE object from the Object Type list.

You can also customize the Form Controls toolbar so that you can directly add specific OLE objects.

To add OLE objects to the Form Controls toolbar

  1. From the Tools menu, choose Options.

  2. In the Controls tab of the Options dialog box, choose ActiveX controls.

    Controls tab of the Options dialog box

  3. In the Selected list, select the OLE objects and ActiveX controls you want to be available from the Form Controls toolbar.

  4. Choose Set as Default, and then choose OK.

  5. In the Form Controls toolbar, choose View Classes, and then choose ActiveX Controls.

To display an OLE object from a General field

  1. In the Form Designer, add an OLE Bound control to your form.

  2. Specify the General field that contains the data by setting the object’s ControlSource property.

    For example, if the table name is Inventory and the General field name is Current, then set the ControlSource property to Inventory.Current.

You can also display an OLE object from a General field programmatically:

Code Comments
frm1 = CREATEOBJECT("form")
Create form.
frm1.ADDOBJECT("olb1",
"oleboundcontrol")
Add control.
frm1.olb1.ControlSource = 
"Inventory.Current"
Bind the data to the control.
frm1.olb1.Visible = .T.
frm1.Visible = .T.
Make the control and form visible.

Interacting with OLE Objects

If you add an OLE object to a form or General field, you can edit the data and display characteristics of the object at run time or design time.

Note   You cannot edit the data of an OLE object in an OLE Bound control at design time.

Some OLE objects support in-place editing so that you can edit the object in the window used by your application. For example, if you double-click a Microsoft Excel worksheet object in a General field, rather than starting a copy of Microsoft Excel in another window, the menu titles change to reflect the Microsoft Excel menu structure and the default Microsoft Excel toolbars are displayed. You or your application user can then edit the Microsoft Excel object without leaving your application.

Note   You can edit only embedded objects in place, not linked objects.

You can also open the Automation server in another window, edit the data or display characteristics there, and have the new values reflected in your application when you return to it.

To edit an OLE object in place in a General field window

To open the application for an OLE object in a General field window

When you add an OLE object to a form in either the OLE Container control or the OLE Bound control, you have more control over the opening and editing of the object.

You can determine whether the OLE object is opened or edited when the control gets the focus or when the user double-clicks the control by setting the AutoActivate property of an OLE bound or container control. The AutoVerbMenu property specifies whether the shortcut menu of the ActiveX control allows a user to open or edit the OLE object.

To control access so that the OLE object can only be opened or edited programmatically with the DoVerb method, set AutoActivate to 0 - Manual and AutoVerbMenu to false (.F.) .

Controlling Menus

When a user is in-place editing an OLE object, the menu bar displays the menus for the OLE object, not the menus for your application. If you create a menu title and want it to be displayed even while the user edits an OLE object, select Negotiate in the Prompt Options dialog box of the Menu Designer. For more information, see Chapter 11, Designing Menus and Toolbars, or the NEGOTIATE clause in the DEFINE PAD topic.

Using ActiveX Controls

ActiveX controls are objects with encapsulated functionality and exposed properties, events and methods. ActiveX controls provide a wide range of functionality that you can easily tap into. ActiveX controls that ship with Visual FoxPro include:

ActiveX controls are versatile because you can subclass them to create other controls and you can control them by using the events, methods, and properties associated with the controls. You cannot create ActiveX controls with Visual FoxPro; however, you can create them using the Microsoft OLE Custom Control Developer’s Kit provided with Microsoft Visual C++® 4.0, and with the Microsoft Visual Basic® Control Creation Edition version 5.0.

For more information about accessing ActiveX controls, see Chapter 27, Extending Visual FoxPro with External Libraries. For more information on creating ActiveX controls specific to Visual FoxPro, see Chapter 28, Accessing the Visual FoxPro API.

Adding ActiveX Controls to a Form

ActiveX controls in Visual FoxPro must be contained in an OLE Container control (the base class is OLEControl). When you add an OLE Container control to a form, you can choose the ActiveX control you want to add to the form.

To add an ActiveX control to a form

  1. From the Form Controls toolbar, choose OLE Container Control and drag it to size in the form.

  2. In the Insert Object dialog box, choose Insert Control.

    Insert Object dialog box

  3. In the Control Type list, select the desired ActiveX control.

  4. Choose OK.

Managing Bound ActiveX Controls

If an ActiveX control supports simple data binding, Visual FoxPro will expose a ControlSource property for the control. All you have to do is set the ControlSource property to a table field and the value displayed in the ActiveX control reflects that value in the underlying field. Changes to the value in the control are saved to the field.

For examples of using ActiveX controls, run Solution.app in the Visual Studio …\Samples\Vfp98\Solution directory.

Note   To ensure all ActiveX control events are processed, set the AutoYield property of the Visual FoxPro Application object to false (.F.).

Manipulating Objects with Automation

OLE objects in your forms or programs, or ActiveX controls inside OLE Container controls, can be manipulated through code in the same way that you can program native Visual FoxPro objects.

Manipulating Extrinsic Object Properties

In code, you can manipulate an object using its properties. The way you reference a property depends on whether the object stands alone or is part of a container, such as the OLE Container control or OLE Bound control.

Note   ActiveX controls are always part of an OLE Container control.

An object in a container has two parts: the object itself and a container around the object. Both the object and the container have properties, and sometimes they have the same property names. To ensure you reference the object’s properties, always append the container’s Object property to the object’s name. For example, the following code refers to the object’s Left property.

frm1.olecontrol1.Object.Left = 25  && Object's Left

If you omit the Object property, you reference the container’s Left property instead.

frm1.olecontrol1.Left= 25  && Container's Left property 

For example, suppose you have an application that sends mail when the user clicks on a compose command button. If you've added a Microsoft MAPI message control to a form as olecontrol1, the code associated with the Click event of the command button might be:

THISFORM.olecontrol1.Object.Compose
THISFORM.olecontrol1.Object.Send(.T.)

In addition to using the Object property to reference properties of the contained object, you can use other properties of the container control. For example, you can reference the read-only OLEClass property to identify the type of object in the container and the Sizable property to prevent users from changing the size of an object. For details about container control properties, see OLE Container Control.

In the Form and Class Designers, the properties of ActiveX controls are displayed in the Visual FoxPro Properties window, but most ActiveX controls also have their own interface for setting common properties. You can see this properties interface by selecting the object-specific Properties option from the ActiveX control’s shortcut menu. For example, to open the Properties dialog box for a rich text control, choose Microsoft RichText Control Properties from the shortcut menu.

Opening the RichText control properties dialog box

Using Extrinsic Object Methods

In addition to setting and retrieving properties of objects, you can manipulate an object using methods it supports. For example, you can use the Add method of a Microsoft Excel collection object to create a new Microsoft Excel workbook.

The following Automation example uses the Add method to create an Excel workbook, the Save method to save the workbook, and the Quit method to end Excel:

Code Comments
oleApp = CREATEOBJECT("Excel.Application")
Start Excel.
OleApp.Visible=.T.
Display Excel.
OleApp.Workbooks.Add
Create a workbook.
OleApp.Cells(1,1).Value=7
Set a cell’s value.
OleApp.ActiveWorkbook.SaveAs("C:\TEMP.XLS")
Save the workbook.
OleApp.Quit
Quit Excel.

If you create an object using the OLE Container control or OLE Bound control, you can use the DoVerb method of the control to execute a verb on the object. For example, use DoVerb(0) to execute the default verb, DoVerb(– 1) to activate the object for visual editing, and DoVerb(– 2) to open the object in a separate window.

Note   See an application’s documentation to determine what Automation commands it supports. For example, Microsoft Excel add-in components are not available for Automation.

Setting Time Outs

When you pass a request to an OLE object, the Automation server processes it. You don’t have much control over the server processing, but you can specify how long you’ll wait for a process to finish by setting the OLERequestPendingTimeout and OLEServerBusyTimeout properties. You can determine what happens when that time has expired by setting the OLEServerBusyRaiseError property.

Accessing Collections of Objects

An object type can represent a single object or a collection of related objects. For example, a Microsoft Excel Workbook object represents a single workbook, whereas the Workbooks object represents all the workbooks currently loaded. Because the Workbooks object represents a collection of objects, it's called a collection object.

In code, a collection is an unordered list in which the position of an object can change whenever objects are added to or removed from the collection. You access an object in a collection by iterating through the collection, using the Count property of the collection. The Count property returns the number of items in the collection. You can also use the Item method to return an item in a collection.

For example, to display the names of worksheets in a Microsoft Excel workbook, use the following code:

oleApp = CREATEOBJECT("Excel.Application")
oleApp.Workbooks.Add
FOR EACH x IN oleApp.Workbooks
 ? x.Name
ENDFOR

You can also access a collection within a collection. For example, you can access a cells collection within a range using the following code:

oleApp = CREATEOBJECT("Excel.sheet")
oleApp.Workbooks.Add
oleApp.Range(oleApp.Cells(1,1),oleApp.Cells(10,10)).Value=100
oleApp.Visible=.T.

Using Arrays of Objects

You can pass arrays to methods, and you can receive arrays back. However, you must pass arrays by reference by prefixing the array name with the @ sign.

For example, to send a Visual FoxPro array to Microsoft Excel, consider the following code. It creates an array in Visual FoxPro, assigns the array some values, starts Microsoft Excel, creates a workbook, sets a value to the first cell of a worksheet, and then copies that value to the other sheets in the array:

DIMENSION aV(3)
aV(1) = "Sheet1"
aV(2) = "Sheet2"
aV(3) = "Sheet3"
oleApp=CREATEOBJECT("Excel.Application")
oleApp.Workbooks.Add
oleI=oleApp.Workbooks.Item(1)
oleI.Sheets.Item(1).Cells(1,1).Value = 83
oleI.Sheets(@aV).;
 FillAcrossSheets(oleI.Worksheets("Sheet1").Cells(1,1))

oleApp.Visible = .T.

Alternatively, the following example returns an array to Visual FoxPro and then displays the contents of the array:

oleApp = CREATEOBJECT("Excel.Application")
aOleArray = oleApp.GetCustomListContents(3)
FOR nIndex = 1 to ALEN(aOleArray)
   ? aOleArray(nIndex)
ENDFOR

Note   With Visual FoxPro, you cannot pass arrays larger than two dimensions to OLE objects. For more information about working with arrays in Visual FoxPro, see Chapter 3, Object-Oriented Programming and Overview of the Language.

Releasing Extrinsic Objects

An Automation server is automatically released if it is not visible and no variables in scope reference the object. You can use the RELEASE command to release the variable associated with an object. If the server is visible, use the Quit method to release it.

Subclassing Objects

You can create custom objects by subclassing the base classes provided with Visual FoxPro. For example, the following code subclasses the Outline control provided with Visual FoxPro:

Subclassing the Outline Control

Code Comments
PUBLIC frmMyForm, cFilename
SET SAFETY OFF
Declare variables and initialize.
frmMyForm = CREATEOBJECT("form")
frmMyForm.Width = 100
frmMyForm.ADDOBJECT("oleOutl","myoutline")
DIMENSION aSection(3)
aSection(1) = "Table"
aSection(2) = "Field"
aSection(3) = "Index"
Create a form, add the custom outline control to the form, and then create an array for the items that the control lists.
cFilename = GETFILE("dbc","Select a DBC")
USE (cFilename)
INDEX ON objecttype FOR (objecttype = "Table" ;
   OR objecttype = "Field" ;
   OR objecttype = "Index" ) ;
   TAG fname
Prompt for a database that contains the information you want the control to list.
FOR nIndex = 1 TO 3 STEP 1
   frmMyForm.oleOutl.AddItem(aSection(nIndex))
   frmMyForm.oleOutl.Indent;
    ((frmMyForm.oleOutl.ListCount-1)) = 1
   SCAN
      IF objecttype = aSection(nIndex)
         frmMyForm.oleOutl.Additem(objectname)
         frmMyForm.oleOutl.Indent;
         ((frmMyForm.oleOutl.ListCount-1)) = 2
      ENDIF
   ENDSCAN
   GO TOP
ENDFOR
Gather information from the database, and then add it to the control.
frmMyForm.oleOutl.Visible = .T.
frmMyForm.Show
Make the control visible, and then display the form.
DEFINE CLASS myoutline AS olecontrol
   OleClass = "msoutl.outline"
   Top = 5
   Left = 5
   Height = 10
   Width = 60
ENDDEFINE
Define a subclass of the OLE Container control and add the outline control by setting the OleClass property of the container, and then defining other custom settings.

If you want to distribute your applications, there are some additional considerations. For more information, see Chapter 25, “Building an Application for Distribution.”

Controlling Visual FoxPro from Other Applications

Because Visual FoxPro acts as a server (with level 2 compliance) as well as a client, applications that support Automation can create instances of Visual FoxPro, run Visual FoxPro commands, and access Visual FoxPro objects.

You can even manipulate Visual FoxPro from applications that don't support Automation by using Fpole.dll.

You control Visual FoxPro from other applications by using the Visual FoxPro Application object. An Application object is automatically created whenever Visual FoxPro is launched, either directly, through DDE or through Automation.

For example, the following lines of code in Visual Basic®, or a Microsoft Excel module create a reference to a Visual FoxPro application object:

Dim oFox as Object
Set oFox = CreateObject("VisualFoxPro.Application")

Once you have a reference to the Visual FoxPro Application object, you can call methods associated with the application object and access other objects through the collection properties of the Application object.

Methods of the Application Object

DataToClip Help
DoCmd Quit
Eval RequestData

The following example uses Visual Basic for Applications code in an Excel module to create a Visual FoxPro Application object, open a Visual FoxPro table, and add the results of a query to the active spreadsheet:

Sub FoxTest()
Dim oFox as Object
Set oFox = CreateObject("VisualFoxPro.Application")

oFox.DoCmd "USE customer"
oFox.DoCmd "SELECT contact, phone FROM customer 
   WHERE country = " + Chr$(39) + USA+ Chr$(39) + " INTO CURSOR cust"
oFox.DataToClip "cust",,3
Range("A1:B1").Select
ActiveSheet.Paste
End Sub

The Visual FoxPro Application Object Model

An application object is automatically created whenever Visual FoxPro is launched, either directly, through Automation or DDE. This application object provides access to all other objects created in a Visual FoxPro session through Collection properties.

Visual FoxPro application object model

Accessing Objects Through Collection Properties

The Visual FoxPro application object and all container objects in Visual FoxPro have a count property and a collection property associated with them. The collection property is an array referencing each contained object. The count property is a numeric property indicating the number of contained objects.

The following table lists objects and the corresponding collection and count properties.

Object Collection Property Count Property
Application Objects
Forms
Count
FormCount
FormSet Forms FormCount
Form Objects
Controls
Count
ControlCount
PageFrame Pages PageCount
Page Controls ControlCount
Grid Columns ColumnCount
CommandGroup Buttons ButtonCount
OptionGroup Buttons ButtonCount
Column Controls ControlCount
ToolBar Controls ControlCount
Container Controls ControlCount
Control Controls ControlCount

These properties allow you to use a loop to programmatically manipulate all or specific contained objects. For example, the following lines of code set the Visible property of all forms to True (.T.):

FOR EACH Form IN Application.Forms
   Form.Visible = .T.
ENDFOR

Creating Automation servers

With Visual FoxPro, you can create Automation servers (COM components) that package code to perform tasks common to many applications, or that implement complex business rules. These tasks and rules are then available to other programmers in your company, and to users of tools that support automation.

For example, you could create one or more classes to handle enterprise-wide business rules. A client application that uses the business rule objects would pass input parameters in a method call, and the Automation server might then do a great deal of work, retrieving data from various sources and performing complex calculations, before returning the answer.

Examples of Automation servers are installed in the Visual Studio …\Samples\Vfp98\Servers directory.

Creating the Server

All you need to create an Automation server in Visual FoxPro is a project that contains classes defined as OLEPUBLIC. You can have as many OLEPUBLIC classes as you want in the project and they can be defined in program files (.prg) or class libraries (.vcx).

For example, the following class definition in a program file creates a custom OLE public class:

DEFINE CLASS person AS CUSTOM OLEPUBLIC
   FirstName = SPACE(30)
   LastName = SPACE(45)

   PROCEDURE GetName
      RETURN THIS.FirstName + " " + THIS.LastName
   ENDPROC
ENDDEFINE

When you're designing a class in the Class Designer, select OLE Public in the Class Info dialog box to designate the class as OLEPUBLIC.

Class Info dialog box

Compiling the Server

In Visual FoxPro, you can create either an out-of-process or an in-process Automation server. An out-of-process component is an executable (.exe file) that runs in its own process. Communication between a client application and an out-of-process server is therefore called cross-process communication. An in-process component is a dynamic-link library (DLL) that runs in the same process address space as the client that calls it.

There are benefits to each. An in-process server is faster because there is no inter-process communication overhead. On the other hand, an out-of-process server can be deployed remotely and an in-process server cannot. Additionally, because the in-process server and the client share a process address space, any serious error in the .dll will terminate the client whereas an error in an out-of-process .exe would only terminate the server.

When you create an executable with OLE Public classes, you don’t lose any of your normal .exe capabilities. You can still run the executable, provide a user interface, and all the normal functionality you would include in an application. You increase the extensibility of your application, though, by allowing other applications to tap into the specific functionality you want to expose.

Note   If more than one user is accessing the Automation server, there can be conflicts. If you've provided Automation access as well as a user interface for your functionality, provide an extra layer of consistency checking in the interface to make sure your environment hasn’t been changed.

To compile an Automation server

  1. From the Project Manager, choose Build.

  2. In the Build Options dialog box, choose Build Executable or Build OLE DLL.

    Build Options dialog box

  3. Choose OK.

    -or-

Once you build the project, you can see the server classes displayed in the Project Information dialog box. Here you can also specify a help file and a Help context ID for each class. This help file can be opened from most generic object browsers.

Project Information dialog box

You can choose class-specific instancing values in the Project Information dialog box. The instancing options are:

When you build a project with OLE public classes, three files are created:

The type library file is a binary file that lists all the published classes in your Automation server, along with their properties, methods, and events. OLE object browsers read this information and present it in a readable interface.

The registry file lists the global unique IDs (GUID) for the classes in your server.

Note   A .vbr registry file is the same as a .reg registry file except that the .vbr file doesn’t include hard-coded paths.

A .vbr file with GUIDs for each OLE public class in a project

Registering an Automation server

Your Automation servers are available to other applications once the servers have been added to the Windows Registry. When you build an Automation server, it's automatically registered on the build machine. You can also register your servers on other machines.

When you use the Visual FoxPro Setup Wizard to create setup disks, the setup program registers your servers on your customers’ machines. You can also manually register servers.

To register an .exe component

To remove an .exe component registry entry

To register a .dll component

To remove a .dll component registry entry

Using the Automation server

Any application that can create Automation objects can create objects based on your Automation server, set properties that are not HIDDEN or PROTECTED, and call methods. For example, assuming that your server is named foxole and contains a class named person with a GetName method, the following code could be run in Visual FoxPro 3.0:

oTest = CREATEOBJECT("foxole.person")
cName = oTest.GetName()

Similar code could be run in Microsoft Excel or Visual Basic:

Set oTest = CreateObject("foxole.person")
cName$ = oTest.GetName()

Raising or Returning Errors from Automation servers

The only interaction with the objects provided by an Automation server (COM component) is through the methods and properties of the exposed classes. When a client application calls a method of an object, and an error occurs in the Automation server, the method either returns an error value or raises an error in the client application.

The client application decides whether to alert the user or proceed with another execution path. The Automation server itself never interacts with the user. This allows the location of the Automation server to be transparent to the client application. The Automation server can be local, running on the user’s computer, or you can use the Remote Automation feature of Visual FoxPro to run it on a network server.

Using Remote Automation

In typical Automation scenarios, both the client and the server are on a single computer and share the same resources, such as memory and processor.

Automation on a single computer

When you create local servers for Automation, you can deploy them remotely. Remote Automation allows you the same flexibility, extensibility, and power of local Automation, but over a network. Remote Automation allows:

You can configure a server and local computer for remote Automation with the Remote Automation Connection Manager, which saves the settings in the registry. The Automation Manager running on the server computer manages the Automation so that the same code that manipulates a local object can automatically manipulate a remote object.

Remote automation

Configuring the Server

The first step in enabling remote Automation is to configure the server computer for client access in the Remote Automation Connection Manager.

To configure the remote automation server

  1. Copy the Automation server executable file (.exe) to the server and run it one time to register it in the Windows Registry.

  2. On the server computer, run Racmgr32.exe, the Remote Automation Connection Manager.

  3. Select your class in the COM Classes list.

  4. In the Client Access tab, choose Allow Remote Creates by Key.

  5. In the Client Access tab, make sure Allow Remote Activation is selected.

After you've enabled client access in the Remote Automation Connection Manager, run the Automation Manager, Autmgr32.exe, on the server computer. Autmgr32.exe is installed in the System folder under Windows 95 or in the System32 folder under Windows NT. This will enable remote automation connections from other computers.

Configuring the Client

When the server computer is set up, you can configure the local client computer.

To configure the local computer for remote automation

  1. Copy the .vbr file that was created when you created the Automation server to the client machine.

  2. Run CLIREG32 with the name of the .vbr file. For example, if the file is Myserver.vbr, run the following command at the Command prompt:
    CLIREG32 MYSERVER.VBR
    
  3. In the dialog box that opens, enter the network address of the server machine and choose the network protocol (usually TCP/IP).

System Security Policy Options

The following table describes the System Security Policy area options in the Client Access tab of the Remote Automation Connection Manager.

Name Value1 Description
Disallow All Remote Creates 0 Do not allow any objects to be created.
Allow Remote Creates by Key 2 An object can be created only if the Allow Remote Activation check box is selected. This alters its CLSID in the Windows Registry to include the following subkey setting: AllowRemoteActivation = Y
Allow Remote Creates by ACL 3 A user can create an object only if the Access Control List for the CLSID in the Windows Registry includes the user. Windows NT only.
Allow All Remote Creates 1 Allow any object to be created. Not recommended outside the development environment.

1. The Value column lists the RemoteActivationPolicy preference setting of the Automation Manager in the Windows Registry.

Using Authentication in Remote Automation

For remote Automation servers running on any Windows operating system, remote call procedure (RPC) provides the following levels of authentication.

Name Value Description
Default 0 Use Network default.
None 1 No authentication.
Connect 2 Connection to the server is authenticated.
Call 3 Authenticates only at the beginning of each remote procedure call, when the server receives the request. Does not apply to connection-based protocol sequences (those that start with the prefix “ncacn”).
Packet 4 Verifies that all data received is from the expected client.
Packet Integrity 5 Verifies that none of the data transferred between client and server has been modified.
Packet Privacy 6 Verifies all previous levels and encrypts the argument values of each remote procedure call.

The need for RPC authentication should be evaluated carefully, because as the level of RPC authentication increases, performance declines. You can specify an authentication level for each class in your Automation server, so that costly levels like encryption need not be applied to the entire component.

For example, a data service implemented as a remote Automation server might have a Logon class used to transmit user and password information, and this class might require Packet Privacy authentication. Other classes exposed by the server might use a much lower level of authentication.

Troubleshooting Remote Automation

Here are some suggestions in case you run into difficulties.

Problem Action
OLE error code 0x800706d9: There are no more endpoints available from the endpoint manager. Make sure the Automation manager is running on the server computer and that the name of the server computer is correctly entered in the Network Address box of the Remote Automation Connection Manager.
Visual FoxPro: Application doesn’t appear in the Remote Automation Manager OLE Classes list.
  1. Run Regedit.exe to open the registry.
    vfp6.exe -r
  2. Delete all references to Microsoft Visual FoxPro.

  3. Run Visual FoxPro with the -r command line tag: