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 #include0014.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] %sn", __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)
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= ユーザー・ウィンドウ
[解説]
今回はステートメントは取得できていないが多くの場合は取得も可能である。
…このようにエラー・メッセージだけでなくエラーの発生場所も合わせて示すように
すれば原因の追究は早まることは言うまでもない。