FoxISAPI Automation Server Samples

Visual FoxPro includes an ISAPI extension called Foxisapi.dll that allows you to access Visual FoxPro custom Automation servers from any ISAPI supported web server such as Microsoft Internet Information Server and Microsoft Personal Web Server. The FoxISAPI extension works by creating an instance of a Visual FoxPro automation server and then calling a method on that server that returns HTML. The HTML is passed from the web server back to a Web browser such as Microsoft Internet Explorer. Visual FoxPro 6.0 provides a new version of the Foxisapi.dll that includes support for pool management of Visual FoxPro Automation servers and improved debugging capabilities.

Visual FoxPro includes two FoxISAPI automation server samples that demonstrate how you can use the power of Visual FoxPro to dynamically support a web site. The first sample, FoxWeb, located in the Samples\Servers\FoxIsapi\FoxWeb folder, is a simple sample designed to demonstrate basic FoxISAPI concepts. This sample steps you through the process of setup and deployment of FoxISAPI servers, both local and remotely. In addition, the sample walks through steps needed to implement pooling of servers for improved scalability.

The second sample, FoxIs, located in the Samples\Servers\FoxIsapi\FoxIs folder, is a more complex sample that contains routines to map visual and functional content of a Visual FoxPro form to HTML. The concepts are the same as FoxWeb; FoxISAPI instantiates a server and invokes a method to return HTML. Because the FoxIs sample uses a visual form, it offers additional versatility by allowing you to run it as a stand-alone program, from OLE clients, and from a Web browser.

If you’re not familiar with creating Visual FoxPro Automation servers, see Chapter 16, Creating Automation Servers, in the Programmer's Guide.

FoxISAPI Components

The following table lists the core FoxWeb Automation server sample files and a description of each.

File Description
Foxisapi.dll The main component of the FoxISAPI Automation server samples, FoxWeb and FoxIs. Foxisapi.dll is used with the Microsoft Internet Information Server or the Microsoft Personal Web Server. Foxisapi.dll creates an instance of a Visual FoxPro Automation server and executes a method on that server. The method then returns the HTML displayed in the Web browser. Foxisapi.dll is used primarily with Visual FoxPro; however, it can be used with any Automation server.
Foxisapi.ini An initialization file for Foxisapi.dll file that allows you to configure Foxisapi.dll.
Odebug.prg A Visual FoxPro program used for debugging your Internet applications.

Configuring FoxISAPI Components

To install the core FoxISAPI components, follow these steps:

  1. Copy the Foxisapi.dll and Foxisapi.ini files to your web server’s script folder. For example, C:\InetPub\scripts\.

  2. Copy the Oldebug.prg program file to your Visual FoxPro root folder (the location returned by HOME( ) function). For example, C:\Program Files\Microsoft Visual Studio\VFP98\.

FoxWeb, a Simplified Visual FoxPro Internet Automation Server

FoxWeb is a simplified ISAPI Automation server sample designed to quickly get a Web site up and running. FoxWeb provides a new version of Foxisapi.dll (also provided with the Visual FoxPro FoxIs server sample) is also included. Foxisapi.dll now can manage multiple instances of Visual FoxPro Automation servers, and provides additional debugging methods for Visual FoxPro applications designed for the Internet.

The FoxWeb Automation Server

The FoxWeb sample uses a simple Visual FoxPro server class intended to demonstrate the basic usage of a server run under FoxISAPI. All the code is stored in a file called Foxweb.prg. This file contains a class called Server which is marked as OLEPUBLIC so that it gets registered as an Automation server COM component when it is built. This class is instantiated by FoxISAPI and contains a number of methods that can be invoked (such as the Hello and Delay methods) as shown below. These methods illustrate the structures required by FoxISAPI in order to function properly.

The FoxWeb Sample Files

The files for the new Visual FoxPro FoxWeb Automation server sample are located in the Visual Studio …\Samples\Vfp98\Servers\Foxisapi\FoxWeb directory.

