Friday 5 April 2013

my rant on qzshSystem

I’ve been writing some c code to get barcode labels printing from JDEdwards on an AS400.  Traditionally people have done this through inefficient UBE’s and things, we’ve been able to get this working with native AS/400 out queues and some special smarts getting temp files sent to the out queues.  This is brilliant for barcodes, as you get instantaneous print outs, no waiting on UBE’s to produce them.  We do other smart things by allowing people to upload their ZPL into a media object and then do variable substitution at runtime.  This is a completely flexible architecture to allow you to change barcode formats when you need to instantly…  Anyways – enough about the solution – back to the rant.

Call object kernels run multi-threaded now, so you need to ensure that if you are using the System API (as I do to execute the print command), you must call code that is muti-threaded too.  My solution was calling a QSH command to print the ZPL, and unfortunately this is not multithreaded.  This gave me a couple of CEE0200 in my kernel job logs and they would eventually die!  It seems to be in relation to activation groups and being able to call programs with a *CALLER activation group.  I wrote a multi-threaded C program to do the printing and called this from the kernel (system command) and got the same problems  - Aarrggh.  I must say that this was a helpful thread http://comments.gmane.org/gmane.comp.lang.as400.c/23.

So I found a reference to QzshSystem p://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzahz%2Fqzshsyst.htm – and it’s rubbish.

I put into into a simple C program, compiled it and nothing works!!!  Joke.  There is very little doco on the internet either.  Great solution,  multi-threaded…  Does Nothing.  Returns 7 every time.  When you look at errno.h (/QOpenSys/usr/include/errno.h), this means  …

My C was too simple to be wrong!!!

#include <stdio.h>
#include <qshell.h>
#include <sys/wait.h>
#include <errno.h>


int main (int argc, char* argv[])
{
    int status = 0;
    char command[256] = {'\0'} ;

    printf("hello world\n parameters %d",argc) ;
    if (argc > 0)
    {
      strcpy(command,argv[1]) ;
      status = QzshSystem(command);
      printf("Just ran %s and got %d\n",argv[1],status);
      if (WIFEXITED(status)) {
         printf("Command %s completed with exit status %d.\n",
                command, WEXITSTATUS(status));
      }
      else if (WIFSIGNALED(status)) {
         printf("Command %s ended with signal %d.\n",
                command, WTERMSIG(status));
      }
      else if (WIFEXCEPTION(status)) {
         printf("Command %s ended with exception.\n", command);
      }
    }
    return 1;
}

CRTCMOD MODULE(MYRIAD/SOURCE1) SRCFILE(MYRIAD/QCLSRC)
CRTPGM PGM(MYRIAD/SOURCE1) MODULE(MYRIAD/SOURCE1) TEXT('hello world')
CALL PGM(MYRIAD/SOURCE1)

Commands are above to compile and run.

The more complicated version for my BSFN is here.  I have so many error logging statements because the thing was crashing hard, I did not know where.

jdeWriteLogEntry(JDEDEBUGLOG, _J("SystemLong"), __FILE__, __LINE__, 0, _J("Beginning."));
   jdeFromUnicodeSimple(szLongCommandString, lpDS->szMailMergeOuputFileName) ;

iReturnVal=QzshSystem(szLongCommandString);

   jdeWriteLogEntry(JDEDEBUGLOG, _J("SystemLong"), __FILE__, __LINE__, 0, _J("It's an AS/400."));
   jdeWriteLogEntry(JDEDEBUGLOG, _J("SystemLong"), __FILE__, __LINE__, 0, lpDS->szMailMergeOuputFileName);
           
   if (WIFEXITED(iReturnVal))
   {
     jdeWriteLogEntry(JDEDEBUGLOG, _J("SystemLong"), __FILE__, __LINE__, 0, _J("Seems to have worked."));
     swprintf(lpDS->ErrorMessage, _J("Command %100s completed with exit status %d.\n"), lpDS->szMailMergeOuputFileName, WEXITSTATUS(iReturnVal));
   }
   else if (WIFSIGNALED(iReturnVal))
   {
     jdeWriteLogEntry(JDEDEBUGLOG, _J("SystemLong"), __FILE__, __LINE__, 0, _J("Error Signaled."));
     swprintf(lpDS->ErrorMessage, _J("Command %100s ended with signal %d.\n"), lpDS->szMailMergeOuputFileName, WTERMSIG(iReturnVal));
   }
   else if (WIFEXCEPTION(iReturnVal))
   {
     jdeWriteLogEntry(JDEDEBUGLOG, _J("SystemLong"), __FILE__, __LINE__, 0, _J("Exception Signaled."));
     swprintf(lpDS->ErrorMessage, _J("Command %100s ended with exception.\n"), lpDS->szMailMergeOuputFileName);
   }


   /************************************************************************
    * Function Clean Up
    ************************************************************************/
   jdeWriteLogEntry(JDEDEBUGLOG, _J("SystemLong"), __FILE__, __LINE__, 0, _J("Returning."));
   return (ER_SUCCESS);

 

So, I eventually had to find another way of printing my barcode, but not without going through some crazy options.  I also finally had to write  a test harness which called the JDEdwards provided system command, so I could get the syntax correct for my “System()” and then put it into my code.

This was a long day in the saddle.  Let me know if you’ve managed to get

No comments: