Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win


CWBX .NET Message Queue

Posted on 2013-01-18
Medium Priority
Last Modified: 2014-11-05
First of all i'm not an expert on as400 OS/command.
I building a prgm in.NET that would monitor DSPMSG MSGQ(QSYS/QSYSOPR)
I tryed to use cwbx.DataQueue object but an error is raised tell me that it can't found DQ QSYSOPR on Library QSYS. Ok now i know that a DataQueue is not a Message Queue ;-) .
But, i wonder if it i can use any other object on CWBX to retreive the content of this MSGQ ?
May be using cwbx.Program object ? if so how can  i retreive the output parameters to get the list of all messages ?

OS400 V5R2M0
VB.NET 2005
Windows 7

Thanks in advance.
Question by:Laurent .
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
LVL 35

Expert Comment

by:Gary Patterson
ID: 38794694
.NET isn't great for this task, if you ask me.  IBM provides great tools for Java in the JTOpen project and in the functionally identical IBM Toolbox for Java, so if that is an option, do that:

JTOpen project: http://jt400.sourceforge.net/

Dealing with messages without using the Java classes is a pain.  The native API (QMHRTVM) is rather complex:


There is a slightly less complex command that you can use called RCVMSG:


If Java isn't an option, post back and I can give you some pointers.  Just be aware that this isn't a beginner task except in Java.

- Gary
LVL 27

Expert Comment

ID: 38795309
IMO, the first step should be to decide if it's a good idea. Generally, the QSYSOPR message queue is not an object that ought to be allocated to a process running off-system. That's true of most objects named starting with "Q*". 'Normal' user message queues would usually be no problem, but QSYSOPR is one that has special meaning to the system itself.

A far better project would be to create a process that runs on the AS/400 to act as middleware. It would do any send/receive operations against QSYSOPR and relay to your .NET process. Data queues would be an excellent communications method between .NET and intermediate function.

Having the intermediary would allow creating methods that could be accessed and controlled by other processes on the AS/400. It would give capability of telling the intermediary to relinquish control when it becomes necessary, as well as other potential actions. That might be much more difficult if a networking issue suspends control from the .NET side.

It's certainly possible to build a .NET function as you seem to want, though I don't know of a direct API for it. It's just potentially a troublesome object to allocate in the way it would need to be done.


Author Comment

by:Laurent .
ID: 38799654
@Tom, @ Gary
Thank you guys for your feedback.
Well, since i prefere not put my nose on a JAVA for the moment, i'm a little bit in the rush so that would be the last option to me, i'm not a native JAVA dev...yet.

May be i need to come back to my original reason why i did open this thread. We have a System iSerie 9406-800, with OS400 V5R2 running MOVEX 10A and DataMirror v2.3 (To a SQL Server DB). Our Storage(HDD) is full at 75%, we can't upgrage it without upgrade the OS, we can't upgrade the OS without upgrade MOVEX/DataMirror. Our group have a plan to switch to SAP in 2014 so the upgrade is not a solution. MOVEX 10A has some knowed bugs, since we do not have support anymore on MOVEX, we have to deal with the situation.
Problem is, some time to time, i have some MOVEX prg that generate some messages on QSYSOPR MSGQ that required a reply.
In order to be as much responsive as possible, i was looking for solution to trigger an alert each time such messages are queued.

IBM Support provide me with a CL prg to send SMTP msg for each critical message (i put the code in attachment for further reference). I didn't test it yet, i would need some help from IBM to test it.
As Tom said, a server side middleware looks be a better solution for the moment.
I will post the result of this prg once tests have been done.

Thanks again to both to pointing me to the right direction.

Windows Server 2016: All you need to know

Learn about Hyper-V features that increase functionality and usability of Microsoft Windows Server 2016. Also, throughout this eBook, you’ll find some basic PowerShell examples that will help you leverage the scripts in your environments!

LVL 27

Accepted Solution

tliotta earned 2000 total points
ID: 38800815
At V5R2, it's harder to be sure. Is there a reason you never went to V5R3?

I could do some testing at V5R3, but I can't determine V5R2 details. At V5R3, I'd use Management Central to monitor disk utilization. I think it's reasonably similar for V5R2.

But at V5R3 (and possibly V5R2), the messages don't have to go to QSYSOPR. They can go to a number of message queues (or users). See the Change Service Attributes (CHGSRVA) command to see message queues configured for it, and see system value QSTGLOWACN to see if it is set to *CRITMSG or *REGFAC. The <Help> text for both will give some guidance. With QSYSOPR out of the way (or simply one of a list of queues), a number of message handling options are less intrusive.

Other options exist besides Management Central and service messaging. In some rare cases, you might even have the AS/400 use NET SEND to send messages over the Windows Messenger service. (Not "NET SEND" but an API that does the work.) Almost all local networks block Messenger messages at the routers, and it's disabled by default at workstations nowadays, but it can be handy for some simple uses.


Author Comment

by:Laurent .
ID: 38808270
@Tom: Thanks for the reply, i will investigate this way too.

Author Comment

by:Laurent .
ID: 38808277
just see that the attachment didn't work on my post from Jan-21th, so here the code of the prg that monitor critial message and perform an action. NEED TO BE CUSTOMIZED.
@courtizy of IBM Vienam


/* Declare the month, day, etc.                                      */
             DCL        VAR(&MONTH) TYPE(*CHAR) LEN(2)
             DCL        VAR(&DAY) TYPE(*CHAR) LEN(2)
             DCL        VAR(&YEAR) TYPE(*CHAR) LEN(4)
             DCL        VAR(&TIME) TYPE(*CHAR) LEN(8)
             DCL        VAR(&HOUR) TYPE(*CHAR) LEN(2)
             DCL        VAR(&MIN) TYPE(*CHAR) LEN(2)
             DCL        VAR(&SEC) TYPE(*CHAR) LEN(2)

/* The variables used to get the values from retrieve system value   */
/*                                                                   */
/* The QDATETIME is returned as this according to the help text :    */
/* The format of the field is YYYYMMDDHHNNSSXXXXXX :                 */
/*  YYYY is the year                                                 */
/*  MM is the month                                                  */
/*  DD is the day                                                    */
/*  HH is the hours                                                  */
/*  NN is the minutes, SS is the                                     */
/*  SS is the seconds                                                */
/*  XXXXXX is the microseconds                                       */
/*                                                                   */
/* DATFMT is the format of the date such like  YMD, MDY, DMY, JUL    */
             DCL        VAR(&QDATETIME) TYPE(*CHAR) LEN(20)
             DCL        VAR(&QDATFMT) TYPE(*CHAR) LEN(3)

/* Misc variables                                                    */
             DCL        VAR(&HEADER) TYPE(*CHAR) LEN(3)
             DCL        VAR(&POS) TYPE(*DEC) LEN(3)
             DCL        VAR(&SEVERITY) TYPE(*CHAR) LEN(2)
             DCL        VAR(&SEV#) TYPE(*DEC) LEN(2)
             DCL        VAR(&HEADERFND) TYPE(*CHAR) LEN(1)

/* Declaring a file to import the output of the history log          */
             DCLF       FILE(QTEMP/QHIST)


             RTVSYSVAL  SYSVAL(QDATFMT) RTNVAR(&QDATFMT)                /* Retrieving date format */

             DLTF       FILE(QTEMP/QHIST)                               /* Recreating the temp file used */
             MONMSG     MSGID(CPF0000)                                  /* for importing the hist log    */

/* Here we are getting the datetime from retrieve system value       */
/* Then we break down the hours/mins/secs                            */
/* and we put it in a format of 'HH:MM:SS' to pass to the dsplog cmd */
             CHGVAR     VAR(&HOUR) VALUE(%SST(&QDATETIME 9 2))
             CHGVAR     VAR(&MIN) VALUE(%SST(&QDATETIME 11 2))
             CHGVAR     VAR(&SEC) VALUE(%SST(&QDATETIME 13 2))
             CHGVAR     VAR(&TIME) VALUE(&HOUR *CAT ':' *CAT &MIN *CAT ':' *CAT &SEC)

/* We dump the history log and will copy it over to our file that we */
/* declared, QHIST in library QTEMP                                  */
/* Then we delete the spoolfile                                      */
             DSPLOG     PERIOD((&TIME)) OUTPUT(*PRINT)

             MONMSG MSDID(CPF0000) EXEC(DO)                             /* OK here what can happen is we can   */
                CHGJOB     LOG(*SAME *SAME *NOLIST)                     /* get an error saying that we can't   */
                SBMJOB     CMD(call histmon) JOB(HISTMON) +             /* spool anymore, if we spool too many */
                          JOBQ(QSYSNOMAX)                               /* times. Submit another monitor job   */
                RETURN                                                  /* and end cleanly                     */


/* The way this works is we need to scan the history for the the word*/
/* SEV like in the below example. The SEV in                         */
/*                                                                   */
/* 5761SS1 V6R1M0 080215                                History Log  */
/*MSGID    SEV MSG TYPE                                              */
/*CPA4067  99  INQUIRY      Save file MCASE in MCASE already contains*/
/*                                                                   */
/* After we find the SEV header, we can now scan the file for that   */
/* position on the next lines for the severity level                 */
             CHGVAR VAR(&POS) VALUE(0)
             CHGVAR VAR(&HEADERFND) VALUE('0')
             MONMSG     MSGID(CPF0864) EXEC(GOTO EXITREAD)              /* End of file, exit to  */
                                                                        /* EXITREAD              */

             IF COND(&HEADERFND *EQ '0') THEN(DO)                       /* Find the header first */
                CHGVAR VAR(&POS) VALUE(&POS + 1)
                IF COND(&POS *GT 129) THEN(DO)
                   CHGVAR VAR(&POS) VALUE(0)
                   GOTO READF
                CHGVAR VAR(&HEADER) VALUE(%SST(&QHIST &POS 3))
                IF COND(&HEADER *EQ 'SEV') THEN(DO)
                   CHGVAR VAR(&HEADERFND) VALUE('1')
                   GOTO READF
                GOTO FINDHDR

             IF COND(&HEADERFND *EQ '1') THEN(DO)                       /* Now to check for severity on  */
                CHGVAR VAR(&SEVERITY) VALUE(%SST(&QHIST &POS 2))        /* the next lines of the histlog */
                CHGVAR VAR(&SEV#) VALUE(&SEVERITY)                      /* We convert the severity #     */
                MONMSG MSGID(CPF0000) EXEC(DO)                          /* character string to decimal   */
                   GOTO READF
                IF COND(&SEV# *GT 50) THEN(DO)                          /* In this example, if the sev      */
                  SNDMSG MSG('got it!!') TOUSR(NNGUYEN)                 /* is greater than 50, do something */

              GOTO READF                                                /* Continue reading the file */

/* Get the current time so we can just dump the history for next     */
/* round. There is a chance we might miss a message but it should    */
/* slim chance                                                       */
              CHGVAR     VAR(&HOUR) VALUE(%SST(&QDATETIME 9 2))
              CHGVAR     VAR(&MIN) VALUE(%SST(&QDATETIME 11 2))
              CHGVAR     VAR(&SEC) VALUE(%SST(&QDATETIME 13 2))
              CHGVAR     VAR(&TIME) VALUE(&HOUR *CAT ':' *CAT &MIN *CAT ':' *CAT &SEC)

              CLOSE                                                     /* Close our temp file so we can */
                                                                        /* open it up again              */
              DLYJOB DLY(60)
              GOTO DMPLOG


Open in new window

LVL 27

Expert Comment

ID: 38811662
I'm not sure what that program is supposed to do. It has a couple questionable parts that need to be examined.

For example, at line 71, the history log is dumped to a spooled file. The entries that are dumped are those beginning at the time specified in variable &TIME and ending at the current time. But the value in &TIME is set by retrieving the QDATETIME system value and extracting the time portion.

That means that all entries beginning at the current time and ending at the current time (because ending time defaults there) are dumped. The result should almost always be a CPF2447 *ESCAPE message saying that no entries exist.

And the result of that would be triggering the MONMSG at line 73 because it checks for the 'template' value of CPF0000 rather than a spool limit message. That causes the program to submit itself to QSYSNOMAX to start over again. And the result of that should be the same thing happening over again.

Also, it is reviewing the history log rather than a service message queue. That might be okay if you are only interested in history log entries. And given your description of your goal, that might be good enough.

But it needs a lot of work. There are numerous other things that would need changing if it is the start of what you want to do.

I would investigate the alternatives before going this way.

LVL 27

Expert Comment

ID: 38811827
I'd look into Management Central first. If that wasn't satisfactory, I'd create a custom message queue monitor. Either way, I'd have my function running against an alternative service message queue that was created specifically for this purpose.


Author Closing Comment

by:Laurent .
ID: 40425548
Upgrade OS to V5R3 solved the issue

Featured Post

Veeam Disaster Recovery in Microsoft Azure

Veeam PN for Microsoft Azure is a FREE solution designed to simplify and automate the setup of a DR site in Microsoft Azure using lightweight software-defined networking. It reduces the complexity of VPN deployments and is designed for businesses of ALL sizes.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

As much as Microsoft wants to kill off PST file support, just as they tried to do with public folders, there are still times when it is useful or downright necessary to export Exchange mailboxes to PST files. Thankfully, it is still possible to e…
This week I attended a Startup Week Chattanooga talk on Gender Diversity in Technology. Check out what I learned.
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…
This lesson discusses how to use a Mainform + Subforms in Microsoft Access to find and enter data for payments on orders. The sample data comes from a custom shop that builds and sells movable storage structures that are delivered to your property. …
Suggested Courses

609 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question