Vb.net 如何在IBM主机访问库中使SendKeys同步运行
我使用作为通过终端仿真器与IBMAS400(又称iSeries,IBMi,green screen,5250)通信的一种方式。我注意到,当您发出“SendKeys”指令时,在IBM emulator使用该命令完成之前,控制将返回到您的应用程序。这可能会导致计时问题,因为您可能会在系统准备接受另一条“SendKeys”指令之前发送该指令 例如:Vb.net 如何在IBM主机访问库中使SendKeys同步运行,vb.net,com,ibm-midrange,terminal-emulator,Vb.net,Com,Ibm Midrange,Terminal Emulator,我使用作为通过终端仿真器与IBMAS400(又称iSeries,IBMi,green screen,5250)通信的一种方式。我注意到,当您发出“SendKeys”指令时,在IBM emulator使用该命令完成之前,控制将返回到您的应用程序。这可能会导致计时问题,因为您可能会在系统准备接受另一条“SendKeys”指令之前发送该指令 例如: Imports AutPSTypeLibrary Imports AutConnListTypeLibrary Imports AutSessTypeLi
Imports AutPSTypeLibrary
Imports AutConnListTypeLibrary
Imports AutSessTypeLibrary
Sub Example
Dim connections As New AutConnList
connections.Refresh()
If connections.Count < 1 Then Throw New InvalidOperationException("No AS400 screen can currently be found.")
Dim connection As IAutConnInfo = DirectCast(connections(1), IAutConnInfo)
_Session = New AutSess2
_Session.SetConnectionByHandle(connection.Handle)
Dim _Presentation As AutPS = DirectCast(_Session.autECLPS, AutPS)
_Presentation.SendKeys("PM70[enter]", 22, 8)
_Presentation.SendKeys("ND71221AD[enter]", 22, 20)
End Sub
导入AUTPSTYPE库
导入列表类型库
进口自动化图书馆
子示例
将连接设置为新的AUTCONLIST
connections.Refresh()
如果connections.Count<1,则抛出新的InvalidOperationException(“当前找不到AS400屏幕”)
作为IAutConnInfo=DirectCast的Dim连接(连接(1),IAutConnInfo)
_会话=新的autses2
_Session.SetConnectionByHandle(connection.Handle)
Dim _表示为AutPS=DirectCast(_Session.autECLPS,AutPS)
_演示文稿。发送键(“PM70[输入]”,22,8)
_Presentation.SendKeys(“ND71221AD[enter]”,22,20)
端接头
在调试程序中单步执行代码时将正常工作,但在正常运行时将失败,因为第二条指令发送得太快
处理这个问题的一种方法是在每个命令后放置一个计时器或循环,以降低调用程序的速度。我认为这不太理想,因为时间的长短并不总是可以预测的,你会经常等待更长的时间来适应偶尔的打嗝。这会减慢整个进程的运行时间
解决此问题的另一种方法是等待屏幕上出现可测试的条件,作为发送命令的结果。这有时会起作用,但某些命令不会导致测试屏幕更改,如果您希望将命令调用抽象到类或子例程中,则必须传递要监视的屏幕条件
我想找到一种在一般情况下有效的“等待”方法。像autECLScreenDesc类这样的选项似乎必须根据非常特定的条件进行定制
autECLPS(又名AutPS)类有许多等待方法(Wait、WaitForCursor、WaitWhileCursor、WaitForString、WaitWhileString、waitforstringinct、WaitWhileString、waitforstrib、WaitForScreen、WaitWhileScreen)但它们似乎也在等待特定条件,不适用于一般情况。一般情况下,它对我很重要,因为我实际上正在尝试编写一个通用字段更新子例程,它可以从.dll内外的许多地方调用
这个例子是用VB.NET编写的,但是我希望C语言、C++、VB6、java都有相同的行为。实际上,任何使用IBM的“Operator Information Area”类的东西似乎都能为这个问题提供解决方案
我的一般情况似乎与此实现正确配合:
Friend Sub PutTextWithEnter(ByVal field As FieldDefinition, ByVal value As String)
If IsNothing(field) Then Throw New ArgumentNullException("field")
If IsNothing(value) Then Throw New ArgumentNullException("value")
_Presentation.SendKeys(Mid(value.Trim, 1, field.Length).PadRight(field.Length) & "[enter]", field.Row, field.Column)
WaitForEmulator(_Session.Handle)
End Sub
Private Sub WaitForEmulator(ByVal EmulatorHandle As Integer)
Dim Oia As New AutOIATypeLibrary.AutOIA
Oia.SetConnectionByHandle(EmulatorHandle)
Oia.WaitForInputReady()
Oia.WaitForAppAvailable()
End Sub
我要感谢一位名为“khieyzer”的用户,他为我们指出了这一干净的通用解决方案
编辑:
经过几周的调试和解决时间和资源释放问题后,此方法现在的内容如下:
Private Sub WaitForEmulator(ByRef NeededReset As Boolean)
Dim Oia As New AutOIA
Oia.SetConnectionByHandle(_Presentation.Handle)
Dim inhibit As InhibitReason = Oia.InputInhibited
If inhibit = InhibitReason.pcOtherInhibit Then
_Presentation.SendKeys("[reset]")
NeededReset = True
WaitForEmulator(NeededReset)
Marshal.ReleaseComObject(Oia)
Exit Sub
End If
If Not Oia.WaitForInputReady(6000) Then
If Oia.InputInhibited = InhibitReason.pcOtherInhibit Then
_Presentation.SendKeys("[reset]")
NeededReset = True
WaitForEmulator(NeededReset)
Marshal.ReleaseComObject(Oia)
Exit Sub
Else
Marshal.ReleaseComObject(Oia)
Throw New InvalidOperationException("The system has stopped responding.")
End If
End If
Oia.WaitForInputReady()
Oia.WaitForAppAvailable()
Marshal.ReleaseComObject(Oia)
End Sub
IBM中端计算机(包括AS/400及其后续产品)的绿屏终端不是3270,而是5250。3270用于IBM大型机(根据维基百科,从System/370开始)。@JohnY你说得对。我把终端的名字划掉了,因为这家公司既有一个使用3270(几年前我编写了屏幕抓取包装器)的基于CICS的旧IBM系统,也有AS400(我们最近通过合并获得)。我将把这个问题更新为5250。