我使用COM自动化的IBM主机访问类库作为通过终端模拟器与IBM AS400(又名iSeries, IBM I,绿屏,5250)通信的一种方式。我注意到,当您发出"SendKeys"指令时,在IBM模拟器完成命令之前,控制就返回到您的应用程序。这可能会导致时间问题,因为您可能会在系统准备好接受它之前发送另一个"SendKeys"指令。
例如: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
在调试器中执行代码时可以正常工作,但在正常运行时会失败,因为第二条指令发送得太快了。
解决这个问题的一种方法是在每个命令后放置一个计时器或循环,以减慢调用程序的速度。我认为这并不理想,因为时间的长度并不总是可预测的,您经常会等待比必要的时间更长,以适应偶尔的打嗝。这会减慢整个进程的运行时间。 另一种解决这个问题的方法是等待,直到屏幕上有一个可测试的条件作为您发送的命令的结果。这有时会起作用,但有些命令不会导致屏幕更改以进行测试,如果您希望将命令调用抽象到类或子例程中,则必须传递要监视的屏幕条件。我想找到的是在一般情况下工作的"等待"方法之一。像autECLScreenDesc类这样的选项似乎必须针对非常特定的条件进行定制。
autECLPS(又名AutPS)类有许多等待方法(等待,WaitForCursor, WaitWhileCursor, WaitForString, WaitWhileString, WaitForStringInRect, WaitWhileStringInRect, WaitForAttrib, waitwhiletrib, WaitForScreen, WaitWhileScreen)但它们似乎也在等待特定的条件,不适用于一般情况。一般情况下,它对我很重要,因为我实际上是试图写一个通用的字段更新子程序,可以从我的。dll内外的许多地方调用。
这个例子是用VB编写的。. NET,但我希望c#, c++, VB6, Java;任何使用IBM Windows 6.0版个人通讯系统的东西主机访问类库。
"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