FoxISAPI 自动服务程序(Automation Server)示例

Visual FoxPro 包含了一个名为 Foxisapi.dll 的 ISAPI 扩充程序,它允许用户通过任何诸如 Microsoft Internet Information 服务程序和 Microsoft 个人 Web 服务程序这样的、由ISAPI 支持的 Web 服务程序访问 Visual FoxPro 的自定义自动服务程序。FoxISAPI 扩充程序的工作是创建 Visual FoxPro 自动服务程序的一个实例,然后调用返回 HTML 的服务程序上的一个方法程序,并将 HTML 从 Web 服务程序传回像 Microsoft Internet Explorer 这样的 Web 浏览器。Visual FoxPro 6.0 提供了新版的 Foxisapi.dll,它支持 Visual FoxPro 自动服务程序的缓冲管理,并拥有改进的调试功能。

Visual FoxPro 包含了两个 FoxISAPI 自动服务程序示例,它们演示了利用 Visual FoxPro 的强大功能动态地对 Web 站点提供支持的方法。第一个示例 FoxWeb 保存在 Samples\Servers\FoxIsapi\FoxWeb 文件夹中。它是一个用于解释 FoxISAPI 基本概念的简单示例。此示例将会一步步地展示安装和使用本地及远程 FoxISAPI 服务程序的全过程。另外,此示例还对为提高可扩充性而进行服务程序缓冲的各个步骤做了说明。

第二个示例 FoxIs 保存在 Samples\Servers\FoxIsapi\FoxIs 文件夹中。它是一个比较复杂的示例,其中包含了将 Visual FoxPro 表单上可见的及功能性内容映射成 HTML 的例程。此示例的基本概念与 FoxWeb 完全相同;FoxISAPI 先实例化一个服务程序,然后调用一个方法程序返回 HTML。由于 FoxIs 示例使用了可视表单,因此它提供了更多的功能,允许以独立程序的方式运行、可以在 OLE 客户端运行、也可以在 Web 浏览器上运行。

如果对创建自动服务程序还不很熟悉,请您参阅《程序员指南》第十六章“添加 OLE”中的“创建自动服务程序”。

FoxISAPI 组件

下表列出了核心的 FoxWeb 自动服务程序示例文件,并对它们分别做了说明。

文件 说明
Foxisapi.dll FoxWeb 自动服务程序示例,及 FoxWeb 和 FoxIs 的主要组件。Foxisapi.dll 可与 Microsoft Internet Information 服务程序或 Microsoft 个人 Web 服务程序一起使用。Foxisapi.dll 会创建 Visual FoxPro 自动服务程序的一个实例,并在该服务程序上执行一个方法程序。然后此方法程序返回 HTML,并显示在 Web 浏览器中。Foxisapi.dll 主要与 Visual FoxPro 一起使用;但它也可与其他任何 自动服务程序一起使用。
Foxisapi.ini Foxisapi.dll 文件的初始化文件,它可用于配置 Foxisapi.dll。
Odebug.prg 用于调试 Internet 应用程序的 Visual FoxPro 程序。

配置 FoxISAPI 组件

按以下步骤可安装核心的 FoxISAPI 组件:

  1. 将 Foxisapi.dll 和 Foxisapi.ini 文件复制到 Web 服务程序的 script 文件夹中。例如,C:\InetPub\scripts\。

  2. 将 Oldebug.prg 程序文件复制到 Visual FoxPro 根文件夹中(HOME( ) 函数返回的位置)。例如,C:\Program Files\Microsoft Visual Studio\VFP98\。

简化的Visual FoxPro Internet 自动服务程序:FoxWeb

FoxWeb 是一种简化了的 ISAPI 自动服务程序示例,它主要用于快速地建立并运行 Web 站点。FoxWeb 提供了新版的 Foxisapi.dll 文件(Visual FoxPro FoxIs 服务程序示例也提供此程序)。现在 Foxisapi.dll 可管理 Visual FoxPro 自动服务程序的多个实例,并提供了其他一些用于调试 Visual FoxPro 的 Internet 应用程序的方法程序。

FoxWeb 自动服务程序

