Getting Started with APIs from RPG - MITEC

24
Your partner in AS/400 and iSeries Education Susan Gantner [email protected] www.Partner400.com Getting Started with APIs from RPG The author, Susan Gantner, is co-founder of Partner400, a firm specializing in customized education and mentoring services for AS/400 and iSeries developers. After a 15 year career with IBM, including several years at the Rochester and Toronto laboratories, Susan is now devoted to educating developers on techniques and technologies to extend and modernize their applications and development environments. This is done via on-site custom classes for individual companies as well as conferences and user group events. Together with her partner, Jon Paris, Susan authors regular technical articles for the IBM publication, IBM Systems Magazine, i5 edition (formerly iSeries Magazine and eServer Magazine, iSeries edition), and the companion electronic newsletter, i5 EXTRA (formerly iSeries Extra). You may view articles in current and past issues and/or subscribe to the free newsletter or the magazine at: http://www.ibmsystemsmag.com/i5/ . Feel free to contact the author at: susan.gantner @ partner400.com or visit the Partner400 web site at http://www.partner400.com . This presentation may contain small code examples that are furnished as simple examples to provide an illustration. These examples have not been thoroughly tested under all conditions. We therefore, cannot guarantee or imply reliability, serviceability, or function of these programs. All code examples contained herein are provided to you "as is". THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. © Copyright Partner400, 2006. APIs from RPG - Page: 1-2

Transcript of Getting Started with APIs from RPG - MITEC

Your partner in AS/400 and iSeries Education

Getting Started with System APIs from RPG

Session A58

Susan [email protected]

Getting Started with APIsfrom RPG

The author, Susan Gantner, is co-founder of Partner400, a firm specializing in customized education and mentoring services for AS/400 and iSeries developers. After a 15 year career with IBM, including several years at the Rochester and Toronto laboratories, Susan is now devoted to educating developers on techniques and technologies to extend and modernize their applications and development environments. This is done via on-site custom classes for individual companies as well as conferences and user group events.

Together with her partner, Jon Paris, Susan authors regular technical articles for the IBM publication, IBM Systems Magazine, i5 edition (formerly iSeries Magazine and eServer Magazine, iSeries edition), and the companion electronic newsletter, i5 EXTRA (formerly iSeries Extra). You may view articles in current and past issues and/or subscribe to the free newsletter or the magazine at: http://www.ibmsystemsmag.com/i5/.

Feel free to contact the author at: susan.gantner @ partner400.com or visit the Partner400 web site at http://www.partner400.com.

This presentation may contain small code examples that are furnished as simple examples to provide an illustration. These examples have not been thoroughly tested under all conditions. We therefore, cannot guarantee or imply reliability, serviceability, or function of these programs.

All code examples contained herein are provided to you "as is". THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED.

© Copyright Partner400, 2006. APIs from RPG - Page: 1-2

Using System APIsThere are hundreds of System APIs

From simple APIs you may already usee.g., QCMDEXC

to more complex APIs to provide lists of information from the systemThink of "Work With ..." commands

Lists of objects, spooled files, members, user profiles, jobs, programs, modules in programs, etc.

APIs provide interfaces to system functions and system information

Documented in the IBM iSeries Information Centerhttp://publib.boulder.ibm.com/iseries/

Choose your OS releaseThen in the left hand pane

Expand the iSeries Information Center, Version 5 Release xExpand the "Programming" topicExpand "APIs" - usually the first entry in the list

List Type APIs require some detailed knowledge of using User Spaces, Pointers and the structure of List API data. We will be discussing that here. Many of the other types of APIs are simpler.

© Copyright Partner400, 2006. APIs from RPG - Page: 3-4

Finding APIsThree ways in Info Center's "API Finder"

By Category Best if you don't know the name of the APISometimes difficult to figure out the right category, however

By NameFull or partial nameEither the actual program or procedure name or the text name or titleTo get a list of APIs related to User Spaces

either "QUS" because the program names begin with that or"User Space" because the API name or title includes it

From an alphabetic list of all APIsWhen all else fails!

A non-Info Center approachOften a Google keyword search specifying site:ibm.com provides a faster way to get to the IBM documentation for a specific API

May not be the release you want on the first hitBut once you have the name, then you can use the API finder easily

Sometimes, finding the API you need can be the toughest part of the task!

If the IBM Information Center doesn't work for you, try Google with site:ibm.com to limit the search to IBM web pages.

© Copyright Partner400, 2006. APIs from RPG - Page: 5-6

Prototyping APIsPrototyping APIs provides many advantages

compared to CALL ... PARM, PARM, PARM...or to CALLB ... PARM, PARM, PARM

Use a more meaningful name for the API calledThe function of the API is often not intuitive from its name

Proto options that are useful (sometimes required) with APIsIncluding options that:

Allow for variable size parameters - Options(*VarSize) Allow for Optional parameters - Options(*NoPass)Allow for Omissible parameters - Options(*Omit)Allow the compiler to accept literal values, BIFs or values that are not exactly the right data type or size - CONST

We'll have a quick review of prototyping basics by looking at a prototype for QCMDEXC

But first, a look at the API documentation for QCMDEXC

The option *NOPASS means that the parameter does not have to be passed on the call. Any parameters following that spec must also have *NOPASS specified. When the parameter is not passed to a program or procedure, the called program or procedure will simply function as if the parameter list did not include that parameter.

The option *OMIT can be used for parameters which are not mandatory but which occur in the middle of a parameter sequence and therefore cannot be designated as *NOPASS. When the option is specified the special value *OMIT is allowed for that parameter on the call

Option *VARSIZE gives the compiler permission to accept a character parameter that is shorter in length than the prototype specifies. This option is often used when the length of the passed field is also passed to the called program, such as in our QCMDEXC example coming up

The use of the CONST keyword allows the compiler to accommodate mismatches in the definition of the parameters between the callee and the caller. For example, if the API we are calling expects a packed decimal value of 15 digits with 5 decimal places, we can pass a zoned decimal number of 3 digits and no decimal places if we prefer or a constant numeric value or a numeric expression..

Using the CONST keyword, you are telling the compiler that it is OK for it to make a copy of the data prior to passing it to accommodate such mismatches. This avoids the need for us to explicitly define a working variable of the correct size and type.

The compiler can accommodate differences in:Size, decimal places, and type (zoned, packed, integer, etc.) - for Numeric fields The date format - for Date fields and Length and type (fixed or varying) - for Character fields

The CONST keyword can be used for all API parameters documented as "Input" (see API documentation example in a later chart.)

© Copyright Partner400, 2006. APIs from RPG - Page: 7-8

Execute Command (QCMDEXC) API

Required Parameter Group:

1 Command string Input Char(*) 2 Length of command string Input Packed (15,5)

Optional Parameter:

3 IGC process control INPUT Char(3)

Example: API Parameter Documentation

Here is an example of part of the API documentation from the iSeries Information Center for one of the APIs you have probably used before: QCMDEXC to execute a command from an RPG program.

Note that the last parameter is marked as "Optional". In this case, it controls the use of double byte character sets, which are rarely used except in some Asian languages.

© Copyright Partner400, 2006. APIs from RPG - Page: 9-10

A Simple API: QCMDEXC

Rather than call QCMDEXC via CALL ... PARM, PARM This Prototype allows you to:

Use a more meaningful name - OvrDBFileUse a Variable size parameter - Options(*VarSize) Avoid having to move values to pre-defined 15,5 fields - ConstHave Optional parameters - Options(*NoPass)

D CusMastOvr S 40 Inz('OVRDBF FILE(CustMast) + D TOFILE(NEWCUST)')

D OvrDBFile PR ExtPgm('QCMDEXC')

D CmdString 3000 Options(*VarSize) Const D CmdLength 15P 5 Const D CmdOpt 3 Options(*NoPass) Const

C CallP OvrDBFile(CusMastOvr: %Len(CusMastOvr))

C CallP OvrDBFile('OVRDBF FILE(' + FileName + C ') TOFILE(' + NameToUse + ')' : 41)

This example of a prototype for QCMDEXC demonstrates a number of the benefits of prototyping.

- First it allows us to use a name indicative of the function performed - in this case OvrDBFile. We used the EXTPGM keyword to supply the "correct" name. Note: if the API you are calling is a bound API, you would need to use the EXTPROC keyword instead.

- Second by using Options(*VarSize) we have made it possible to pass the 40 character parameter CusMastOvr when the prototype specifies that the length should be 3,000 characters long. That's 2,940 bytes saved!

