动态调用内部过程

时间:2018-06-20 10:30:52

标签: ibm-midrange rpgle

有人可以向我解释为什么我不能使用%paddr() BIF将内部过程的地址(存储在字符串变量中)分配给ProcPointer吗?

我的想法是创建一个数字为键的关联数组,并将某个子过程的名称为值。当用户在DSPF中输入数字2时,程序必须调用具有键“ 2”的过程。

据我了解,BIF %paddr()采用硬编码的过程名称或包含过程名称的字符串。但是,当给一个字符串变量时,编译器会抱怨%PADDR的参数无效。

2 个答案:

答案 0 :(得分:4)

这是因为过程是由编译器静态绑定的。因此,编译器需要在编译时知道要调用什么程序。但是,有些API可在运行时用于绑定服务程序。艾伦·坎宾(Alan Campin)有一些例子here

让我们再谈谈绑定。调用程序和过程时,IBM i提供两种不同类型的绑定。对于程序,绑定在第一次调用给定程序时在运行时发生,它会解析并绑定到调用方。程序名称可以保存在变量中,并且由于该程序是在运行时绑定的,因此首次通过变量调用该程序时,它将被解析并绑定到调用方,此后,当变量中的值更改时,该程序在下一次调用时再次解析。这称为动态绑定。绑定发生在运行时,可能在每次调用程序时发生,并且在调用者或激活组结束时,绑定会丢失。

过程在编译期间是静态绑定的。过程或过程指针没有内置的运行时绑定。您可以通过使用过程指针来近似动态绑定,但是在内部将过程绑定到过程指针,并且如果通过%paddr()为过程指针提供地址,则绑定将在该点进行。甚至使用回调的API都是静态绑定的。 API绑定到过程指针,调用者将过程指针绑定到回调过程本身,然后将绑定传递给API。在运行时没有解决方案发生。您可以使用此简单程序进行测试。

**free
ctl-opt dftactgrp(*no) actgrp(*new) BndDir('mybnddir');

dcl-s procPtr       Pointer(*proc);

dcl-pr proc         ExtProc(procPtr);
end-pr;

procPtr = %paddr('MissingProcedure');
proc();
return;

程序无法编译。它在绑定步骤中失败,因为找不到MissingProcedure。期望接收回调作为参数的API,但是即使不知道回调是什么或回调是否存在也能够编译,因为它仅绑定到程序内部已经存在的过程指针本身。

因此,RPG不提供任何工具来在运行时动态地绑定过程,但是IBM i确实提供了系统API,我们可以使用它们来手动解析服务程序中的过程。这就是我上面提到的Alan Campin的例子。因此,从技术上讲,是的,我们可以动态绑定到服务程序中的过程,但是RPG不提供这样做的便利。那只会在编译时发生。

答案 1 :(得分:2)

%paddr的参数名称必须是常量,正如Charles和Mark所说的那样。

最简单的方法是创建一个过程指针数组。

这里有个例子:

**FREE

ctl-opt main(main) dftactgrp(*no) actgrp(*caller);


dcl-c UPPER 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
dcl-c LOWER 'abcdefghijklmnopqrstuvwxyz';


dcl-proc main;
  dcl-pi *n;
    index char(1) const;
  end-pi;

  dcl-s line char(50);
  dcl-s procedureName char(256);
  dcl-s transformPtr pointer(*proc);

  dcl-pr transform char(50) extproc(transformPtr);
    input char(50) const;
  end-pr;

  dcl-s procedures pointer(*proc) dim(2);
  procedures(1) = %paddr('TOLOWER');
  procedures(2) = %paddr('TOUPPER');

  transformPtr = procedures(%int(index));

  line = 'Hello, world. =)';
  line = transform(line);
  dsply line;
end-proc;


dcl-proc toUpper;
  dcl-pi *n char(50);
    input char(50) const;
  end-pi;

  return %xlate(UPPER : LOWER : input);
end-proc;


dcl-proc toLower;
  dcl-pi *n char(50);
    input char(50) const;
  end-pi;

  return %xlate(LOWER : UPPER : input);
end-proc;