FoxWeb 示例使用一个简单的 Visual FoxPro 服务程序类来对运行在 FoxISAPI 下的服务程序的基本用法进行了演示。所有代码都保存在名为 Foxweb.prg 的文件中。此文件中包含了一个名为 Server 的类,它已标记为 OLEPUBLIC,因此在其连编时注册为自动服务程序 COM 组件。此类由 FoxISAPI 进行实例化,类中包含了 Hello 和 Delay 等方法程序,它们可以通过以下方法进行调用。这些方法程序对 FoxISAPI 正常工作所需的结构做了说明。

FoxWeb 示例文件

新的 Visual FoxPro FoxWeb 自动服务程序的示例文件保存在 Visual Studio ...\Samples\Vfp98\Servers\Foxisapi\FoxWeb 目录下。

安装 FoxWeb 自动服务程序

以下几节内容对使用 Visual FoxPro 建立 Web 站点,以及使用 FoxWeb 使站点正常运作的方法做了说明。

注册 Visual FoxPro FoxWeb 自动服务程序

必须注册返回 HTML 的 Visual FoxPro 自动服务程序。如果 .exe 或 .dll 文件是与 Visual FoxPro“项目管理器”或者是与 BUILD EXE 或 BUILD DLL 命令连编的,那么注册将自动进行。例如,如果在“项目管理器”中打开带有 Foxweb 示例的 Foxweb 项目,则可选择“连编”以创建一个自动服务程序,它可以是进程内的 .dll 文件或是进程外的 .exe 文件。请注意,注册临时表只在文件连编的机器上才有。

连编成进程外的 .exe 文件的 Visual FoxPro 自动服务程序也可通过指定带有 /RegServer 开关的自动服务程序的名字进行注册。例如,以下命令可注册 Visual FoxPro FoxWeb 自动服务程序:

Foxweb.exe /RegServer

连编成进程内的 .dll 文件的 Visual FoxPro 自动服务程序也可使用 Regsvr32.exe 进行注册。例如,以下命令可注册 Visual FoxPro FoxWeb 自动服务程序:

Regsvr32 Foxweb.dll

注释 如果 Visual FoxPro ISAPI 自动服务程序使用了.gif 或 .jpg 等额外文件,那么就需要确认这些文件都放置在 Internet Information 服务程序或个人 Web 服务程序可以访问的目录中。

使用 Web 浏览器访问 Visual FoxPro ISAPI 自动服务程序

只需给出 Visual FoxPro ISAPI 自动服务程序的 URL,即可在 Web 浏览器中访问此 自动服务程序。Web 浏览器会向 Internet Information 服务程序或个人 Web 服务程序发出一条 HTTP 请求。自动服务程序将此请求发送给 Foxisapi.dll,然后再由 Foxisapi.dll 将该请求返还给自动服务程序。

例如,以下的 URL 可以访问名为 Foxweb.Server 的 ISAPI 自动服务程序:

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

下表是对上述 URL 示例中各元素的说明。

URL 元素 说明
Myserver Internet Information 服务程序或个人 Web 服务程序的实际文件夹。
Scripts/Foxisapi.dll Internet Information 服务程序或个人 Web 服务程序的 Scripts 文件夹和 Foxisapi.dll 文件。
Foxweb.Server 所要调用的 Visual FoxPro ISAPI 自动服务程序的已注册名称 (ProgID)。

在此示例中, Foxweb 是 Visual FoxPro 自动服务程序的 .exe 或 .dll 文件的文件名。Sever 是在创建自动服务程序的 DEFINE CLASS 命令中的 OLEPUBLIC 子句中指定的类名。

Foxweb.Server 也是自动服务程序的 ProgID,它保存在 Windows 的注册表中。可使用 RegEdit 来查看或修改自动服务程序的 ProgID。

Delay 要在Visual FoxPro 自动服务程序上执行的方法程序的名字。
?30 传递给方法程序的参数。问号是分隔符,它表明后面所带的是参数。对于此方法程序,30 指定了方法程序在 30秒后执行。参数是以字符串形式传递的。

将参数传递给方法程序

以下是 Foxweb.prg 的 Delay 方法程序中的部分代码,通过它可以了解在 Visual FoxPro ISAPI 自动服务程序上执行的方法程序的结构。

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

cParm1

传递给方法程序的字符串。在 Delay 方法程序中,此参数指定了方法程序执行前要延迟的时间(以秒为单位)。

cIniFile