- Third we don't have to create a 15,5 work field just so that we can pass an integer length!Has that ever struck you as being rather odd? Why would a length ever need any decimal positions, much less 5 of them!CONST can be used on any API parameters defined as "Input" (see documentation chart earlier)

- Lastly we can safely leave out the third parameter You did know that QCMDEXC has three parameters didn't you?If you didn't, don't feel bad - the third one is only used for DBCS (Double Byte Character Set) support.

© Copyright Partner400, 2006. APIs from RPG - Page: 11-12

Create User Space (QUSCRTUS) API Required Parameter Group: 1 Qualified user space name Input Char(20) 2 Extended attribute Input Char(10) 3 Initial size Input Binary(4) 4 Initial value Input Char(1) 5 Public authority Input Char(10) 6 Text description Input Char(50)

Optional Parameter Group 1: 7 Replace Input Char(10) 8 Error code I/O Char(*)

Example: API Parameter Documentation

Here is an example of the API documentation from the iSeries Information Center for another one of the APIs we will be using - Create User Space.

We will talk about these data types and how to define them in RPG in upcoming charts.

Note also the use of Optional Parameters. We will discuss the impact of these on our RPG programs in upcoming charts as well.

© Copyright Partner400, 2006. APIs from RPG - Page: 13-14

Interpreting API DocumentationTranslation of API documentation into RPG prototypes can be confusing

Data types often seem foreign

Some of the more common data types used in APIs include:

Note: "n" means any number of charactersChar(*) fields are typically defined with the prototype keyword Options(*Varsize) to allow for different lengths

API Documentation

EnglishDescription

RPGDefinition

Binary(4) 4 byte integer 10 I 0Binary(2) 2 byte integer 5 I 0Char(n) n byte Character field n AChar(*) Character field of indeterminate length n APTR(SPP) Pointer *

One of the first things that seem to be mysterious about APIs to RPGers are the data types.

Note the use of the I (integer) data type compared with the B (binary) data type. While many programmers (including those who write many of the examples in the IBM manuals and the includes in QSYSINC) still use the B type, it is better to use I (or U for unsigned integers). I supports the full range of possible values (which B cannot) and it also performs much better.

If the API specifies an unsigned binary parameter, use type U instead of I. The length of the I or U field should be 10 for 4 byte fields or 5 for 2 byte fields. (Note: RPG also supports other length Integer fields, but they are rarely used in APIs.)

Unfortunately many published examples (including most from IBM) continue to use the old fashioned type B data. Don't follow that lead - use the I or U data types.

© Copyright Partner400, 2006. APIs from RPG - Page: 15-16

APIs use 3 Parameter Types: Required: All of the parameters must be used in the specified orderOptional: All or none of the parameters within the optional group

You must either include or exclude the entire groupYou must include all preceding parametersOptional Parameters may (should) be specified with prototype parameter keyword Options(*Nopass)

Omissible: The parameters will accept a null pointer in place of a valueOmissible Parameters may (should) be specified with prototype parameter keyword Options(*Omit) AND a special value of *Omit must be passed

Parameter Types for APIs

D CrtUsrSpc Pr ExtPgm('QUSCRTUS')D SpaceQname 20a ConstD SpaceAttr 10a ConstD SpaceSize 10i 0 ConstD SpaceInit 1a ConstD SpaceAuth 10a ConstD SpaceText 50a ConstD Replace 10 Const Options(*NoPass)D ErrorFeedbk Like(ErrorInfo) D Options(*NoPass:*Varsize)

Most, if not all, APIs have Required parameters. Many also have Optional Parameters. Omissible parameters are fairly rare among APIs.

The prototype on this chart uses many of the features we have discussed on the last few charts, such as optional parameters and Binary(4) or Integer data types.

© Copyright Partner400, 2006. APIs from RPG - Page: 17-18

User SpacesWhat is a User Space?

Contrary to popular belief, it's not what you find between a user's ears

It is:An iSeries object of type *USRSPCA simple stream of bytes that you can access directly from within a programAnything the programmer wants it to be!

"List Type" APIs use User Spaces The API dumps a variable length list of items into the User SpaceYour program retrieves the list from the User Space

The most efficient way to process the data in a User Space is by using one or more pointers

Mapping the User Space to one or more Data Structures using the Based keyword

The nearest that traditional programming can come to this concept is a data area, but you have to input and output data areas to and from programs.

