AS/400 Programming Tips, Tricks, & Techniques

May 3, 2013  7:12 PM

How to Create a UIM Menu from Scratch

Eric Witham Eric Witham Profile: Eric Witham

Happy Friday Everyone!
(Originally I meant last Friday, when I started writing this)

One of the projects on my Side List is to convert the User Menus on our system from either a DSPF type or a MNUDDS/MNUCMD type member to a UIM Menu. I must say, ever since I started modifying UIM Menus as small service requests, I’ve always been intrigued by them. They’re straight forward and allow you a great opportunity to create help text in a very easy and efficient manner.

The only issue is that if you don’t know how to write one, it’s very frustrating locating all the exact pieces that need to be in place. This post is going to save you all that time spent investigating and trying various things out.
First things first, this is a Panel Group, so this is going to feel a little bit different the syntax you typically write on your AS/400. To me, it feels a little bit more like HTML just because of the fact that you have to use tags. So let’s begin, shall we?

Navigate yourself to your PDM File & Library, hit F6 to create a new Member with the type MENU.

When it opens up of course you’ll have a blank slate to work with. Since the member is waiting for you to give it life, you must first acknowledge its existence by giving it a Member Header. All commented source needs to begin with a period (.) and and asterisk (*).


The next thing we have to do is begin the panel group code. We start by entering the tag PNLGRP (and put a colon (:) before the P in PNLGRP), . as you can see in the below screen shot. This is done merely to start the Panel Group. The next statement will add your Company’s name to the bottom of the menu on line 24 of the screen.

One important thing to remember is that before the tag name is entered a colon (:) is required and after the tag a period (.) is required as well.

The next tag after that is the variable command that allows you to set up the name of the Menu on the top right-handside of the screen.  The keyword ZMENU retrieves the member name and uses it as the name of the menu.

UIM_Panel Start

Now let’s set up the function keys.

Tag :KEYL opens the section to definethe List of Function Keys. Now,  if you notice, i didn’t put the period until after the 2nd line. This is because the line continues and the compiler picks it up. It looks at the whole string and acknowledges it accordingly. The :KEYL gives the block of menu keys a name to reference.  Take note that we are using the name menukeys and setting up the help for the block in keyl.  A lot of entry here refers to to another place in the member. I

For each Function Key you want to define, you must have 4 lines in place all under 1 tag named :KEYI, or Key Item,  in order to describe the key. Think of it as a mutated D-Spec.
The KEY code will setup which CF Key you are doing. The HELP key will indicate the help panel associated with this key. The ACTION will obviously indicate the Action to be taken once this key is pressed and lastly, you’ll need to put Text for this command key. This information gets left-justified as shown below.

For F3 & F12 you will need to add an additional keyword & initialize it to No by typing VARUPD=NO. This keyword specifies whether dialog variables are to be updated when the user presses the function key. All of the keys and reserved keywords in there are ready for use when you input the text. Once you’re done with the function key definitions, you end the block with an :EKEYL.

Another important and pretty cool thing you can do in these menus is setup and customize the Help. In this section when you specify the keyword HELP=helpf1, you are pre-defining the help text block. That name, helpf1, or whatever you end up using for the name there, will be used at the end of this member which will be linked to the help text we create.  Just bare with me and we’ll get there.


So far so good eh? Looks like we’re moving right along. Next on the agenda is to define the Menu Panel and the Menu Area. Start by adding the tag to define the Panel by typing a colon (:) then PANEL as 1 word and set the NAME to mnupnl since the member we are creating is a Menu Panel, i.e. mnupnl. (I had to separate : and the P or else it would’ve looked like this :P) We set up the name of the block we are going to use for Help Text. The keys we setup earlier was in the block named menukeys. When the user hits ENTER, if there is no option taken, we send the message CPD9816 (because here we are monitoring for it) which has the text, “Type option number or command.” The keyword PANELID specifies what text to display as the identifier for this panel, which appears in blue at the top-left corner of the screen. Since we’ve specified ZMENU, the menu name appears there. Finally, the TOPSEP=SYSNAM keyword specifies that the system name is to be used as a separator at the top of the panel-meaning that the system name will appear on the menu to the right on the line after the menu title.

Now that we’ve defined the menu, we have to setup the Menu Area. The DEPTH=’*’ keyword indicates that the menu area will have as many lines as are left after allocating space for the title, function keys, command line, message line, and so on. You can also supply a specific number of lines, but I can’t see why you would. Using the keyword & value SCROLL=YES is what makes this a rolling menu, meaning you can page down for more options once you setup multiple options that require a second page. The bottom separator BOTSEP keyword indicates what to use at the bottom of the menu area to separate it from the command line. Entering SPACE will simply leave a blank line at the bottom. Finally, the TOPINST. along with Select one of the following: will place the text on the top of the screen above the menu options and below the menu definition.

UIM_Define Menu

Now we finally get to the setting up of the actual options. I’m telling you, once you get passed the initial part of creating the actual menu for the first time, creating menus by copying & modifying is the easiest thing in the world.

In order to setup the menu options you really only need 4 lines:

Line 1 – The Menu Item Tag.  This tag along with the keyword OPTION and the number of the option, sets up a menu item, or menu option.

Line 2 – The ACTION keyword.  This runs a command to be processed once the option has been entered. The command string must always start with CMD and must always be in single quotes. Another important thing to remember is that when you need to use parameters in your call statements, use 2 single quotes  here for every single quote you would use if you were putting that call statement into a CL program.

Line 3 – The name of the Help block that will be used to describe Option 1 when the user hits F1 for Help on the menu. Please Note that the value must be in single quotes and at the end of this line is where the period must go.

Line 4 – This is where you enter in the text for the menu option. No need to put a number with a period, just left justify your text and enter it in. For each of these values, I believe 55 positions is the maximum length you can use.

If you notice in the below screen shot, i have highlighted the text in options 3-7 in purple. I did this because I wanted to let the user of this menu know that these options are the only ones on the menu that require a specific action to be done before taking those options. In order to make everything line up, I’ve placed a Green Attribute Hex-character before the other menu option’s text.

For information on changing the color of your source, please review my previous article:

We finish off the :MENU block that was created on Line# 90 in the above screen shot by closing out with an :EMENU tag on line 143 in the below screenshot.

UIM_Menu Options

At long last, we have the 2 final pieces for the Main Panel group: The Command Line & the End Panel Group Tag.
Enter in the command :CMDLINE  along with the keyword SIZE= and use the value LONG if you want the command line to be a long field, as seen via STRPDM, or SHORT if you want a small field for the option to be taken. No command line entry is allowed if you have it set to SHORT.

Also, we finally get to close the Panel Group by using the command :EPANEL. Think of it like this. If you have a /FREE specified in your free-form program, then you’re going to need an /END-FREE to close out the block, right? Same thing.

UIM_Panel End
Well here we are, finally at the end of what needs to be done. This part, I’m going to go through a little less in-depth than i have with the previous items. I’ll explain the instructions based on the Statement Numbers.

The help area is pretty straight-forward and easy to do.

Line Numbers 156.00 – 162.00
Start by setting up the :HELP block and link the command key block from earlier in the source to the function keys. We named the function keys KEYL so we have that module name be the value for the Help Name. The text “Function Keys – Help” I believe is only there to indicate that this block of Help Text refers to the Function Keys. On 161.00 the :XH3 displays this text as a Starting Group of help to fall underneath it, kind of like a Title with chapters underneath it. At the end i’ll show you the completed Menu & Help screens. Don’t forget to close out the Help Block with :EHELP.

Line Numbers 164.00 – 171.00
This next block of code writes the Help Text for Command Function 1. So if the user puts their cursor over option 1 and hits F1 a small window will be displayed showing the text on lines 168.00 & 169. The value we use for the Name of the help is helpf1 which was setup on line 36.00 in the Key Items block for Key F1. We’re using the :PARML keyword because we’re using the F1=Help as a parameter list. Once hit and the cursor is on that option it displays the text and there you go. Close out the block by putting an :EPARML & :EHELP.

As you can see in the rest of the Source member, I added in all the Help text I could, following the rules of using the keywords, module names and wrote as much help text as I could to assist the user in whatever He or She may need.

Line Number 389.00
Ends the Panel Group of the Entire Member. If you recall in line number 17.00 we started this with a :PNLGRP. Now that we’re done, we close it off and Compile the hell out of it.

The End of UIM

So here it is, the End Result, your Menu…

Finished Menu

And here is what happens when you put the Cursor on option 3 and hit F1…

Opt 3 Help

I hope I have helped some of you get a better understanding on UIM Menus, how to write them, how to understand them, and most of all, how easy it is to come up with a Professional looking menu that scrolls instead of having to deal with DSPF menus with random options on the side of the screen or hidden options that some users know about. One of my side projects at my current position is to convert all menus to UIM menus in order to clean things up and make the system a little bit more organized and have a professional look for the users.

There is a decent amount of information out there that can help you understand UIM menus on a more technically instructed level, but as I said previously, I am no expert in UIM Menus. I found out how to do all this by Research, Trial & Error.  I figured it might be nice for someone, who has no idea how to do this, to wow their bosses and higher ups on how great and efficient they can make their menus. Here are a few articles I found that helped me along the way and one that I actually just found a few minutes ago. The last one is pretty good and it looks like it’s more current than the first two:

Create IBM-Style Rolling Menus with UIM
Written by Ernie Malaga
Wednesday, June 30, 1993

Dynamic UIM Menu Help
Written by Mike Faust
Wednesday, December 14, 2011

Create Better Menus with UIM
Written by Scott Klement
Thursday, August 11, 2011

April 24, 2013  8:07 PM

Make your Documentation *SHINE*

Eric Witham Eric Witham Profile: Eric Witham

Greetings Everyone,

I realize this is a topic that may have been discussed a long time ago, but I have some changes that may prove useful and less time-consuming to setup.

What i’m talking about is Highlighting your Source Code.

Please note that I don’t use Mocha. It’s not for me. I’m a Client Access guy all the way. In this post I’m going to be referring to the keyboard mapping function within Client Access.

Now, obviously you can’t highlight the Active source code because the compiler is going to expect the syntax to not have any hexadecimal values on the line. So basically, you can only highlight Commented Source code. Which is fine, because that’s how we write our documentation.
First, let’s take a look at how this works:

There are hexadecimal values that can be used to change the attribute of a character. You can figure out what they are the hard way, by tracking them down in the settings of Client Access or trolling through boards and forums, or you can take a look at the Member I created below:

Attribute Legend
Basically, I have this listed out in 3 columns: The 1st being the description of the Attribute, the 2nd is my personal mapping of these attributes and the 3rd is the Hex Value for these attributes.
When I first started highlighting my documentation and commented out source, I didn’t realize that I could use this directly in a program while I was coding it without having to copy in a line from this member. It used to be that I always kept a member named @@ATR in my QTESTSRC file and when I needed to highlight code, I would copy in the line, remove the text and keep put a CR on it. Then on the code I wanted highlighted, I marked it with OO in loops in the sequence number area in order to overwrite my code.

After reading an article years ago on Search400 I found that I was able to modify the actual keyboard mapping file and insert it that way. Boy was that a pain in the butt. I did it once and saved the file and took it with me to every job that I had.

Now I know better.

You certainly don’t have to go in and modify some keyboard mapping script file and attempt to stay sane through all that mumbo-jumbo.
Why don’t you Developers do this right now? You’re obviously reading this to learn something new, or to see if there is a new take on something you already know how to do.

Simply go into your Keyboard mapping Functions screen within Client Access by clicking the Remap Keyboard Functions button. Or you could go to EDIT>PREFERENCES>KEYBOARD…
Once you’re there, click the Button that says Customize.
Click on the letter W
On the bottom right-hand side of the screen there will be an area labeld Change Current Actions for Selected Key
In the text box designated for Ctrl type the following:  apl 22
In the text box designated for Alt type the following:  apl 23
In the text box designated for CtrlShift type the following:  apl 26

Save your changes and exit the Keyboard Mapping Area.
Just as a precaution, make sure that the Keyboard Mapping file you changed is the one shown in the window where you originally hit Customize.

Go into an RPGLE Source Member
Insert a line and make it a Commented Line of source code.
Place your cursor in the position directly BEFORE the Asterisk.
Hold the Ctrl Button down and hit W, then ENTER.

You have some highlighted Source code.

Other than documentation comments, why else would you use this other than to seem flashy? I’m glad you asked.

I’m sure just about everyone has had to follow a Programmer whose skills do not in fact, pay the bills.
Multiple lines of code commented out with an asterisk followed by more un-commented code, no blank lines in between to save your eyes, things like that.

Well, if you place apl 28 in the Ctrl area for the letter R you can put your cursor on the specification letter, hit Ctrl + R and bam, you have a Red line of commented code.

How much easier is it to figure out what lines of code are actually seen and processed by the compiler without making your eyes go nuts as you troll through 5000 lines?

Much Easier.

This can be done in any source member. In my CLLE programs, I put the highlighted code character after the /* and then before the */ i put a green colored character code in there.
Even better, let’s say you have a big project you’re working on which means multiple programs. You can only take certain programs so far and you had to name them in a numeric fashion. How do you remember which ones you need to go back to for testing, for additional logic because you need to add new business rules and the person with the answers isn’t there, or which programs you already analyzed during your investigative process?


Check it out, just insert a blank space on the Text line and in that position, hit Ctrl+W for White or Ctrl+B for Blue, even block highlight it, or make it blink red. Do what you want!

Below are some examples for you to check out.

The most important lesson in this is to have fun in your organizational OCD tantrums. I know i sure do.

Highlighting Commented out Source
Commented out
Highlighting the Source Headers in CLLE/CLP with Notes to make you remember before Deployment
CLLE example

Highlighting in PDM so you know what member needs your attention and which one doesn’t
PDM Example

Highlighting RPGLE Source Code
RPGLE Example

Again, Thank you everyone who takes the time to read these articles I put up.
If you have a specific topic you’d like me to discuss and expand on, please let me know via with the Subject Line of ITKE Blog Ideas

Thank you all and Have a Great Day!

Eric T. Witham

April 17, 2013  6:54 PM

Resolving a Common Issue: CPD90B1 – Distribution Limit of 9999 Reached

Eric Witham Eric Witham Profile: Eric Witham

Greetings Readers.

This being my first post, please allow me to introduce myself. My name is Eric and I am currently a Administrator/Senior Programmer for H&M International Transportation, Inc. in Central NJ. Although I have only been working here for 3 months now, I have been in the AS/400 World for about 15 years now. I started doing Programming at 19 and have loved the work ever since.

I wanted to address an issue that I have seen pop-up throughout my career. However, this is the first time I’ve seen an actual resolution that worked.

The Error Message received to our *SYSOPR is as follows:

Message ID

Distribution limit of 9999 reached.

The sender has sent 9999 distributions. These distributions still exist on the system.

Either delete any incoming distributions that you sent to yourself or any outgoing distributions that you sent with confirmation of delivery

In a lot of our programs we use the SNDDST command to send emails and reports to users all over the county. As it turns out, my company has had a problem with this issue for years. The only resolution they could find that worked (for them) was to create duplicate User Profiles and use that when doing the SNDDST command.

I know what you’re thinking, “That’s Absurd!” Well, you’re right. It is absurd. When I found this out, I was determined to find a resolution which would not only help the company, but also give me some points in the new job.

I contacted IBM and informed them of the issue and the resolution my predecessors took in order to “fix” the problem. They laughed, which is fine, because I did too.

Apparently this is a pretty common issue and they even wrote a Technical Document for it. The document contains 4 programs that clean up the mail on the system. The only thing is, they left out a big part of what needs to be done before implementing what was in the Technical Document.

Here is what you need to do:

  1. Navigate to the Work with Directory Entries screen – WRKDIRE
  2. Take Option 2 to make changes to the User Profile in the list.
  3. Page-Down 4 times until you get to the screen with the Mail Service Level entry.
  4. Change the value for Mail Service Level to 2 for System Message Store
  5. Change the value for Preferred Address to 3 for SMTP Name
  6. Submit the Job to call the Control Program CLEANMAILC  (Code is Below)