每次访问 Visual FoxPro ISAPI 自动服务程序时都要创建的 .ini 文件的文件名,它由 Foxisapi.dll 传递给方法程序。创建的每个 .ini 文件都存放在 Scripts 文件夹中,并都有以“Fox.”开始的唯一文件名。例如,可使用 Foxweb.prg 中的 GetPrivateProfileString 函数来读取 .ini 文件中的信息,并根据用户的配置返回自定义的 HTML。

nPersistInstance

指定 Visual FoxPro ISAPI 自动服务程序的实例在执行完方法程序后是否保持活动。nPersistInstance 通过 Foxisapi.dll对方法程序的引用来传递。如果在 Web 应用程序中将nPersistInstance 设置为 0,那么当方法程序执行完成后自动服务程序的实例仍然是活动的。如果 nPersistInstance 设置为非 0的数,则当方法程序执行完成后将释放自动服务程序的实例。将 nPersistInstance 设置为 0 可获得更好的执行性能,否则下一次调用自动服务程序时还需要重新启动它。

使用 Foxisapi.dll 来缓冲自动服务程序

由于 Foxisapi.dll 是自由线程的,因此它可以缓冲多个 Visual FoxPro ISAPI 自动服务程序以便为网络应用程序提供更好的可扩充性。缓冲的 ISAPI 自动服务程序可使空闲的 ISAPI 自动服务程序在其他 ISAPI 自动服务程序忙时对请求提供服务。为了充分利用 ISAPI 自动服务程序缓冲的优点,需在 Web 应用程序中将 nPersistInstance 设置为 0 使 ISAPI 自动服务程序的实例保持活动。

可为请求提供服务的 ISAPI 自动服务程序的数目取决于 Foxisapi.ini 初始化文件中的设置。要创建多个 ISAPI 自动服务程序的缓冲,可在方括号中加入一项,该项带有要创建缓冲的 ISAPI 自动服务程序的名字。该项后应跟有组成缓冲的所有 ISAPI 自动服务程序的列表,以及用来指定每个 ISAPI 自动服务程序可创建的最多实例数的数值。

例如,将下列几行文字放置在 Foxisap.ini 文件中,可创建一个由 7 个 ISAPI 自动服务程序组成的缓冲,它可为向 Foxweb.myserver 发出的请求提供服务。Foxisapi.dll 最多可创建 Foxweb.server ISAPI 自动服务程序的 4 个实例和 Foxweb2.server ISAPI 自动服务程序的 3 个实例来为请求提供服务。

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

以下的 URL 会在 Foxweb.server 或 Foxweb2.server ISAPI 自动服务程序的实例上执行 Delay 方法程序:

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

Foxisapi.ini 可指定在收到某一服务请求之前将 ISAPI 自动服务程序实例化。在实例数目之后加上逗号及星号即可做到这一点,如下例所示:

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

在多台机器上使用缓冲管理器

Foxisapi.dll 提供了在多台机器上管理 Visual FoxPro ISAPI 自动服务程序的功能。您可利用 Remote Automation 或 DCOM (Distributed Component Object Model) 来访问 ISAPI 自动服务程序。请注意为使 ISAPI 自动服务程序的实例保持活动,在 Web 应用程序中应将 nPersistInstance 设置为 0,这样做 ISAPI 自动服务程序会具有更好的执行性能和可扩充性。

以下示例对两个 Visual FoxPro ISAPI 自动服务程序:Foxweb 和 Foxweb2 分别放在两台机器的情况做了说明。

Machine_A 是运行着 Windows 95、DCOM、和个人 Web 服务程序的本地机。Machine_B 是运行着 Windows NT 和 DCOM 的远程机,可通过网络对其进行访问。

  1. Machine_A 是 Visual FoxPro 的开发机器,在这台机器上安装了 Visual FoxPro ISAPI 自动服务程序示例。在这台机器的 Visual FoxPro“项目管理器”中打开 Foxweb 项目,然后选择“连编”以将 ISAPI 自动服务程序创建为进程外的 .exe 文件。连编 .exe 文件时,机器会自动将其中的 ISAPI 自动服务程序注册为 Foxweb.exe。现在在 Visual FoxPro“项目管理器”中打开 Foxweb2 项目,然后选择“连编”以将另一个 ISAPI 自动服务程序创建并注册为 .exe 文件。

  2. 使用 RegEdit 来搜索 Foxweb 和 Foxweb2 的注册项可查证 ISAPI 自动服务程序 Foxweb 和 Foxweb2是否已正确注册。请注意这些服务程序的 ProgID 分别是 Foxweb.Server 和 Foxweb2.Server。Server 是创建 ISAPI 自动服务程序的 DEFINE CLASS 命令中的 OLEPUBLIC 子句所指定的类名。Foxweb.prg 是包含在 Foxweb 和 Foxweb2 项目中的 Visual FoxPro Internet 应用程序。

  3. ISAPI 自动服务程序的 ProgID 都是指向本地机 Machine_A 的。Foxweb2 ISAPI 自动服务程序的注册设置需改为指向远程机 Machine_B。Clireg32.exe 是 Visual Studio 通用工具的一部分,使用它可改变注册表中的指针。Clireg32.exe 可用于将 Foxweb2 的调用重新定向到 Machine_B 上。在 Windows 的“运行”对话框中执行以下的命令即可运行 Clireg32.exe:
    CLIREG32 FOXWEB2.VBR
    

    命令执行后,将会出现一个对话框,在其中将对 Foxweb2 的调用定向到作为远程机的 Machine_B 上。对话框中的“远程传送”选项可用于选择 DCOM 或 Remote Automation 作为传送方法;请选择 DCOM。

  4. 现在请将 Foxweb2.exe、Foxweb2.vbr、和 Foxweb2.tlb 文件从本地机 Machine_A 复制到远程机 Machine_B 上。

  5. 在 MS-DOS 提示符下使用 /RegServer 选项将 Foxweb2.exe 注册到 Machine_B 上:
    C:\VFP\FOXWEB2.EXE /RegServer
    
  6. 最后,终止并重新启动 Machine_A 上的个人 Web 服务程序,以确认注册表的变化。

可在 Foxisapi.dll 上执行 Status 命令,以查看在 Foxisapi.ini 中注册的所有 ISAPI 自动服务程序的状态。以下的 URL 可执行 Status 命令:

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

可在 Foxisapi.dll 上执行 Reset 命令,以重置在 Foxisapi.ini 中注册的所有 ISAPI 自动服务程序。Reset 命令将释放所有 ISAPI 自动服务程序实例。以下的 URL 可执行 Reset 命令:

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

打开与缓冲中的 ISAPI 自动服务程序数目相同的 Web 浏览器实例,可对安装情况进行测试。Web 浏览器可以在多台连接在同一网络的机器上。在每个 Web 浏览器的 URL 中调用 Delay 方法程序,Foxisapi.dll 就会将服务请求发送到其他空闲的 ISAPI 自动服务程序上。当所有 Web 浏览器的 Delay 方法程序都执行完毕后,可使用 Status 方法程序查看是否缓冲中的所有 ISAPI 自动服务程序都收到了服务请求。

调试 ISAPI 自动服务程序

用 Foxisapi.dll 可在本地机上调试 ISAPI 自动服务程序。将要调试的 ISAPI 自动服务程序的实例数设定为 0,如下 Foxisapi.ini 示例文件所示:

[FOXWEB.MYSERVER]
FOXWEB.SERVER=0

在 Visual FoxPro 根文件夹中必须有 Odebug.prg 程序文件和 ISAPI 自动服务程序的源文件。请确认要调试的 ISAPI 自动服务程序已配置成永久的 ISAPI 自动服务程序,并且在包含 ISAPI 自动服务程序源文件的项目中调试信息是显式的。

在对 ISAPI 自动服务程序进行实例化时,Foxisapi.dll 将会启动 Visual FoxPro 进行调试,调试过程中允许设置断点、跟踪代码等。

Foxisapi.dll 命令

Foxisapi.dll 命令可用于确定 ISAPI 自动服务程序的状态,以及重置服务程序。下表列出了 Foxisapi.dll 命令,并对每条命令做了说明。

命令 说明
Status 显示 ISAPI 自动服务程序的当前状态、Foxisapi.ini 设置、以及 SingleMode 或 MultiMode 是否有效。
Reset 释放 ISAPI 自动服务程序的所有实例。
SingleMode 执行 Reset 命令,然后将 ISAPI 自动服务程序的实例数限制为 1。可在进行维护时执行此命令;例如当 SingleMode 有效时可以独占方式打开表格。
MultiMode 执行 Reset 命令,然后将 ISAPI 自动服务程序的实例数限制为在 Foxisapi.ini 文件中设置的值。