In contrast, you can immediately change the content of a User Space by merely changing the value of a field in your program.

User Spaces have a fixed length and can be extended or truncated using the Change User Space Attributes (QUSCUSAT) API. This API also allows you to allow the User Space to automatically extend its size if necessary, much as physical files are set up by default.

© Copyright Partner400, 2006. APIs from RPG - Page: 19-20

List Database File Members (QUSLMBR)List Database Relations (QDBLDBR)List Fields (QUSLFLD)List ILE Program Information (QBNLPGMI)List Job (QUSLJOB)List Job Log Messages (QMHLJOBL)List Module Information (QBNLMODI)List Object Locks (QWCLOBJL)List Objects (QUSLOBJ)List Objects That Adopt Owner Authority (QSYLOBJP)List Objects User Is Authorized to or Owns (QSYLOBJA)List Open Files (QDMLOPNF)List Program Temporary Fixes (QpzListPTF)List Record Formats (QUSLRCD)List Save File (QSRLSAVF)List Server Information (QZLSLSTI)List Service Program Information (QBNLSPGM)List Signed-On Users (QEZLSGNU)List Spooled Files (QUSLSPL)List Users Authorized to Object (QSYLUSRA)

A Few Examples of List Type APIs

There are many additional List APIs available as well.

© Copyright Partner400, 2006. APIs from RPG - Page: 21-22

List Item 1

List Item 2

. . . .

. . . .

Last List Item

General Information . . .

Offset to List Data Section

List data Section Total Size

Number of Items in the List

Length of Each List Item format

More General Information . . .

Layout of Data in the User Space

ListItems DS

HeaderInfo DS

This chart depicts how the List APIs interact with the User space. The List of Items is depicted by the box on the right. But the API puts out some Header information in the User Space as well to let you know interesting things such as the number of entries in the list, the size of each entry and where in the user space the first entry in the list is located.

© Copyright Partner400, 2006. APIs from RPG - Page: 23-24

Using Pointers

Pointers have a data type of '*' and you don't define a lengthThey actually use 16 bytes of storage

Pointers are used to Base the storage of data in the program

You need a value in the basing pointer before referencing the based data

It can be set using the %Addr BIF or you can get the value from a called program, procedure or APIIn our example, we will be getting a value from an API

D HeaderInfo DS Based(pHeaderInfo)D 103AD ListStatus 1AD 20AD ListOffset 10I 0D ListSize 10I 0D NbrEntries 10I 0D EntryLen 10I 0

You don't actually have to define Pointers. If the compiler comes across a pointer in a Based keyword, it will automatically define it for you - so watch the spelling! In the example on the page above we do not need to explicitly defind pHeaderInfo. The compiler will implicitly create it for us.

Pointers are always 16 bytes in length and must be aligned on a 16 byte boundary. Therefore, definition of pointers in data structures may require the compiler to generate filler space. When defining pointers in data structures, refer to chapter 7 of the ILE RPG/400 Reference for more details on this phenomenon. In particular check out the ALIGN keyword.

In our case, the address value for the pointer will come from the call to an API to get a pointer to the user space.

© Copyright Partner400, 2006. APIs from RPG - Page: 25-26

User Space APIs

Working with User Spaces involves two APIs: Create User Space (QUSCRTUS)Retrieve Pointer to User Space (QUSPTRUS)

The pointer retrieved is used to set the basing pointer of the field or DS

D CrtUsrSpc Pr ExtPgm('QUSCRTUS')D SpaceQname 20a ConstD SpaceAttr 10a ConstD SpaceSize 10i 0 ConstD SpaceInit 1a ConstD SpaceAuth 10a ConstD SpaceText 50a ConstD Replace 10 Const Options(*NoPass)D ErrorFeedbk Like(ErrorInfo) Options(*NoPass)

D Ptr2UsrSpc Pr ExtPgm('QUSPTRUS')D UsrSpcName 20 ConstD PtrToUsrSpc *D ErrorFeedbk Like(ErrorInfo)

You must use APIs to create User Spaces and manipulate their contents unless you have a program and/or command someone has created for you to do it. Some shops have a command to create a user space from the tools package in QUSRTOOLS that was once part of OS/400.

The only OS/400 user space CL command you will find is the Delete User Space (DLTUSRSPC) command.