Setting up the FoxWeb Automation server

The following sections describe how to use Visual FoxPro to quickly get a Web site up and running with FoxWeb.

Registering the Visual FoxPro FoxWeb Automation server

The Visual FoxPro Automation servers that return HTML must be registered. Registration is done automatically if your .exe or .dll was built with the Visual FoxPro Project Manager or with the BUILD EXE or BUILD DLL commands. For example, if you open the Foxweb project provided with the FoxWeb sample in the Project manager, you can choose Build to create an Automation server as an in-process .dll or an out-of-process .exe file. Note that the registration occurs only on the machine on which the file was built.

A Visual FoxPro Automation server built as an out-of-process .exe can also be registered by specifying the Automation server name and including the /RegServer switch. For example, the following command registers the Visual FoxPro FoxWeb Automation server:

Foxweb.exe /RegServer

A Visual FoxPro Automation server built as an in-process .dll can also be registered with Regsvr32.exe. For example, the following command registers the Visual FoxPro Foxweb Automation server:

Regsvr32 Foxweb.dll

Note   If your Visual FoxPro ISAPI Automation server uses additional files such as .gif or .jpg files, be sure to place these files in directories that your Internet Information Server or Personal Web Server can access.

Using your Web Browser to access a Visual FoxPro ISAPI Automation Server

A Visual FoxPro ISAPI Automation server is accessed from your Web browser by providing the URL (Universal Resource Locator) of the Automation server. The Web browser makes an HTTP request that is passed to your Internet Information Server or Personal Web Server. The Automation server passes the request to Foxisapi.dll, which, in turn, passes the request to your Automation server.

For example, the URL below accesses the ISAPI Automation server named Foxweb.Server:

HTTP://MyServer/Scripts/Foxisapi.dll/Foxweb.server.Delay?30

The following table describes each of the elements of the URL example above.

URL Element Description
Myserver The virtual folder of your Internet Information Server or the Personal Web Server.
Scripts/Foxisapi.dll The Internet Information Server or the Personal Web Server Scripts folder and Foxisapi.dll.
Foxweb.Server The registered name (ProgID) of the Visual FoxPro ISAPI Automation server to call.

In this example, Foxweb is the name of the .exe or .dll file for the Visual FoxPro Automation server. Server is the class name specified in the OLEPUBLIC clause of the DEFINE CLASS command that creates the Automation server.

Foxweb.Server is also the ProgID for the Automation server as it is stored in the Windows Registry. You can use RegEdit to view or modify the Automation server’s ProgID.

Delay The name of the method to execute on the Visual FoxPro ISAPI Automation server.
?30 A parameter passed to the method. The question mark is a delimiter that specifies that a parameter follows. For this method, 30 specifies that execution is delayed for 30 seconds. The parameter is passed as a character string.

Passing Parameters to Methods

The following code is from the Delay method in Foxweb.prg, and demonstrates the structure for methods executed on the Visual FoxPro ISAPI Automation servers.

PROCEDURE Delay
   LPARAMETERS cParm1, cIniFile, nPersistInstance
   *** Your code here ***
   RETURN AnHTMLString
ENDPROC

cParm1

A character string passed to the method. In the Delay method, this parameter specifies the number of seconds that execution is delayed.

cIniFile

The name of the .ini file (passed to the method by Foxisapi.dll) created each time a Visual FoxPro ISAPI Automation server is accessed. Each .ini file is created in the Scripts folder and has a unique name that begins with “Fox.” You can use the GetPrivateProfileString function in Foxweb.prg, for example, to read information from the .ini file and return custom HTML based on a user’s configuration.

nPersistInstance

Specifies if the instance of the Visual FoxPro ISAPI Automation server persists after it is finished executing your method. nPersistInstance is passed by reference to the method by Foxisapi.dll. If nPersistInstance is set to 0 in your web application, the instance of the Automation server remains alive after execution is finished. If nPersistInstance is a value other than 0, the instance of the Automation server is released. For optimal performance, nPersistInstance should be set to 0, otherwise the Automation server must be launched again the next time it is called.