每一条 Foxisapi.dll 命令都可由 Foxisapi.ini 文件中指定的 URL 调用。以下是 Foxisapi.ini 示例文件的内容,其中的 URL 为默认设置:

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

以下 URL 可执行 Status 命令:

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

在以下的 Foxisapi.ini 示例文件中,Status 命令的 URL 由 Status 改变为 MyStatus:

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

对Foxisapi.ini 文件做了修改后,以下的 URL 可执行 Status 命令:

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

注释 在对 Foxisapi.ini 文件做了修改后,为使所做的修改生效必须用 Reset 命令重置 Foxisapi.dll。

FoxISAPI.ini 的其他设置

Foxisapi.dll 读取 Foxisapi.ini 文件,并根据其中各项配置自身的设置。下表对其他可在 Foxisapi.ini 文件中使用的项目做了说明。

项目 说明
AutoRefreshStatus 指定 Status 页两次刷新之间的秒数。如果没有 Foxisapi.ini 文件或文件中不包含此项,则默认值为 0 秒,即 Status 页不刷新。
BusyTimeout 指定出现超时信息之前 Foxisapi.dll 等待 Visual FoxPro 应用服务程序作出响应的秒数。如果没有 Foxisapi.ini 文件或文件中不包含此项,则默认值为 2 秒。
ReleaseTimeout 指定执行 Reset 命令之前 Foxisapi.dll 等待正忙的 Visual FoxPro 应用服务程序作出响应的秒数。如果没有 Foxisapi.ini 文件或文件中不包含此项,则默认值为 2 秒。

以下是 Foxisapi.ini 示例文件中部分内容,通过它可了解可用于此文件的其他各项的格式:

[FOXISAPI]
BusyTimeout = 5
ReleaseTimeout = 15

注释 在对 Foxisapi.ini 文件做了修改后,为使所做的修改生效必须用 Reset 命令重置 Foxisapi.dll。

Microsoft Internet Information 服务程序配置提示

有两个 Microsoft Internet Information 服务程序注册项,PoolThreadLimit 和 ThreadTimeout,可添加到注册表中,用以提高 Visual FoxPro FoxISAPI 自动服务程序的执行性能。这两个注册项确定了 Internet Information 服务程序最多可创建的线程数,以及线程存在的时间长短。有关它们的详细内容,请参阅 Internet Information 服务程序文档。

www.microsoft.com 站点上有一篇题为“How to Launch Automation servers from ISAPI Extensions” (number Q156223) 的 Microsoft 知识库文章。此文章提供了有关启动 Visual FoxPro ISAPI 自动服务程序这样的自动服务程序时所需的访问安全权限的信息。

Visual FoxPro Internet 服务程序:FoxIs

FoxIs 保存在 Visual Studio ...\Samples\Vfp98\Servers\Foxisapi\FoxIs 目录中。它说明了使用 ISAPI 的功能创建进程外的 .exe 文件或进程内的 .dll 文件的方法,这些文件可在 Visual FoxPro 内部作为独立程序进行访问,也可从自动客户端或 Web 浏览器上访问。对自动服务程序的类进行修改可提高其性能,而不必管它是如何运行的。

若要打开 FoxIs 示例项目

运行 FoxIs 示例

可以用四种方式来运行 FoxIs 示例。当实验这些代码时,最好是按照如下的方式来运行示例:

在 Visual FoxPro 内运行

要在 Visual FoxPro 内运行 FoxIs 示例,请在“命令”窗口中运行如下的代码:

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

要作为一个独立的可执行文件运行

使用如下的代码,可以将该示例连编为一个可执行文件:

BUILD EXE foxis FROM foxis

被编译好的文件 FOXIS.EXE 是一个 Windows 程序,可以将它添加到“开始”菜单上,也可在资源管理器中运行,等等。

作为一个自动服务程序运行

示例被编译成一个可执行文件 .exe 或一个 .dll 文件之后,它就会在 Windows 注册标中作为一个自动服务程序进行注册。从任何一个自动服务控制器(诸如 Excel、Visual Basic 和 Visual FoxPro 3.0)中,您都可在 employee 类的基础上创建一个对象:

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

