Message subfiles are special subfiles designed to hold messages. Message subfiles have some unique properties that make them very useful. They load themselves automatically from messages on a given program message queue. Message subfiles also allow users to view the second-level help text associated with a message, without any additional programming effort. Message subfiles make it possible to setup a consistent set of information, warning, or error messages in a message file for a given program or application, and to display those messages to the user with ease. To implement a message subfile the following steps are to be done, Set up a message file (*MSGF) containing the messages you want to use in your application. One can use an existing message file or create one of your own. You should not usually modify system-supplied message files, such as QCPFMSG. Message files are created with the CRTMSGF command. New messages can be added via the ADDMSGD command or the WRKMSGF command. Define a message subfile in your display file. Below is the sample display file that has been used. DISPLAY: SFMSGDSP 0000.30 0000.40 0000.60 0000.70 0000.80 0000.90 0001.00 0001.10 0001.20 0001.30 0001.50 0001.60 0001.70 0001.80 0002.00 0002.10 0002.20 0002.30 0002.40 0002.50 0002.60 A A A A A A A A A A A A A A A A A A A 81 A A DSPSIZ (24 80 *DS3) R RECORD1 CA03 (03 'EXIT') OVERLAY 3 3’MESSAGE SUBFILE' B 7 13 I 7 46 23 2‘MESSAGE:' 24 3'F3=EXIT' SFL SFLMSGRCD (19) SFLMSGKEY SFLPGMQ(10) SFLCTL (SFMSFL) SFLSIZ (0002) SFLPAG (0001) CA03 (03 'EXIT') OVERLAY SFLDSP SFLINZ SFLPGMQ (10)




The display contain three record format highlighted in red. Filling and clearing the message subfile are not like the normal subfile programming. With message subfiles, we don't explicitly clear the subfile in the program rather; we link the subfile to a program message queue and remove messages from that message queue. Similarly By linking the message subfile to a specific program message queue and sending messages to that queue, the message subfile will automatically load itself with records from the program message queue. In the message subfile record format, the following keywords are required: • SFLMSGRCD is used to set the starting line on the display for the message subfile. In most cases it is set to 24 (the bottom line of the display). • SFLMSGKEY controls the message key of the first message that is to be displayed in the message subfile. Every message on a message queue has a unique message key that is assigned as the message arrives on the message queue. In certain cases, you may wish to maintain old messages on the queue and only display messages from a certain point forward in the message subfile. Setting the message key allows you to control which messages are displayed.

SFLPGMQ controls which program message queue the messages are pulled from. In the program it is fetched from a program status data structure which then is associated with display file field. This keyword also defines the output fields, No explicit code is necessary to define your subfile fields. Also, SFLPAG must be at least one less than SFLSIZ in a message subfile, they cannot be equal. Specifying SFLPGMQ keyword in the subfile record format allows you to link the subfile to a specific program message queue, which then allows you to clear and possibly load the subfile by controlling the program message queue. If not defined one will have to code the load routine in the program. Now one can Code their application program, wherein based on some validations, program messages can be send to the program message queue. The best way to accomplish this in RPG is to use the QMHSNDPM (Send Program Message) API or use the SNDPGMMSG command, while coding in a CL program. Both the approaches are discussed below. After displaying the message subfile, clear the messages from the program message queue using the QMHRMVPM (Remove Program Message) API or RMVMSG via CL. •

Message subfile is basically implemented in the following methods, a).Through a CL program, using SNDPGMMSG and RMVMSG command. b).Through RPG wherein one can use API’s like QMHSNDPM and QMHRMVPM

a).Through a CL program, using SNDPGMMSG and RMVMSG command:
In this approach we write a RPG program from where we pass certain parameters to a CL program. The CL program Based on the received parameters, will either fetch message from a message file from a valid library or will pass an immediate text as message to the message subfile. The parameters that the CL program receives are as follows, SND_ID (*CHAR LEN (7)) : This represents the message id that is to be showed on the message subfile SND_DT (*CHAR LEN (80)) : This hold the direct text that is supposed to be passed as message to the message subfile. On specifying a variable to this field, SND_ID, SND_FI, SND_LB are to be made blanks (highlighted in red below). SND_TY (*CHAR LEN (10)) : The type of the message. Following values can be used *comp,*diag ,*escape,*info,*inq,*notify,*rqs,*status. SND_FI (*CHAR LEN (10)) : This is a qualified message file name from which the messages are to be fetched SND_LB (*CHAR LEN (10)) : Valid library in which the message file is present. SND_MS (*CHAR LEN (3)) : This is user defined parameter based on which message is fetched from a *MSGF or a direct text is passed as message. Valid values are MSF (message file), IMD (immediate text). This purely user defined and is not mandatory. For more information on SNDPGMMSG and RMVMSG visit

RPG CODE: RPGLE: SFMSGCLRPG 0002.00 FSFMSGDSP CF E WORKSTN 0003.00 DPSDS SDS 0004.00 DPGM_NAM *PROC 0004.01 DMSF PR EXTPGM ('MSGSFCL') 0004.02 Dsnd_id 7a 0004.03 Dsnd_dt 80a 0004.04 Dsnd_ty 10a 0004.05 Dsnd_fi 10a 0004.06 Dsnd_lb 10a 0004.07 Dsnd_ms 3a

0004.08 Dsnd_id s 7a Inz (*Blank) 0004.09 Dsnd_dt s 80a Inz (*blanks) 0004.10 Dsnd_ty s 10a Inz ('*DIAG') 0004.11 Dsnd_fi s 10a Inz ('MESSAGE') 0004.12 Dsnd_lb s 10a Inz ('WKBZ37NX') 0004.13 Dsnd_ms s 3a Inz (*blanks) 0005.00 /FREE 0006.00 sfmpmq=PGM_NAM; 0007.00 DOW NOT *IN03; 0008.00 write sfmctl; 0009.00 exfmt record1; 0010.00 *IN81=*ON; 0011.00 if *in03; 0012.00 leave; 0013.00 endif; 0013.01 if opt<>'S' and opt<>'E' and opt<>*blanks; 0013.03 snd_id='MSG0002'; 0013.04 snd_fi='MESSAGE'; 0013.05 snd_lb='WKBZ37NX'; 0013.06 snd_ms='MSF'; 0013.07 callp MSF (snd_id: 0013.08 snd_dt: 0013.09 snd_ty: 0013.10 snd_fi: 0013.11 snd_lb: 0013.12 snd_ms); 0013.13 opt=*blank; 0013.14 endif; 0013.15 if opt='S'; 0013.16 snd_id=MSGF; 0013.17 snd_fi='MESSAGE'; 0013.18 snd_lb='WKBZ37NX'; 0013.19 snd_ms='MSF'; 0013.20 callp MSF (snd_id: 0013.21 snd_dt: 0013.22 snd_ty: 0013.23 snd_fi: 0013.24 snd_lb: 0013.25 snd_ms); 0013.26 opt=*blank; 0013.27 endif; 0013.28 if opt='E'; 0013.29 snd_id=*blanks; 0013.30 snd_fi=*blanks; 0013.31 snd_lb=*blanks; 0013.32 snd_ms='IMD'; 0013.33 snd_dt='This message is executed via message subfile'; 0013.34 callp MSF (snd_id: 0013.35 snd_dt: 0013.36 snd_ty: 0013.37 snd_fi: 0013.38 snd_lb:

0013.39 snd_ms); 0013.40 opt=*blank; 0013.41 endif; 0013.42 enddo; 0013.43 *inlr=*on; 0014.00 /end-free In the RPG program, we make some validation based on the option that is being entered by the user. On entering a option other then ‘S’ or ‘ E’ then a message id MSG0002 of message file MESSAGE /WKBZ37NX is send has parameter to the CL program MSGSFCL. At the same time parameter snd_ms =msf is also passed which indicates the CL program to fetch message from the message file. Similar process happens with the option ‘S’, were message is fetched from a screen field MSGF. On entering the option ‘E’ a direct text from the RPG program is passed as a message data to SNDPGMMSG IN the CL program. While passing a direct text as message, message id, message file, message library are made blanks (highlighted in red) CL CODE: CLLE- MSGSFCL 0001.00 SENDMSG: PGM PARM (&SND_ID &SND_DT &SND_TY &SND_FI &SND_LB + 0001.01 &SND_MS) 0001.02 DCL VAR (&SND_ID) TYPE (*CHAR) LEN (7) 0002.00 DCL VAR (&SND_DT) TYPE (*CHAR) LEN (80) 0002.01 DCL VAR (&SND_TY) TYPE (*CHAR) LEN (10) 0002.02 DCL VAR (&SND_FI) TYPE (*CHAR) LEN (10) 0002.03 DCL VAR (&SND_LB) TYPE (*CHAR) LEN (10) 0002.04 DCL VAR (&SND_MS) TYPE (*CHAR) LEN (3) 0002.05 MONMSG MSGID (CPF0000) 0002.07 /*------------------------------------------------------------------------------------------*/ 0002.08 /*Command to remove the message from the previous queue */ 0002.09 /*-----------------------------------------------------------------------------------------*/ 0003.00 RMVMSG PGMQ (*PRV (* *NONE *NONE)) CLEAR (*ALL) 0003.02 /*--------------------------------------------------------------------------------------------*/ 0003.03 /*Command to load the messages into the subfile based on validation */ 0003.04 /*--------------------------------------------------------------------------------------------*/ 0003.05 IF COND (&SND_MS = 'MSF') THEN (DO) 0004.00 SNDPGMMSG MSGID (&SND_ID) MSGF (&SND_LB/&SND_FI) + 0005.00 MSGDTA (&SND_DT) TOPGMQ (*PRV (* *NONE + 0006.00 *NONE)) MSGTYPE (&SND_TY) 0006.01 ENDDO 0006.02 IF COND (&SND_MS = 'IMD') THEN (DO) 0006.03 SNDPGMMSG MSG (&SND_DT) TOPGMQ (*PRV (* *NONE *NONE)) + 0006.04 MSGTYPE (&SND_TY) 0006.05 ENDDO 0008.00 ENDPGM Above CL program processes the parameters received from the RPG and process the message on to message subfile. Based on the SND_MS, CL validates to process messages form message file or to consider direct text passed as message. If passed parameter SND_MS=MSF, fetches message from message file. If SND_MS=IMD, considers a direct text as message. In the above code TOPGMQ is set to *PRV because CL being called from a RPG and the message is to be displayed in the display associated in the RPG so *PRV is given. Else it will consider the current program message queue which does not have an associated message subfile with it.

b).Through RPG wherein one can use API’s like QMHSNDPM and QMHRMVPM: API: QMHSNDPM AND QMHRMVPM:
The Send Program Message (QMHSNDPM) API sends a message to a call message queue or the external message queue. I t has nine required parameters which are as follows. MESSAGE IDENTIFIER (INPUT, CHAR (7)): This represents the message id associated with a message file in your library e.g. (MSG0022).On specifying message identifier, one must specify specify a qualified message file name. QUALIFIED MESSAGE FILE NAME (INPUT, CHAR (20)): This is a qualified message file name from which the messages are to be fetched. The first 10 characters specify the file name, and the second 10 characters specify the library e.g. (MESSAGE *LIBL ). REPLACEMENT DATA(INPUT; CHAR(*)) : This parameter specifies the complete text of an immediate message, were message id will be blanks or can specify some message id in to which this particular data is to be sent in the message file. LENGTH OF REPLACEMENT DATA (INPUT; BINARY (4)): The length of the replacement data message text, in bytes. MESSAGE TYPE (INPUT; CHAR (10)): The type of the message. Following values can be used *comp,*diag,*escape,*info,*inq,*notify,*rqs,*status. CALL STACK ENTRY(INPUT; CHAR(*)):The call stack entry to send the message to, or the call stack entry to start counting from when using a value other than 0 for the Call stack counter parameter. The call stack entry you specify must be in the call stack. You can also specify the external message queue. Default values is given has ‘*’, which represents the current queue. CALL STACK COUNTER(INPUT; BINARY(4)): A number identifying the location in the call stack of the call stack entry to whose message queue the message is to be sent. Value can be 0 - Send the messages to the message queue of the entry specified by the Call stack entry parameter. MESSAGE KEY (OUTPUT; CHAR (4)): The key to the message being sent. This API assigns the key when it sends a message of any type except status. ERROR CODE (I/O; CHAR (*)): The structure in which to return error information. The Remove Program Messages (QMHRMVPM) API removes messages from call message queues and the external message queue. It has following parameters, CALL STACK ENTRY(INPUT; CHAR(*) ): The call stack entry from whose message queue the message are to be removed, or the call stack entry to start counting from when using the call stack counter parameter. Default values is given has ‘*’, which represents the current queue. MESSAGE KEY(INPUT; CHAR(4)): MESSAGES TO REMOVE (INPUT; CHAR (10)): Valid values are *all,*bykey,*scope,*old,*new… ERROR CODE (I/O; CHAR (*)): The structure in which to return error information. For more information on QMHSNDPM AND QMHRMVPM visit

RPG CODE: RPGLE: SFMSGRPG 0002.00 FSFMSGDSP CF E WORKSTN 0003.00 DPSDS SDS 0004.00 DPGM_NAM *PROC 0004.01 ************************************************************** 0005.00 DMSF_RMV PR EXTPGM ('QMHRMVPM') 0006.00 Drmv_qu 10a 0007.00 Drmv_sc 8b 0 0008.00 Drmv_ky 4a 0009.00 Drmv_rm 10a 0010.00 Derr_ds 116a 0010.01 ***************************************************************

0010.02 DMSG_SNDF PR EXTPGM ('QMHSNDPM') 0010.03 Dsnd_id 7a 0010.04 Dsnd_fi 20a 0010.05 Dsnd_dt 80a 0010.06 Dsnd_ln 8b 0 0010.07 Dsnd_ty 10a 0010.08 Dsnd_qu 10a 0010.09 Dsnd_sc 8b 0 0010.10 Dsnd_ky 4a 0010.11 Derr_ds 116a 0010.12 ************************************************************* 0011.00 Derr_ds ds INZ 0012.00 Dbyt_prv 9b 0 0013.00 Dbyt_avl 9b 0 0014.00 Dexcp_id 7a 0015.00 Dresrv 1a 0016.00 Ddata 100a 0017.00 ************************************************************* 0018.00 Drmv_qu s 10A Inz ('*') 0019.00 Drmv_sc s 8B 0 Inz (0) 0020.00 Drmv_ky s 4A Inz (*Blank) 0021.00 Drmv_rm s 10A Inz ('*ALL') 0022.00 ************************************************************* 0023.00 Dsnd_id s 7A Inz (*Blank) 0024.00 Dsnd_fi s 20A Inz ('MESSAGE *LIBL ') 0025.00 Dsnd_dt s 80A Inz (*Blank) 0026.00 Dsnd_ln s 8B 0 Inz (0) 0027.00 Dsnd_ty s 10A Inz ('*DIAG') 0028.00 Dsnd_qu s 10A Inz ('*') 0029.00 Dsnd_sc s 8B 0 Inz (0) 0030.00 Dsnd_ky s 4A Inz (*Blank) 0031.00 ************************************************************** 0032.00 /FREE 0032.01 sfmpmq=PGM_NAM; 0033.00 DOW NOT *IN03; 0034.00 write sfmctl; 0035.00 exfmt record1; 0035.02 *IN81=*ON; 0036.00 if *in03; 0037.00 leave; 0038.00 endif; 0038.01 exsr remove; 0043.02 if opt<>'S' and opt<>'E' and opt<>*blanks; 0043.04 exsr remove; 0043.05 snd_id='MSG0002'; 0043.06 exsr send; 0043.14 opt=*blank; 0043.15 endif; 0044.00 if opt='S'; 0044.02 exsr remove; 0045.00 snd_id=MSGF; 0045.01 exsr send;

0054.01 opt=*blank; 0055.00 endif; 0056.00 if opt='E'; 0056.02 exsr remove; 0056.03 snd_id=*blanks; 0057.00 snd_dt='This message is executed via message subfile'; 0058.00 snd_ln=%Len (%trim (snd_dt)); 0059.00 // snd_sc=0; 0059.01 exsr send; 0068.01 opt=*blank; 0068.02 endif; 0068.03 enddo; 0069.00 *inlr=*on; 0069.01 //___________________________ 0070.00 Begsr remove; 0070.01 rmv_qu='* '; 0071.00 callp MSF_RMV (rmv_qu: 0072.00 rmv_sc: 0073.00 rmv_ky: 0074.00 rmv_rm: 0075.00 err_ds); 0076.00 Endsr; 0076.01 //_____________________________ 0076.02 Begsr send; 0076.03 callp MSG_SNDF (snd_id: 0076.04 snd_fi: 0076.05 snd_dt: 0076.06 snd_ln: 0076.07 snd_ty: 0076.08 snd_qu: 0076.09 snd_sc: 0076.10 snd_ky: 0076.11 err_ds); 0076.12 Endsr; 0077.00 /END-FREE ADVANTAGES: Message subfile have some unique property loading themselves automatically from messages on a given program message queue. Message subfile doesn’t necessitate the creation of a output subfile fields, rather it is taken care by SFLPGMQ. Message subfile allow one to a send text messages to the program message queue and use no message file at all. No separate loading/ clearing routine are required for a message subfile. Just by linking the subfile to a program message queue one can remove/load messages from that message queue. For every call stack entry, there exists a corresponding program message queue with the same name. Just by knowing the call stack name, one can pass message to any message queue one deals with.