Tivoli 服务台 6.0 开发工具包脚本程序设计指南
本章介绍使用 TSD 脚本联网扩展语句来跨网络通信所必要的基本概念。本章也描述特殊联网概念和 TSD 脚本联网语句以及常量。
这些 TSD 脚本语句可用来为已安装的应用程序定制源代码或创建自己的自定义 TSD 脚本分布式应用程序。
尽管本章涉及 TSD 脚本语言和联网原则的一些基本方面,我们仍假定您熟悉这两领域。如果正修改应用程序,您可能希望与已定制过其它应用程序或已使用过 TSD 脚本和开发工具包的人合作。
TSD 脚本语言中包括的语句允许两种不同类型的联网结构:
在本章中,TSD 脚本联网服务的描述一般都适用于两种结构。在两种结构间有区别处,会给出声明。
有很多术语用来描述网络上计算机间的交互。尽管您可能熟悉这些术语中的一些或全部,在与 TSD 脚本联网扩展一起使用的上下文中还特别定义它们。
当两台机器都既充当客户机又充当服务器时,产生双向通信。换句话说,机器 A(客户机)可请求机器 B(服务器)执行一些服务。反过来,机器 B 可转换角色,而成为客户机,请求机器 A 执行一些服务。另见反向连接的定义。参见对等。
客户机是从服务器请求服务的应用程序。客户机的一个实例是网络上连接到文件服务器的工作站。该连接由客户机启动。
连接是客户机和服务器之间的逻辑链接。
事件处理器是特殊的 TSD 脚本函数,用于处理异步事件。事件处理器在服务器上运行,来处理要求服务的网络请求。
每个连接有一个句柄。句柄包括关于客户机机器和服务器正提供的服务的信息。
TSD 脚本服务器是运行在提供服务的已联网计算机上的 TSD 脚本进程。
本地事件处理器是在本地机器上操作的事件处理器。如果此事件处理器正为来自不同机器的请求服务,则此机器是服务器。
NETx 语句,即扩展,是以前缀 NET 开头的 TSD 脚本语句。创建这些语句以允许 TSD 脚本应用程序跨网络通信。
对等环境是单个机器既可充当客户机又可充当服务器的环境。
注册事件处理器把处理器和事件源相联系。
在对等环境中,当服务器请求客户机执行一些有效转换客户机和服务器的角色服务时,可建立反向连接。要处理此通信,在本地和远程服务器间建立反向连接。
服务器是向客户机提供服务的机器。服务器的一个实例是已联网的打印机。
服务是由服务器执行的功能。如果打印机是服务器,它提供的服务是打印。
在整个 TSD 脚本和开发工具包中,使用事件处理器以支持事件驱动环境。在事件驱动环境中,事件(如击键、鼠标点击或网络消息)触发应用程序的响应(如打开一个新对话框或选择字段中的一项)。要处理事件,每个应用程序使用为它们特殊设计的事件处理器。
使用事件处理器的应用程序不必询问或“轮询”网络事件。正常情况下,事件处理器“休眠”(不活动)直到发生事件,然后处理要求服务的请求。
单个服务器可有多个事件处理器。每个事件处理器提供特定服务或一组相关服务,在本章的后面部分解释这些内容。
在 TSD 脚本程序的例程段中定义事件处理器。必须把网络事件处理器说明为 NETCONNECTION 类型。
此事件处理器类型不同于缺省类型 WINDOW。由于类型决定使用的 $Handle,只有类型为 NETCONNECTION 的事件处理器可和 NETx 语句一起使用。
NETCONNECTION EVENT TalkConnectEvent(REF whdl: WINDOW )IS
当定义事件处理器时,必须也注册它的服务,这在下面部分中说明。注册事件处理器把处理器与事件源相联系。
有两个不同的语句可用来注册事件处理器:
用 NetRegister 注册的事件处理器称作 NetRegister 事件处理器。用 NetListen 注册的事件处理器称作 NetListen 事件处理器。
本章集中说明 NetRegister 的使用,它频繁用于“标准”事件处理器。要定制事件处理器,请参见本章的“高级语句”部分。
必须用服务器注册事件处理器,使它能接收和处理要求服务的请求。要用 NetRegister 语句注册事件处理器,使用下列语法:
NetRegister( TalkConnectEvent, 'Talk' );
当注册事件处理器时,指定它提供的服务的名称。服务是事件处理器执行的操作的类型。
在下例中,为 TalkConnectEvent 网络事件处理器定义的服务名称是 Talk。
NETCONNECTION EVENT TalkConnectEvent(REF whdl: WINDOW )IS ACTIONS . .. END; NetRegister( TalkConnectEvent, 'Talk' );
除了前面提到的服务,还支持端口号码扩展,它指定 IP 端口。端口号码控制下列端口:
缺省端口是 5001,缺省服务是 asenet/tcp。如果该服务在服务文件中,使用 asenet/tcp,而不使用缺省号码。
可在命令提示中使用下列命令指定端口号码:
/p=nnn
从命令提示发出的端口号码覆盖缺省端口和缺省服务。
注:对客户机和服务器端口号码必须相同。
用带有定义为零长度字符串('')或
$Unknown 的服务可创建事件处理器。这种类型的服务称为通配符服务。
当在服务器上定义通配符服务时,对于客户机指定的,而服务器不能找到匹配的服务名的任何请求,通配符服务满足它们。
也可在客户机上定义通配符服务。在这种情况下,服务器必须有服务名为''或 $Unknown 的服务。
注:只有用 NetRegister 语句注册事件处理器时,才可定义通配符服务。(NetListen 总使用通配符服务。)
当注册事件处理器时,在服务器上定义该服务的模板。此模板包括来自两方面的信息,其一是来自代码例程段中的事件处理器的定义,其二来自当注册事件处理器时指定的信息。
直到请求连接时,模板保存在存储器中。然后使用模板中的信息,以用具体例证说明连接的服务。
对模板所作的更改有两种基本类型:
任何时侯,需要更改模板时,都可重新注册事件处理器或注册其服务。当重新注册事件处理器时,新参数值立即生效。为模板打开的所有新连接将使用新值。对模板的更改不影响现有的连接。
警告:必须把服务名指定为在原模板中指定的名。否则,NetRegister 语句为事件处理器创建一个新模板,不修改现有的模板。
一旦创建了模板,它立即并连续可接受要求服务的请求。但是,在任何时侯,可使模板停止响应要求服务的请求。要这样作,必须用特殊的事件处理器 $NullHandler 重新注册服务:
NetRegister ($Nullhandler, '服务');
在此语法中,"服务"是与要停止的事件处理器相关联的服务名称。
在用 $NullHandler 重新注册服务后,忽略将来自模板的要求服务的请求,但不影响使用该模板的任何现有连接。
如果需要重新启动服务器,则必须重新注册事件处理器及其服务。
事件处理器可服务于与许多不同客户机的连接。只通过查看连接句柄,要确定正在执行的服务可能很困难。
同样,要确定哪个服务器正执行服务或哪个客户机正接受服务可能也很困难。对于 NetListen 事件处理器(它响应其收到的每个要求服务的请求并共享其实例数据)情况更是如此。
TSD 脚本提供两个语句,用来从连接句柄获得关于主机(服务器)和服务的信息:
因为 TSD 脚本支持客户机/服务器结构和对等结构,无论远程机器是否充当服务器,NetGetHostName 语句都可得到关于远程机器的信息。
如果在客户机上调用 NetGetHostName 语句,您将得到关于服务器的信息。如果在服务器上调用 NetGetHostName 语句,您将得到客户机的名称。
在任何服务器上,可能有许多 NETCONNECTION 事件处理器。有时,用户可能需要在它们之间传递消息。因为跨网络发送这些消息效率不高,开发工具包提供 NetLoopBack 语句。NetLoopBack 允许用户把消息从本地机器发送到网络事件处理器。
TSD 脚本联网应用程序使用基于连接的协议。通过连接进行网络上机器间的交互。服务器要向客户机提供请求的服务,连接必须打开。
在每个连接中有三个元素:
这三个元素的组合使连接唯一。打开和关闭连接的进程涉及其中每个元素。
在客户机和服务器间可以打开多个连接。但是,对服务器/端口上的特定服务,一个客户机只能打开一个连接。
注:如果客户机和服务器上的特定事件处理器间的连接已经打开,则请求特定服务时返回现有连接的句柄。
在注册事件处理器及其相关服务后,服务器就绪,可以接收要求指定服务的请求。
此部分描述打开连接的进程,并列出打开连接所用过程的步骤。
打开连接的过程和每一步骤的解释如下。
当客户机请求服务时,该客户机必须指定它需要的服务的确切名称。(当在服务器上注册事件处理器时,定义了此服务的名称。)没有服务器提供的可用服务的综合列表,服务名称不区分大小写。
可把端口指定为服务字符串的一部分。如果没有指定端口,则使用缺省值。
通过指定零长度字符串或 $Unknown,客户机可请求通配符服务。在这种情况下,服务器必须有服务名称为 NetListen 或 $Unknown 的服务,来满足请求。
注:如果客户机请求了未在服务器上定义的服务,及如果有通配符服务或定义了 NetListen,则服务器把客户机的请求与通配符服务相匹配。
如果客户机不能与服务器通信,则 HOST_UNREACHABLE 错误代码(-13)返回给客户机。
如果 TSD 脚本服务器没有运行,则把 -13 HOST_UNREACHABLE 错误代码返回给客户机。
如果已经建立连接,则把 TRUE 返回给客户机。还返回连接的句柄。
如果找到匹配的服务名称,服务器向客户机返回句柄。该句柄指向提供此服务的模板的拷贝。当客户机接收到句柄时,它可以继续其处理。
如果服务器找到通配符服务,则服务器把句柄返回给客户机。该句柄指向提供通配符服务的模板的拷贝。当客户机接收到句柄时,它可以继续其处理。
如果找到 NetListen 事件处理器,把句柄返回给客户机,该句柄描述到客户机机器的连接。如果找到,则句柄直接指向 NetListen 事件处理器。当客户机接收句柄时,它继续处理事件数据。
如果找到 NetListen 事件处理器,转至步骤 10。如果没有找到 NetListen 事件处理器,继续执行步骤 8。
一旦在服务器上处理了 $MsgNetConnect,则连接打开并可使用服务。
关闭连接的进程通常由客户机启动。但是,服务器也可启动关闭。在两种情况下,都使用 NetClose 语句以关闭连接。
注:如果客户机或服务器停机,它们之间的连接终止。要重新建立机器间的通信,必须重新打开连接。
当客户机关闭连接时,下列进程发生:
注:如果事件处理器是 NetListen 事件处理器,则没有为连接特别定义的实例数据。当句柄标记为关闭时,关闭进程完成。不发送 $MsgNetDestroy 消息。
如果客户机或服务器程序结束,或网络断开,仍进行步骤 2 和 3。
如果服务器启动关闭连接,则不存在从服务器返回给客户机的通信。
下次客户机试图与服务器通信时,客户机检测到关闭并产生错误消息,如“无效句柄”。
在对等环境中,NetClose 关闭客户机连接和服务器连接。
实例数据是用户定义的、与连接相联系的 TSD 脚本数据。当创建连接时,创建实例数据;当关闭连接时,破坏实例数据。
对连接的每个消息,事件处理器都接收对实例数据的引用。实例数据存储对连接特定的信息。
当用 NetRegister 注册事件处理器时,可为该事件处理器的实例数据指定初始值。所有为模板打开连接接收实例数据的拷贝,该实例数据初始化为指定的值,如果没有提供初始值,则初始化为 $Unknown。
当指定实例数据时,记住下列内容:
例如:
connectionData is Record callCount = INTEGER; . . . END;
NETCONNECTION EVENT MyEvent (REF data: ConnectionData); ACTIONS When $Event IS $MsgCreate Then data.callCount=1; . . . END; END; StmtData : ConnectionData; NetRegister( MyEvent {StartDate}, 'Service');
当连接打开时,在连接的模板副本中用实例说明为事件处理器定义的实例数据,并给实例数据分配初始值。此进程称作初始化。
如果把模板中实例数据的值设置为 $Unknown,则意味着不进行初始化。
如果不为实例数据的初始值设置值,则也不进行初始化。如果不设置值,初始值假定为 $Unknown。
单个 NetRegister 事件处理器可能有多个打开的连接。这些连接中的每一个有其自己实例数据拷贝。
在任何时侯,不管服务器当前是否正在处理前面的请求,客户机都可以向服务器发送请求。取决于客户机要求服务器响应的速度,以及客户机是否要求从服务器返回数据,客户机可使用阻塞或非阻塞语句发送其请求:
当服务器接收请求时,它把请求添加到其队列中。当可以处理时,服务器按接收请求的顺序处理请求。(在有些情况下,服务器可能把队列中的阻塞消息放在非阻塞消息的前面)。取决于网络的条件,可能要过一段时间,服务器才能服务于请求。
如果发送给服务器的语句是阻塞语句,则直到在服务器上完成整个进程,才向客户机返回信息。
SendMessage 是 TSD 脚本中唯一的阻塞语句。
为防止客户机和服务器间发生死锁,一次在连接上只能有一个 SendMessage 活动。
如果发送给服务器的语句是非阻塞语句,则当把该语句添加到队列中时,服务器向客户机返回回答,指示“收到请求”。然后客户机可继续其处理。
下面列出几个非阻塞语句:
可以选择阻塞语句或非阻塞语句来和服务器通信。选择任何一种类型都需要意识到下列风险:
在 TSD 脚本和开发工具包中,广泛使用句柄来跟踪窗口和网络活动。
带有 SendMessage 或 PostMessage 语句的连接需要句柄。这些语句分别是阻塞和非阻塞语句。这种特性决定客户机和服务器的行为。
当服务器查找带服务(该服务与客户机请求的服务匹配)的事件处理器模板时,服务器打开句柄。句柄包括在 $Handle 参数中,并传递给服务于连接的事件组。
当服务器关闭自己一端连接时,它把句柄标记为已关闭。如果试图访问已关闭的连接,会收到一条错误消息(Invalid_Handle)。
在客户机/服务器和对等结构中都可使用 TSD 脚本 NETx 语句。有两种格式的 NetConnect 语句可处理这些不同的结构。
在客户机/服务器体系结构中,客户机必须指定主机名和服务,这样服务器才能对客户机的请求做出响应并返回所请求的服务。
FUNCTION NetConnect(REF hndlHost: NETCONNECTION, .VAL hostName: STRING, . VAL service: STRING .): INTEGER;
在对等结构中,要响应客户机,服务器必须打开返回的连接。对等格式实际是创建返回连接的快捷方式。此格式是可选的;通过使用客户机/服务器格式可得到相同的结果。
FUNCTION NetConnect( VAL hndlHost: NETCONNECTION ): INTEGER;
对等连接只需要一个句柄。该句柄将包括关于连接的所有数据。
欲获取 NetGetHostName 或 NetGetService 的详细说明,请参见下一章。
使用 $Handle 常量向远程服务器发送回答。可使用下列语句初始化返回的连接:
NetConnect( $Handle );
到现在为止,本章集中说明使用 NetRegister 语句创建和注册事件处理器这一“标准”方法。对于需要对连接进行更多控制的应用程序,TSD 脚本提供替代语句组,它们可一起使用来注册事件处理器。这些语句是:
NetAccept 事件处理器与 NetRegister 事件处理器非常相似。
注:不一定要使用 NetListen 或 NetAccept 语句以达到完全功能的联网应用程序。
此表总结 NetRegister 和 NetListen 事件处理器的差异。
因为 NetListen 不为每个连接创建新实例数据,通过 NetListen 打开连接的进程稍微要快一些。
对于不需要在消息间维护上下文的轻量级服务,NetListen 非常适用。
比较项 | NetRegister | NetListen |
事件处理器数目 | 在一个服务器上可同时运行很多 NetRegister 事件处理器。 | 对一个服务器只能定义一个 NetListen 事件处理器。 |
已注册的服务 | NetRegister 事件处理器是用特定服务注册的。客户机必须准确请求该服务名称,以得到与相应模板匹配的服务。 | 没有特定的服务与 NetListen 事件处理器相关联。只有在服务器上没有其它匹配模板的情况下,才用 NetListen 事件处理器进行服务匹配。 |
模板 | 当注册 NetRegister 事件处理器时,创建它的模板。该模板包括所有的连接特定信息。 | 当注册 NetListen 事件处理器时,不创建模板。必须由应用程序维护连接特定信息。 |
实例数据 | 每个连接有其自己的实例数据拷贝。 | 为事件处理器定义了一组实例数据。为该事件处理器打开的每个连接共享该实例数据。 |
端口 | 服务可使用替代端口。 | 服务可能只使用缺省端口。 |
在一台服务器上可能同时运行着一个 NetListen 事件处理器和一个 NetRegister 事件处理器。因为客户机不知道如何服务于请求,所以客户机不能特定请求使用哪个事件处理器。
对于不需要为连接维护上下文信息的服务,使用 NetListen 事件处理器。相对于 NetRegister 事件处理器,NetListen 事件处理器需要的服务器资源稍微少一些,且创建连接稍微快一些。
只有找不到其它匹配(包括通配符模板)时,才使客户机的请求与 NetListen 事件处理器匹配。客户机把服务名称发送给服务器上的 NetListen 事件处理器。NetListen 事件处理器必须用 NetGetService 查询服务的句柄。
但是,客户机不保证服务器支持该服务。
既然每个连接与其它打开的连接共享相同的实例数据,则可能同时打开多个 NetListen 连接。因此,当关闭一个 NetListen 连接时,不破坏实例数据。
当关闭一个 NetListen 连接时,需要清除正在关闭的连接的资源。
每个 NetListen 连接的句柄有一些信息,该信息是关于客户机正在请求的特定类型服务的。
NetListen 事件处理器不把实例数据与每个连接相关联。相反,用户必须跟踪每个连接及其活动。跟踪单个连接的能力是使用 NetListen 语句注册事件处理器的附加好处。
为 NetListen 打开的每个连接共享为 NetListen 事件处理器定义的实例数据的拷贝。如果要把特定的实例数据组与一个打开的 NetListen 连接相关联,可为该连接调用 NetAccept 语句。
注:只可为 NetListen 连接调用 NetAccept。用户使用句柄访问连接。NetAccept 也可把一个新事件处理器与连接相关联。
与连接相关联的实例数据不能和任何以下情况的其它连接一起使用:当前为 NetListen 事件处理器打开或将来有可能为 NetListen 事件处理器打开。一旦用户调用 NetAccept,则连接更改。
要求相同的主机/服务对的所有请求直接转至新事件处理器。
注:用户可能发现使用 NetRegister 更容易,因为 NetListen 和 NetAccept 的组合达到相同的结果。
本实例演示如何在两台联网的计算机间建立简单的对话程序。本程序演示在对等环境中两台机器间的交互。
KNOWLEDGEBASE NetTalk;
CONSTANTS menuList IS { '~File', 'e~Xit', '', '~Host', '~Open', '', '~Help', '~About', '' }: LIST OF STRING; MsgUserChar IS $MsgUser; MsgRemoteChar IS $MsgUser + 1; MsgTalkClose IS $MsgUser + 2;
ROUTINES
EVENT TalkMainEvent; FUNCTION CreateTalkWindow( VAL host: NETCONNECTION ) : WINDOW; PROCEDURE NetTalkMain;
PRIVATE TYPES TALK_RECORD IS RECORD xLen: INTEGER; -- Width of window in characters yLen: INTEGER; -- Height of window in characters whdlMe: WINDOW; -- Window where local input is displayed whdlYou: WINDOW; -- Window where remote input is displayed host: NETCONNECTION; -- Handle host END;
PANNEL_DATA IS RECORD whdlParent: WINDOW; curX: INTEGER; -- X location of cursor on the window curY: INTEGER; -- Y location of cursor on the window lines: LIST OF STRING; -- List of all lines being edited END;
ROUTINES
NETCONNECTION EVENT TalkConnectEvent(REF whdl: WINDOW )IS VARIABLES result : INTEGER;
ACTIONS WHEN $Event IS $MsgNetConnect THEN -- Create a talk window. -- Create a connection to service this talk session result := NetConnect( $Handle ); IF result < 1 THEN WinMessageBox(whdl,'Error',$MBOk + $MBIconError, 'Connection failed ERROR ' & result ); Exit( 0 ); END; whdl := CreateTalkWindow( $handle ); IF whdl = $UNKNOWN THEN WinMessageBox(whdl,'Error',$MBOk + $MBIconError, 'Window creation failed' ); NetClose( $Handle ); Exit( 0 ); END; ELSWHEN MsgRemoteChar THEN -- Pass the character from the remote machine to the talk window SendMessage( whdl, MsgRemoteChar, $KeyCode ); ELSWHEN MsgTalkClose THEN NetClose( $Handle ); ELSWHEN $MsgNetClose THEN -- When the windows close on the remote machine clean up here SendMessage( whdl, $MsgClose ); NetClose( $Handle ); END; END;
EVENT TalkMainEvent IS VARIABLES host : NETCONNECTION; hostName : STRING; result : INTEGER;
ACTIONS WHEN $Event IS $MsgCreate THEN WinSetMenuBar( $Handle, menuList ); ELSWHEN $MsgMenu THEN WHEN $MenuSelection IS 101 THEN SendMessage( $Handle, $MsgClose ); ELSWHEN 201 THEN WinEditField($Desktop, hostName, 0, 0, 40, 'Enter host name', BitOr($WinTitle, $WinBorder, $WinAutoPos ) ); -- Create a talk connextion to hostname result := NetConnect( host, hostName, 'Talk' ); IF result <> 1 THEN WinMessageBox($Handle, 'Error', $MBOk + $MBIconError, 'Connection failed ERROR ' & result ); END; END; END; END; EVENT TalkPannelEvent( REF pannelData: PANNEL_DATA ) IS ACTIONS WHEN $Event IS $MsgCreate THEN pannelData.curX := 1; pannelData.curY := 1; ListInsert( pannelData.lines, '' ); ELSWHEN $MsgPaint THEN -- Clear window, and re display contents WinSetFont($Handle, 'System Monospaced', 10, 0 ); WinClear($Handle ); WinWriteLn($Handle, pannelData.lines ); ELSWHEN $MsgChar THEN -- The parent window processes all characters entered SendMessage(pannelData.whdlParent, $MsgChar, $KeyCode ); ELSWHEN MsgUserChar THEN WHEN $KeyCode IS $KeyReturn THEN -- Enter key is a new line pannelData.curX := 1; pannelData.curY := pannelData.curY + 1; ListInsert(pannelData.lines, '' ); ELSE -- Add character to current line, and display it WinSetFont($Handle, 'System Monospaced', 10, 0 ); WinGotoXY($Handle, pannelData.curX, pannelData.curY ); WinWrite($Handle, Char( $KeyCode ) ); pannelData.curX := pannelData.curX + 1; pannelData.lines[ $CURRENT ] := StrInsert(pannelData.lines [ $CURRENT ], Char( $KeyCode ), 1000 ); END; END; END;
EVENT TalkEvent( REF talkData: TALK_RECORD ) IS VARIABLES pannel : PANNEL_DATA; yLen : INTEGER;
ACTIONS WHEN $Event IS $MsgCreate THEN -- Create 2 display panels for local, and remote characters and pass in parent pannel.whdlParent := $Handle; yLen := talkData.yLen / 2; WinCreate($Handle, talkData.whdlMe, TalkPannelEvent{ pannel }, 0, 0, talkData.xLen, yLen, '', $WinField ); yLen := talkData.yLen - yLen; WinCreate($Handle, talkData.whdlYou, TalkPannelEvent{ pannel }, 0, yLen + 1, talkData.xLen, yLen,'', $WinField ); ELSWHEN $MsgDestroy THEN PostMessage( talkData.host, MsgTalkClose ); ELSWHEN $MsgSize THEN -- Position and size panels to fit window when it is resized talkData.xLen := $EventParm( 1, INTEGER ); talkData.yLen := $EventParm( 2, INTEGER ); yLen := talkData.yLen / 2; SendMessage(talkData.whdlMe,$MsgSetSize talkData.xLen, yLen); yLen := talkData.yLen - yLen; SendMessage(talkData.whdlYou,$MsgSetSize, talkData.xLen,yLen ); SendMessage(talkData.whdlYou,$MsgMove,1, yLen + 1 ); ELSWHEN $MsgChar THEN -- Send local characters to top pannel for display SendMessage(talkData.whdlMe, MsgUserChar, $KeyCode ); -- also send character to remote host to display PostMessage(talkData.host, MsgRemoteChar, $KeyCode ); ELSWHEN MsgRemoteChar THEN -- Send remote character to bottom pannel for display SendMessage(talkData.whdlYou, MsgUserChar, $KeyCode ); ELSWHEN $MsgPaint THEN WinClear( $Handle ); END; END;
FUNCTION CreateTalkWindow( VAL host : NETCONNECTION ) : WINDOW IS VARIABLES whdlNetTalk: WINDOW; talkData: TALK_RECORD; result: INTEGER;
ACTIONS talkData.host := host; result := WinCreate($Desktop, whdlNetTalk, TalkEvent{talkData}, 0, 0, 0, 0, NetGetHostName(host), BitOr($WinBorder, WinTitle, $WinResize, $WinSysMenu, $WinAutoSize, $WinAutoPos, $WinTaskList)); IF result < 1 THEN WinMessageBox($Desktop, 'Error', $MBOk + $MBIconError, 'Cannot create talk main window. Error: '&result ); END; EXIT( whdlNetTalk ); END;
PROCEDURE NetTalkMain IS VARIABLES whdlNetTalk: WINDOW; result: INTEGER;
ACTIONS result := WinCreate($Desktop, whdlNetTalk, TalkMainEvent, 0, 0, 40, 0, 'Network talk program', BitOr($WinBorder, $WinTitle, $WinResize, $WinSysMenu, $WinMenu, $WinTaskList)); IF result < 1 THEN WinMessageBox($Desktop, 'Error', $MBOk + $MBIconError, 'Cannot create talk main window. Error: ' &result ); END; NetRegister( TalkConnectEvent, 'Talk' ); WinWait( whdlNetTalk ); END;
Tivoli 服务台 6.0 开发工具包脚本程序设计指南