Q: How can I read an exported variable into a ILE CL program? I know how to do it with RPG by using the IMPORT keyword, but I can't find a way to do the same thing from CL.
A: I'll show you how, but I personally dislike using exported variables. I'd much prefer to see you call a "getter" procedure to retrieve values from another ILE language. I feel that using global variables makes maintaining your application more difficult because you have no control over how the exported variables might be used. However, we all have to work in environments in which we don't make the rules, and we have no choice but to try to import a variable.
Fortunately, even though CL lacks an IMPORT type keyword, it can call the Get Export Long (QleGetExpLong) API, which can return a pointer to where the exported data sits in memory. Because CL supports pointers (as of V5R4), you can exploit this support to retrieve the export data.
For the sake of a really simple example, suppose you have an RPG service program named ExportVar that looks like this:
h nomain
* This is a trivial service program that exports a variable
* to the activation group.
* Scott Klement June 26, 2008
*
* To Compile:
*> crtrpgmod ExportVar dbgview(*list)
*> crtsrvpgm ExportVar export(*all)
D TestVar s 50a export
D InitVar pr
P InitVar b export
D InitVar pi
/free
TestVar = 'Tinky Winky, Dipsy, Laa-Laa, Po';
return;
/end-free
P e
The goal is to call the InitVar subprocedure to initialize the exported variable named TESTVAR, and then import that TESTVAR variable so it's visible to the CL program.
To do that, my CL program calls the QleGetExpLong API to get a pointer to the TESTVAR exported by the RPG program and then uses the V5R4 pointer support to retrieve the value of the variable.
/* Demonstration of reading and changing an exported variable */
/* from an ILE CL program. */
/* Scott Klement, June 26, 2008 */
/* */
/* NOTE: Because this is ILE CL, the source member type should */
/* be CLLE (not CLP). */
/* */
/* To Compile: */
/*> CRTCLMOD READVAR DBGVIEW(*LIST) <*/
/*> CRTPGM READVAR BNDSRVPGM(EXPORTVAR) <*/
PGM
dcl var(&varlen) type(*int)
dcl var(&varname) type(*char) len(50)
dcl var(&varptr) type(*ptr)
dcl var(&testvar) type(*char) len(50) +
stg(*based) basptr(&varptr)
/* Initialize RPG module -- this causes it to +
set the value of TESTVAR */
callprc prc(InitVar)
/* Use the QleGetExpLong() API to get a pointer +
to the exported value */
chgvar var(&varname) value('TESTVAR')
chgvar var(&varlen) value(7)
callprc prc('QleGetExpLong') +
parm(*omit +
*omit +
&varlen +
&varname +
&varptr +
*omit +
*omit )
sndpgmmsg msgid(cpf9897) msgf(qcpfmsg) msgtype(*comp) +
msgdta('The RPG is exporting: ' *CAT &TESTVAR)
ENDPGM