Using Foxisapi.dll to Pool Automation Servers

Because Foxisapi.dll is free-threaded, it can now pool multiple Visual FoxPro ISAPI Automation servers to provide better scalability for your web applications. Pooled ISAPI Automation servers allow a free ISAPI Automation server to service a request when other ISAPI Automation servers are busy. To take advantage of ISAPI Automation server pooling, the instances of the ISAPI Automation servers should be made persistent by setting nPersistInstance to 0 in your web application.

The number of ISAPI Automation servers available to service requests is determined by settings in your Foxisapi.ini initialization file. To create a pool of multiple ISAPI Automation servers, include an entry in square brackets with the name of the ISAPI Automation server for which a pool is created. This entry is followed with a list of ISAPI Automation servers that comprise the pool, with a numeric value that specifies the maximum number of instances of each ISAPI Automation server that can be created.

For example, placing the following lines in Foxisap.ini creates a pool of seven ISAPI Automation servers for service requests to Foxweb.myserver. Foxisapi.dll creates up to four instances of the Foxweb.server ISAPI Automation server and up to three instances of the Foxweb2.server ISAPI Automation server to service requests.

[FOXWEB.MYSERVER]
FOXWEB.SERVER=4
FOXWEB2.SERVER=3

The following URL executes the Delay method on either an instance of the Foxweb.server or the Foxweb2.server ISAPI Automation servers:

HTTP://MyServer/Scripts/Foxisapi.dll/Foxweb.Myserver.Delay?30

Foxisapi.ini can specify that the ISAPI Automation servers are instantiated up front before a service request is received. To do so, add a comma followed by an asterisk (*) after the number of instances, as shown in the following example.

[FOXWEB.MYSERVER]
FOXWEB.SERVER=4,*
FOXWEB2.SERVER=3,*

Using the Pool Manager across Multiple Machines

Foxisapi.dll provides the ability to manage Visual FoxPro ISAPI Automation servers on multiple machines. You can use Remote Automation or DCOM (Distributed Component Object Model) to access the ISAPI Automation servers. Note that for optimal performance and scalability the instances of the ISAPI Automation servers should be made persistent by setting nPersistInstance to 0 in your web application.

The following example describes a scenario where two Visual FoxPro ISAPI Automation servers, Foxweb and Foxweb2, are placed on two machines.

Machine_A is your local machine running Windows 95, DCOM, and Personal Web Server. Machine_B is your remote machine, accessible over your network, running Windows NT and DCOM.

  1. Machine_A is your Visual FoxPro development machine on which you’ve installed the Visual FoxPro FoxISAPI Automation server samples. On this machine, open the Foxweb project in the Visual FoxPro Project manager, and choose Build to create an ISAPI Automation server as an out-of-process .exe file. Building the .exe automatically registers the ISAPI Automation server on the machine as Foxweb.exe. Now open the Foxweb2 project in the Visual FoxPro Project manager, and choose Build to create and register another ISAPI Automation server as a .exe.

  2. To verify that the ISAPI Automation servers Foxweb and Foxweb2 are properly registered, you can use RegEdit and search for Foxweb and Foxweb2. Note that the ProgIDs for the servers are Foxweb.Server and Foxweb2.Server, respectively. Server is the class name specified in the OLEPUBLIC clause of the DEFINE CLASS command that creates the ISAPI Automation server. Foxweb.prg is the Visual FoxPro Internet application included in both the Foxweb and Foxweb2 projects.

  3. The ProgIDs for the ISAPI Automation servers both point to Machine_A, the local machine. The Registry settings for the Foxweb2 ISAPI Automation server need to be changed to point to Machine_B, the remote machine. Use Clireg32.exe, included as part of the Visual Studio common tools, to change the pointer in the Registry. Clireg32.exe is used to redirect calls to Foxweb2 to Machine_B. The following command, executed in the Windows Run dialog, runs Clireg32.exe:
    CLIREG32 FOXWEB2.VBR
    

    A dialog box is displayed, allowing you to specify Machine_B as the remote server to which calls to Foxweb2 are directed. The Remote Transport option in this dialog box lets you choose DCOM or Remote Automation as the transport method; choose DCOM.

  4. Now copy the Foxweb2.exe, Foxweb2.vbr, and Foxweb2.tlb files from Machine_A, the local machine, to Machine_B, the remote machine.

  5. Use the /RegServer option to register Foxweb2.exe on Machine_B at the MS-DOS prompt:
    C:\VFP\FOXWEB2.EXE /RegServer
    
  6. Finally, stop and restart the Personal Web Server on Machine_A to ensure that it is aware of the changes to the Registry.

You can execute the Status command on Foxisapi.dll to check the status of all the ISAPI Automation servers registered in Foxisapi.ini. The following URL executes the Status command:

HTTP://Machine_A/Scripts/FoxISAPI.dll/Status

You can execute the Reset command on Foxisapi.dll to reset all the ISAPI Automation servers registered in Foxisapi.ini. The Reset command releases all ISAPI Automation server instances. The following URL executes the Reset command:

HTTP://Machine_A/Scripts/FoxISAPI.dll/Reset

To test the installation, you can open up as many instances of your Web browser as there are ISAPI Automation servers in the pool. The Web browsers can be on multiple machines connected to your network. You can then call the Delay method in the URL from each Web browser so that Foxisapi.dll routes service requests to the other free ISAPI Automation servers. After the Delay method is executed from each Web browser, you can use the Status method to check to see if all ISAPI Automation servers in the pool received service requests.

Debugging your ISAPI automation Servers

Foxisapi.dll also lets you debug your ISAPI Automation servers on your local machine. Set the number of instances of the ISAPI Automation server you wish to debug to 0 as shown in the following example Foxisapi.ini file:

[FOXWEB.MYSERVER]
FOXWEB.SERVER=0

The Odebug.prg program file must be present in your Visual FoxPro root folder and the ISAPI Automation server source files must be present. Be sure that the ISAPI Automation server you wish to debug is configured as a persistent ISAPI Automation server, and debugging information is turned on in the project containing the ISAPI Automation server source files.

When the ISAPI Automation server is instantiated, Foxisapi.dll starts Visual FoxPro for debugging, allowing you to set breakpoints, trace through code, and so on.

Foxisapi.dll Commands

Foxisapi.dll has commands you can call to determine the status of your ISAPI Automation servers and to reset the servers. The following table lists the Foxisapi.dll commands with a description of each.

Command Description
Status Displays the current status of the ISAPI Automation servers, the Foxisapi.ini settings, and whether SingleMode or MultiMode is in effect.
Reset Releases all instances of the ISAPI Automation servers.
SingleMode Executes the Reset command, then limits the number of ISAPI Automation server instances to one instance. Execute this command to perform maintenance; for example, you can open tables exclusively in when SingleMode is in effect.
MultiMode Executes the Reset command, then limits the number of ISAPI Automation server instances to the values specified in Foxisapi.ini.

Each of the Foxisapi.dll commands is called by a URL that is specified in Foxisapi.ini. The following is the contents of the sample Foxisapi.ini file with the default URLs:

[FOXISAPI]
StatusURL = Status
ResetURL = Reset
SingleModeURL = SingleMode
MultiModeURL = MultiMode

The following URL executes the Status command:

HTTP://MyServer/Scripts/Foxisapi.dll/Status

In the following sample Foxisapi.ini file, the URL for the Status command is changed from Status to MyStatus:

[FOXISAPI]
StatusURL = MyStatus
ResetURL = Reset
SingleModeURL = MSingleMode
MultiModeURL = MultiMode