在一个 Web 浏览器上运行

可以在一个 Internet 浏览器上运行 FoxIs 示例,该浏览器可放在其他的机器上,如运行 MS-DOS 的一台 286,或是一个 Unix 机器,也可以是 Macintosh 或者 Personal Digital Assistant。

使用 Internet 的系统需求

若要从一个 Web 浏览器上运行 FoxIs 示例,您首先必须运行:

如果正在使用 Windows NT 4.0,则需要运行 DCOMCNFG 实用程序来设置 DCOM,这样可给 IIS 服务权限来实例化 OLE 对象。

若要设置 Windows NT 4.0 DCOM

  1. 在命令提示符下,键入 DCOMCNFG,而后回车。

  2. 在“Applications”选项卡上,选择自动服务程序的名字。当要连编该自动服务程序时,默认的应用程序为“employee”。

  3. 在“Distributed COM Configuration Properties”对话框的“Default Security”选项卡上,为每个区域选择“Edit Default”、“Default Access Permissions”、“Default Launch Permissions”和“Default Configuration Permissions”。

  4. 在“Registry Value Permissions”对话框的每个区域上,选择“Add”。

  5. 在“Add Users and Groups”对话框的“Add Names”框中,键入您的 WWW 服务器的名字和您的用户注册名字。

    这样,您可以在 Microsoft Internet Service Manager Properties 窗口中,看到该服务器的名字。如果机器的名字是 FOO,则在“Add Names”框中用下面内容创建一个默认的用户:

    \FOO\IUSR_FOO
    

    如果机器的名字是 FOO,并且作为 HOMER 来注册,当您注册时,则在“Add Names”框中用下面内容创建许可权限:

    \FOO\HOMER
    

为 Internet 访问建立 FoxIs 示例

若要设置 FoxIs 示例,您需要从 FoxIs 项目中创建一个 .exe 或 .dll 文件并将文件复制到 Inetsvr\Scripts 目录中。

若要建立 FoxIs 示例

  1. 打开 FOXIS 项目。

  2. 选择“连编”按钮,然后选择“连编 COM DLL”。

  3. 将 Foxisapi.dll 复制到您的 Inetsrv\Scripts 文件夹中。

初级测试

您可以在不同的级别上测试 FoxIs 示例应用程序,这样可查看是否正确进行了配置。

若要查看代码是否工作

  1. 从“程序”菜单中选择“运行”。

  2. 在 Visual FoxPro 的 Samples\Servers\Foxisapi 文件夹中选择 Main.prg。

  3. 选择“运行”。

若要查看 .EXE 是否工作

  1. 从 Visual FoxPro 的“命令”窗口中,执行如下命令:
    build exe Foxis.exe from foxis
    
  2. 在 Windows 资源管理器中双击 Foxis.exe。

若要查看 FoxIs 自动服务程序是否工作

FOXISAPI 中,将自动服务程序实例化之前,在一个 OLE 控制器(如 Visual FoxPro)内调试服务程序非常容易。

创建 HTML 页面

若要使示例正常开始运行,需要一个 HTML 页面,该 HTML 页面包含对一个 URL 的引用。例如,编写下面的代码,并把它放到 Wwwroot\default.htm 文件中。

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

然后,使用一个浏览器(可以在同一台机器上),并连接到“您的机器名称”的机器上。例如,如果您的机器名字为“foobar”,将键入“foobar”作为要使用的 URL,这将在名字为“foobar”的机器上产生 Default.htm 页面。

这时,会初始化一个 CreateObject("foxis.employee") 对象,并激活该对象上的 Startup 方法程序,此方法返回一个生成的 HTML 页面。如果还没有创建“ISAPI 自动服务程序”,Foxisapi.dll 会返回一个 HTML 错误页面。

然后使用您的 web 浏览器访问上述的 herf 标识中的网址。如果得到一个 HTML 错误页面,标明“Foxisapi error”,这时您就知道了 DLL 正在被加载,它已经开始工作了。

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

实际上,您可以放入任何有效的 MS-DOS 命令,该命令都会在服务程序所在的机器上执行。如果命令为“Reset”(默认),这将使 ISAPI 自动服务程序释放第一个实例,同时释放它自己,从而完全释放了 ISAPI 自动服务程序。

另外,您可以计算任意的 Visual FoxPro 表达式。但是,如果 Visual FoxPro 表达式显示了一个模式界面(如 MESSAGEBOX( ) 函数所作的那样),自动服务程序就会挂起,等待一个不能由机器提供的响应。但是,对于一个进程内的 .dll 文件,Visual FoxPro 自动地管理其模式界面并且自动服务器不会挂起。

<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>

调试服务程序

Windows NT 没有 Desktop,因此在服务程序的机器上就没有用户界面。这就意味着您在使用服务器应用程序之前,需要对它们进行调试。

若要使用 Visual C++ 5.0 跟踪 Foxisapi.dll

  1. 打开 Foxisapi.mak 文件。

  2. 将注释符号从 HttpExtensionProc 的下面代码中去掉:
    //    _asm int 3
    
  3. 重新连编项目。

  4. 使用 Inetinfo.exe 的过程 id (PID) 号开始运行 MSDEV。您可以在 Windows NT Task Manager 中获得此过程 id 号。

以上过程使用于 Windows NT 4.0。

提示 在调试中,无须关闭 web 服务器来改变自动服务程序,而向 cmd 方法程序发送一个重新设置值,可以只终止进程外的组件,正如上面描述的那样。也可以使用 Win32 SDK 的工具 TLIST、KILL,或者使用 Windows NT 4.0 的 Task Manager。

ISForm 类

本示例的“engine”是 Isapi.vcx 文件中的 ISForm 类。

ISForm 类的入口点

下面的方法程序可以从 Web 浏览器上调用,并通过 FOXISAPI.DLL 来返回 HTML 页面。

方法程序 返回
Cmd 计算一个 Visual FoxPro 表达式或者 MS-DOS 命令的结果。
DoSave 保存用户对数据的改变,并返回雇员的 HTML 页面。
Skipit 表中指定雇员的信息。Skipit 将所传递的 cookie 信息作为 Web 浏览器使用的一个参数,检查 cookies 表寻找前一个记录号码,并根据 cookies 表中存储的记录号码,将记录指针向前或向后移动。新的记录号码再写回 cookies 表中,然后调用 GenHTML 方法程序。
Startup 表中第一个雇员的信息。Startup 为用户创建一个新的 cookie id 号,并将它作为 HTML 中一个隐藏的输入区域传送回来。

保持服务程序的活动状态

一般来说,对一个 web 客户的每个请求,都将自动服务程序实例化,并产生一个 HTML 页面,再通过调用 Foxisapi.cpp 中 CallObject( ) 的 Release( ) 将其释放。对每个请求来说,这意味着整个 Visual FoxPro 运行时间都要启动和关闭服务程序。

如果自动服务器作为 Multi-Use 注册,而且没有调用 Release( ),那么第一个请求会启动服务程序,而接下来的请求会使用相同的服务程序实例,这会提高性能。在 Foxisapi.dll 中,以及 ISForm 的 Load、Cmd、DoSave、Startup 和 Skipit 方法程序中,代码用来管理同一个活动的服务程序实例。

在 DLL 中的变量

有两个变量被声明:pdispObj 和 pdispDoRelease。当初始创建服务程序时,pdispObj 作为 OLE 对象的发送句柄,而 pdispDoRelease 变量被设置为和 pdispObj 相同的值,并以引用传递的方式作为参数传给 ISForm 服务程序的方法程序,Web 浏览器需要使用该参数。Visual FoxPro ISForm 自动服务程序中的代码改变了 pdispDoRelease 的值。

提示 有关本示例的详细内容,请参阅 ISForm 和 FOXISAPI.CPP 中的代码注释。

表单的 Load 事件

当创建 ISForm 时,Load 事件代码创建两个公共变量:gpInstancegpDisp。当第一次装载 ISForm 服务程序时,变量 gpInstance 被设置为 1,接下来的实例依次增加该变量。当释放实例时,依次减少该变量。

输入点的方法程序

当通过 Foxisapi.dll 激活 ISForm 的一个方法程序(Cmd、DoSave、Skipit 或者 Startup)时,.dll 将一个发送指针作为参数,以引用传递方式传给此方法程序。

第一次运行服务程序时,实例计数器设置为 1,同时将发送指针存储到全局变量中,并将发送指针的值存为 0。

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