Consider writing prototypes for all the User Space APIs so they can be easily accessed from RPG programs when needed. In many cases it will be preferable to "wrapper" them with a simple RPG subprocedure. This means that only one person needs to really understand the APIs. The others in the shop can use a simplified method to access the API. This also allows for an update to the error handling process, switching to a new improved API, etc. etc. all without changes to the "using" program.

The documentation for the Pointer to User Space API looks like this:

Retrieve Pointer to User Space (QUSPTRUS) API

Required Parameter Group:

1 Qualified user space name Input Char(20)2 Return pointer Output PTR(SPP)

Optional Parameter:

3 Error code I/O Char(*)

© Copyright Partner400, 2006. APIs from RPG - Page: 27-28

D HeaderInfo DS Based(pHeaderInfo)D 103AD ListStatus 1AD 20AD ListOffset 10I 0D ListSize 10I 0D NbrEntries 10I 0D EntryLen 10I 0

C CallP CrtUsrSpc ('MODULEINFOQTEMP' :C 'DTA' : 10000 : '*' : '*ALL' :C 'ILE Program Info': '*YES' : ErrorInfo)

C CallP Ptr2UsrSpc ('MODULEINFOQTEMP': pHeaderInfo:C ErrorInfo )

Create & Get Access to a User Space

This code creates a User Space and gets access to it via the pHeaderInfo pointer

Note that this is the basing pointer for our Data StructureThis code exerpt uses the prototypes from the previous chartAfter this code runs, the Data Structure is located in the User Space

In this example, we are simply creating a User Space object by calling the CrtUsrSpc prototype (which corresponds to the QUSCRTUS API - see the prototype in the D specs on the previous chart).

Then we get access to the User Space by getting an address using the Ptr2UsrSpc prototype (QUSPRTUS API). Note that the address obtained is placed into the basing pointer for the DS.

© Copyright Partner400, 2006. APIs from RPG - Page: 29-30

Example of a "List Type" APITo illustrate using list APIs, we will look at QBNLPGMI

List module information for ILE programsThere are several formats of data available

Think of a format as analogous to a record formatWe are using only one format: PGML0100

The layout for each format is documented in the API manual(s)Our program will create a module cross-reference database file for all the ILE programs in a libraryTo shorten the code, our example assumes the User Space already exists

List APIs place data into a user spaceData begins with the Header Block of information

It contains the status of the list, the number of entries retrieved, length of each entry, offset to the beginning of the first entry, etc.Using this information, your program can set a pointer to the first entryAfter processing an entry, increment pointer by the length of the entry to advance to the next one

The following pages show a coded example of using the List ILE Program API.

Our sample program simply writes the module information to a DB file to provide a module cross-reference database file.

Note that we pass a parameter to the program which is the name of the library for which we want to capture module information. Special values such as *ALLUSER, *LIBL, etc. are allowed as well as a specific library name. Of course, with a bit of extra logic, we could have allowed multiple library names, etc. The program collects data for all the modules for all the ILE programs in the requested library or libraries.

We are collecting a subset of the data available in the API format in our sample program. The field names in the externally described DB file match the field names in the ListItems data structure. Therefore, after setting the pointer for each entry, we simply need to write the data base record.

© Copyright Partner400, 2006. APIs from RPG - Page: 31-32

D ListPgmInf PR ExtPgm('QBNLPGMI') D UsrSpcNam 20A Const D Format 8A Const D QualPgmName 20A Const D ErrorFeedbk Like(ErrorInfo)

The API documentation for QBNLPGMI is included below:

Prototyping QBNLPGMI

List ILE Program Information (QBNLPGMI) API

Required Parameter Group:

1 Qualified user space name Input Char(20) 2 Format name Input Char(8) 3 Qualified ILE program name Input Char(20) 4 Error Code I/O Char(*)

The API documenation for the parameters for QBNLPGMI and the RPG translation for those parameters are shown here.

On the following pages, we will see this prototype in use, along with the User Space API prototypes.

© Copyright Partner400, 2006. APIs from RPG - Page: 33-34

Documentation for Format PGML0100

Offset Dec

OffsetHex Type Field

0 0 CHAR(10) Program name

10 A CHAR(10) Program library name

20 14 CHAR(10) Bound module name

30 1E CHAR(10) Bound module library name

40 28 CHAR(10) Source file name

50 32 CHAR(10) Source file library name

60 3C CHAR(10) Source file member name

