Sign in to follow this  
Followers 0
DangerousDan

AS400 PCOMM session objects

8 posts in this topic

#1 ·  Posted (edited)

I use IBM's AS400 Client Access software for work and over the last year or so have figured out how to connect to the session itself. This greatly simplifies sending and getting text as controlsend and clipget functions are not necessary. This will obviously be a little confusing to users who do not currently automate their AS400 tasks, but trust me it's much easier and infinitely more reliable using this method to send/get text. The below code is very rudimentary, I have offered it up so that someone else may not have to do quite as much reading/research to connect using only AutoIt. It was much easier finding VBA code to do this.

I'm in sales, not software development, so my code is not going to be all that impressive to some of you. Please feel free to make any and all types of suggestions/comments/criticisms, I consider this one of the best ways to learn. Enough of my long winded explanations... on to the details.

I use $Ps and $Oia as Globals so any/all functions can utilize them.

The function sendtosession simply adds the "waitforinputready" ($Oia.InputInhibited) functionality to the default SendKeys function. This waits for the session to allow key presses so they don't all go to the buffer before the AS400 can accept your keys. In most instances the keys can be buffered with no ill effects, but I have run into some errors so I use it.

I am not sure the autECLConnMgr is needed. I'm going to try commenting it out the next time I run one of my scripts, but perhaps someone else has some knowledge to add to this?

Global $Ps, $Oia ;$Ps is the part you interact with, $Oia is the current message in the status bar

$Session = "A" ; can be any session letter
 
;or you can use string functions to parse it from the active window as below(my typical usage as I use multiple monitors and sessions)
$window = WinGetTitle("")
$AS400hwnd = WinGetHandle($window)
$Session = StringMid(WinGetTitle($AS400hwnd), 9, 1)


$Obj_ConnMgr = ObjCreate("PCOMM.autECLConnMgr") ; Maybe this is not needed? Anyone know what it is for?
$OBJ_EmulSession = ObjCreate("PCOMM.autECLSession") ; getting closer
$OBJ_EmulSession.SetConnectionByName($Session) ; now you are connected to the session
$Ps = $OBJ_EmulSession.autECLPS ; Object for the user interface
$Oia = $OBJ_EmulSession.autECLOIA ; Object for the message interface (terminology... remember I'm in sales;) )

Func sendtosession($keys, $rownum = 1, $colnum = 1, $inhibit = 1)
$Ps.SendKeys($keys, $rownum, $colnum) ; actual usage for AS400 macros too
if $inhibit = 1 Then 
While $Oia.InputInhibited <> 0
WEnd
EndIf
EndFunc

$Ps.GetText("Row","Col","Length") ; actual usage for AS400 macros too

Again, I'm not trying to provide a working example with the above, I'm just passing the information along. Below is a simple script I created to update contract prices for over 400 items (manually it took hours, now it takes only minutes)

you can run this code, but it will not do anything unless you have the data and the AS400 session. You get the gist of it though, I'm sure.:x

Hopefully this helps someone else out there.

Dan

#include <GUIConstantsEx.au3>
#include <Excel_CPU.au3>
#include <array.au3>
#include <WindowsConstants.au3>
#include <C:\Documents and Settings\r060091\My Documents\Requires Backup\send to as400 session.au3>
;sendtosession($keys, $rownum = 1, $colnum = 1, $inhibit = 1)
Opt("guioneventmode", 1)
Opt("mustdeclarevars", 1)
Opt("trayicondebug", 1)
;********************************** set contract expiration date
Global $Expiration_Date = "013111";**
;**********************************
Global Const $Col_Price = 12
Global Const $Col_Item = 1
Global Const $Col_Cust = 1
Global Const $Col_UOM = ""
Global Const $District = 12

Global $Obj_ConnMgr, $OBJ_EmulSession, $Ps, $Oia, $OBJ_Excel, $AS400hwnd, $GUI_hwnd, $Array_Excel_Price_Sheet, $Screen_ID

Create_Helper_GUI()
Func SET_AS400()
    Local $window, $Session
    $window = WinGetTitle("")
    $AS400hwnd = WinGetHandle($window)
    $Session = StringMid(WinGetTitle($AS400hwnd), 9, 1)
    $Obj_ConnMgr = ObjCreate("PCOMM.autECLConnMgr")
    $OBJ_EmulSession = ObjCreate("PCOMM.autECLSession")
    $OBJ_EmulSession.SetConnectionByName($Session)
    $Ps = $OBJ_EmulSession.autECLPS
    $Oia = $OBJ_EmulSession.autECLOIA
EndFunc   ;==>SET_AS400

Func SET_Excel()
    GUISetState(@SW_HIDE)
    HotKeySet("^1")
    Local $exwindow
    $exwindow = WinGetTitle("")
    $OBJ_Excel = _ExcelBookAttach($exwindow, "Title")
    $Array_Excel_Price_Sheet = _ExcelReadSheetToArray($OBJ_Excel, 2, 1)
;~  _ArrayDisplay($Array_Excel_Price_Sheet)
    GUISetState(@SW_SHOW)
EndFunc   ;==>SET_Excel

Func Change_Prices()
    GUIDelete($GUI_hwnd)
    Local $Price, $UOM, $Customer, $Item, $Cust_Item, $Delimiter

    For $COUNTER_Row = 1 To UBound($Array_Excel_Price_Sheet) - 1
        $Price = Round($Array_Excel_Price_Sheet[$COUNTER_Row][$Col_Price], 3)
        If $Col_UOM <> "" Then $UOM = $Array_Excel_Price_Sheet[$COUNTER_Row][$Col_UOM]
        If $Col_Cust <> $Col_Item Then
            $Customer = $Array_Excel_Price_Sheet[$COUNTER_Row][$Col_Cust]
            $Item = $Array_Excel_Price_Sheet[$COUNTER_Row][$Col_Item]
        Else
            $Cust_Item = $Array_Excel_Price_Sheet[$COUNTER_Row][$Col_Cust]
            $Delimiter = StringInStr($Cust_Item, "-")
            $Customer = StringMid($Cust_Item, $Delimiter + 1)
            $Item = StringLeft($Cust_Item, $Delimiter - 1)
        EndIf

        sendtosession($District & $Customer, 10, 45)
        sendtosession($Item, 12, 45)
        sendtosession("[eraseeof]", 12, StringLen($Item) + 45)
        sendtosession("[PF11]")

        $Screen_ID = $Ps.GetText(2, 1, 8)
        If $Screen_ID = "PM413-01" Then

            Switch $Ps.GetText(24, 2, 7)
                Case "INV0010"
                    $OBJ_Excel.Application.Cells($COUNTER_Row + 1, $Col_Item).Interior.ColorIndex = 6
                    MsgBox(0, "Error", "No item code available; the affected cell has been highlighted yellow. Click OK to continue." & @CRLF & @CRLF & "This message closes automatically after ~30 seconds.", 30)
                    ContinueLoop
                Case "INV0011"
                    $OBJ_Excel.Application.Cells($COUNTER_Row + 1, $Col_Item).Interior.ColorIndex = 3
                    MsgBox(0, "Error", "The item code appears to be invalid; the affected cell has been highlighted red. Click OK to continue." & @CRLF & @CRLF & "This message closes automatically after ~30 seconds.", 30)
                    ContinueLoop
                Case "AR00002"
                    $OBJ_Excel.Application.Cells($COUNTER_Row + 1, $Col_Cust).Interior.ColorIndex = 3
                    MsgBox(0, "Error", "The Customer number appears to be invalid; the affected cell has been highlighted red. Click OK to continue." & @CRLF & @CRLF & "This message closes automatically after ~30 seconds.", 30)
                    ContinueLoop
                Case "AR00062"
                    sendtosession("[PF10]")
                Case "CNS0003"
                    sendtosession("[PF5]")
                    While $Ps.GetText(2, 1, 8) <> "PM413-02"
                    WEnd
                    sendtosession("Y", 21, 46)
                    sendtosession("[enter]")
                    sendtosession("[PF11]")
            EndSwitch
        EndIf
        While $Ps.GetText(2, 1, 8) <> "PM413-02"
        WEnd

        sendtosession($Price, 10, 48)
        sendtosession("[eraseeof]", 10, StringLen($Price) + 48)
        If $Col_UOM <> "" Then sendtosession($UOM, 11, 48)
        If $Col_UOM <> "" Then sendtosession("[eraseeof]", 11, StringLen($UOM) + 48)
        sendtosession($Expiration_Date, 12, 48)
        sendtosession("[Enter]")

        While $Ps.GetText(2, 1, 8) <> "PM413-01"
        WEnd
        Switch $Ps.GetText(24, 2, 7)
            Case "CNS0008"
                $OBJ_Excel.Application.Cells($COUNTER_Row + 1, $Col_Item).Interior.ColorIndex = 6
                MsgBox(0, "Error", "For some reason this item was not accepted; the affected cell has been highlighted yellow. Click OK to continue." & @CRLF & @CRLF & "This message closes automatically after ~30 seconds.", 30)
                ContinueLoop
            Case "CNS0005"
                ContinueLoop
            Case "CNS0074"
                ContinueLoop
            Case "CNS0004"
                ContinueLoop
            Case Else
                $OBJ_Excel.Application.Cells($COUNTER_Row + 1, $Col_Item).Interior.ColorIndex = 7
                MsgBox(0, "Error", "An unknown error has occured. The affected cell has been highlighted pink. Click OK to continue." & @CRLF & @CRLF & "This message closes automatically after ~30 seconds.", 30)
                ContinueLoop
        EndSwitch
    Next
    MsgBox(0, "", "Success!")
    Exit
EndFunc   ;==>Change_Prices

Func Create_Helper_GUI()
    Local $GUI_Instruct_Label, $GUI_Window_Label, $Last_Title, $Contract_Expires, $Change_Prices_Button
    $GUI_hwnd = GUICreate("AS400 Contract Maintenance Tool", 600, 75, -1, -1, $GUI_SS_DEFAULT_GUI, $WS_EX_TOPMOST)
    GUISetState(@SW_SHOW)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents", $GUI_hwnd)
    $GUI_Instruct_Label = GUICtrlCreateLabel("Activate the AS400 session you would like to use to update the contract prices, then press CTRL-1.", 10, 10, 580)
    $GUI_Window_Label = GUICtrlCreateLabel("Current Window: " & WinGetTitle("[active]"), 10, 30, 580)
    HotKeySet("^1", "SET_AS400")
    While $AS400hwnd = ""
        If WinGetTitle("[active]") <> $Last_Title Then
            GUICtrlSetData($GUI_Window_Label, "Current Window: " & WinGetTitle("[active]"))
            $Last_Title = WinGetTitle("[active]")
        EndIf
    WEnd
    HotKeySet("^1")

    GUICtrlSetData($GUI_Instruct_Label, "OK, now activate the Excel document that contains your contract prices and press CTRL-1")
    HotKeySet("^1", "SET_EXCEL")
    While Not IsObj($OBJ_Excel)
        If WinGetTitle("[active]") <> $Last_Title Then
            GUICtrlSetData($GUI_Window_Label, "Current Window: " & WinGetTitle("[active]"))
            $Last_Title = WinGetTitle("[active]")
        EndIf
    WEnd
    HotKeySet("^1")

;~  GUICtrlSetData($GUI_Instruct_Label, "What is the contract expiration date?")
    GUICtrlSetData($GUI_Window_Label, "")
    GUICtrlDelete($GUI_Window_Label)
;~  $Contract_Expires = GUICtrlCreateDate("Expires:", 10, 30, 250, 25)
    $Change_Prices_Button = GUICtrlCreateButton("Change Prices", 410, 30)
    GUICtrlSetOnEvent($Change_Prices_Button, "change_prices")

    While 1
    WEnd


EndFunc   ;==>Create_Helper_GUI

Func SpecialEvents()
    Exit
EndFunc   ;==>SpecialEvents
Edited by DangerousDan

Share this post


Link to post
Share on other sites



This could be pure gold for me. At the moment AS400 is the only program I can't control in a good way and I"m just using clipget to get information. I'm gonna try this out next week :) . Tnx for sharing!

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

DangerousDan you are my hero :)

Actually I had a week vacation but I really wanted to try your script out. It works like a charm <3. To make it more usable as a UDF I made it like this:

Func sendtosession($keys, $rownum = 1, $colnum = 1, $inhibit = 1)
Global $Ps, $Oia 

$window = WinGetTitle("")
$AS400hwnd = WinGetHandle($window)
$Session = StringMid(WinGetTitle($AS400hwnd), 9, 1)


$Obj_ConnMgr = ObjCreate("PCOMM.autECLConnMgr") 
$OBJ_EmulSession = ObjCreate("PCOMM.autECLSession") 
$OBJ_EmulSession.SetConnectionByName($Session) 
$Ps = $OBJ_EmulSession.autECLPS 
$Oia = $OBJ_EmulSession.autECLOIA   
    
$Ps.SendKeys($keys, $rownum, $colnum) 
if $inhibit = 1 Then 
While $Oia.InputInhibited <> 0
WEnd
EndIf
EndFunc

Func getinfo ($row, $col, $lengte)
Global $Ps, $Oia 

$window = WinGetTitle("")
$AS400hwnd = WinGetHandle($window)
$Session = StringMid(WinGetTitle($AS400hwnd), 9, 1)


$Obj_ConnMgr = ObjCreate("PCOMM.autECLConnMgr") 
$OBJ_EmulSession = ObjCreate("PCOMM.autECLSession") 
$OBJ_EmulSession.SetConnectionByName($Session) 
$Ps = $OBJ_EmulSession.autECLPS 
$Oia = $OBJ_EmulSession.autECLOIA   
    
