Grab Data from the Screen, Part 2

Article ID: 57349

In the October 9, 2008, issue of this newsletter, I published an article that explained how you can use the dynamic screen manager APIs from an RPG program to extract data from the current screen. The article demonstrated a program that runs under the user's attention key to extract data from the screen and pass it as a parameter to a web browser.

I received a response from Robert Jokisch explaining how to do the same thing from CL using DDS instead of calling APIs.

But wait...

Before I show you Robert's technique, I'd like to give you a little background about how both techniques work and what the differences are between them.

Both techniques do the same thing. They send a 5250 "Read Screen" order to the terminal, causing the terminal to send back the contents of the display. Both techniques read that display into a buffer and then let you work with the contents of that buffer.

So what's the difference between the two techniques? Robert manually builds the 5250 commands as a series of hex characters in a string. He uses a user-defined DDS record format to let him send that raw 5250 code to the terminal. He uses the same user-defined DDS screen to retrieve the response from the terminal.

My technique creates the same underlying 5250 code, but instead of hand-coding the hex characters in a string, I call an API that generates them. The API retrieves the contents of the screen into memory (without any need for DDS), and a second API call gets a pointer to that space in memory.

Robert's technique has the advantage that it can be used from any release, it can be used in OPM languages, and it does not require any use of pointers.

My technique requires an ILE language because the APIs are implemented as ILE subprocedures. It requires some minimal pointer work to get the display buffer. This precludes you from using an OPM language. And because pointers are required, you can't use ILE CL unless you're running i5/OS V5R4 or higher.

The advantage of my technique is that you don't have to generate the 5250 codes yourself. The APIs generate the 5250 sequence and verify that the 5250 sequence is correct. With Robert's technique, if you send the wrong hex codes, there's no safety net! You may cause an error in your job or even cause the terminal to go haywire. This isn't as bad as it sounds, however, since the hex codes have already been written and tested. You'd have to code your own only if you wanted to make it work differently. My technique has another advantage as well: It can provide the entire code sample in one member, whereas Robert's technique uses three members--two DDS members and one CL program.

So each approach has pros and cons; if you're a CL programmer who is uncomfortable with APIs, pointers, and RPG code, Robert's technique will be a better choice.

Robert's Technique

The technique starts by defining a DDS record format that can retrieve all the data on the screen in one go. This format isn't actually used by the program when it runs, but it's used to establish the record format that the CL program reads from the screen. So it's really only needed to compile the CL program.

This is member SCR_SHOT of file QDDSSRC.

     A          R SCRFMT
     A                                      OVERLAY CLRL(*NO)
     A            R1DATA1     1782   B  1  2
     A            R1DATA2     1782   B  1  2

The next DDS format is the one that does the actual work. Note that the first format in the following display file is named SCRFMT, the same as the first format of the preceding one.

This is member SCR_SHOT1 of file QDDSSRC:

     A                                      DSPSIZ(*DS3 *DS4)
     A          R SCRFMT                    USRDFN
      *
     A          R SCRFMT01
     A            FILLER1     1782   B  1  2
     A            FILLER2     1782   B  1  2

Note that the SCRFMT record format in this display file has the USRDFN keyword. This means that you will be working directly with the raw 5250 data stream. Notice that the SCRFMT record format has no subfields in it--that's why we needed the SCR_SHOT display file--to give the CL compiler a place to get external field definitions when it compiles the Declare File (DCLF) CL command.

The SCRFMT01 record format exists only to control the size of the buffer used by this display file. It ensures that the buffer will be large enough for all data that can fit on the screen. You see, a screen that can have 27 rows of 132 columns needs space for 3,564 bytes (27 x 132 = 3,564). Because that's too long for one field, it's split into two fields that are 1,782 bytes long.

Here's the CL program that uses Robert's technique to extract data from the screen. For information about the fields being extracted, see my RPG example from the October 9 newsletter.

PGM
      DCL  VAR(&SCREENDATA) TYPE(*CHAR) LEN(3564)
      DCL  VAR(&ORDNO)      TYPE(*CHAR) LEN(5)
      DCL  VAR(&CUST)       TYPE(*CHAR) LEN(4)
      DCL  VAR(&SCREEN)     TYPE(*CHAR) LEN(9)
      DCLF FILE(SCR_SHOT) RCDFMT(SCRFMT)

      OVRDSPF FILE(SCR_SHOT) TOFILE(SCR_SHOT1) LVLCHK(*NO)
      CHGVAR  VAR(&R1DATA1) VALUE(X'00021518730462')
      SNDRCVF RCDFMT(SCRFMT)

      CHGVAR VAR(&SCREENDATA) VALUE(&R1DATA1 *CAT &R1DATA2)
      CHGVAR VAR(&SCREEN)     VALUE(%SST(&SCREENDATA 71 9))
      CHGVAR VAR(&ORDNO)      VALUE(%SST(&SCREENDATA 49 5))
      CHGVAR VAR(&CUST)       VALUE(%SST(&SCREENDATA 173 4))

      IF (&SCREEN *EQ 'OEICBDS2C') DO
         STRPCO
         MONMSG MSGID(IWS4010)

         STRPCCMD PCCMD('rundll32 url,FileProtocolHandler +
                    http://as400.EXAMPLE.com/cgi-bin/oeiinvhr4.pgm+
                    ?order=' *TCAT &ORDNO *TCAT +
                    '&cust=' *TCAT &CUST) +
                  PAUSE(*NO)
      ENDDO

ENDPGM

Note that the program declares the SCR_SHOT display file but uses the OVRDSPF command to force the program to use the SCR_SHOT1 display file instead. So the "normal" display file will be replaced with the user-defined one, but we'll still use the record format from the "normal" one.

Because Robert's technique makes it much more difficult to determine whether the screen is in 80- or 132-column mode, the preceding example assumes that there are 80 columns on the screen. Because CL has no arrays, the screen data is loaded into one big field named &SCREENDATA in the preceding example. Positions 1-80 of &SCREENDATA contain the first row of the screen. Positions 81-160 contain the second row, positions 161-240 contain the third row, and so forth.

Therefore, when the program extracts the &CUST variable by substringing four bytes starting at position 173 of the &SCREENDATA variable, it's actually extracting four bytes starting at column 13 on the third row of the screen.

To compile the sample code in this article, please run the following commands:

   CRTDSPF FILE(SCR_SHOT) SRCFILE(MYLIB/QDDSSRC)
   CRTDSPF FILE(SCR_SHOT1) SRCFILE(MYLIB/QDDSSRC)
   CRTCLPGM PGM(GRABDATA) SRCFILE(MYLIB/QCLSRC)

Part 1 of this article is titled "Grab Data from the Screen."

Robert Jokisch provided the sample code in this article. Thank you, Robert!

ProVIP Sponsors

ProVIP Sponsors