Sometimes you want to see messages that tell you things went right instead of wrong.
In the previous article, "More On Sending Messages from an Application Program", the Send Program Message (QMHSNDPM) API was used to send a user error message indicating that a severe error had been encountered and, if appropriate, diagnostic messages explaining the cause of the error. But not all programs encounter problems—at least I hope not all of your programs do! In this article, the QMHSNDPM API will also be used, but now to send a variety of non-error related messages.
We'll start with a simple completion message indicating that some function of the application has successfully finished. Similar to how message descriptions APP0001 and APP0002 were used in previous articles, create the new message APP0003 using this command:
ADDMSGD MSGID(APP0003) MSGF(QGPL/APPLMSGF) +
MSG('Task finished successfully.')
The message text for APP0003 is vaguer than I would recommend, but as I do not intend to write a full application, with specific functional tasks, as part of this article, it is sufficient for now. For any application programs you write in the future, I'm sure you can come up with more meaningful message text—for instance, "Customer &1 added," or "Month-end balancing successful," or the like.
To send message APP0003 to the programs caller, we will use the same Send Program Message (QMHSNDPM) API as in previous articles. Here's the code to do this:
dSndMsg pr extpgm('QSYS/QMHSNDPM')
d MsgID 7 const
d QualMsgF 20 const
d MsgDta 65535 const options(*varsize)
d LenMsgDta 10i 0 const
d MsgType 10 const
d CallStackEntry 65535 const options(*varsize)
d CallStackCntr 10i 0 const
d MsgKey 4
d QUSEC likeds(QUSEC)
d LenCSE 10i 0 const options(*nopass)
d CSEQual 20 const options(*nopass)
d DSPWaitTime 10i 0 const options(*nopass)
d CSEType 10 const options(*nopass)
d CCSID 10i 0 const options(*nopass)
/copy qsysinc/qrpglesrc,qusec
dMsgFName ds
d Name 10 inz('APPLMSGF')
d Lib 10 inz('QGPL')
dMsgKey s 4
/free
QUSBPRV = 0;
SndMsg( 'APP0003' :MsgFName :' ' :0 :'*COMP'
:'*PGMBDY' :1 :MsgKey :QUSEC);
*inlr = *on;
return;
/end-free
Let's say that the previous source is stored in member SNDAPP0003 of source file QRPGLESRC. The following commands can be used to create and then call the program.
CRTBNDRPG PGM(SNDAPP0003)
CALL PGM(SNDAPP0003)
Assuming these commands are done from QCMD, you will now see the message "Task finished successfully." If you are not calling SNDAPP0003 from a command line, you may need to display your job log in order to see the message. Not too much of a change in calling the API to start sending messages of a non-error nature! We changed the message type (the fifth parameter when calling the QMHSNDPM API) from *ESCAPE to *COMP (completion) and, as there is no replacement data for message APP0003, also the third and fourth parameters to reflect that no variable data is being provided. If you want to provide variable data in the completion message, you can do so in the same way message IDs APP0001 and APP0002 did in the previous articles (or as will be seen shortly with message APP0004).
What if the task associated with message APP0003 is potentially long-running? How might we provide status information to the user, similar to how some long-running system commands such as Copy File (CPYF) do, so that the user doesn't think he's stuck in some problem within the program? As you might expect, we could again use the QMHSNDPM API. Create the new message APP0004 using this command:
ADDMSGD MSGID(APP0004) MSGF(QGPL/APPLMSGF) +
MSG('Step &1 of &2 in progress.') +
FMT((*UBIN 2) (*UBIN 2))
Message APP0004 will be used to provide ongoing status information to the user while the SNDAPP0003 program is running. In our fictitious task, there will be three steps and APP0004 will tell the user what step is currently being performed. When all steps are done, APP0003 will indicate successful completion of the task.
APP0004 defines two replacement variables. The first variable, &1, is defined as a 2-byte unsigned integer and represents the current step being performed. The second variable is also defined as a 2-byte unsigned integer and represents the total number of steps to be run.
Adding APP0004 support (and a few other items we'll discuss) to the previous SNDAPP0003 program results in the following RPG program:
h dftactgrp(*no)
dSndMsg pr extpgm('QSYS/QMHSNDPM')
d MsgID 7 const
d QualMsgF 20 const
d MsgDta 65535 const options(*varsize)
d LenMsgDta 10i 0 const
d MsgType 10 const
d CallStackEntry 65535 const options(*varsize)
d CallStackCntr 10i 0 const
d MsgKey 4
d QUSEC likeds(QUSEC)
d LenCSE 10i 0 const options(*nopass)
d CSEQual 20 const options(*nopass)
d DSPWaitTime 10i 0 const options(*nopass)
d CSEType 10 const options(*nopass)
d CCSID 10i 0 const options(*nopass)
dSleep pr 10u 0 extproc('sleep')
d Seconds 10u 0 value
/copy qsysinc/qrpglesrc,qusec
dMsgFName ds
d Name 10 inz('APPLMSGF')
d Lib 10 inz('QGPL')
dMsgKey s 4
dAPP0004 ds
d Step 5u 0
d Total 5u 0 inz(3)
/free
QUSBPRV = 0;
for Step = 1 to Total;
SndMsg( 'APP0004' :MsgFName :APP0004 :%size(APP0004) :'*STATUS'
:'*EXT' :0 :MsgKey :QUSEC);
Sleep(Step);
endfor;
SndMsg( 'APP0003' :MsgFName :' ' :0 :'*COMP'
:'*PGMBDY' :1 :MsgKey :QUSEC);
*inlr = *on;
return;
/end-free
By compiling and again running program SNDAPP0003, you should now see the APP0004 message appear on line 24 of the display, get updated at each step (iteration of the FOR loop) of the program, and finally display the APP0003 message when the program finishes. If you don't see the APP0004 message, then your user profile probably has USROPT(*NOSTSMSG) specified or your job is defined with STSMSG(*NONE).
Displaying the status message only required the definition of the APP0004 data structure (to reflect the two replacement data variables) and the additional call to the QMHSNDPM. When calling the API, this version of the program, when contrasted to the sending of message APP0003, references message ID APP0004, uses a sixth parameter value of *EXT (external message queue), and indicates that the message is of type *STATUS. The other changes to SNDAPP0003 are related to delaying the running of the steps so that you have an opportunity to see the status messages!
To give you time to view the status messages, the program uses the sleep API documented here. The sleep API defines one input parameter (the number of seconds to delay the thread) and a return value indicating whether the API returned prior to the requested number of seconds having elapsed. Why the API might return earlier is not relevant to our discussion and will not be discussed further (at least in this article). The SNDAPP0003 program, in order to simulate some processing, essentially sleeps for the number of seconds reflected by the number of the step being run. That is, step one takes one second, step two takes (or sleeps) for two seconds, etc. As sleep is a bound API, SNDAPP0003 also added an H-spec indicating that the default activation group is not being used.
One of the nice features of a status message is that the system takes care of displaying the message on line 24. If you run SNDAPP0003 from the command line, you see the APP0004 message. If you were to embed the SNDAPP0003 calling of QMHSNDPM for the sending of status messages within an interactive RPG application using a *DSPF, you would also see the APP0004 message on line 24 of your display file record format—and with no change to the *DSPF required. When the program ends, or other activity is directed to the display device, the status message is gone. And "gone" includes not being in your job log.
In this article, you've seen how easy it can be to provide positive feedback to your users. Next month, we will continue our review of message handling on the system.
In the meantime, if you have any API questions, send them to me at
LATEST COMMENTS
MC Press Online