70 46 CHAR(10) Module attribute

80 50 CHAR(13) Module creation date and time

93 5D CHAR(13) Source file updated date and time

106 6A CHAR(10) Sort sequence table name

116 74 CHAR(10) Sort sequence table library name

126 7E CHAR(10) Language identifier

136 88 BINARY(4) Optimization level

A subset of the API documenation for the information in the format we're going to use with the QBNLPGMI is shown here. Format PGML0100 contains much more data than is shown here. We're just providing a glimpse at what the format documentation looks like.

In addition to defining more information that is available via PGML0100 format, there are 5 other different formats of information available from this API. We could decide to retrieve other information from the other formats if we wanted to.

© Copyright Partner400, 2006. APIs from RPG - Page: 35-36

Module Cross-Reference

* Copyright Partner400, 2001-2006. * Sample code only -- no warranties expressed or implied

FXrefModuleO E DISK

D Ptr2UsrSpc PR ExtPgm('QUSPTRUS') D UsrSpcName 20 Const D PtrToUsrSpc * D ErrorFeedbk Like(ErrorInfo)

D ListPgmInf PR ExtPgm('QBNLPGMI') D UsrSpcNam 20A Const D Format 8A Const D QualPgmName 20A Const D ErrorFeedbk Like(ErrorInfo)

D QualPgmName DS D Program 10A Inz('*ALL') D Library 10A

D ErrorInfo DS * Definition of the ErrorInfo DS will be shown in a later chart

D LibName S 10A D I S 10I 0

Here you see the prototypes for the necessary system APIs to build the module cross-reference file. API QBNLPGMI is the "Get ILE Program information" API.

We are assuming here that the User Space object has already been created. We are simply filling it (or re-filling it for update purposes).

The ErrorInfo data structure is a standard error feedback mechanism that is used by most of the list type APIs. For space reasons on this chart, it is not shown here, but we will see it in detail on a later chart.

© Copyright Partner400, 2006. APIs from RPG - Page: 37-38

Module Cross-Reference (Cont.)

As noted in the source, we are only using some of the fields available in format PGML0100

See the API documentation for details of other fields available

D HeaderInfo DS Based(pHeaderInfo)D 103AD ListStatus 1AD 20AD ListOffset 10I 0D ListSize 10I 0D NbrEntries 10I 0D EntryLen 10I 0

* More fields are available in this format, but not used hereD ListItems DS Based(pListItems)D Pgm 10AD PgmLib 10AD Mod 10AD ModLib 10AD Srcf 10AD SrcLib 10AD SrcMbr 10A

The API writes information to the User Space in 2 distinct pieces: The header information, followed by multiple entries - in this example one entry represents details for a module in an ILE program.

Note that we have left several bytes in the header DS unnamed because we didn't need the information the API puts in those locations. For our program's purposes, the most important entries in the Header Information that the API puts into the user space are:

The list status which will hopefully contain a "C" (for complete), which means the list of program information is both complete and correct. If it contains a "P" (for partial), it means the list information is accurate, but is not complete - probably because the user space wasn't large enough to hold the information. If it contains "I" (for incomplete), the information in the user space should NOT be used because it is not accurate - probably because of some error that occurred while creating the list.

The offset to the first "real" entry in the list of program information. That is, this is the beginning of the first entry for the first module in the first program in the library we requested information about. The information in each entry is outlined in the second DS, called ListItems. Note that we have only included the first few items from the format. More info is available to us, but we selected to pay attention and collect only this information.

The number of entries in the API wrote to the User Space for us. This will tell us how many entries to process in our RPG logic.

The length of each entry in the list. This will help us to move our pointer from one entry to the next.

© Copyright Partner400, 2006. APIs from RPG - Page: 39-40

Module Cross-Reference (Cont.)

C *Entry PlistC Parm Library

* Get pointer to user space (assume user space already exists)C CallP Ptr2UsrSpc ('MODULEINFOQTEMP': pHeaderInfo:C ErrorInfo ) * Populate User Space with *PGM Module Info with API QBNLPGMI

C CallP ListPgmInf ('MODULEINFOQTEMP': 'PGML0100':C QualPgmName: ErrorInfo )

* Position pListItems pointer to first entry in User Space * using ListOffset from Header information

C Eval pListItems = pHeaderInfo + ListOffset

The name of the library to be analyzed is passed in as a parameterQUSPTRUS is used to obtain a pointer to an existing User SpaceQBNLPGMI is then used to fill that space with module informationThe List Offset value from the fixed portion of the data returned is used to set the basing pointer pListItems to the first entry in the list

In this example, for simplicity, we assume the User Space already exists. We just need to get a pointer to it by calling the API QUSPTRUS. We could use the QUSCRTUS API (prototype for it was included earlier) to create one if it did not exist.

Next we need to ask the API to dump information into the User Space for the programs we're interested in. The programs we want were passed to us as input parameters.

Then, using the List Offset value from the Header information in the User Space, we set the pointer to the Data Structure for the first entry in the list.

© Copyright Partner400, 2006. APIs from RPG - Page: 41-42

Module Cross-Reference (Cont.)Relevant data from entry in the User Space is written to the databaseThe basing pointer is then updated to point to the next entryAnd we loop back to process the next entry until all are processed

* Process each entry in list in user space and write info to DB file

C Eval I = 1

C DoW I <= NbrEntries

C Write MODXREFR

* Increment to next entry by adding Entry Length (from Header Info)

C Eval pListItems = pListItems + EntryLen

C Eval I = I + 1

C EndDo

C Eval *INLR = *ON

The logic to retrieve the information from the User Space is fairly simple, straightforward RPG logic.

In this case, we manipulate the pointer directly to get from one "entry" in the list to the next by adding the entry length of each entry (retrieved from the Header info) to the current address of the pointer.

Alternatively, we could have padded the ListItems Data Structure out to the maximum length and made it either a Multiple Occurrence Data Structure or a Data Structure array. In that case, we wouldn't need to add the length to the pointer as we did here. We would use either Occur or an array index value to move from one to the other. The potential danger in using this technique is that the API information could change over time - typically adding new information to the end of each list entry. So if you want to use this technique, it would be a good idea to have the program logic compare the EntryLength value to the length (preferably using %Len) of the ListItems DS.

© Copyright Partner400, 2006. APIs from RPG - Page: 43-44

Handling API Errors

// Standard API Error Structure D ErrorInfo DS D BytesAv 10U 0 Inz(%Size(ErrorInfo)) D BytesUsed 10U 0 D ExpID 7A D Reserved 1A D ExcData 80A

// Try to obtain pointer to User Space CallP Ptr2UsrSpc ('MODULEINFOQTEMP': pHeaderInfo: ErrorInfo );

If BytesUsed <> 0; // Error - Assume means not found, so create it CallP CrtUsrSpc ('MODULEINFOQTEMP' :'DTA' : 10000 : '*' : '*ALL' : 'ILE Program Info': '*YES' : ErrorInfo); CallP Ptr2UsrSpc ('MODULEINFOQTEMP': pHeaderInfo: ErrorInfo ); EndIf;

The "Bytes Used" field is set non zero to indicate an errorThe actual exception Id will have been placed in ExpIDThe message text is in ExcData (the first 80 characters in this case)The example below shows how we could have used this

Many system APIs use this same data structure for error feedback. Check the BytesUsed field for > 0 to see if an error occurred. If it did, then we can check the exception ID and/or message text.

We used /Free form in this example because it occupies so much less space, it gives us the ability to get a more complete example on the chart.

Note that if you prefer to just let the system API send an escape message rather than monitor for and handle it yourself, you may just pass a value of 0 (zero) in the first parameter (BytesAv in our example). Replace our Inz(%Size(ErrorInfo)) with Inz(0).

© Copyright Partner400, 2006. APIs from RPG - Page: 45-46

List API ConclusionsThat's it!

List APIs all work using the same techniques we have discussed hereYou simply need to know how to:

Find the right APIRead/interpret the API documentation and translate it into:

RPG prototypes for the APIs, and Data definitions for the list items

Defined a based variable or DS (based on a pointer)Create a User Space object and get access to it via a pointer in your programDefine the generic List API header DS

They all have the same header information and formatManipulate the basing pointer to the List Items

Position to the first entry, then move through the list by adding the entry length each time

Detect errors that may occur when calling APIsVia the error feedback structure and the List Status field in the list API header

And we've covered all thatSo go find the list API you need and you should be able to use it!

Questions ?

That's All Folks!

© Copyright Partner400, 2006. APIs from RPG - Page: 47-48