QGYOLMSG API C code sample

I was trying to help debug an RPG program where the developer wanted to use the QGYOLMSG API to extract messages sent to the QSYSOPR message queue when I became embroiled in my own problems with the API.

Here is the link to the RPG post. As you can see the problems the RPG programmer encountered were all about the offsets to the passed parameters, I had a further problem due to the structure being built having to be a _Packed structure. Once we had resolved this the program ran but returned a CPF240F message which isn’t listed in the returned messages in the manual! I decided to post the code to the C/C++ forum to see if anyone could see what I was doing wrong. Here is the post.
Carsten Flensburg kindly ran the code through the debugger and pointed out the fact that the key passed into the Selection Information are being corrupted! The API was taking the int value field and converting it to Oct! This is not in the manual but who is surprised any more? After changing the key passed in from ‘0301’ to ‘301’ as in the code below the Error Code structure was sending back a strange message ID! So I decided to run the debugger myself to see what was going on. Carsten pointed me in the right direction in that the addresses of the pointer passed and the user space didn’t match! I had made the CLASSIC mistake of passing in the address of the pointer not the address of the User Space object! This was causing the whole memory map within the API to be thrown off, and it didn’t complain!

So in hindsight here are a couple of points to remember when coding the List API QGYOLMSG in C.

1. Make sure the selection Info is passed in a _Packed Structure.
2. Make sure you pass the address of the Buffer not its pointer!
3. The offsets are critical and the resulting messages are not always helpful.
4. Always delete the resource using the QGYCLST API to free up the List resource!

Carsten did mention the fact that the buffer passed in is not used for returning the messages if the QGYGTLE API is used, but my testing seems to point to the fact that the buffer is actually used to store the initial data at least, perhaps the messages which cant be stored are stored in another resource which is used by the QGYGTLE API once it has read through the initial store?? I did not move the testing any further as it was only intended to be a quick trial of the code!

The program code below works, it does provide limited information about the messages returned which can be expanded to meet your needs! Its not production code and needs more error checking to be added, so be warned!

#include
#include
#include 
#include 
#include 
#include               /* Create User Space */
#include 
#include 
#include 
#include 
#include 

typedef struct Msg_Ret_x {
        int Num;
        char Q_Inf[2][20];
        }Msg_Ret_t;

typedef char SelC[10];
typedef char MsgK[4];

typedef _Packed struct SelInf_x {
        char  List_Direction[10];
        char  Reserved[2];
        int   Severity_Criteria;
        int   Max_Msg_Length;
        int   Max_Help_Length;
        int   Sel_Criteria_Offset;
        int   Num_Sel_Criteria;
        int   Start_Msg_Keys_Offset;
        int   Retd_Fields_IDs_Offset;
        int   Num_Fields;
        char  Sel_Cri[1][10];
        char  Msg_Key[1][4];
        int   FieldID[2];
        }SelInf_t;

#define _16MB 16776704

int main(int argc, char **argv) {
int Ret_Recs = -1;
int Num_Ents = 0;
int i;
int Initial_Size = _16MB;
char Sort_Info = '0';
char ListInfo[80];
char QueueInfo[21] = "0QSYSOPR             ";
char Queue_List[44];
char SPC_Name[20] = "QGYOLMSG  QTEMP     ";
char Ext_Atr[10];
char Initial_Value = ' ';
char Auth[10] = "*CHANGE   ";
char SPC_Desc[50] = {' '};
char Replace[10] = "*YES      ";
char Msg_Buf[1024];
SelInf_t Sel_Info;
char *space;
Qgy_Olmsg_ListInfo_t *ret_info;
Qgy_Olmsg_RecVar_t *ret_msg;
Msg_Ret_t *Q_Info;
Qus_EC_t Error_Code = {0};

Error_Code.Bytes_Provided = sizeof(Error_Code);

Q_Info = (Msg_Ret_t *)Queue_List;
memset(Ext_Atr,' ',10);

memcpy(Sel_Info.List_Direction,"*NEXT     ",10);
Sel_Info.Severity_Criteria = 0;
Sel_Info.Max_Msg_Length = 132;
Sel_Info.Max_Help_Length = 0;
Sel_Info.Sel_Criteria_Offset = 44;
Sel_Info.Num_Sel_Criteria = 1;
Sel_Info.Start_Msg_Keys_Offset = 54;
Sel_Info.Retd_Fields_IDs_Offset = 58;
Sel_Info.Num_Fields = 2;
memcpy(Sel_Info.Sel_Cri[0],"*ALL      ",10);
memset(Sel_Info.Msg_Key[0],0x00,4);
Sel_Info.FieldID[1] = 301;
Sel_Info.FieldID[0] = 1001;

QUSCRTUS(SPC_Name,
         Ext_Atr,
         Initial_Size,
         &Initial_Value,
         Auth,
         SPC_Desc,
         Replace,
         &Error_Code);
if(Error_Code.Bytes_Available > 0) {
   printf("Msg received CRTUS %.7sn",Error_Code.Exception_Id);
   /* send message */
   }

QUSPTRUS(SPC_Name,              /* get pointer to USRSPC */
         &space,
         &Error_Code);
if(Error_Code.Bytes_Available > 0) {
   printf("Msg received PTRUS %.7sn",Error_Code.Exception_Id);
   /* send message */
   }

QGYOLMSG(space,
         _16MB,
         ListInfo,
         Ret_Recs,
         &Sort_Info,
         &Sel_Info,
         sizeof(Sel_Info),
         QueueInfo,
         Queue_List,
         &Error_Code);
if(Error_Code.Bytes_Available > 0) {
   printf("Msg received LMSG %.7sn",Error_Code.Exception_Id);
   return -1;
   }
ret_info = (Qgy_Olmsg_ListInfo_t *)ListInfo;
printf("Available %d Returned %dn",ret_info->Total_Records,
       ret_info->Records_Retd);
Num_Ents = ret_info->Records_Retd;
/* Use QGYGTLE to return the messages to the program */
ret_msg = (Qgy_Olmsg_RecVar_t *)Msg_Buf;
for(i = 1; i <= Num_Ents; i++) {
   QGYGTLE(Msg_Buf,
           sizeof(Msg_Buf),
           ret_info->Request_Handle,
           &ListInfo,
           1,
           i,
           &Error_Code);
   printf("Msg_ID GTLE %.7sn",ret_msg->Msg_ID);
   }
/* clean up the resources  */
QGYCLST(ret_info->Request_Handle,
        &Error_Code);
if(Error_Code.Bytes_Available > 0) {
   printf("Msg received CLST %.7sn",Error_Code.Exception_Id);
   }
return 1;
}

Hope the program helps those who are trying th get the list API’s working.

Chris…

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.