我正在尝试获得RPGLE和IBM i方面的经验并不断学习。由于大多数原始代码似乎都是经典的位置代码,因此我会坚持使用它来习惯它。所以我宁愿不使用/ free-/ end-free的东西。顺便说一句,我是在只有V4R5的旧9401-150上执行此操作的。
TL; DR:如何从自己的激活组(*NEW
)中的外部调用的ILE程序(具有其自己的MAIN部分,即它本身是独立的)获得返回值,被叫人?
我有一个准备好的子文件程序,并且可以正常运行。我想调用一个外部程序来处理子文件中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)
,并在%STATUS
之后从PF获取CHAIN
。那个的状态值为1218,我想将此值返回给调用程序,因此它可能会使用消息行告诉用户该记录目前处于锁定状态并且不可用。
我只能在网上找到呼叫的原型,并定义一个可能仅适用于过程的呼叫接口(PI)。
因此,我想到了一个“临时文件”,就像我在Unix / Linux上的Bash和C中所使用的那样。似乎没有mktemp()
等效项,但是我可以在QTEMP中创建具有相同名称的文件。这适用于文件类型*DTAARA
。不幸的是(可能吗?)此文件仅对调用程序可见。也许可以使用SENDERID(*YES)
创建一个全局键* DTAQ,但这可能是过大了?
为什么我不将外部程序中的功能放入一堆函数中并使用CALLP
?好吧,我还在学习。我决定将子例程中的内容移出主要来源,以结束因子例程进行填充而导致的状态更改带来的麻烦。当SR执行READ时,数据库指针指向另一个记录,该记录在继续子文件填充时会带来多种不稳定行为。
此外,全局变量(字段内容)将被覆盖,这将添加更多代码以将内容移到一边,保存DB的键值,调用SR并再次还原变量,然后执行SETLL
返回到声明我以前去过的地方。我希望这会更容易,但是也许我仍然是关于ile rpg的新秀。
我愿意就如何正确避免潜在问题(文件指针和全局变量)提出其他建议。
答案 0 :(得分:4)
由于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有一些误解。它是基于每个作业定义的,因此,如果您在其中写一些东西(在文件或用户空间对象中,如果您喜欢使用指针,则比文件更方便),其他程序绝对可以在其中找到它在该作业中运行以查找直到该作业结束或被明确删除。进行一些试验以确认这一点,并在必要时提出一个单独的问题,因为它确实应该可以用作多个程序的共享存储。
答案 1 :(得分:4)
我知道您说过/ 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;
CALLINGPGM.RPGLE
**FREE
/Include MYHDR
Dcl-S Error Char(7) Inz;
MyPgm(Error);
// Error should now contain 'RFE1234'
...
答案 2 :(得分:2)
好吧,您的第一个问题是操作系统的年龄。如果您使用的是更现代的平台,则可以创建带有本地文件描述的子过程,并消除如下文件指针问题:
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,我的模块
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