如何在 IBM 主机访问库中使 SendKeys 同步运行 [英] How to make SendKeys act Synchronously in IBM Host Access Library

查看:12
本文介绍了如何在 IBM 主机访问库中使 SendKeys 同步运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 用于 COM 自动化的 IBM 主机访问类库 作为通过终端仿真器与 IBM AS400(又名 iSeries、IBM i、绿屏、5250)进行通信的一种方式.我注意到当您发出SendKeys"指令时,控制权会在 IBM 模拟器完成命令之前返回到您的应用程序.这可能会导致计时问题,因为您可能会在系统准备好接受之前发送另一个SendKeys"指令.

I use the IBM Host Access Class Library for COM Automation as a way to communicate with an IBM AS400 (aka iSeries, IBM i, green screen, 5250) through a terminal emulator. I notice that when you issue a "SendKeys" instruction, control returns to your application before the IBM emulator finishes with the command. This can lead to timing problems because you might then send another "SendKeys" instruction before the system is ready to accept it.

例如:

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

在调试器中单步执行代码时可以正常工作,但在正常运行时会失败,因为第二条指令发送得太快了.

would work correctly when stepping through code in a debugger, but would fail when running normally because the second instruction was sent too soon.

解决这个问题的一种方法是在每个命令之后放置一个计时器或循环来减慢调用程序的速度.我认为这不太理想,因为时间长度并不总是可预测的,您通常会等待比必要的时间更长的时间来适应偶尔的打嗝.这会减慢整个过程的运行时间.

One way to work with this is to put a timer or loop after each command to slow the calling program down. I consider this less than ideal because the length of time is not always predictable, you will often be waiting longer than necessary to accommodate an occasional hiccup. This slows down the run time of the entire process.

解决此问题的另一种方法是等待,直到由于您发送的命令在屏幕上出现可测试的条件.这有时会起作用,但有些命令不会导致屏幕更改以进行测试,如果您希望将命令调用抽象为类或子例程,则必须传入要监视的屏幕条件.

Another way to work around this is to wait until there is a testable condition on the screen as a result of your sent command. This will work sometimes, but some commands do not cause a screen change to test and if you are looking to abstract your command calling into a class or subroutine, you would have to pass in what screen condition to be watching for.

我想找到一种在一般情况下有效的等待"方法.autECLScreenDesc 类之类的选项似乎必须针对非常特定的条件进行定制.

What I would like to find is one of the "Wait" methods that will work in the general case. Options like the autECLScreenDesc class seem like they have to be tailored to very specific conditions.

autECLPS(又名 AutPS)类有许多等待方法(Wait、WaitForCursor、WaitWhileCursor、WaitForString、WaitWhileString、WaitForStringInRect、WaitWhileStringInRect、WaitForAttrib、WaitWhileAttrib、WaitForScreen、WaitWhileScreen)似乎也等待特定条件,不适用于一般情况.一般情况对我来说很重要,因为我实际上是在尝试编写一个通用字段更新子例程,该子例程可以从我的 .dll 内部和外部的许多地方调用.

The autECLPS (aka AutPS) class has a number of Wait methods (Wait, WaitForCursor, WaitWhileCursor, WaitForString, WaitWhileString, WaitForStringInRect, WaitWhileStringInRect, WaitForAttrib, WaitWhileAttrib, WaitForScreen, WaitWhileScreen) but they also seem to be waiting for specific conditions and do not work for the general case. The general case it important to me because I am actually trying to write a general purpose field update subroutine that can be called from many places inside and outside of my .dll.

这个例子是用 VB.NET 编写的,但我希望 C#、C++、VB6、Java 有相同的行为;真的任何使用 IBM 的 Windows 个人通信,版本 6.0主机访问类库.

This example is written in VB.NET, but I would expect the same behavior from C#, C++, VB6, Java; really anything that uses IBM's Personal Communications for Windows, Version 6.0 Host Access Class Library.

推荐答案

操作员信息区"类似乎为这个问题提供了解决方案.

The "Operator Information Area" class seems to provide a solution for this problem.

我的一般情况似乎与此实现正常工作:

My general case seems to be working correctly with this implementation:

 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

感谢此留言板 指出我们这个干净且通用的解决方案.

I give thanks to a user named "khieyzer" on this message board for pointing our this clean and general-purpose solution.

经过几周的调试和处理时间和资源释放问题后,此方法现在读作:

After a few weeks debugging and working through timing and resource release issues, this method now reads like:

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 主机访问库中使 SendKeys 同步运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