内部过程的动态调用

Dynamic call of internal procedure

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

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

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

这是因为过程是由编译器静态绑定的。所以编译器需要在编译时知道要调用什么过程。但是,有一些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 不提供这样做的功能。这只发生在编译时。

%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;