系列文章目录
综述: https://blog.csdn.net/m0_54284125/article/details/132774505
AS400: https://blog.csdn.net/m0_54284125/article/details/132778839
SAP: https://blog.csdn.net/m0_54284125/article/details/132778954
Lotus Notes: https://blog.csdn.net/m0_54284125/article/details/132779011
网页: https://blog.csdn.net/m0_54284125/article/details/132779052
Dynamics365: https://blog.csdn.net/m0_54284125/article/details/132779089
通用桌面应用: https://blog.csdn.net/m0_54284125/article/details/132779109
RPA从小白到大师之一:AS400绿屏5250终端仿真器自动化
前言
IBM的AS400是非常经典的商用服务器,发源于上世纪70年代,历经半个世纪,至今仍在售(不过改名Power i系列了)。访问AS400, 用的是终端仿真器(Emulator)。 对仿真器做RPA工具,与常规的Windows区别还是比较大的,本篇就来全面介绍一下如何开发AS400 PC5250仿真器的RPA程序。
一、关于仿真器
1. 什么是仿真器
这里说的"仿真器",也就是俗称的“绿屏”,是一个用来连接主机的程序。长得象这样(很容易理解为什么叫绿屏,因为黑底绿字啊):
好好的一个电脑程序,为什么要叫仿真器呢,听起来象电子行业里的设备一样。说来话长,计算机发展初期,个人电脑还没问世,大中型主机盛行,要访问主机靠的是终端(Terminal), 长这个样子:
终端没什么计算能力,它的作用就是连接到主机(通过同轴电缆),将用户端的输入传送给主机并将主机的反馈显示给用户。
等到个人电脑发展起来,主机与终端的关系跟着演化,主机(Host)变成了今天的“服务器”(Server),终端也由个人电脑来代替。为了兼容之前的系统,在个人电脑上开发出程序,模拟当初“终端”的行为,这个程序就是终端仿真器
,简称仿真器。
那经常在IBM文档中看到的什么PC3270,PC5250仿真器又是什么意思呢?其实这些代号是当年实体终端的型号。比如上面那张图片就是5250终端。下面这个是3270终端:
可以想象,不同的终端显示格式和样式是有区别的,所以要有对应的仿真器。不过多数是兼容的,所以并不是每一款终端都一定会有对应的仿真器。对IBM,最常见的仿真器是PC5250, PC3270. 当然了,市面上也有其它厂家生产终端,比如说DEC的VT系列也很出名,所以也有对应的VT终端仿真器
2. 常用的IBM5250仿真器
既然仿真器只是一个电脑程序,而且仿真的终端又很清楚,所以显然会有不同的公司(个人)开发不同版本的仿真器。
对于RPA, 当然是优先IBM自己的仿真器,有PCOMM和ACS两个系列。
- PCOMM系列
PCOMM是Personal Communications的简称。 实际上这个系列分两个阶段。在V6.0及之前,它是IBM i Access for Windows的一部分。再后来就独立出来了,目前最新版本是15.0.
IBM i Access for Windows在2019年已经停止支持,官方说法是该程序只支持到Windows8 (以本人的实际经验,Windows 10上也是可以的,Windows11不知道是否还行)。
上面那张绿屏的图就是PCOMM V6.0的,不同的版本外观所说是没什么变化(本人实际使用过的只到V6.0) - ACS系列
ACS是Access Client Solution的简写,它是IBM最近几年新推出的基于Java的主机管理器,可以理解为对标 i Access for Windows,里面也包含有一个5250仿真器。
外观上ACS仿真器与PCOMM仿真器没什么差别, 但是在自动化(automation)支持上,二者区别还是有些区别的:
- PCOMM 是全功能的,支持EHLLAPI和HCAL接口。而ACS并不支持HCAL。
- PCOMM类似于开箱即用,不需要做什么特别设置就可以支持自动化;而ACS需要安装EHLLAPI增强工具。
说明:IBM提供有4种仿真器API, 除了上面提到的EHLLAPI和HCAL(正式名称叫ECL), 还有DDE和PCSAPI。基本上日常操作都是用EHLLAPI或者HCAL。
二、系统准备及避坑指南
1.ACS安装
如果你公司用的是IBM i Access for Windows 或是Personal Commulications高版本,那就没什么需要准备的。
如果是用ACS, 那注意以下几点:
- ACS要安装1.1.8.1以上的版本(当然越新越好)
- ACS分32bit和64bit的,安装64bit的 (道理后面会讲到)
- ACS是基于Java的,所以需要Java JRE。Oracle几年前开始对企业用户收费了,如果你们公司没有为你购买license,IBM提供了解决方案:你可以安装第三方的免费JRE。JRE下载地址
- 安装ACS EHLLAPI Enablement Tool, 下载地址
2. 关于32-bit和64-bit的坑
如果你遇到“An attempt was made to load a program with an incorrect format” 或是"无法找到dll“之类的错误提示,大概率是32位和64位程序不兼容造成的。
要理解为什么会有这个问题,要先理解32-bit和64bit的区别, 以及RPA的三个参与方:
所谓的32-bit和64-bit, 是指系统一次处理的一个字(WORD)
有几个Bit(位)
,显然64位的效率是32位的2倍。
-
32-bit VS 64-bit
- 电脑硬件(CPU)分32-bit与64-bit。现在你能用到的电脑基本上都已经是64-bit了。
- 操作系统分32-bit与64-bit。现在的操作系统(Windows10/11)基本上都是 64-bit的
- 应用程序分16-bit, 32-bit与64-bit。特别新的程序,大概率是64-bit的,但是历史遗留下来的32-bit程序也多如牛毛,甚至还有16-bit程序至今在用。(如果有谁知道8-bit的程序还在跑,请分享一下,让我们也见识一下)
平时是不用太担心这些的,因为操作系统会向上兼容,很好地处理这些:32-bit的操作系统可以跑在64-bit的电脑上,16-bit的应用程序可以跑在32-bit的操作系统上 – 虽然这浪费了硬件投资。
但是如果是应用程序之间打交道,这个事儿就复杂了。 -
RPA 涉及方的位数
所谓而RPA,实质就是用一个程序A(Robot), 通过程序B(API接口), 去控制另一个程序C(在这里就是仿真器
)。这里程序位数就成了重要因素。正常情况下,这三方的bit需要保证是一样的,否则传递的参数不能正常解析。
不过一个API出来以后,后续的仿真器可能会做些特别处理,兼容之前的API, 比如说,仿真器升级到64位了,可能会开发配套的64位的API, 对之前32位的API也可能继续支持。具体情况要看官方文档。-
ACS
ACS原生并不支持Automation API, 它需要安装一个增强包。这个增强包里,只有EHLLAPI和PCSAPI, 并不包含HACL。基本上,这个增强包等同于i Access for Windows中的PCOMM V6.0中的部分文件(少了HACL)。可以参见IBM的官方文档。
ACS 分32-bit和64-bit. 但它还跟JRE的位数相关。现在IBM提供的32-bit的JRE只有8.0, 实际测下来32-bit的ACS并不能真正运行。要使用64-bit的JRE + 64-bit的ACS。
但是因为ACS用的是32-bit的API, 所以开发出来的控制仿真器的程序(Robot)必须也是32-bit的. 也就是说:- 如果你是用VBA写的程序, Excel必须是32-bit的, 64-bit的不行(这里Robot就是Excel)。如果你的Excel是64-bit的,要么重装32-bit的,要么改用64-bit 的PCOMM .
- 如果你是用VBScript写的程序,注意要强制用32-bit的解释器 (c:\windows\syswow64\cscript *.vbs), 参见IBM官方文档。否则系统默认会使用C:\windows\system32\下的解释器,它是64-bit的(现在操作系统基本都是64位的),结果就是程序无法执行,提示“ActiveX component can’t create objec”错误。
- 如果是用C#或其它语言开发程序,要指定编译后的程序是32-bit的。
-
PCOMM
- PCOMM V6.0 (iAccess for Windows自带的)是32-bit的,自然也只支持32-bit的Robot。要求跟上面ACS一样 – ACS使用的API就是同一款的嘛。
- PCOMM V12/13/14/14没用过,但是根据官方文档,V12/13这两个版本也都还是32-bit的, 那么从道理上来说,要求跟V6.0是一样的。从V14.0开始,PCOMM改为了64-bit, 它要求Robot必须是64-bit的
所以,如果你正在使用PCOMM V14.0及以上的版本:- 如果你是用VBA写的程序, Excel必须是64-bit的, 32-bit的不行(这里Robot就是Excel)。而且如果使用的是32-bit的API,需要在引用dll文件时加上PtrSafe 关键字以兼容64-bit
Declare Function pcsStartSession Lib "PCSAPI32.DLL" (ByVal buffer As String, ByVal SessionID As Integer, ByVal CmdShow As Integer) As Integer
- 如果你是用VBScript写的程序,没啥特别需要注意的,因为系统默认会使用C:\windows\system32\下的解释器,它是64-bit的。
- 如果是用C#或其它语言开发程序,也没有需要特别注意的, 因为默认编译后的程序就是64-bit的。
- 如果你是用VBA写的程序, Excel必须是64-bit的, 32-bit的不行(这里Robot就是Excel)。而且如果使用的是32-bit的API,需要在引用dll文件时加上PtrSafe 关键字以兼容64-bit
-
三、使用EHLLAPI编写RPA程序
1. EHLLAPI介绍
前面已经多次提到了EHLLAPI, 它是Emulator High Level Language API的简写,直译就是“仿真器高级语言接口”。 实际上,EHLLAPI是一个系列API的统称,包含3个不同的API:
- IBM Standard HLLAPI
- IBM Enhanced HLLAPI
- Windows High Level Language API (WinHLLAPI)
这3个API提供的基本功能都一样,使用方法也一样,入口函数都是hllapi(参数1,参数2,参数3,参数4)。只是有些提供一些额外的功能。在大多数日常工作场景中,它们没有什么区别。不同的API对应的dll文件名不同,所以想用哪一个API就引用对应的文件名就是了。
以下是API dll文件名对照表, IBM官网上有详细介绍.
有意思的是,对于32-bit的Standard API和Enhanced API对应的dll文件,IBM自己的官方文档说法不一致。上图中,EHLAPI32.dll是Standard API, 而在下图中, 实验室是Enhanced API. PCSHLL32.dll正好相反。下图正确的可能性大。
安装完ACS的EHLLAPI增强包后,可以看到这些dll文件:
2.EHLLAPI的基本语法
前面介绍过了,3个EHLLAPI基本相同,所以以下示例均使用EHLAPI32.dll
因为VBScrip 不支持引入dll文件,所以以下只介绍VBA和C#, 当然C/C++和Java也是官方标准支持的。
2.1 入口函数hllapi()
EHLLAPI 用的是非常古早的接口方法,整个API就只有一个函数, 这个函数有4个参数。其中第一个参数是功能代码,剩下的3个参数和根据功能代码不同,其含义也不同。以下是几个常用功能码:
- 连接到仿真器:1
- 设置光标位置:40
- 发送字符到仿真器: 3
- 读取仿真器上指定位置的内容:8
- 查询仿真器是否允许输入(Wait): 4
- 配置参数设置: 9
日常用到的功能也就是这些了。想象一下用户的操作:
- 在屏幕上输入(需要定位光标,需要确定系统可用允许输入,需要发送字符)
- 后台系统处理输入后,会反馈显示一些信息(需要定位光标,读取指定个数的字符)
注意: hllapi()函数执行结果通常是通过第4个参数指示的,函数返回值没有意义,不应使用。
2.2 使用Excel VBA编程
再没有比Excel更顺手的编程工具了:
- 自带UI
- 自带数据库(工作表)
- 无需安装任何辅助库
而且IBM对VBA/VBScript提供了特别支持。
2.2.1 引用API dll文件
Declare Function hllapi Lib "EHLAPI32.Dll" (Func%, ByVal Buffer$, bSize%, RetC%) As Long
注意这里4个参数的类型,除了第2个为String
外,其它3个是Integer
, 返回值是Long
。如前所述,返回值没有意义,不要使用。
参数类型一定要按照这样定义,否则大概率你会通不过。
2.2.2 封装常用的功能函数
Function SendKeys(strData$) As Integer
Dim intPar_1%, strPar_2$, intPar_3%, intPar_4%
intPar_1 = 3 'Send string to PS
strPar_2 = strData
intPar_3 = Len(strPar_2)
intPar_4 = 0
Call hllapi(intPar_1, strPar_2, intPar_3, intPar_4)
SendKeys = intPar_4
End Function
Function ConnectToPS(strData$) As Integer
Dim intPar_1%, strPar_2$, intPar_3%, intPar_4%
intPar_1 = 1
strPar_2 = strData
intPar_3 = Len(strPar_2)
intPar_4 = 0
Call hllapi(intPar_1, strPar_2, intPar_3, intPar_4)
ConnectToPS = intPar_4
End Function
Function DisconnectFromPS()
Dim intPar_1%, strPar_2$, intPar_3%, intPar_4%
intPar_1 = 2
strPar_2 = ""
intPar_3 = Len(strPar_2)
intPar_4 = 0
Call hllapi(intPar_1, strPar_2, intPar_3, intPar_4)
DisconnectFromPS = intPar_4
End Function
Function ReadScreen(ByRef strData$, intRow%, intCol%, intLength%) As Integer
Dim intPar_1%, strPar_2$, intPar_3%, intPar_4%
intPar_1 = 8
strPar_2 = String(5000, " ")
intPar_3 = intLength 'How many characters need to read
intPar_4 = (intRow - 1) * intScreenCol + intCol 'Position that read from
Call hllapi(intPar_1, strPar_2, intPar_3, intPar_4)
strData = Left(strPar_2, intLength)
ReadScreen = intPar_4
End Function
Function SetCursorPos(intRow%, intCol%)
Dim intPar_1%, strPar_2$, intPar_3%, intPar_4%
intPar_1 = 40
strPar_2 = ""
intPar_3 = Len(strPar_2)
intPar_4 = (intRow - 1) * intScreenCol + intCol 'Position that set to
Call hllapi(intPar_1, strPar_2, intPar_3, intPar_4)
SetCursorPos = intPar_4
End Function
Function GetCursorPos(ByRef intRow%, ByRef intCol%)
Dim intPar_1%, strPar_2$, intPar_3%, intPar_4%
intPar_1 = 7
strPar_2 = ""
intPar_3 = Len(strPar_2)
intPar_4 = 0 ' (intRow - 1) * intScreenCol + intCol 'Position that set to
Call hllapi(intPar_1, strPar_2, intPar_3, intPar_4)
If intPar_4 = 0 Then
intCol = intPar_3 Mod intScreenCol
intRow = (intPar_3 - intCol) / intScreenCol + 1
End If
GetCursorPos = intPar_4
End Function
Function SetParameter(strData$)
Dim intPar_1%, strPar_2$, intPar_3%, intPar_4%
intPar_1 = 9
strPar_2 = strData
intPar_3 = Len(strPar_2)
intPar_4 = 0 'Position that set to
Call hllapi(intPar_1, strPar_2, intPar_3, intPar_4)
SetParameter = intPar_4
End Function
Function Wait() As Integer
Dim intPar_1%, strPar_2$, intPar_3%, intPar_4%
intPar_1 = 4
strPar_2 = ""
intPar_3 = Len(strPar_2)
intPar_4 = 0
Call hllapi(intPar_1, strPar_2, intPar_3, intPar_4)
Wait = intPar_4
End Function
注意这里使用了两个常量:
Const intScreenRow = 24
Const intScreenCol = 80
它指定了仿真器屏幕的尺寸大小, 常规的大小是有24行,每行有80个字符(ASCII)。虽然不太经常发生,但是有时候在仿真器上也可以设为别的尺寸,比如说25行。为简单起见,这里要求用户用标准的24 * 80屏幕。
在上面程序中读/设光标位置时,要用到这个设置来计算位置。其背后的原理是:
整个仿真器上显示的内容可以认为是一个大的字符串
,第1行第1列的字符是字符串中的第一个,第2行第2列就是第81个(假定设定的是每行80列),以此类推。第r行第c列在字符串中的位置就是 (r-1) * 80 + c
2.2.3 根据实际要求进一步封装并完成最终程序
这个要根据实际情况来做,比如说,要做一个函数,用来判断仿真器是不是允许输入
Function ReadyForInput(intSec%) As Integer
Dim intCNT%, intResult%
intCNT = 0
Do While intCNT < intSec
intResult = Wait()
Select Case intResult
Case 0
ReadyForInput = 0
Exit Function
Case 1, 9
ReadyForInput = 99
Exit Function
End Select
Application.Wait (Now + TimeValue("00:00:01"))
intCNT = intCNT + 1
Loop
'Time expired
ReadyForInput = 1
End Function
以下文件提供了一个实际的案例。该工具是在S2K (一款极其古早的财务软件)中做固定资产转移(从一家公司转到另一家关联公司)。整个过程涉及5屏。
2.2.4 关于ACS的EHLLAPI增强包
上面的代码中是直接使用EHLLAPI 的标准dll。实际上这个增强包里有提供一些封装好的dll (bridge, 桥接API), 有趣的是封装的格式 居然还是4参数的格式。
在安装好的目录里可以看到一些*.bas文件,这些是导出的VBA模块,里面是一些如何使用这些demo。实测下来确实是可用的。可以参考这个文件
2.3 使用C#
2.3.1 引用dll文件
public class EhllapiFunc
{
//You can use EHLAPI32.dll instead, there is just tiny difference.
[DllImport(@"PCSHLL32.dll")]
public static extern UInt32 hllapi(out UInt32 Func, StringBuilder Data, out UInt32 Length, out UInt32 RetC);
}
注意参数类型。
2.3.2 同VBA, 对hllapi()函数功能做封装,并构建最终程序
方法与VBA类同,只是语法上略有区别而已。
实例C#代码下载
2.4 一些细节
2.4.1 关于dll文件的位置
在引用dll时,尽量不要指定具体位置,让系统会根据path参数设定自己去找,这样同一个程序,不管用户用的是i Access for Windows还是ACS, 都不影响.
2.4.2 要关注绿屏程序自身的处理方法
如前所述,绿屏程序的特点就是改写一个大字符串中的某些字符。这时一定要仔细观察主机端程序的处理规则。比如说,某个字段是输入FA#, 上一笔做完以后,如果系统自动将这个字段清空了,那RPA程序就只管输新FA#就好了。但是如果上一笔的FA#还在,那RPA程序就需要对输入的内容做下调整,要么补一些前导空格,要么补一些后导空格,根据系统规则而定。
2.4.3 仿真器功能键
通常F3是Exit (对应"@3"), F12是Cancel(对应"@c")。 在仿真器上可以自定义回车是用Ctrl健还是Enter键,但是编程时,其实不区分,都是"@E"
@ 符号在IBM 仿真器中是特殊符号,是功能键的标志。要输入一个@字符,需要用"@@"
参见官方文档中的特殊字符定义
四、使用HACL API编写RPA程序
4.1 HACL简介
HACL 是Host Access Class Library的简称,它是一个面向对象的API。与EHLLAPI用一个单一函数做入口不同, HACL用一系列的对象来处理用户功能,因此使用起来更方便。
HACL 是官方推荐使用的API,只要有可能,尽量使用它。
注意:ACS没有提供HACL API接口
HACL的对外接口架构
Automation对象层次
基本上,使用的最多的是autECLSession对象。
4.2 用VBA编程
使用前要添加PCOMM引用。
Option Explicit
Dim number_of_connections, connection_choice, input_choice
Dim autECLConnMgr As AutConnMgr
Dim autECLConnList As AutConnList
Dim autECLSession As AutSess
Sub test()
Dim number_of_connections, connection_choice, input_choice
Dim autECLConnMgr As AutConnMgr
Dim autECLConnList As Object
Dim autECLSession As AutSess
autECLConnList = CreateObject("PCOMM.autECLConnList")
autECLConnList.Refresh
number_of_connections = autECLConnMgr.autECLConnList.Count
If number_of_connections > 1 Then
input_choice = InputBox("enter a connection number between 1 and " & number_of_connections)
If input_choice = "" Then
MsgBox ("invalid input")
ElseIf IsNumeric(input_choice) Then
' variables used with the pcomm interface must be variants
' convert the connection number to an integer variant
connection_choice = CInt(input_choice)
Call display_info(connection_choice)
Else
MsgBox ("non numeric input" & input_choice)
End If
' autECLSession.autECLXfer.SendFile "d:\pcomm\private\ad1.mac", "ad1 mac a5", "CRLF ASCII"
ElseIf number_of_connections = 1 Then
Call display_info(1)
Else
MsgBox (" no connections ")
End If
End Sub
Sub display_info(index)
Dim input_choice
If (index > 0 And index <= number_of_connections) Then
Call display_ConnList(autECLConnMgr.autECLConnList(index))
input_choice = MsgBox("Display Session Object? ", 3)
If input_choice = 6 Then
Call display_Session(autECLConnMgr.autECLConnList(index).Handle)
Else
End If
Else
MsgBox ("invalid input range " & connection_choice)
End If
End Sub
Sub display_ConnList(dis_object)
Dim button_id
button_id = MsgBox( _
"Name " & dis_object.Name & (Chr(13)) & _
"Handle " & dis_object.Handle & (Chr(13)) & _
"ConnType " & dis_object.ConnType & (Chr(13)) & _
"CodePage " & dis_object.CodePage & (Chr(13)) & _
"Started " & dis_object.Started & (Chr(13)) & _
"CommStarted " & dis_object.CommStarted & (Chr(13)) & _
"APIEnabled " & dis_object.APIEnabled & (Chr(13)) & _
"Ready " & dis_object.Ready, _
0, "autECLConnMgr.autECLConnList")
End Sub
Sub display_Session(SessHandle)
Dim button_id
autECLSession.SetConnectionByHandle (SessHandle)
'autECLSession.ConnectCommunication(Boolean ConnFlag)
'autECLSession.ConnectCommunication(FALSE)
button_id = MsgBox( _
"Name " & autECLSession.Name & (Chr(13)) & _
"Handle " & autECLSession.Handle & (Chr(13)) & _
"ConnType " & autECLSession.ConnType & (Chr(13)) & _
"CodePage " & autECLSession.CodePage & (Chr(13)) & _
"Started " & autECLSession.Started & (Chr(13)) & _
"CommStarted " & autECLSession.CommStarted & (Chr(13)) & _
"APIEnabled " & autECLSession.APIEnabled & (Chr(13)) & _
"Ready " & autECLSession.Ready, _
0, "autECLSession")
Call display_PS
Call display_OIA
Call display_Xfer
Call display_WinMetrics
End Sub
Sub display_PS()
Dim button_id
button_id = MsgBox( _
"NumRows " & autECLSession.autECLPS.NumRows & (Chr(13)) & _
"NumCols " & autECLSession.autECLPS.NumCols & (Chr(13)) & _
"CursorPosRow " & autECLSession.autECLPS.CursorPosRow & (Chr(13)) & _
"CursorPosCol " & autECLSession.autECLPS.CursorPosCol & (Chr(13)) & _
"Name " & autECLSession.autECLPS.Name & (Chr(13)) & _
"Handle " & autECLSession.autECLPS.Handle & (Chr(13)) & _
"ConnType " & autECLSession.autECLPS.ConnType & (Chr(13)) & _
"CodePage " & autECLSession.autECLPS.CodePage & (Chr(13)) & _
"Started " & autECLSession.autECLPS.Started & (Chr(13)) & _
"CommStarted " & autECLSession.autECLPS.CommStarted & (Chr(13)) & _
"APIEnabled " & autECLSession.autECLPS.APIEnabled & (Chr(13)) & _
"Ready " & autECLSession.autECLPS.Ready, _
0, "autECLSession.autECLPS")
Call display_FieldList
End Sub
Sub display_FieldList()
Dim button_id
Dim field_data
autECLSession.autECLPS.autECLFieldList.Refresh
If autECLSession.autECLPS.autECLFieldList.Count > 0 Then
Dim FieldText
FieldText = autECLSession.autECLPS.autECLFieldList(1).GetText
button_id = MsgBox( _
"StartRow " & autECLSession.autECLPS.autECLFieldList(1).StartRow & (Chr(13)) & _
"StartCol " & autECLSession.autECLPS.autECLFieldList(1).StartCol & (Chr(13)) & _
"EndRow " & autECLSession.autECLPS.autECLFieldList(1).EndRow & (Chr(13)) & _
"EndCol " & autECLSession.autECLPS.autECLFieldList(1).EndCol & (Chr(13)) & _
"Length " & autECLSession.autECLPS.autECLFieldList(1).Length & (Chr(13)) & _
"Modified " & autECLSession.autECLPS.autECLFieldList(1).Modified & (Chr(13)) & _
"Protected " & autECLSession.autECLPS.autECLFieldList(1).Protected & (Chr(13)) & _
"Numeric " & autECLSession.autECLPS.autECLFieldList(1).Numeric & (Chr(13)) & _
"HighIntensity " & autECLSession.autECLPS.autECLFieldList(1).HighIntensity & (Chr(13)) & _
"PenDetectable " & autECLSession.autECLPS.autECLFieldList(1).PenDetectable & (Chr(13)) & _
"Display " & autECLSession.autECLPS.autECLFieldList(1).Display & (Chr(13)) & _
"text of field " & FieldText, _
0, "autECLSession.autECLPS.autECLFieldList")
Else
MsgBox ("No FieldList elements to display ")
End If
End Sub
Sub display_OIA()
Dim button_id
button_id = MsgBox( _
"Alphanumeric " & autECLSession.autECLOIA.Alphanumeric & (Chr(13)) & _
"APL " & autECLSession.autECLOIA.APL & (Chr(13)) & _
"Katakana " & autECLSession.autECLOIA.Katakana & (Chr(13)) & _
"Hiragana " & autECLSession.autECLOIA.Hiragana & (Chr(13)) & _
"DBCS " & autECLSession.autECLOIA.Dbcs & (Chr(13)) & _
"UpperShift " & autECLSession.autECLOIA.UpperShift & (Chr(13)) & _
"NumLock " & autECLSession.autECLOIA.NumLock & (Chr(13)) & _
"CapsLock " & autECLSession.autECLOIA.CapsLock & (Chr(13)) & _
"InsertMode " & autECLSession.autECLOIA.InsertMode & (Chr(13)) & _
"CommErrorReminder " & autECLSession.autECLOIA.CommErrorReminder & (Chr(13)) & _
"MessageWaiting " & autECLSession.autECLOIA.MessageWaiting & (Chr(13)) & _
"InputInhibited " & autECLSession.autECLOIA.InputInhibited & (Chr(13)) & _
"Name " & autECLSession.autECLOIA.Name & (Chr(13)) & _
"Handle " & autECLSession.autECLOIA.Handle & (Chr(13)) & _
"ConnType " & autECLSession.autECLOIA.ConnType & (Chr(13)) & _
"CodePage " & autECLSession.autECLOIA.CodePage & (Chr(13)) & _
"Started " & autECLSession.autECLOIA.Started & (Chr(13)) & _
"CommStarted " & autECLSession.autECLOIA.CommStarted & (Chr(13)) & _
"APIEnabled " & autECLSession.autECLOIA.APIEnabled & (Chr(13)) & _
"Ready " & autECLSession.autECLOIA.Ready, _
0, "autECLSession.autECLOIA")
End Sub
Sub display_Xfer()
Dim button_id
button_id = MsgBox( _
"Name " & autECLSession.autECLXfer.Name & (Chr(13)) & _
"Handle " & autECLSession.autECLXfer.Handle & (Chr(13)) & _
"ConnType " & autECLSession.autECLXfer.ConnType & (Chr(13)) & _
"CodePage " & autECLSession.autECLXfer.CodePage & (Chr(13)) & _
"Started " & autECLSession.autECLXfer.Started & (Chr(13)) & _
"CommStarted " & autECLSession.autECLXfer.CommStarted & (Chr(13)) & _
"APIEnabled " & autECLSession.autECLXfer.APIEnabled & (Chr(13)) & _
"Ready " & autECLSession.autECLXfer.Ready, _
0, "autECLSession.autECLXfer")
End Sub
Sub display_WinMetrics()
Dim button_id
button_id = MsgBox( _
"WindowTitle " & autECLSession.autECLWinMetrics.WindowTitle & (Chr(13)) & _
"Xpos " & autECLSession.autECLWinMetrics.XPos & (Chr(13)) & _
"Ypos " & autECLSession.autECLWinMetrics.YPos & (Chr(13)) & _
"Width " & autECLSession.autECLWinMetrics.Width & (Chr(13)) & _
"Height " & autECLSession.autECLWinMetrics.Height & (Chr(13)) & _
"Visible " & autECLSession.autECLWinMetrics.Visible & (Chr(13)) & _
"Active " & autECLSession.autECLWinMetrics.Active & (Chr(13)) & _
"Minimized " & autECLSession.autECLWinMetrics.Minimized & (Chr(13)) & _
"Maximized " & autECLSession.autECLWinMetrics.Maximized & (Chr(13)) & _
"Restored " & autECLSession.autECLWinMetrics.Restored & (Chr(13)) & _
"Name " & autECLSession.autECLWinMetrics.Name & (Chr(13)) & _
"Handle " & autECLSession.autECLWinMetrics.Handle & (Chr(13)) & _
"ConnType " & autECLSession.autECLWinMetrics.ConnType & (Chr(13)) & _
"CodePage " & autECLSession.autECLWinMetrics.CodePage & (Chr(13)) & _
"Started " & autECLSession.autECLWinMetrics.Started & (Chr(13)) & _
"CommStarted " & autECLSession.autECLWinMetrics.CommStarted & (Chr(13)) & _
"APIEnabled " & autECLSession.autECLWinMetrics.APIEnabled & (Chr(13)) & _
"Ready " & autECLSession.autECLWinMetrics.Ready, _
0, "autECLSession.autECLWinMetrics")
End Sub
4.3 用VBScript
方法跟VBA基本一样
sub subSub1_()
dim autECLSession
Dim ExcelApp, DataFile, DataSheet, SKU,Status, intExcelRow, intExcelCol
set autECLSession = CreateObject("PCOMM.autECLSession")
autECLSession.SetConnectionByName("A")
WScript.Echo "Session hanlde: " & autECLSession.Handle
Set ExcelApp = CreateObject("Excel.Application")
ExcelApp.Visible = True
Set DataFile = ExcelApp.Workbooks.Open("C:\temp\Data.xlsx")
set DataSheet = DataFile.Worksheets("Data")
intExcelRow = 2
do while trim(DataSheet.Cells(intExcelRow,3).Value) <>""
SKU = trim(DataSheet.Cells(intExcelRow,"C").Value)
status = trim(DataSheet.Cells(intExcelRow,"D").Value)
REM Start from "Define the Query" screen
autECLSession.autECLOIA.WaitForAppAvailable
autECLSession.autECLOIA.WaitForInputReady
REM **** "Select records"
autECLSession.autECLPS.WaitForCursor 13,3,10000
autECLSession.autECLPS.SetText "1", 13, 3
autECLSession.autECLOIA.WaitForInputReady
autECLSession.autECLPS.SendKeys "[enter]"
REM **** Input criteria **********
autECLSession.autECLPS.WaitForCursor 7,10,1000
autECLSession.autECLOIA.WaitForAppAvailable
autECLSession.autECLOIA.WaitForInputReady
autECLSession.autECLPS.SetText "IPROD", 7,10
autECLSession.autECLPS.WaitForCursor 7,28,1000
autECLSession.autECLOIA.WaitForAppAvailable
autECLSession.autECLOIA.WaitForInputReady
autECLSession.autECLPS.SetText "EQ",7,28
autECLSession.autECLPS.WaitForCursor 7,35,1000
autECLSession.autECLOIA.WaitForAppAvailable
autECLSession.autECLOIA.WaitForInputReady
autECLSession.autECLPS.SetText "'" & SKU & "'",7,35
autECLSession.autECLOIA.WaitForAppAvailable
autECLSession.autECLOIA.WaitForInputReady
autECLSession.autECLPS.SendKeys "[enter]"
autECLSession.autECLOIA.WaitForAppAvailable
autECLSession.autECLOIA.WaitForInputReady
autECLSession.autECLPS.SendKeys "[pf5]"
autECLSession.autECLPS.Wait 1000
autECLSession.autECLOIA.WaitForAppAvailable
autECLSession.autECLOIA.WaitForInputReady
autECLSession.autECLPS.SendKeys "[enter]"
intExcelRow = intExcelRow +1
loop
end sub
4.4 用C#
没有实质性区别,同理,使用前添加PCOMM的引用。
4.5 ACS和PCOMM的录屏和回放功能
ACS和 都提供录屏回放功能,相当于Excel中的宏录制。
PCOMM是基于VBScript的,使用的是HACL API, 上面VBScript的代码就是在录屏的基础上改的。
ACS是基于xml形式的,还没有仔细研究。
不过通常不建议用这种方式,因为可控性太差了。
总结
基本上,掌握了以上技巧,AS400绿屏仿真器RPA就没什么问题了,剩下的只是多实践了。
遇到问题,多看官方文档,多数情况下都可以解决。