Handling Fat screens in RPG with IBM i API’s QsnQryModSup and QuiLngTx

I was having a mini-rant earlier about the problems with the old 24×80 screen size. Basically, the newer wider 27×132 is much nicer ( we all know that ) but older 24×80 5250 sessions will get very upset when they try to display a menu or screen that is designed at the 132 characters wide format. Luckily there is a nice easy, and generic way of programming your way out of that particular corner using the snazzily titled ‘QsnQryModSup‘ and ‘QUILNGTX‘ program interfaces.

Of course, all RPG programmers know that we could go the complicated route of adding DDS descriptions for *DS3 and *DS4 screen formats. We could setup multiple versions of our screen layouts for both screen sizes. But we’ve told the kids to use 27×132 as standard so it’s time to get harsh with those naughty boys and girls if they insist on running with a small screen size.

But, I prefer this solution using two nice little IBM i *APIS:

QsnQryModSup

The QuesonquuerieMowdSupp API will accept an input of a screen size, compare it against your 5250 signon session and tell you if you are able to display that screen size. You pass a ‘3’ to check if it can handle 24×80 and a ‘4’ to see if it can handle widescreen 27×132.

QUILNGTX

The QueueueuyLungTax API will let us send a message to the user, regardless of his screen size, in a nice looking standard IBM window without using our programs *DSPF.

So, here is our problem, let’s imagine we know that a menu is written using 27×132 and we want to prevent a nasty “screen format cannot be handled” type error message if the user accidentally signs on with a 24×80 screen size and we cant be bothered to redesign the menu DDS to add all the alternate screen field positions and field sizes for both formats.

Luckily, we have a nice easy and elegant solution — We can add some error handling to the RPG program without changing any DDS in our *DSPF! #YAY

The basic idea is before we open the 27×132 DSPF, and potentially crash if the terminal is in 24×80 mode, we simply check the 5250 screen size can handle wide screen. If it cannot then we display a nice IBM style window telling the user to expand their terminal mode to 27×132 and gracefully end the program.

Sound easy right?

It really is, we just add a couple of RPG Procedures to our program

Procedure 1 – Check the 5250 Screen size can be handled

// +---------------------------------------------------------------+
// | Procedure to check if a given screen mode is valid. +
// | - Parm(p_screensize) can be '3' for 24x80 or '4' for 27x132 +
// +---------------------------------------------------------------+
RPG Code Snippetdcl-proc ValidScreenSize export;

dcl-pi ValidScreenSize ind;
  p_screensize char(1) const;
end-pi;

dcl-s IsValid char(1);

dcl-pr QsnQryModSup extproc( 'QsnQryModSup' );
  *n char(1) const; // DspMode
  *n ind; // IsValid
  *n int(10) options( *omit ); // Handle
  *n options( *omit: *varsize ) like( apierror ); // ErrorDS
end-pr;

QsnQryModSup ( p_screensize
             : IsValid
             : *Omit
             : *Omit 
             ); 

Return IsValid;

end-proc;

(obviously this code should be in a service program to make it re-useable but for code readability in this blog I’ve copy/pasted it separately)

 

Procedure 2 – Display Window with error message

// +---------------------------------------------------------------+
// | Display String of Data in Popup IBM i Window +
// +---------------------------------------------------------------+
// The Display Long Text (QUILNGTX) API displays a pop-up window containing
// the string of text that is passed to it.
// This API may not be used to display text that is bidirectional right2left. 
//
// Required Parameter Group
// Text string
//   INPUT; CHAR(*)
//   The text string that is to be displayed in a pop-up window.
// Length of text string
//   INPUT; BINARY(4)
//   The length of the text string, in bytes. The value must be greater
//   than zero and less than or equal to 15 728 640.
// Message ID
//   INPUT; CHAR(7)
//   The specified message ID of the panel title text that will be retrieved.
//   If the message ID is not found in the specified message file, the message
//   ID will be displayed at the top of the panel as the title. If the message
//   ID is blank, the title for the panel is blank.
// Qualified message file name
//   INPUT; CHAR(20)
// Error code
//   I/O; CHAR(*)
//
// Error Messages
//   Message ID Error Message Text
//   CPF3C90 E Literal value cannot be changed
//   CPF6A4C E At least one parameter value is not correct. Reason code is &1
//   CPF9871 E Error occurred while processing 
dcl-proc dspWindow export;
 dcl-pi dspWindow;
 p_Text varchar(8192) const;
 p_MsgId char(7) Options(*nopass:*omit);
 p_MsgFile char(21) Options(*nopass:*omit);
 end-pi;

