|
|
![]() |
|
|
Back To Basics: Message Subfiles by Kevin Vandever [The code for this article is available for download.]
Many of you have used subfiles at one time or another. You may or may not understand everything about subfiles, but you've probably been exposed to them at some point in your career. However, you've may have missed an opportunity to employ a certain type of subfile, because you weren't aware of it or didn't understand it. In this back to basics installment, I want to touch upon that lesser used but very potent type of subfile: the message subfile. Get the Message Message subfiles are special subfiles designed to hold--you guessed it--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 the greatest of ease. If it all sounds a little too good to be true, you're not far off, but you don't have to pinch yourself to wake up from a dream because it is true. With just a little direction from your RPG and DDS, message subfiles pretty much take care of themselves. Here is how you use a message subfile:
For every call stack entry, which can be an OPM program or an ILE procedure, there exists a corresponding program message queue with the same name. This is important to know, especially when you start dealing with ILE and, potentially, multiple call stack entries. The good news is that you don't have to do any work to set up those queues. Just know that with ILE you have to know which call stack entry you are dealing with. I created my own message file, but you can certainly use the system-supplied messages and plug in your own text. For instance, if users are accustomed to seeing message ID CPF9898 from the system-supplied message file, QCPFMSG, as being something serious, you could still use that message ID and substitute your own message. This doesn't mean you change the CPF9898 message in the actual message file. You simply override the message text in your program. If there are substitution parameters associated with a specific message, you can also fill in those parameters using the program message APIs. If message files aren't your bag, you can also send text messages to the program message queue and use no message file at all. Let's look at some code. The DDS In my example, I have setup two messages, SFL0001 and SFL0002, in a message file called SFLMSGF. MSGSFLDF is a display file that demonstrates the use of message subfiles. It consists of three record formats: SCREEN1, MSGSFL, and MSGCTL. SCREEN1 is the primary screen, and it allows the user to enter data. As you will see in the RPG, this data isn't going anywhere; its purpose is purely to demonstrate how to use a message subfile. MSGSFL is the message subfile record format, and MSGCTL is the control format for MSGSFL. These formats work much the same way as regular subfile control and record formats. There are, however, some differences between regular subfiles and message subfiles. With regular subfiles, you have to handle the loading and clearing in your program. Typically, in your RPG program, you will set on the indicator used to condition the SFLCLR keyword in your DDS, write to the subfile control format, and set off the indicator to get ready to load and display. With message subfiles, you don't explicitly clear the subfile in your program; rather, you link the subfile to a program message queue and remove messages from that message queue. This, in essence, clears the subfile. This same theory holds true for loading the subfile. When displaying subfile records in a regular subfile, you must first execute some sort of load routine. This routine usually consists of a DO loop that reads records from a database file and writes them to the subfile record format. Message subfiles will have none of that. 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. Message subfiles require the use of several special DDS keywords, listed below. In the message subfile record format, the following keywords are required:
When in a message subfile, SFLCTL, SFLSIZ, SFLPAG, SFLDSP, SFLEND, and SFLDSPCTL behave normally, except that SFLDSP and SFLDSPCTL must be used without conditioning indicators. Also, SFLPAG must be at least one less than SFLSIZ in a message subfile; they cannot be equal. Message subfiles are considered load-all subfiles. Notice also that I don't use the *MORE parameter on my message subfile. The reason is, using the *MORE parameter causes "More..." and "Bottom" to display one line under the last line on the display. Since I am using line 24, which is the last possible line on the display, I would get an error if I tried to use the *MORE parameter. The plus sign (+) works for me, but if you're dying to use *MORE with your message subfiles, try starting on line 23--SFLMSGRCD(23)--and keeping SFLPAG as 1. Then you won't get an error. Let's look at the differences in the way two of the keywords behave when they are in a message subfile.
The RPG The RPG, SFLMSGRG, is basically used to control SCREEN1. It doesn't have any direct contact with the message subfile. The RPG program will send messages to, and remove messages from, the program message queue and help the message subfile link to the program message queue by retrieving the message queue name from the program data structure and sharing it the display file. But, as you will soon see, it doesn't directly load, clear, or display the subfile. The program status data structure provides information about the program, just as a file information data structure provides information about a specific file. In my example, I want to retrieve the procedure name associated with this program, which I can get by specifying the keyword *PROC. I will the define SDS_PROC to associate with the *PROC keyword. Notice that this is the same name I used in my DDS. That way, I can pass the name of the procedure, and subsequently the program message queue name, to the display file and allow it to link the program message queue to the message subfile. I also specified the program name, which can be retrieved from positions 334 through 343. I am not going to use that field in my example, but I thought I would show you it's there for your convenience, should you choose to use it. The mainline of the RPG is simply a DOU loop that processes SCREEN1. Before SCREEN1 is written to allow the user to enter some data, I perform a WRITE to the message subfile control format, MSGCTL. This write causes the message subfile to be loaded with any messages in the program message queue and then be displayed on the screen. The first time through, I haven't sent any messages to the program message queue, so the message subfile is empty. The initial screen allows the user to enter a first and last name. Once the Enter key is pressed, the RPG program is going to interrogate the names and determine whether a message should be sent. In my example, if the user doesn't enter Kevin as the first name message ID, SFL0001 is moved to the msgID field and the SNDMSG subroutine is executed. If Vandever isn't entered as the last name, msgID is evaluated to SFL0002 and SNDMSG is executed again Each time the SNDMSG subroutine is executed, a message is written to the program message queue and displayed to the screen when the WRITE operation is performed. Since I want the messages removed after they have been displayed, the first thing I do upon returning from SCREEN1 is to execute the RMVMSG subroutine. This clears the program message queue, and subsequently the message subfile, for the next interrogation of data. If the user were to spell both names incorrectly (how dare he), two messages would be written to the program message queue. Now when the message subfile is displayed on the screen, you will see the first message with a plus sign (+) on the far right-hand sign, signifying more records. If you place your cursor on the subfile record and press the Page Down key to get the next record, you would see the second error message. If you are using a message file and added second-level help for your messages, you can see those second-level messages by placing the cursor on the message subfile record and pressing the Help key. You can search all day for the extra code I left out of this program to allow this feature, but you won't find it. That's because it's taken care of for you by OS/400. I think you should take a moment now to thank OS/400 and message subfiles for making your life so much easier. A Powerful Combination This technique provides you with a lot of options. Download the code, create a message file and add some messages, and give the example a try. You may also want to further investigate the message APIs. Due space constraints, I did not cover them fully in this article, but they are pretty self-explanatory and easy to use. Using the program message queue to communicate information to the user provides you much flexibility. Add the wizardry of message subfiles, and you're on your way toward creating a killer application--and you haven't even started coding the business logic.
|
Editors
Contact the Editors |
|
Last Updated: 8/29/02 Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved. |