这时,两个变量指向同一个发送指针的值:在 ISForm 自动服务程序中的 gpDisp 以及 Foxisapi.dll 中的 pdispObj。在 .dll中的 pdispDoRelease 值为 0,它随 ISForm Automaiton 服务程序具体情况而变化。

接下来继续调用服务程序时,实例计数器的值增加,在 .dll 中产生一个新的 pdispObj,并存储到 pdispDoRelease 中,通过引用传递方式传给所需要的方法程序。因为这时 gnInstance 值不是 1,因此不改变 gpDisp 变量的值。从这时起,自动服务程序中的 gpDisp 开始和 .Dll 中的 pdispObj 和 pdispDoRelease 值不同。

在 DLL 中的代码

在 Foxisapi.cpp 中,下面的 C++ 代码对服务程序的释放进行管理。在创建了第一个实例之后,由于 pdispObj 和 pdispDoRelease 被设置为相同的非 0 值,所以接下来的实例通常用 Foxisapi.cpp 中 CallObject( ) 的 Release( ) 调用来释放。

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

      }
   }
}

ISForm 的 Destroy 事件减少实例计数器的值。当只剩下一个实例时,pdispDoRelease 被设置为 0,并且当 pdispObject 和 pdispDoRelease 相等时,不会调用释放代码,后面的实例被释放了,但原始的实例却依然保留。

释放服务程序

如果要强制释放服务程序,则 pdispDoRelease 不能为 0,而且必须和 pdispObject 不相等。下面的 HTML 文本向服务程序发送一个值,会导致将服务程序释放:

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

在 cmd 方法程序中,下面的代码将 pdispDoRelease 值设置为第一个实例的发送值:

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

在 .dll 中的代码会释放当前的实例,同时保存原始的实例,防止在 Visual FoxPro 运行时刻每次调用服务程序时,重新加载服务程序。

向客户程序送回 HTML

每个入口方法程序都调用 ISForm 类的 GenHTML 方法程序。从 GenHTML 方法程序返回的 HTML 通过 Internet Information Server 会返回给 web 浏览器。

如果传递给 GenHTML 方法程序的模式参数不是“FORM”,则 GenHTML 方法程序只在表中简单地查询此值,并传送回预先格式化的 HTML。

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

如果模式参数是“FORM”,则在 GenHTML 中的代码标识每个表单上的标签和文本框,按照从上到下、从左到右的顺序将它们分类,计算这些控件的 Captions 和 ControlSources 属性值,然后使用 Visual FoxPro 的文本合并功能创建相应的 HTML 文本,以满足表单的显示要求。

如果向表单上添加附加的标签和文本框,它们会在生成的 HTML 上自动显示。

创建并使用 Cookies

本应用程序作为一个 web 服务器,它可以被多个客户几十次的调用,同时我们需要跟踪用户的状态。这时,我们只需跟踪用户的当前记录号。可以为用户提供一个注册屏幕,将用户名作为 cookie 的一个关键字,但是这里我们在 MakeCookie 方法程序中生成了一个 cookie 值,并将它作为 HTML 的一个隐藏值传送回用户。每次用户选择运行不同的记录时,可从传送到 .dll 的 HTTP 字符串中读取这个 cookie 值,在 Cookies 表中找到这个 cookie,查出当前的记录号,并根据这个号来移动记录。

在 cookie 操作过程中,使用了下面的属性和方法程序:

错误处理

如果发生了一个错误,ISForm 类的 Error 事件代码会调用带有“ERROR”参数的 GenHTML 方法程序。GenHTML 会读取预先格式化的 HTML 错误文本,并将它返回给 Error 事件代码。Error 事件代码将错误信息代替 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

当 ErrorHTML 属性非空时,GenHTML 将 ErrorHTML 的值传送回客户。

在 FoxIs 示例中使用的表

在 FoxIs 中,除了用来进行数据输入和显示的 employee 表外,还使用了如下的表。

说明
HTML 作为 FoxCMD 和 DosCMD 计算结果的头部或万一出现错误时,保存要传送给 Web 浏览器的 HTML 文本。
Cookies 对不同的 Web 浏览器跟踪记录号。这个唯一的 cookie 字段值作为 HTML 文本中的一个隐藏值传递给特殊用户。