Search code examples
ibm-midrangerpglerpg

Having dynamic text with MSGID in DSPF


I'm modifying an interactive program, having DSPF with an Output field:

MSGERR        80A  O 24  2MSGID(&§MSGID FILE_MSG) 

I pass an ID into MSGID and it's work perfectly.

Now I have a message like this:

VALUE CAN BE: &1, &2, &3

and I need to replace &1, &2, &3 with a TEXT.

Is it possible using the current method? Because I can't operate directly on MSGERR on RPGLE, because it isn't visible.


Solution

  • No, you can't. Instead of using MSGID, ERRMSGID, etc. I prefer a message subfile. It looks like this:

     A* ========================================================================
     A* Message Subfile
     A* ------------------------------------------------------------------------
     A          R MSGSFL                    SFL
     A                                      SFLMSGRCD(24)
     A            MSGKEY                    SFLMSGKEY
     A            PGMQ                      SFLPGMQ
     A* ------------------------------------------------------------------------
     A* Message Subfile - Control forrmat
     A* ------------------------------------------------------------------------
     A          R MSGCTL                    SFLCTL(MSGSFL)
     A                                      OVERLAY
     A                                      SFLINZ
     A                                      SFLPAG(1)
     A                                      SFLSIZ(2)
     A                                      SFLDSP SFLDSPCTL
     A  52
     AON52                                  SFLEND(*PLUS)
     A            PGMQ                      SFLPGMQ
    

    To use it you send messages to a program message queue, and then write MSGCTL as part of you screen transaction. So if you normally have a single record format on you screen named RECORD, you would do this:

    pgmq = <Program Name>;
    write msgctl;
    exfmt record;
    

    Any messages that are in the program message queue will be displayed in a one line subfile at line 24 on your display. This subfile is scrollable.

    You will need two sub-procedures to make this work easily, one to write the message, and another to clear the message queue. I name mine ClearDspfMsg(pgmq) and SendDspfMsg(pgmq: msgid: msgdata).

    Here are the procedures:

    // ------------------------------------
    // Clear Display File Messages
    // Clears the messages in the display file message subfile
    //
    // Parameters:
    //  pgmq        - Program message queue. This must be the same as the pgmq
    //                specified in the display file.
    // ------------------------------------
    dcl-proc ClearDspfMsg Export;
      dcl-pi *n;
        pgmq           Char(10) const;
      end-pi;
    
      dcl-ds ec            LikeDs(errCode_t) Inz(*LikeDs);
    
      qmhrmvpm(pgmq: 0: '': '*ALL': ec);
      // TODO Provide error checking here
    end-proc;
    
    // ------------------------------------
    // Send Message to Display File (MSGID)
    // Sends a message to the display file message subfile
    //
    // Parameters:
    //  pgmq        - Program message queue. This must be the same as the pgmq
    //                specified in the display file.
    //  messageId   - The message id of the message to be sent
    //  messageData - Message data for replacement values in the message. Format
    //                of the message data is defined by the message. This is
    //                optional, if missing, blanks are used.
    //  messageFile - The qualified name of the message file containing the
    //                message. The first 10 characters is the messafe file name,
    //                the second 10 characters is the library. This is optional,
    //                if blank, CNVMSG in *LIBL is used.
    // ------------------------------------
    dcl-proc SendDspfMsg Export;
      dcl-pi *n;
        pgmq           Char(10) const;
        messageId      Char(7) const;
        messageData    Varchar(256) const options(*varsize: *nopass);
        messageFile    LikeDs(qualName_t) const options(*nopass);
      end-pi;
    
      dcl-ds msgf      LikeDs(qualName_t) Inz(*likeds);
      dcl-ds ec        LikeDs(errCode_t) Inz(*likeds);
    
      dcl-s msgData    Char(256) Inz('');
    
      if %parms() >= %parmnum(messageData);
        msgData = messageData;
      endif;
      if %parms() >= %parmnum(messageFile);
        msgf = messageFile;
      else;
        msgf.name = 'MSGF';  // This is your default message file
      endif;
    
      qmhsndpm(messageId: msgf: msgData: %size(msgData): '*INFO': pgmq: 0: '': ec);
      // TODO Provide error checking here
    end-proc;
    

    I have prototypes for qmhsndpm and qmhrmvpm, but you can look up those and the format of the error code parameter in the documentation easily enough.

    Call SendDspfgMsg() to send a message, and ClearDspfMsg() to clear the message queue at the beginning of your transaction. PGMQ should have the same value for all of these parts, and it will just work.

    NOTE: This will not work for RPG since you don't have access to sub-procedures. If necessary, convert your program to RPGLE, and it will work fine. Or use subroutines rather than sub-procedures in that case.