• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Guru: The SND-MSG Op Code And Message Subfiles

    September 12, 2022 Ted Holt

    If you’re one of the many IBM i programmers who still writes green-screen applications, think about how your programs communicate with the users. How do you tell a user that a value that he’s just entered is invalid, or that he needs to press a command key to proceed? I’ve seen several methods, but a common one — and my favorite — is to communicate through a message subfile.

    The nice thing about message subfiles is that I can report two or more messages at one time. I like the computer to find as many errors as possible and let the user address all of them before he tries again. It annoys me to use an application (even Web pages) that tell me to fix one error at a time, yet I have seen green-screen applications that work this way. I have probably written some.

    This story contains code, which you can download here.

    To use a message subfile in a program, you need to define a message subfile and corresponding subfile control record in a display file. Here’s the source code I always use. The only thing I change is the value in the SFLMSGRCD keyword, depending on the display size (24×80 or 27×132) or window size.

         A          R MSGSFL                    SFL
         A                                      SFLMSGRCD(24)
         A            MSGKEY                    SFLMSGKEY
         A            PGMNAME                   SFLPGMQ
         A          R MSGCTL                    SFLCTL(MSGSFL)
         A                                      OVERLAY
         A                                      SFLDSP
         A                                      SFLDSPCTL
         A                                      SFLINZ
         A N99                                  SFLEND
         A                                      SFLSIZ(10)
         A                                      SFLPAG(1)
         A            PGMNAME                   SFLPGMQ 
    

    The RPG program interacts with the message subfile in two ways:

    • The program sends appropriate messages to the program message queue.
    • After the user has had an opportunity to view the messages, the program clears the program message queue.

    The usual way to send messages to the program message queue is to use the Send Program Message (QMHSNDPM) API. To remove the messages so that user doesn’t continue to see them, use the Remove Program Messages (QMHRMVPM) API. Through the years we’ve published quite a few articles that featured these APIs. Here’s one from 20 years ago. The source code is antiquated, but the principles still apply.

    I was delighted to learn recently that IBM made this process even easier with the introduction of the SND-MSG op code. SND-MSG and QMHSNDPM do, more or less, the same thing, but SND-MSG is easier to use. You still need QMHRMVPM, as IBM did not give us an RPG counterpart for that.

    Here’s an example you can compile and play with if you’re interested. First, here’s the DDS for display file THQ0051D.

         A                                      DSPSIZ(24 80 *DS3)
         A                                      CA03(03 'F3=EXIT')
    
         A          R REC1
         A                                      OVERLAY
         A                                  1 36'Data Entry'
         A                                  3  3'Fill in the blanks, press Enter.'
         A                                  5  3'Your name . . . . . :'
         A            NAME          24   B  5 25
         A  61                                  DSPATR(PC RI)
         A                                  7  3'Your age  . . . . . :'
         A            AGE            3  0B  7 25
         A  62                                  DSPATR(PC RI)
         A                                  9  3'Your address  . . . :'
         A            STREET        24   B  9 25
         A  63                                  DSPATR(PC RI)
         A                                 10  5'City, state, ZIP  :'
         A            CITY          16   B 10 25
         A  64                                  DSPATR(PC RI)
         A            STATE          2   B 10 43
         A  65                                  DSPATR(PC RI)
         A            ZIP            5  0B 10 47
         A  66                                  DSPATR(PC RI)
         A                                 23  5'F3=Exit'
    
         A          R MSGSFL                    SFL
         A                                      SFLMSGRCD(24)
         A            MSGKEY                    SFLMSGKEY
         A            PGMNAME                   SFLPGMQ
    
         A          R MSGCTL                    SFLCTL(MSGSFL)
         A                                      OVERLAY
         A                                      SFLDSP
         A                                      SFLDSPCTL
         A                                      SFLINZ
         A N99                                  SFLEND
         A                                      SFLSIZ(10)
         A                                      SFLPAG(1)
         A            PGMNAME                   SFLPGMQ 
    

    REC1 is a simple data-entry format. The user enters a name, age, and address.

    Here’s RPG program THQ0051R, which drives the screen.

    **free
    ctl-opt actgrp(*new) option(*srcstmt: *nodebugio);
    
    dcl-f  THQ0051D   workstn;
    
    dcl-ds  psds  psds;
       PgmName   char(10);
    end-ds;
    
    dcl-pr QMHRMVPM  extpgm;
       CallStackEntry    char(10)  const;
       CallStackCounter  int (10)  const;
       MessageKey        char( 4)  const;
       MessagesToRemove  char(10)  const;
       ErrorCode         int (10)  const;
    end-pr QMHRMVPM;
    
    dcl-s  DataIsValid    ind;
    
    *inlr = *on;
    
    dou *in03
     or DataIsValid;
       write MsgCtl;
       exfmt Rec1;
       QMHRmvPM (PgmName: *zero: *blanks: '*ALL': *zero);
       if not *in03;
          exsr Validate;
       endif;
    enddo;
    
    // Do something with the data
    
    return;
    
    begsr Validate;
    
       %subarr(*in: 61: 6) = *all'0';
    
       if Name = *blanks;
          *in61 = *on;
          Snd-Msg 'Your name is required.';
       endif;
    
       if Age < 18;
          *in62 = *on;
          Snd-Msg 'Age must be 18 or greater.';
       endif;
    
       if not (State in %list('TX': 'OK': 'LA'));
          *in65 = *on;
          Snd-Msg 'The state "' + State + '" is not authorized.';
       endif;
    
       // Similar code to validate the other fields.
    
       DataIsValid = not (   *in61 or *in62 or *in63
                          or *in64 or *in65 or *in66 );
    
    endsr; 
    

    Let me direct your attention to the Validate subroutine. Notice the simplicity of the SND-MSG operations to send impromptu informational messages to the program message queue. I don’t see how it could be any easier.

    In my zeal to make the example easy to understand, I kept the DDS and RPG source code short and simple. If I were writing this code for production, I would make a few enhancements.

    • I would qualify the display file so that the compiler would not assign global variables to the fields.
    • I would use a subprocedure instead of a subroutine to validate the data so that I could pass the data through parameters instead of using global data.
    • I would add a global catch-all monitor so that the user would never see the Display Program Messages display. IBM kindly provides the Resend Escape Message (QMHRSNEM) API, which works well in this context.

    Here is the same application beefed up a bit. The display file needs only one change: qualifying the file in the RPG program requires the display file DDS to have the INDARA keyword.

    A                                      DSPSIZ(24 80 *DS3)
    A                                      INDARA            
    A                                      CA03(03 'F3=EXIT')
     . . . and so on . . .
    

    Here’s the RPG program with the changes I mentioned.

    **free
    ctl-opt main(THQ0054R) actgrp(*new) option(*srcstmt: *nodebugio);
    
    dcl-f  Display    workstn   qualified
                                extdesc('THQ0052D') extfile(*extdesc)
                                alias
                                indds(wsi)
                                usropn;
    
    dcl-ds  Rec1_t   LikeRec(Display.REC1  : *all)   template;
    dcl-ds  MsgCtl_t LikeRec(Display.MsgCtl: *all)   template;
    
    // Indicator data structure for display file
    dcl-ds wsi             len(99)   qualified    inz;
       ExitRequested       ind       pos( 3);
       ErrorInds           char(6)   pos(61);
       ErrorInd_Name       ind    overlay(ErrorInds:  1);
       ErrorInd_Age        ind    overlay(ErrorInds:  2);
       ErrorInd_Street     ind    overlay(ErrorInds:  3);
       ErrorInd_City       ind    overlay(ErrorInds:  4);
       ErrorInd_State      ind    overlay(ErrorInds:  5);
       ErrorInd_Zip        ind    overlay(ErrorInds:  6);
    end-ds wsi;
    
    dcl-ds  psds  psds     qualified;
       PgmName   char(10);
    end-ds;
    
    dcl-pr QMHRMVPM  extpgm;
       CallStackEntry    char(10)  const;
       CallStackCounter  int (10)  const;
       MessageKey        char( 4)  const;
       MessagesToRemove  char(10)  const;
       ErrorCode         int (10)  const;
    end-pr QMHRMVPM;
    
    dcl-pr QMHRSNEM extpgm;
       MessageKey        char( 4)   const;
       ErrorCode         int (10)   const;
    end-pr QMHRSNEM;
    
    dcl-proc THQ0054R;
    
       monitor;
          THQ0054R_Main ();
       on-error;
          QMHRsnEM (*blanks: *zero);
       endmon;
    
    end-proc THQ0054R;
    
    dcl-proc THQ0054R_Main;
    
       dcl-s  DataIsValid    ind;
    
       dcl-ds  Rec1_data   likeds(Rec1_t)   inz;
       dcl-ds  MsgCtl_Data likeds(MsgCtl_t) inz;
    
    
       open Display;
    
       dou wsi.ExitRequested
        or DataIsValid;
          MsgCtl_data.PgmName = psds.PgmName;
          write Display.MsgCtl MsgCtl_data;
          exfmt Display.Rec1   Rec1_data;
          QMHRmvPM (psds.PgmName: *zero: *blanks: '*ALL': *zero);
          if not wsi.ExitRequested;
             Validate (Rec1_data: DataIsValid);
          endif;
       enddo;
    
       // Do something with the data
    
       close Display;
    
    end-proc THQ0054R_Main;
    
    dcl-proc Validate;
    
       dcl-pi *n;
          inRec1_data      likeds(Rec1_t)   const;
          ouDataIsValid    ind;
       end-pi;
    
       wsi.ErrorInds = *zeros;
    
       if inRec1_data.Name = *blanks;
          wsi.ErrorInd_Name = *on;
          Snd-Msg 'Your name is required.' %target(psds.PgmName);
       endif;
    
       if inRec1_data.Age < 18;
          wsi.ErrorInd_Age = *on;
          Snd-Msg 'Age must be 18 or greater.' %target(psds.PgmName);
       endif;
    
       if not (inRec1_data.State in %list('TX': 'OK': 'LA'));
          wsi.ErrorInd_State = *on;
          Snd-Msg ('The state "' + inRec1_data.State + '" is not authorized.')
                   %target(psds.PgmName);
       endif;
    
       // Similar code to validate the other fields.
    
       ouDataIsValid = (wsi.ErrorInds = *zeros);
    
    end-proc Validate; 
    

    I see no need to try to explain all of this code, but I should point out the change to the SND-MSG operation, since that’s the topic of this article. Since SND-MSG is in a subprocedure, I have to use the %TARGET keyword to specify the name of the program message queue.

    Snd-Msg 'Your name is required.' %target(psds.PgmName);
    

    I also want to point out that the RPG program uses the message subfile control record, but not the message subfile record itself. That’s true whether the display file is qualified or not.

    Communication skills are important in all areas of life, and it’s unfortunate that many people never learn to communicate effectively in either spoken or written form. Fortunately, it’s not difficult to make a green-screen program communicate with the user, and now that it we have the SND-MSG op code, it’s easier than ever.

    RELATED STORIES

    RPG Subprocedure Error-Handling with APIs

    Guru: Qualified Files – Underused and Unappreciated

    Using APIs to Send Impromptu Messages

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags: Tags: 400guru, API, FHG, Four Hundred Guru, IBM i, RPG

    Sponsored by
    Maxava

    Migrate IBM i with Confidence

    Tired of costly and risky migrations? Maxava Migrate Live minimizes disruption with seamless transitions. Upgrading to Power10 or cloud hosted system, Maxava has you covered!

    Learn More

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    IBM Rejiggers RPM Repos for Open Source Software Thoroughly Modern: Four Ways Staff Augmentation Is Helping IT Get Things Done

    2 thoughts on “Guru: The SND-MSG Op Code And Message Subfiles”

    • Steven Easton says:
      September 12, 2022 at 9:23 am

      Better to have an error message beside each data field. Make the text red for the error. Works even better for HTML screens.

      Reply
    • Elio Mussi says:
      September 22, 2022 at 8:10 am

      I would have added, at the beginning oh the article that SND-MSG requires V5.7

      Thanks for your time on writing the article. Cheers Elio

      Reply

    Leave a Reply Cancel reply

TFH Volume: 32 Issue: 59

This Issue Sponsored By

  • TL Ashford
  • Fresche Solutions
  • WorksRight Software
  • Computer Keyes
  • Manta Technologies

Table of Contents

  • The Scoop On The Full Subscription Power S1014 With IBM i
  • Thoroughly Modern: Four Ways Staff Augmentation Is Helping IT Get Things Done
  • Guru: The SND-MSG Op Code And Message Subfiles
  • IBM Rejiggers RPM Repos for Open Source Software
  • IBM i PTF Guide, Volume 24, Number 36

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • POWERUp 2025 –Your Source For IBM i 7.6 Information
  • Maxava Consulting Services Does More Than HA/DR Project Management – A Lot More
  • Guru: Creating An SQL Stored Procedure That Returns A Result Set
  • As I See It: At Any Cost
  • IBM i PTF Guide, Volume 27, Number 19
  • IBM Unveils Manzan, A New Open Source Event Monitor For IBM i
  • Say Goodbye To Downtime: Update Your Database Without Taking Your Business Offline
  • i-Rays Brings Observability To IBM i Performance Problems
  • Another Non-TR “Technology Refresh” Happens With IBM i TR6
  • IBM i PTF Guide, Volume 27, Number 18

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle