• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • APIs Sometimes Fail (But Programmers Don’t Have To)

    October 3, 2007 Ted Holt

    My ambition is to eventually be as smart as my teenagers. Some days I think I’ll make it. After all, my old man became downright brilliant once I left home and had to start paying my own bills. On other days, like days when I try to write computer programs, I have the gravest of doubts.

    One of those days occurred recently, when I spent half a day trying to find a bug in my code. It turned out that a call to the Send Program Message API, QMHSNDPM, was failing, and I wasn’t bothering to check whether the call succeeded or not. My friend Cletus the Codeslinger reveled in ragging me about it. “What moron told you you were fit to be a programmer?” he sneered. “If you’d read my assertions article, that wouldn’t have happened.” Of course, I did read the article–I’m the editor. But it’s foolish to argue with someone when he’s right.

    Most System i APIs, including QMHSNDPM, use a data structure to report errors. (Exceptions are the ILE CEE APIs, which use feedback codes and conditions, and the Unix-type, and National Language Data Conversion, which use the errno variable.) The data structure has two formats–ERRC0100 and ERRC0200. You can use either one. Or you can tell the API to send an escape message, rather than load a data structure.

    Let’s look at an RPG prototype for the API that got me in trouble.

    D SendPgmMsg      pr                  extpgm('QMHSNDPM')
    D   MsgID                        7    const
    D   MsgFile                     20    const
    D   MsgDta                      80    const
    D   MsgDtaLen                   10i 0 const
    D   MsgType                     10    const
    D   MsgQ                        10    const
    D   MsgQNbr                     10i 0 const
    D   MsgKey                       4
    D   Error                      ????
    

    The ninth parameter, which I have defined with question marks for now, tells QMHSNDPM how the programmer wants the API to report errors. The first four bytes of the error parameter contain a binary number, which is the key to the whole thing. If that number is zero, the API is to report errors by sending diagnostic and escape messages. If that number is positive, the API is to report errors through a data structure formatted according to the ERRC0100 format. If that number is negative one, the API is to report errors through the data structure according to the ERRC0200 format.

    If you want to receive diagnostic and escape messages, you don’t even need a data structure. A scalar value will do. Notice the last line of the prototype, where the error parameter is defined as a four-byte integer.

    D SendPgmMsg      pr                  extpgm('QMHSNDPM')
    D   MsgID                        7    const
    D   MsgFile                     20    const
    D   MsgDta                      80    const
    D   MsgDtaLen                   10i 0 const
    D   MsgType                     10    const
    D   MsgQ                        10    const
    D   MsgQNbr                     10i 0 const
    D   MsgKey                       4
    D   Error                       10i 0 const
    

    Here’s a call to the API that illustrates this option.

     /free
         monitor;
            SendPgmMsg ('CPF9898': 'QCPFMSG   QSYS':
                MsgDta: %len(MsgDta): '*INFO': '*PGMBDY': 1:
                MsgKey: *zero);
            on-error;
                // it bombed; do something
            endmon;
    

    If you prefer to use the data structure, that’s fine. I have found ERRC0100 to be sufficient. You can pass it as many bytes as you wish. I recommend a minimum of 16 bytes, but I have come to prefer 272, as this length allows for 256 bytes of message data.

    Here’s the revised prototype and the data structure for the error feedback.

         D SendPgmMsg      pr                  extpgm('QMHSNDPM')
         D   MsgID                        7    const
         D   MsgFile                     20    const
         D   MsgDta                      80    const
         D   MsgDtaLen                   10i 0 const
         D   MsgType                     10    const
         D   MsgQ                        10    const
         D   MsgQNbr                     10i 0 const
         D   MsgKey                       4
         D   Error                             like(ErrorDS)
    
         D ErrorDS         ds           272    qualified
         D   BytesProv                   10i 0 inz(%size(ErrorDS))
         D   BytesAvail                  10i 0
         D   ExceptionID                  7
         D                                1
         D   ExceptionDta               256
    

    Here’s the call.

    SendPgmMsg ('CPF9898': 'QCPFMSG   QSYS':
       MsgDta: %len(MsgDta): '*INFO': '*PGMBDY': 1:
       MsgKey: ErrorDS);
    if ErrorDS.BytesAvail > *zero;
       // it bombed; do something
    endif;
    

    If the call succeeds, you will find a zero in the bytes-available subfield. If the call fails, you will receive a positive value in the bytes-available subfield, a seven-byte message ID in ErrorDS.ExceptionID, and the message data for the error in ErrorDS.ExceptionDta. Do not test the call by checking those last two subfields for non-blanks. After a successful call, they may continue to contain data from an earlier, failed call.

    You must use ERRC0200 if you want convertible character support. I’ve never used ERRC0200, so I threw together an example. You may come up with something better.

    Here’s the prototype again, with the revised error data structure and a separate scalar variable for exception data.

    D SendPgmMsg      pr                  extpgm('QMHSNDPM')
    D   MsgID                        7    const
    D   MsgFile                     20    const
    D   MsgDta                      80    const
    D   MsgDtaLen                   10i 0 const
    D   MsgType                     10    const
    D   MsgQ                        10    const
    D   MsgQNbr                     10i 0 const
    D   MsgKey                       4
    D   Error                             like(ErrorDS)
    
    D ErrorDS         ds          1024    qualified
    D   Key                         10i 0 inz(-1)
    D   BytesProv                   10i 0 inz(%size(ErrorDS))
    D   BytesAvail                  10i 0
    D   ExceptionID                  7
    D                                1
    D   CCSID                       10i 0
    D   ExcDtaOffset                10i 0
    D   ExcDtaLength                10i 0
    
    D ExceptionDta    s            256
    

    The stand-alone exception data variable is necessary because the location of exception data is not fixed within the data structure. You have to look at the offset and length subfields in order to find the exception data. The following code loads the exception data if the call fails.

    clear ExceptionDta;
    SendPgmMsg ('CPF9898': 'QCPFMSG   QSYS':             
        MsgDta: %len(MsgDta): '*INFO': '*PGMBDY': 1:     
        MsgKey: ErrorDS);                                
    if ErrorDS.BytesAvail > *zero;                      
       // it bombed                                     
       // retrieve the exception data                   
       if ErrorDS.ExcDtaLength <= %size(ExceptionDta);  
          ExceptionDta = %subst(ErrorDS:                
                             ErrorDS.ExcDtaOffset + 1:  
                             ErrorDS.ExcDtaLength);     
       else;                                            
          ExceptionDta = %subst(ErrorDS:                
                             ErrorDS.ExcDtaOffset + 1:  
                             %size(ExceptionDta));      
       // do whatever else                              
       endif;                                           
    endif;
    

    I learned a lesson from my experience: Checking for API execution errors is easy. The hard part might be remembering to do so.



                         Post this story to del.icio.us
                   Post this story to Digg
        Post this story to Slashdot

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Rocket Software

    Two Steps Forward, No Steps Back

    For over 35 years, Rocket Software’s solutions have empowered businesses to modernize their infrastructure, unlock data value, and drive transformation – all while ensuring modernization without disruption.

    LEARN MORE

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    COMMON:  Join us at the annual 2008 conference, March 30 - April 3, in Nashville, Tennessee
    Help/Systems:  Discover Robot/SECURITY, the i5/OS security monitoring and auditing software
    NowWhatJobs.net:  NowWhatJobs.net is the resource for job transitions after age 40

    IT Jungle Store Top Book Picks

    The System i RPG & RPG IV Tutorial and Lab Exercises: List Price, $59.95
    The System i Pocket RPG & RPG IV Guide: List Price, $69.95
    The iSeries Pocket Database Guide: List Price, $59.00
    The iSeries Pocket Developers' Guide: List Price, $59.00
    The iSeries Pocket SQL Guide: List Price, $59.00
    The iSeries Pocket Query Guide: List Price, $49.00
    The iSeries Pocket WebFacing Primer: List Price, $39.00
    Migrating to WebSphere Express for iSeries: List Price, $49.00
    iSeries Express Web Implementer's Guide: List Price, $59.00
    Getting Started with WebSphere Development Studio for iSeries: List Price, $79.95
    Getting Started With WebSphere Development Studio Client for iSeries: List Price, $89.00
    Getting Started with WebSphere Express for iSeries: List Price, $49.00
    WebFacing Application Design and Development Guide: List Price, $55.00
    Can the AS/400 Survive IBM?: List Price, $49.00
    The All-Everything Machine: List Price, $29.95
    Chip Wars: List Price, $29.95

    Laserfiche Scales to Meet Content Management Needs of i5/OS Shop IBM Preps Update to Virtualization Manager

    Leave a Reply Cancel reply

Volume 7, Number 34 -- October 3, 2007
THIS ISSUE SPONSORED BY:

WorksRight Software
Vision Solutions
ARCAD Software

Table of Contents

  • IFS Commands Give You Generic Access
  • APIs Sometimes Fail (But Programmers Don’t Have To)
  • Admin Alert: Remotely Accessing an HMC System Console, Part 1

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • Liam Allan Shares What’s Coming Next With Code For IBM i
  • From Stable To Scalable: Visual LANSA 16 Powers IBM i Growth – Launching July 8
  • VS Code Will Be The Heart Of The Modern IBM i Platform
  • The AS/400: A 37-Year-Old Dog That Loves To Learn New Tricks
  • IBM i PTF Guide, Volume 27, Number 25
  • Meet The Next Gen Of IBMers Helping To Build IBM i
  • Looks Like IBM Is Building A Linux-Like PASE For IBM i After All
  • Will Independent IBM i Clouds Survive PowerVS?
  • Now, IBM Is Jacking Up Hardware Maintenance Prices
  • IBM i PTF Guide, Volume 27, Number 24

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle