C400

139. エラー場所も報告する MonitorMSG

C言語では #pragma exception_handler を定義しておくと
プログラム内で発生する予測できなかったエラーを監視することができる。
これはCLPのMONMSGと同じである。

多くはエラーが発生したときにはエラー・メッセージを出力して
終了するがそのエラーがプログラムのどこで発生したのかが
わからないとエラー原因を追跡することができない。

そこでここに紹介するTESTMON というプログラムでは
エラー・メッセージだけでなくエラーの発生した場所も
報告するようにしたものである。

エラーの発生した場所は受け取ったメッセージ・データの中の
送信者プログラムステートメントという形で記録されている。
それをエラー・メッセージとともに報告できるようにしたのが
このTESTMONである。

一般のC言語による適用業務を開発するときに
すべてのC言語のエラー・モニターとして使えるサンプルである。

[ TESTMON :エラー監視のテスト ]

ソースはこちらから

0001.00 /********************************************************************/    
0002.00 /*                                                                  */    
0003.00 /*   TESTMON     : MONMSG のテスト                                  */    
0004.00 /*                                                                  */    
0005.00 /*          Office Quattro Co,.Ltd 2021/03/28 08:08:08 created      */    
0006.00 /*                                                                  */    
0007.00 /*                                                                  */    
0008.00 /********************************************************************/    
0009.00 #pragma comment(COPYRIGHT, "as400-net.com EnterpriseServer (C) CopyRight 
0010.00 Office Quattro.Corp. 2020- All right reserved. Users Restricted          
0011.00 Rights - Use, duplication or disclosure restricted by Office Quattro     
0012.00 Corp. Licenced Materials-Property of Office Quattro.")                    
0013.00 #include                                                         
0014.00 #include                                                        
0015.00 #include                                                        
0016.00 #include  /* triml */                                         
0017.00 #include                                                       
0018.00 #include                                                      
0019.00 #include                                                         
0020.00 #include                                                        
0021.00                                                                           
0022.00 #define TRUE         0                                                    
0023.00 #define FALSE       -1                                                    
0024.00 int    bLR = FALSE;                                                   
0025.00 typedef struct {                                                      
0026.00    int  BYTESPRO;                                                     
0027.00    int  BYTESAVL;                                                     
0028.00    char MSGID[7];                                                     
0029.00    char RESRVD;                                                       
0030.00    char EXCPDATA[100];                                                
0031.00 } ERRSTRUCTURE;     /* Define the error return structure            */
0032.00 ERRSTRUCTURE  errcode;/* Error Code Structure for RCVMSG      */      
0033.00 volatile _INTRPT_Hndlr_Parms_T ca;                                    
0034.00                                                                       
0035.00 /*************************************************************/       
0036.00 /*       内 部 使 用  関  数                          */       
0037.00 /*************************************************************/       
0038.00 void  GetParam(int argc, char *argv[]);                               
0039.00 void  INZSR(void);                                                    
0040.00 void  LRRTN(char *argv[]);                                            
0041.00 void  MonitorMSG(_INTRPT_Hndlr_Parms_T ca, char *argv[]);             
0042.00                                                                       
0043.00 /*************************************************************/       
0044.00 /*       IMPORT  関  数                            */       
0045.00 /*************************************************************/       
0046.00 /*************************************************************/       
0047.00 /*       IMPORT  変  数                            */       
0048.00 /*************************************************************/         
0049.00 /*************************************************************/         
0050.00 /*       外 部 呼 出 し  関  数                      */         
0051.00 /*************************************************************/         
0052.00 /*************************************************************/         
0053.00 /*        グ ロ ー バ ル 変 数                         */         
0054.00 /*************************************************************/         
0055.00   /*------( 受取りパラメータ値 )----------*/                            
0056.00   /*------( 受取りパラメータ値 )----------*/                            
0057.00   char ref[133], MSG[133], ERR[1];                                      
0058.00 /********************************************************************/  
0059.00 /*            m  a  i  n --- main module of this pgm                */  
0060.00 /*                                                                  */  
0061.00 /*           1.                                          */  
0062.00 /*                      2.                                          */  
0063.00 /*                      3.                                          */  
0064.00 /*                                                                  */  
0065.00 /*------------------------------------------------------------------*/  
0066.00                                                                         
0067.00 int  main(int argc, char *argv[]){                                      
0068.00    int rc, sho=10, bunbo = 0;                                           
0069.00                                                                         
0070.00    #pragma exception_handler(MONMSG, ca, 0, _C2_MH_ESCAPE, _CTLA_HANDLE)
0071.00    GetParam(argc, argv);  /*[ パラメータの取得 ]*/                      
0072.00    INZSR();               /*[ 初期設定 ]*/            
0073.00                                                       
0074.00    rc = sho / bunbo;                                  
0075.00                                                       
0076.00    LRRTN(argv);                                       
0077.00    exit(0);                                           
0078.00                                                       
0079.00 MONMSG:                                               
0080.00    #pragma disable_handler                            
0081.00    MonitorMSG(ca, argv);                              
0082.00                                                       
0083.00    exit(0);                                           
0084.00 }                                                     
0085.00 /*************************************/               
0086.00 void  GetParam(int argc, char *argv[])                
0087.00 /*************************************/               
0088.00 {                                                     
0089.00 }                                                     
0090.00 /****************/                                    
0091.00 void  INZSR(void)                                     
0092.00 /****************/                                    
0093.00 {                                                     
0094.00    errcode.BYTESPRO = 160;                            
0095.00    errcode.BYTESAVL = 0;                              
0096.00    ERR[0] = ' ';                                                     
0097.00 }                                                                    
0098.00 /************************/                                           
0099.00 void  LRRTN(char *argv[])                                            
0100.00 /************************/                                           
0101.00 {                                                                    
0102.00    if(bLR == TRUE) return;                                           
0103.00    bLR = TRUE;                                                       
0104.00    exit(0);                                                          
0105.00 }                                                                    
0106.00 /********************************************************/           
0107.00 void  MonitorMSG(_INTRPT_Hndlr_Parms_T ca, char *argv[])             
0108.00 /********************************************************/           
0109.00 {                                                                    
0110.00    char Send_Program_Name[13], Send_Instruction_Num[5], msg[512];    
0111.00    int  msglen, wait_time = 0, len;                                  
0112.00    typedef struct {                                                  
0113.00      Qmh_Rcvpm_RCVM0200_t rcvm0200;                                  
0114.00      char msg[512];                                                  
0115.00    } RCVM0200;                                                       
0116.00    RCVM0200 rcvm0200;                                                
0117.00                                                                      
0118.00    _GetExcData(&ca);                                                 
0119.00    QMHRCVPM(&rcvm0200, sizeof(RCVM0200), "RCVM0200", "*         ",1, 
0120.00              "*ANY      ", (char*)&ca.Msg_Ref_Key, wait_time,"*SAME     ", &errcode);
0121.00    msglen = rcvm0200.rcvm0200.Length_Message_Available;                              
0122.00    memcpy(msg, rcvm0200.msg, msglen);                                                
0123.00    msg[msglen] = 0x00;                                                               
0124.00    memcpy(Send_Program_Name, rcvm0200.rcvm0200.Send_Program_Name, 12);               
0125.00    Send_Program_Name[12] = 0x00;                                                     
0126.00    len = triml(Send_Program_Name, ' ');                                              
0127.00    if(len > 0) Send_Program_Name[len] = 0x00;                                        
0128.00    memcpy(Send_Instruction_Num, rcvm0200.rcvm0200.Send_Instruction_Num, 4);          
0129.00    Send_Instruction_Num[4] = 0x00;                                                   
0130.00    sprintf(MSG, "MONMSG プログラム %s-STMT:%s で次のエラーがありました。 n %s",     
0131.00         Send_Program_Name, Send_Instruction_Num, msg);                               
0132.00    printf("TESTMON[%d] %sn", __LINE__, MSG);                                        
0133.00    getchar();                                                                        
0134.00    ERR[0] = 'E';                                                                     
0135.00    LRRTN(argv);                                                                      
0136.00 }     


                                                                                 

[コンパイル]

CRTBNDC OBJLIB/TESTMON SRCFILE(MYSRCLIB/QCSRC) AUT(*ALL)

[解説]

0070.00    #pragma exception_handler(MONMSG, ca, 0, _C2_MH_ESCAPE, _CTLA_HANDLE)

で以降に発生するエラーをモニターしてエラーがあれば MONMSG というタグにジャンプすることを
宣言している。

0079.00 MONMSG:                                               
0080.00    #pragma disable_handler                            
0081.00    MonitorMSG(ca, argv); 

が MONMSGタグであり関数: MonitorMSG を呼び出して実行している。

0106.00 /********************************************************/           
0107.00 void  MonitorMSG(_INTRPT_Hndlr_Parms_T ca, char *argv[])             
0108.00 /********************************************************/

からが主題である。

0119.00    QMHRCVPM(&rcvm0200, sizeof(RCVM0200), "RCVM0200", "*         ",1, 
0120.00              "*ANY      ", (char*)&ca.Msg_Ref_Key, wait_time,"*SAME     ", &errcode);

は エラー・メッセージ・ハンドラー ca に入っているメッセージ・キー: ca.Msg_Ref_Key によって
発生したエラー・メッセージそのものを取得しにいっている。
メッセージを受信しているのではなくメッセージそのものを取得しているのである。

エラー・メッセージ・ハンドラー ca にはmsgidだけでなくメッセージ・キーも入っているので
これを利用しない手はない。
次にやはりエラー・メッセージ・ハンドラー caには送信者プログラムとステートメント
入っているのでこれを取得してメッセージとして組み立てている。
結果は次のように表示される。


   TESTMON[132] MONMSG プログラム TESTMON-STMT:0000 で次のエラーがありました。  
     固定小数点演算でゼロによる除算を実行しようとした。                         
                                                                                
 ===>                                                                           
                                                                                
 F3= 終了   F4= ファイルの終わり   F6= 印刷   F9= 検索   F17= 先頭              
 F18= 最後   F19= 左   F20= 右   F21= ユーザー・ウィンドウ                      

[解説]

今回はステートメントは取得できていないが多くの場合は取得も可能である。

…このようにエラー・メッセージだけでなくエラーの発生場所も合わせて示すように
すれば原因の追究は早まることは言うまでもない。