在rpgle中将被调用程序的返回值返回到主例程



我正在努力获得RPGLE和IBM的经验,并不断学习。由于大多数代码似乎都是经典的位置代码,我会坚持使用它来适应它。所以我宁愿不使用/free--/end-free的东西。顺便说一句,我在一台只有V4R5的旧9401-150上做这件事。

TL;DR:如何从外部调用ILE程序(有自己的MAIN部分,也就是说,它本身是独立的)的激活组(*NEW)中向被调用者返回返回值?

我已经准备好了一个子文件程序,运行良好。我想调用一个外部程序,通过子文件中的OPT值来处理请求。所以我在被叫的D-Spec:中定义了一个PR

DROEDETPG         PR                  EXTPGM('ROEDETPG')
DC_MODE                               LIKE(MODE)
DC_TYP                                LIKE(TYP)         

稍后,我调用该程序,该程序也运行良好。

C                   SELECT
C     OPT           WHENEQ    '2'
C                   MOVE      'CHG'         MODE
C                   CALLP     ROEDETPG(MODE:TYP)
C                   ENDSL

这是被调用程序的入口点:

C     *ENTRY        PLIST
C                   PARM                    C_MODE            3
C                   PARM                    C_TYP            16

现在,也许我想更改的记录已经锁定。因此,我在外部程序中使用CHAIN(E),并在CHAIN之后从PF获得%STATUS。它的状态值是1218,我想把这个值带回调用程序,这样它就可以使用消息行告诉用户,记录已锁定,目前不可用。

我在网上能找到的只是对调用进行原型化,并定义一个可能仅适用于过程的调用接口(PI)。

因此,我想到了一个"临时文件",就像我在Unix/Linux上的Bash和C中习惯的那样。似乎没有等效的mktemp(),但我可以在QTEMP中创建同名文件。这适用于文件类型*DTAARA。不幸的是(可预期?)该文件仅对调用程序可见。也许可以用SENDERID(*YES)创建一个全局键控*DTAQ,但这可能有些过头了?

为什么我不把外部程序中的功能放在一堆函数中,并使用CALLP?嗯,我还在学习。我决定将子例程中的内容从主源代码中移出,以结束子例程执行任务时涉及状态更改的持续麻烦。当SR执行READ时,数据库指针指向另一条记录,该记录在继续子文件时会带来大量不稳定的行为。

此外,全局变量(字段内容)会被覆盖,这会添加更多的代码来将内容移到一边,保存DB的键值,再次调用SR并恢复变量,并执行SETLL以恢复到以前的状态。我希望这会更容易,但也许我对ile rpg还是个新手。

关于如何正确避免潜在问题(文件指针和全局变量),我愿意接受其他建议。

因为ILE中的参数是通过引用传递的,所以从外部程序返回一个或多个返回值的一种简单方法是在原型和调用的程序参数中定义它们。来自其他编程环境,这对我来说有点奇怪,因为这么多年来,我一直被灌输到BYVAL而不是BYREF中,但实际上,这就是函数返回值的全部内容,堆栈上的一个值会传递回调用方。有些语言会将它们定义为out参数,但它们实际上是inout,您将其视为out

DROEDETPG         PR                  EXTPGM('ROEDETPG')
DC_MODE                               LIKE(MODE)
DC_TYP                                LIKE(TYP)
DC_ERR                        7        

C     *ENTRY        PLIST
C                   PARM                    C_MODE            3
C                   PARM                    C_TYP            16
C                   PARM                    C_ERR             7

这种方法的一个优点是,您可以返回给定任务所需的任意多个值,而无需定义数据结构来保存所有值,而不是像RPGLE子过程和大多数编程语言中的函数那样返回一个值。

QTEMP是一个很好的库,但我认为创建一个文件对于简单的参数传递来说太过分了。不过,我确实认为你可能对QTEMP有一些误解。它是在每个作业的基础上定义的,所以如果你在那里写一些东西(在文件或用户空间对象中,如果你熟悉指针,这可能比文件更方便),它绝对会在那里供该作业中运行的其他程序查找,直到作业结束或被明确删除。做一点实验来证实这一点,如果必要的话,可以问一个单独的问题,因为它确实应该能够用作多个程序的共享存储。

我知道你说不/free或**free,但我会忽略这一点,因为就我而言,固定格式的东西可能会在它产生的地狱之火中燃烧。欢迎您自行将以下代码翻译回固定格式。为了正确地执行此操作,您应该简单地将一个变量传递给将包含错误的程序。

MYPGM.RPGLE

**FREE
/Include MYHDR
Dcl-Pi *N;
ErrorRet Char(7); // or whatever type you want to return
End-Pi;
ErrorRet = 'RFE1234';
*InLR = *On;
Return;

MYHDR.RPGLE

**FREE
Dcl-Pr MyPgm ExtPgm('MYPGM');
ErrorRet Char(7); // or whatever type you want to return
End-Pr;

呼叫PGM.RPGLE

**FREE
/Include MYHDR
Dcl-S Error Char(7) Inz;
MyPgm(Error);
// Error should now contain 'RFE1234'
...

好吧,您的第一个问题是操作系统的年龄。如果你在一个更现代的平台上,你可以创建一个带有本地文件描述的子流程,并消除像这样的文件指针问题:

dcl-proc myFileIsLocked;
dcl-pi *n Ind;
mode     Char(3) const;
type     Char(16) const;
end-pi;
dcl-f myfile  keyed usage(*Update);
dcl-c RECORD_LOCKED      1218;
chain(e) (type) myfile;
return (%status = RECORD_LOCKED);
end-proc;

然而,即使在v4r5中,您也可以使用子过程来实现您的目标。将您的过程放入服务程序中,并在模块的全局区域中定义文件。像这样:

对于V4R5

qrpglesrc,mymodule

h NoMain
fmyfile    up   e           k disk usropn
/copy qprotosrc,mymodule
pmyFileIsLocked   b                   export
d *n              pi              n
d mode                           3a   const
d type                          16a   const
d*
d RECORD_LOCKED   c                   1218
c*
c                   if        not %open(myfile)
c                   open      myfile
c                   endif
c*
c     type          chain(e)  myfile
c                   if        %status = RECORD_LOCKED
c                   eval      result = *On
c                   endif
c*
c                   close     myfile
c                   return    (%status = RECORD_LOCKED)
p                 e

qprotosrc,mymodule

dmyFileIsLocked   pr              n
d mode                           3a   const
d type                          16a   const

qsrvsrc,mymodule

STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('myModule')
/********************************************************************/
/*  ------ DO NOT CHANGE THE ORDER OF THESE EXPORTS!!! ---------    */
/*  ------ ADD NEW SYMBOLS TO THE END OF THE LIST ONLY ---------    */
/********************************************************************/
EXPORT SYMBOL(myFileIsLocked)
ENDPGMEXP

然后创建这样的模块和服务程序:

CRTRPGMOD  MODULE(MYMODULE) SRCFILE(QRPGLESRC)
CRTSRVPGM  SRVPGM(MYMODULE) SRCFILE(QSRVSRC) BNDDIR(MYMODULE) +
STGMDL(*INHERIT)

注意命名。我将服务程序命名为与模块相同的名称,以及服务源和绑定目录。我总是为每个服务程序创建一个绑定目录。这样可以避免以后更新服务程序时出现名称冲突。我还创建了一个通用绑定目录,用于构建使用服务程序的程序。但我离题了。如果服务程序不依赖于任何其他程序,则此服务程序特定的绑定目录可能为空。这不是问题。在某个时刻,您可能会扩展服务程序,然后可能需要向绑定目录中添加一些内容。

在这一切建立之后,你可以简单地

c                   if        myFileIsLocked('CHG': 'TYPE')
c*                    do something
c                   endif

最新更新