After this change to Foxisapi.ini, the following URL executes the Status command:

HTTP://MyServer/Scripts/FoxISAPI.dll/MyStatus

Note   You must reset Foxisapi.dll with the Reset command after you make changes to Foxisapi.ini file in order for the changes to take effect.

Additional FoxISAPI.ini Settings

Foxisapi.dll reads Foxisapi.ini and configures its settings according to the items contained in Foxisapi.ini. The following table describes each of the additional items you can place in your Foxisapi.ini file.

Item Description
AutoRefreshStatus Specifies the number of seconds between Status page refreshes. The default is 0 seconds (the Status page isn’t refreshed) if this item is omitted or if Foxisapi.ini isn’t present.
BusyTimeout Specifies the number of seconds Foxisapi.dll waits for the Visual FoxPro application servers to respond before a time-out message is generated. The default is 2 seconds if this item is omitted or if Foxisapi.ini isn’t present.
ReleaseTimeout Specifies the number of seconds Foxisapi.dll waits for a busy Visual FoxPro application server to respond before the Reset command is executed. The default is 2 seconds if this item is omitted or if Foxisapi.ini isn’t present.

The following is taken from the sample Foxisapi.ini file, and demonstrates the formats of the additional items you can place in the file:

[FOXISAPI]
BusyTimeout = 5
ReleaseTimeout = 15

Note   You must reset Foxisapi.dll with the Reset command after you make changes to Foxisapi.ini file in order for the changes to take effect.

Microsoft Internet Information Server Configuration Tips

Two Microsoft Internet Information Server registry entries, PoolThreadLimit and ThreadTimeout, can be added to your registry to improve performance with the Visual FoxPro FoxISAPI Automation servers. These registry entries determine the total number of threads that Internet Information Server can create, and the length of time the threads exist. For more information about these registry entries, see your Internet Information Server documentation.

A Microsoft Knowledge Base article titled “How to Launch Automation servers from ISAPI Extensions” (number Q156223) is available on www.microsoft.com. This article provides information about the access security permissions required to launch Automation servers such as the Visual FoxPro ISAPI Automation Servers.

FoxIs, a Visual FoxPro Internet Server

FoxIs, located in the Visual Studio …\Samples\Vfp98\Servers\Foxisapi\FoxIs directory, illustrates creating an out-of-process .exe or in-process .dll with ISAPI functionality that can be accessed from within Visual FoxPro as a stand-alone program, from Automation clients, and from a Web browser. Changes you make to its classes can enhance the Automation server, no matter how it is run.

To open the FoxIs sample project

Running the FoxIs Sample

You can run the FoxIs sample four different ways. When you are trying out the code, it’s a good idea to go run the sample in this order:

Running from Within Visual FoxPro

To run the FoxIs sample from within Visual FoxPro, run the following code in the Command window.

SET DEFAULT TO (HOME(2) + 'servers\foxisapi\foxis\')
SET CLASSLIB TO employee
ox = Createobject('employee')
ox.show

Running as an Independent Executable

You can build the sample into an executable file with the following line of code:

BUILD EXE foxis FROM foxis

The compiled file, FOXIS.EXE, is a Windows program that can be added to the Windows Start menu, started from the Windows Explorer, and so on.

Running as an Automation server

Once the FoxIs sample has been compiled into a .exe or a .dll, it is registered as an Automation server in the Windows registry. You can create an object based on the employee class from any OLE controller, for example Excel, Visual Basic, and Visual FoxPro 3.0:

ox = Createobject('foxis.employee')
ox.SHOW

Running from a Web Browser

You can even run the FoxIs sample from a Web browser, which could be on another machine such as a 286 running MS-DOS, a Unix machine, a Macintosh, or a Personal Digital Assistant.

System Requirements for Internet Use

To run the FoxIs sample from a Web browser, you must be running:

If you're using Windows NT 4.0, you need to run the DCOMCNFG utility to configure DCOM to give rights to the IIS service to instantiate OLE objects.

To configure Windows NT 4.0 DCOM

  1. At the Command prompt, type DCOMCNFG and press Enter.

  2. In the Applications tab, select the name of the Automation server. When you build the server, the application is “employee” by default.

  3. In the Default Security tab of the Distributed COM Configuration Properties dialog box, choose Edit Default for each area: Default Access Permissions, Default Launch Permissions, and Default Configuration Permissions.

  4. In the Registry Value Permissions dialog box for each area, choose Add.

  5. In the Add Names box of the Add Users and Groups dialog box, type your WWW server’s name and your login user name.

    You can see the server’s name in the Microsoft Internet Service Manager Properties window. If your machine name is FOO, the following line in the Add Names box sets up a default user:

    \FOO\IUSR_FOO
    

    If your machine name is FOO and you log in as HOMER, the following line in the Add Names box sets up permissions for you when you login:

    \FOO\HOMER
    

Setting Up the FoxIs Sample for Internet Access

To set up the FoxIs sample, you need to create a .exe or .dll from the FoxIs project, and then copy the file to your Inetsvr\Scripts directory.

To set up the FoxIs Sample

  1. Open the FOXIS project.

  2. Choose the Build button, and then choose Build COM DLL.

  3. Copy Foxisapi.dll to your Inetsrv\Scripts folder.

Preliminary Testing

You can test the FoxIs sample application at various levels to see if you are configured correctly.

To see if the code works

  1. From the Program menu choose Do.

  2. Select Main.prg in the Visual FoxPro Samples\Servers\Foxisapi folder.

  3. Choose Do.

To see if the .EXE works

  1. From the Visual FoxPro Command window, issue the following command:
    build exe Foxis.exe from foxis
    
  2. Double-click Foxis.exe in the Windows Explorer.

To see if the FoxIs Automation server works

It is much easier to debug Automation servers from an Automation controller (such as Visual FoxPro) before instantiating it in foxIs.

Set up the HTML page

To get things started, you need an HTML page that contains a reference to a url. For example, take the following code and put it in the Wwwroot\default.htm file.

<a HREF="/scripts/foxisapi.dll/FoxIS.employee.startup"> <i>VFP ISAPI AUTOMATION SERVER DEMO PAGE</i> </a> 

Then use a browser (which can be on the same machine) and connect to YourMachineName. For example, if your machine name was "foobar," then type "foobar" as the URL to go to. This would bring up the Default.htm page on the server named "foobar"

A CreateObject("foxis.employee") is initiated and the Startup method is invoked on the object, which returns a generated HTML page. If the ISAPI Automation server hasn't been built yet, then the Foxisapi.dll returns an HTML error page.

Then use your web browser to access the href above. If you get an error HTML page that says “Foxisapi error”, then you know the DLL is being loaded and is working.

 <form action = "/scripts/foxisapi.dll/foxis.employee.cmd">
<input name="Cmd" value = "Reset">
<input type="submit" value="Dos Command">
</form>

You can actually put in any valid MS-DOS command and it will be executed on the server machine. If the command is "Reset" (default), then it will make the ISAPI Automation server release the first instance as well as it's own, thus releasing the ISAPI Automation server completely.

In addition, you can evaluate any Visual FoxPro expression. However, if the Visual FoxPro expression displays a modal interface, as the MESSAGEBOX( ) function does, the Automation server will hang waiting for a response that cannot be provided. However, for an in-process .dll, the modal interface is automatically managed and the Automation server won’t hang.

<form action = "/scripts/foxisapi.dll/foxis.employee.cmd?FOXCMD">
<input name="Cmd">
<input type="submit" value="Fox Expression">
like "today is "+ cdow(date()) or 45 * 3 or SYS(2004)
</form>

Debugging the Server

A Windows NT service has no Desktop, therefore no user interface will appear on the server machine. This means you should debug your server applications before deploying them.

To trace through Foxisapi.dll with Visual C++ 5.0

  1. Open Foxisapi.mak.

  2. Remove the comment mark from the following line in HttpExtensionProc:
    //    _asm int 3
    
  3. Rebuild the project.

  4. Start MSDEV with the process id (PID) of Inetinfo.exe. You can get the process id in the Windows NT Task Manager.

This process applies to Windows NT 4.0.

Tip   When debugging, you don't have to shut down the web server to change the Automation server. You can just terminate the out-of-process component by sending a reset value to the cmd method, as described above, or by using the Win32 SDK tools TLIST, KILL, PVIEW, or the Task Manager in Windows NT 4.0.

The ISForm Class

The “engine” of the sample is the ISForm class in Isapi.vcx.

Entry Points into the ISForm Class

The following methods can be called from the Web browser, by way of Foxisapi.dll, to return HTML pages.

Method Returns
Cmd Evaluation of a Visual FoxPro expression or the results of a MS-DOS command.
DoSave Saves the user changes to the data and returns the employee HTML page.
Skipit The employee information for the specified employee in the table. Skipit takes cookie information passed in as a parameter from the Web browser, checks the cookies table to find the previous record number, and moves the record pointer forward or backward relative to the record number stored in the cookies table. The new record number is written back to the cookies table and the GenHTML method is called.
Startup The employee information for the first employee in the table. Startup creates a new cookie id for the user and sends it back as a hidden input area in the HTML.

Keeping the Server Active

Normally, for each request from a web client, the Automation server is instantiated, generates an HTML page, and is released with the Release( ) call in CallObject( ) in Foxisapi.cpp. This means the entire Visual FoxPro runtime will start up and shut down for each request.

If the ISAPI Automation server is registered as Multi-Use, and the Release( ) is not called, then the first request will start up the server but subsequent requests will use the same instance of the server, making performance much better. Code in Foxisapi.dll and in the Load, Cmd, DoSave, Startup, and Skipit methods of the ISForm manage keeping the same instance of the server active.

Variables in the DLL

Two variables are declared: pdispObj and pdispDoRelease. When the server is initially created, pdispObj is the dispatch handle to the OLE object. The pdispDoRelease variable is set to the same value as pdispObj and passed by reference as a parameter to the method of the ISForm server that was requested by the Web browser. Code in the Visual FoxPro ISForm Automation server can change the value of pdispDoRelease.

Tip   For more information about this sample, see the comments in the code in ISForm and Foxisapi.cpp.

The Form Load Event

When the ISForm is created, code in the Load event creates two public variables, gpInstance and gpDisp. The first time the ISForm server is loaded, the gpInstance variable is set to 1. Subsequent instances increment this variable. When an instance is released, gpInstance is decremented.

The Entry Point Methods

When a method (Cmd, DoSave, Skipit, or Startup) of the ISForm is invoked through Foxisapi.dll, the .dll passes a dispatch pointer by reference as a parameter to the method.

The first time the server is run, the instance count is set to 1 and the dispatch pointer is stored to the global variable. Then value 0 is stored to the dispatch pointer.

IF m.gnInstance = 1 
   IF TYPE('pDisp') $ 'NI' 
      gpDisp = m.pDisp
      pDisp = 0
   ENDIF
ENDIF

At this point, two variables point to the same dispatch pointer value: gpDisp in the ISForm Automation server and pdispObj in Foxisapi.dll. The value of pdispDoRelease in the .dll is 0, as changed in the ISForm Automation server.

Subsequent times the server is called the instance count in incremented, a new pdispObj is generated in the .dll, stored to pdispDoRelease, and passed by reference to the requested method. Because the gnInstance value is not 1, the gpDisp variable is not changed. From this point on, gpDisp in the Automation server holds a different value than pdispObj and pdispDoRelease in the .dll.

Code in the DLL

The following C++ code in Foxisapi.cpp manages releasing the server. After the first instance is created, subsequent instances are released normally with the Release( ) call in CallObject( ) in Foxisapi.cpp because pdispObj and pdispDoRelease are set to the same non-zero value.

if (pdispDoRelease != 0) {
   pdispObj->Release();  //nonzero, so release the current object
   if (pdispObj != pdispDoRelease) {
      __try {   
         (pdispDoRelease)->Release();
      } __except  (EXCEPTION_EXECUTE_HANDLER) {

      }
   }
}

The Destroy event of the ISForm decrements the instance count. When there is only one instance, pdispDoRelease has been set to 0 and the release code is not called. if the pdispObject and pdispDoRelease are the same, subsequent instances are released, but the original instance is not released.

Releasing the Server

To force a release, pdispDoRelease cannot be 0 and must be a different value than pdispObject. The following HTML text sends a value to the server that affects a release:

 <form action = "/scripts/foxisapi.dll/foxis.employee.cmd">
<input name="Cmd" value = "Reset">
<input type="submit" value="Dos Command">
</form>

The following code in the cmd method sets the pdispDoRelease value to the dispatch value of the first instance.

CASE 'RESET'$upper(m.p1)
   m.pDisp= m.gpDisp

Code in the .dll will now release the current instance and the original instance that has been kept in existence to prevent the Visual FoxPro runtime from having to be reloaded each time the server was called.

Sending HTML Back to the Client

The GenHTML method of the ISForm class is called from each of the entry point methods. The HTML returned from the GenHTML method is returned to the web browser through the Internet Information Server.

If the mode parameter passed to the GenHTML method is not “FORM,” the GenHTML method simply looks up the value in a table and sends back preformatted HTML.

IF m.mode != 'FORM'
   =SEEK(m.mode,'html')
   rv = html.html
  RETURN m.rv
ENDIF

If the mode parameter is “FORM,” code in GenHTML identifies each of the labels and textboxes on the form, sorts them in top to bottom and left-to-right order, evaluates the Captions and ControlSources of the controls, and uses Visual FoxPro’s text merge capabilities to construct the appropriate HTML text to approximate the display of the form.

If you add additional labels and text boxes to the form, they are automatically displayed in the generated HTML.

Creating and Using Cookies

As a web server this application can be hit dozens of times by various clients, and we need to keep track of the user state. In this case, we only track the current record number for that user. We could present the user with a login screen, and use the username as a key for the cookie, but instead we generate a cookie value in the MakeCookie method and pass it as a hidden value in the HTML sent back to the user. Each time the user chooses to go to a different record, we can read the cookie value from the HTTP string sent to the .dll, locate the cookie in the Cookies table, find the current record number and move the record number relative to this number.

The following property and methods are used in the cookie manipulation process:

Error Handling

If an error occurs, code in the Error event of the ISForm class calls the GenHTML method with a parameter of “ERROR.” GenHTML reads the pre-formatted HTML text for errors and returns it to the Error event code. The Error event code substitutes error information for placeholders in the HTML:

   LOCAL rv
   rv = THIS.GenHTML('ERROR')
   rv = strtran(m.rv,'%METHOD%',m.cMethod)
   rv = strtran(m.rv,'%ERRORNO%',STR(m.nError,4))
   rv = strtran(m.rv,'%ERRORMSG%',Message(1))
   rv = strtran(m.rv,'%LINENO%',STR(m.nLine,4))
   THIS.ErrorHTML = m.rv

When the ErrorHTML property isn’t empty, GenHTML sends the value of ErrorHTML back to the client.

Tables Used in the FoxIs Sample

In addition to the employee table used for data entry and display, the FoxIs sample uses the following tables.

Table Description
HTML Holds HTML text to be sent back to the Web browser as a header for FoxCMD and DosCMD evaluations or in case of an error.
Cookies Keeps track of record numbers for various web browsers. The unique cookie field value is passed as a hidden value in HTML text sent to a particular user.