The reason we change the Mail Service Level to System Message Store is so that the mail can be stored in the System Supported Message store. This can be accessed by using the industry standard mail API’s on the client.

The reason we change the Preferred Address to SMTP is so that when a SNDDST command is executed, the mail doesn’t somehow get stuck in the IBM Limbo.

So let’s say you’re running a process that sends a report to 10 users in your community. What if one or two of those users no longer works for the company anymore?  That User ID or Email Address was most likely deactivated or removed from the system. Well if the report is being sent to that deactivated address and SMTP Name isn’t specified, the user requesting the report will NEVER know. However, if specified, the requesting user will receive an email saying that it was Undeliverable to that specific address or addresses.

Once all Users are changed in the Work with Directory Entries screen, you can submit the below calling program which in turn will submit 3 other programs and by the end of it, all distributions will be cleared.
Here is what the procedure contains:

Type:            CLLE
Text:             Process Mail: Inbound/Outbound/In-Error
Role:              Control Program

Member:    MAILINC
Type:            CLLE
Text:             Process Inbound Mail 

Member:    MAILOUTC
Type:            CLLE
Text:             Process Outbound Mail

Member:    MAILERRC
Type:            CLLE
Text:             Process Mail in Error

Here’s the IBM Technical Document
Finally, here is my code. I realize it may not fit on the entire screen. But if you give it a click, it should open in a new window which will allow you to save it and check it out in Paint or Word or whatever other program works for you best.

Syntax for Control Program CLEANMAILC

Syntax for Control Program CLEANMAILC

Syntax for Control Program MAILINC

Syntax for Control Program MAILINC

Syntax for Control Program MAILOUTC

Syntax for Control Program MAILOUTC

Syntax for Control Program MAILERRC

Syntax for Control Program MAILERRC

Thank you for taking the time to read this article. Please be on the lookout for more articles from me.

If anyone has any topic suggestions, or wants some assistance with an issue they have, please don’t hesitate to email me at

Have a Great Day.


November 6, 2012  3:59 PM

All About the SQL Query Engine

John Andersen Profile: John Andersen

In my past posts I mentioned the SQL Query Engine that evaluates, plans and drives your SQL queries on the IBM i platform. For speed and performance you really should understand why using the SQE is where its at.

Here is a good article that dives more deeply into the SQE versus the CQE engines on your system:

If performance is a concern and you are still using Query/400, OPNQRYF or the QQQQry API you are blowing it big time!

Here are the key takeaways from the article:
Use SQL driven tools and programs that utilize the SQE…
Why it pays to stay current with your IBM i OS level and more importantly the Database Group PTFs that contain new features.
Utilities to monitor database performance and optimization.

-John Andersen

November 6, 2012  12:08 AM

The IBM i Sucks

John Andersen Profile: John Andersen

Here is an article for you to check out:

Of course the IBM i doesn’t really suck, click on the article and find out why.

-John Andersen

November 5, 2012  9:13 PM

Getting Started With IBM i SQL

John Andersen Profile: John Andersen

In my previous article I talked about the virtues of moving from Query/400 to DB2 Query Manager, with the major advantage being you can use SQL and all of the features that come with it… But how do you get started?

Well if you are a salty sea dog that has been around the platform but are not up to date with SQL, first there is a new vernacular you will need:

A physical file in SQL is a table.

A logical file is an index.

A record is a row.

A field is a column.

A library is a schema.

Views are something new and really cool. SQL views are implemented on the IBM i as a non-keyed logical file. These are queries that are treated like a file but the data is retrieved when accessed.

These new terms are somewhat important because when you start working with SQL based tools, reading IBM Infocenter docs or hanging out in SQL circles those are the terms that will be used and they are more or less universal across database platforms.

Now where do you get started entering in SQL statements on the IBM i? I prefer using the “Interactive SQL” program accessed by simply entering STRSQL command on a command line.

There are a few reasons why I like and use STRSQL for day to day queries:

You are instantly connected to the database without a layer in between; Interactive SQL plain works without any problems and eliminate any of the hassles of using another program via ODBC.

Do you need to run a query to the screen, output those results to table or create an ad-hoc spool file and printable report? You can do all three in the “Change Session Attributes” option screen by pressing F13 and selecting the output type you would like. I use the printer output type frequently for whipping up reports on the fly.

STRSQL automatically saves your session and each SQL statement you enter is recorded in history where you can easily retrieve it for later use even if you exit out of the program, log off and come back to it later.

Now a drawback. Because interactive SQL is traditional green screen based it is character and not graphical… some people have problems with this, but it does not limit the capabilities of the program and is a matter of your personal preference. If you absolutely abhor green screen then check out the Run SQL feature in i Navigator.

As I mentioned in my previous article about Query/400… The IBM i is optimized for SQL and the SQL Query Engine versus traditional access methods that use the old Classic Query Engine. Let this optimizer do the work for you and optimize your statements, if you are staying current with OS releases you have bought and paid for these features!

If you are just getting started then you need not worry about messing up any data as long as you stick with basic SELECT statements. They will query data from a table and display it to the screen, where you can get into trouble are UPDATE and DELETE statements that can change or delete entire tables in a single keystroke.

Finally, here is a YouTube video that shows the interactive SQL program in action creating a table… enjoy:

-John Andersen

John Andersen is an irreverent IT manager and champion of the IBM i platform.

November 2, 2012  5:55 PM

Time To Dump Query/400

John Andersen Profile: John Andersen

I admit opening up Query/400 (IBM Query for i) on the rare occasion to crank out a straight forward report. I think its more for nostalgic reasons because Query was the first reporting tool I learned on the AS/400 so many years ago.

But my Query/400 use is becoming less and less and instead I am opting for reports, database mining and ad-hoc queries with interactive SQL or with IBM DB2 Query Manager product if I need something more polished or a paper and ink report.

Frankly, if your STILL running with Query/400 here is why you should be making the switch to SQL based tools and programs:

1. Query is getting really long in the tooth.

Have you noticed new features in the product? And because it’s not actively being developed you have to wonder how much longer IBM will license the product, or if the next operating system release will just break Query altogether.

It may be better to switch today than being forced to switch down the road.

2. The SQL standard is the now and the future of the IBM i platform.

The “native” tools like Query and OPNQRYF came about long ago when the database was not standardized on SQL. Starting on OS version 5 the database engine that plans and executes your queries evolved into the Classic Query Engine for older “native” tools and the SQL Query Engine for SQL based tools.

All new research and development is going into the SQE engine. And the performance gap is really widening, for instance you don’t have to make any changes to your SQL but a simple Database Group PTF can yield amazing performance gains… but only if your using SQL and the SQL Query Engine.

And by switching to SQL all of those quirky hacks in Query/400, like using the microseconds portion of a TIMESTAMP in a result field to convert data, are a thing of the past by using features built right into the SQL language like casts.

You can also add logic into your SQL statements with features like CASE, that just are not possible with Query or you had to kludge together multiple queries and some CL code.

3. You have a perfectly capable replacement reporting tool in Query Manager.

Sometimes you want a nice formatted report for printing, this is where marrying SQL and the DB2 Query Manager tool works.

Query Manager is really cool and even though its been around it is driven by SQL and is modern. And the real beauty is you probably already have Query Manager licensed, some shops don’t even realize they have it!

Query Manager addresses all of the shortcomings of Query/400… in particular data security and job management.

Using the configuration options in Query Manager, if you have regular users writing queries, you can keep them from wiping out data by accident or swamping the system by with excessive previews.

Some 400 shops are highly leveraged with query definitions… but there are some tools to convert them to QM Queries for you. To get started check out the RTVQMQRY and RTVQMFRM commands that will extrapolate the SQL and report form (Query Manage uses a query and report form together for output) out of your query definitions into QM objects that are ready to run.

-John Andersen

John Andersen is an irreverent IT manager and champion of the IBM i platform. For more information on cranking out reports with Query Manager check out his site at

Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: