为何RPGLE中从过程调用SNDPGMMSG时消息子文件不显示?
RPGLE过程调用CL程序时消息子文件失效,子例程调用正常问题
问题概述
作为IBM i平台RPGLE和显示文件的新手,我编写的程序中,通过子例程调用CL程序MSGSFLCL时,消息子文件(SFLMSG)能正常显示消息;但将该子例程重构为过程后,其他代码未做修改,消息却不再显示在子文件中。
相关代码实现
显示文件DDS
A R MSGSFL SFL A SFLMSGRCD(24) A MSGKEY SFLMSGKEY A PGMQ SFLPGMQ A R MSGCTL SFLCTL(MSGSFL) A OVERLAY A SFLDSP A SFLDSPCTL A SFLINZ A N99 SFLEND A SFLSIZ(0010) A SFLPAG(0001) A PGMQ SFLPGMQ
CL程序(MSGSFLCL)
PGM PARM(&MSGID &MSGF &MSGOPT) DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) DCL VAR(&MSGF) TYPE(*CHAR) LEN(10) DCL VAR(&MSGOPT) TYPE(*CHAR) LEN(1) IF COND(&MSGOPT *EQ 'I') THEN(SNDPGMMSG + MSGID(&MSGID) MSGF(&MSGF) TOPGMQ(*PRV) + MSGTYPE(*INFO)) IF COND(&MSGOPT *EQ 'C') THEN(RMVMSG PGMQ(*PRV (*)) CLEAR(*ALL)) ENDPGM
原RPGLE程序
**free ctl-opt dftactgrp(*no) actgrp(*new) option(*srcstmt:*nodebugio); exec sql set option commit = *none; dcl-f Employee Usage(*input) Keyed; dcl-s RRN packed(4: 0); dcl-f EMPSFL WorkStn SFILE(SFLDATA: RRN) INFDS(DSPFDS); dcl-ds MyDs ExtName('EMPLOYEE'); end-ds; dcl-ds DSPFDS qualified; MIN_RRN int(5) pos(378); end-ds; dcl-ds psds psds; PgmName char(10); end-ds; dcl-s MSGID char(7); dcl-s MSGF char(10) inz('AF_MSGF'); // Message File dcl-s MSGOPT char(1); dcl-pr MSGSFLCL extpgm; MessageID char(7) const; MsgF char(10) const; MsgOpt char(1) const; end-pr; RCDNBR = 1; PGMQ = PgmName; loadPage(); Dou *In03; write MSGCTL; ExFMT SFLCTL; RCDNBR = DSPFDS.MIN_RRN; MSGID = 'MSG0001'; exsr sendMessage; if (*IN05 = *ON); MSGID = 'MSG0001'; Exsr clearMsg; EndIf; EndDo; *INLR = *ON; begsr sendMessage; exsr clearMsg; MSGOPT = 'I'; MSGF = 'AF_MSGF'; MSGSFLCL(MSGID: MSGF: MSGOPT); endsr; dcl-proc loadPage; clearPr(); loadPr(); write Footer; end-proc; dcl-proc clearPr; *IN50 = *OFF; Write SFLCTL; *IN50 = *ON; RRN = 0; End-proc; dcl-proc loadPr; Exec sql declare c1 cursor for select EMPID, NAME, DEPT, SALARY from employee; Exec sql open c1; Exec sql fetch c1 into :MyDs; Dow (sqlcode = 0); RRN = RRN + 1; Write SFLDATA; Exec sql fetch c1 into :MyDs; EndDo; End-proc;
调用方式对比
正常工作的子例程调用
begsr sendMessage; exsr clearMsg; MSGOPT = 'I'; MSGF = 'AF_MSGF'; MSGSFLCL(MSGID: MSGF: MSGOPT); endsr;
此时消息子文件可正常显示消息。
失效的过程调用
dcl-proc sendMessage; MSGID = 'MSG0001'; MSGOPT = 'I'; MSGF = 'AF_MSGF'; MSGSFLCL(MSGID: MSGF: MSGOPT); end-proc;
此时消息不再显示在子文件中。
问题原因与解决方法
核心原因
RPGLE过程默认采用本地作用域,而子例程是全局作用域。过程版本存在两个关键问题:
- 未调用
clearMsg清除旧消息,导致消息队列中残留的旧消息阻塞新消息显示; - 过程内部未显式关联主程序的全局变量,默认创建了局部同名变量,导致传递给CL程序的参数上下文与子例程调用时不一致。
修复方案
方案1:通过参数传递变量(推荐)
修改过程定义,添加参数接收主程序的变量值,并确保调用clearMsg:
dcl-proc sendMessage; dcl-pi *n; p_MsgID char(7) const; p_MsgF char(10) const; p_MsgOpt char(1) const; end-pi; exsr clearMsg; // 先清除旧消息 MSGSFLCL(p_MsgID: p_MsgF: p_MsgOpt); end-proc;
主程序中调用过程时传递参数:
MSGID = 'MSG0001'; MSGOPT = 'I'; MSGF = 'AF_MSGF'; sendMessage(MSGID: MSGF: MSGOPT);
方案2:声明全局变量
如果希望过程直接使用主程序的全局变量,可在过程中用global关键字声明:
dcl-proc sendMessage; dcl-s MSGID char(7) global; dcl-s MSGF char(10) global; dcl-s MSGOPT char(1) global; exsr clearMsg; MSGSFLCL(MSGID: MSGF: MSGOPT); end-proc;
额外注意事项
- 确保主程序中
PGMQ变量已正确设置为当前程序名,CL程序的SNDPGMMSG指令使用TOPGMQ(*PRV)才能将消息发送到当前RPG程序的消息队列; - 在
ExFMT SFLCTL前必须正确WRITE MSGCTL,确保消息子文件控制块完成初始化。
内容的提问来源于stack exchange,提问作者Afnan
相关产品推荐
相关产品推荐