$info = $Ps.GetText($row,$col,$lengte) 
return $info
Endfunc

I tried to figure out how you sent other keys then numbers. It seems like AS400 uses a different language, for example to send F7 you have to sent "[PF7]"

http://publib.boulder.ibm.com/infocenter/pcomhelp/v5r9/index.jsp?topic=/com.ibm.pcomm.doc/books/html/host_access11.htm

A list with all the keys ^

Edited by Rigest

Share this post


Link to post
Share on other sites

I don't know if this goes up for all of AS400 clients, but we work with a lot of different screens within AS400. I made something simple to check if you're in the right place.

Func Checkscreen ($sign, $row, $colnum, $length)
    readycheck()
        $sign2 = getinfo ($row, $colnum, $length)
        If $sign = $sign2 Then
            sleep (1)
        Else
            Error($code)
        EndIf
Endfunc

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Not to raise a dead topic, but I wanted to come back and say a big "thank you!" to Dan and Rigest here for getting me pointed in the right direction on automating PCOMM sessions.

My usage isn't for AS400, but a regular IBM mainframe environment. We still use the IBM Personal Communications software as the emulator for it however.

I wanted to add some of my findings to this thread for future reference. You are perfectly able to create only the Presentation Space object on it's own (see $oPS below), it does not need to be accessed from the root "autECLSession" object. Same for the Operator Information Area object (see $oOIA below). And for most cases I can think of, using only the $oPS object allows you to accomplish pretty near anything as far as interacting with the session.

Two main issues I ran into when setting up automation of some tasks:

First, the $oPS.WaitForString() method seems like practically an answer to prayer for a method to wait for a specific screen to be displayed. However in actual usage, I found it to be incredibly slow, often taking upwards of 2 or 3 seconds after the session had returned to a "ready" state before returning the string position information to my script. I ended up replacing every usage of it with a combination of $oOIA.WaitForInputReady() and $oPS.SearchText(). After that change, the script is able to navigate the mainframe interface faster than the eye can follow, but without ever getting ahead of the mainframe when it hits a slowdown.

The second issue was with $oPS.SearchText(), specifically when trying to actually find the position of a string. According to the documentation, the SearchText() method can take an optional 3rd and 4th parameters of row and column variables, which upon return would be set to the row and column of the start of the string that was found. I believe I had read in the help (or somewhere) that AutoIt does not support this type of interaction with a COM object at this time. At any rate, when I tried it out for the heck of it, the variables were not altered when the string was found. So this method ends up being great to check that you're on the right track by telling you if the string is on the screen, but you'll have to write your own function to parse the output from $oPS.GetText() to find the row and column of a string if you need it.

After going through this I wonder if a PCOMM UDF would be useful. Though with only this single topic on the subject, there probably isn't a practical demand for it.

Code use example for some of the most used methods in the PCOMM objects:

$oPS = ObjCreate("PCOMM.autECLPS")
$oPS.SetConnectionByName("A")

$oOIA = ObjCreate("PCOMM.autECLOIA")
$oOIA.SetconnectionByName("A")

;; Intermediate code here...

$oPS.SetCursorPos($iRow, $iCol)

$oPS.SendKeys("s[enter][newline]s[enter]")

$oOIA.WaitForInputReady()

If Not $oPS.SearchText("*********** Top of Data *************") Then
    MsgBox(0,"error", "Error - Mainframe has stopped responding as expected.")
    Return 1
EndIf


$sText = $oPS.GetText()

$oPS.SendKeys("[PF3][PF3]")
Edited by bwochinski
1 person likes this

Share this post


Link to post
Share on other sites
bwochinski, this works even better! This opens so much possibilities for me <3. Thanks!

Share this post


Link to post
Share on other sites

Hi All,

I know this is a super old post but I was hoping some of the guys who contributed are still working with AS400.

Recently I have moved to a new company who run AS400 as there main mainframe system, one of the issues I noticed from the beginning is they have no way of automating very simple tasks or having the ability to capture data without the use of keying it directly into a worksheet. In the past I have always used emulators such as extra attachment which you can control from VBA in excel to send and capture data. After I did some research on Google I came across this nugget of information, whoever I'm still a little confused on a few things.

1) Is the code above VBA excel script ?

2) If so has anyone got anyone got any old examples I could look at.

King regards

Share this post


Link to post
Share on other sites

I know this is a super old post but I was hoping some of the guys who contributed are still working with AS400.

This is only 3 years, - it not so old.

1) Is the code above VBA excel script ?

No.  It is AutoIT scirpt.

 

2) If so has anyone got anyone got any old examples I could look at.

 

'?do=embed' frameborder='0' data-embedContent>>

'?do=embed' frameborder='0' data-embedContent>>

'?do=embed' frameborder='0' data-embedContent>>

'?do=embed' frameborder='0' data-embedContent>>

'?do=embed' frameborder='0' data-embedContent>>

What you want to achieve ?

 

King regards

 

Welcome to the forum.

Cheers

mLipok


Signature beginning:   Wondering who uses AutoIT and what it can be used for ?
* GHAPI UDF - modest begining - comunication with GitHub REST API *
ADO.au3 UDF     POP3.au3 UDF     XML.au3 UDF    How to use IE.au3  UDF with  AutoIt v3.3.14.x  for other useful stuff click the following button

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST API *

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 - BETA * ADO.au3 UDF SMTP Mailer UDF *

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Best coding practices * 

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * 

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2017-06-04

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0