dcl-ds myApiError likeds(apierror); 

dcl-pr QUILNGTX extpgm('QUILNGTX');
 *n char(8192) const; // MsgText
 *n int(10) const; // MsgLength
 *n char(7) const; // MessageId
 *n char(21) const; // MessageFile
 *n options( *omit: *varsize ) like( apierror ); // ErrorDS
 end-pr;

dcl-s MsgId like(p_MsgId);
dcl-s MsgFile like(p_MsgFile);

If %Parms = 1;
  MsgId = 'CPF9999';
  MsgFile = 'QCPFMSG';
Elseif %Parms = 2;
  MsgId = p_MsgId;
  MsgFile = 'QCPFMSG';
Elseif %Parms = 3; 
  MsgId = p_MsgId;
  MsgFile = p_MsgFile;
Endif ;

QUILNGTX ( p_Text
         : %Len(p_Text)
         : MsgId
         : MsgFile
         : myApiError
         );
 
end-proc;

 

Mainline 1 – Check screen size before opening DSPF

So, now we just need to check our 5250 screen size before we issue the OPEN DSPF statement.

If the screen size is returned as 24×80 then we will use the new dspWindow procedure to popup a nice little window.

Lets add a global Data Structure (to capture some errors) — alternatively this could have been added locally in each subprocedure of course.

 

// Global Error Capture DataStructure used by a few procedures 
dcl-ds ApiError inz qualified;
 Bytes int(10) inz( %size( apierror ));
 BytesAvailable int(10) inz;
 ErrorID char(7) inz;
 Reserved char(1) inz( x'00' );
 MessageData char(128) inz;
end-ds;

/title -------------------- MAINLINE -------------------------

// Check that this DSPF screen size can be displayed on this monitor (3=24x80; 4=27x132)
If not ValidScreenSize('4'); 
 dspWindow ('This program needs a screen resolution of 27x132 to operate. +
             But your 5250 signon sessions is configured at a smaller screen size. + 
             Please signon with a 27x132 widescreen format and run the +
             command again. Press ENTER or F12 to Exit');
else;

 Open 'program DSPF';
 // force load of initial page
 pfKey(05) = *on;
 .. do all our program logic stuff

endif;

*inlr = *on;

That makes sense right?

 

Let’s test this schnizzle

If I signon with a 27×132 screen, the checks are passed and I see my widescreen subfile:

If I deliberately signon with a 24×80 screen I see this nice little error message:

QsnQryModSup

 

If you look at the DspWIndow subprocedure you will see I coded some extra twiddly bits (thats a technical term) to allow a little more flexibility to our window display.

So, how about you tweak it yourself and perhaps go with something like this:

Declare a variable to hold the screen message. I always think it’s neater to use variables:

dcl-s dspWindowText varchar(8192);

dspWindowText='Enter any message you like here. It will be displayed +
               in a standard IBM i style ''window'' with a nice little +
               F12=Cancel function key to proceed. This is a +
               particularly handy technique to use if you want to +
               display a short message (or content of some variable) +
               when debugging, or from a simple program that doesn''t +
               need a DSPF to be coded just for a clean screen message. +
               It wraps word text and displays on both 24x80 and 27x132 +
               screen formats';

dspWindow ( dspWindowText );

or we could use a message file if you want to soft-code your messages or build a multi-language interface:

// optionally you can qualify the messagefile if you want to send a msgid
dspWindow  ( ' ' : 'ABC1234' : 'NLMSGF' );

// or you could send the message as MSGDTA if you were being really fancy
dspWindow  ( 'this is the data in to the MSGDTA value' : 'CPF9898' : 'QCPFMSG' );

And that, say they say, is that…

(0 votes) 0/10