Find out the rest of the story about the User Application Information APIs.
In the last column, we saw how to use the Update User Application Information API to set default values for a new user of the RPG_DEVELOPER_MY_APPLICATION application. Today, we will look at how to combine the Update API with the Retrieve User Application Information API in order to provide application awareness of past user preferences.
Specifically, we will see how to recall the previous file, library, member, and full-screen mode that was in use by the application user in the most recent use of the Start My Application (STRMYAPP) command. The command processing program (CPP) SMACPP used by STRMYAPP is provided here:
h dftactgrp(*no)
fMyAppFile if f32766 disk usropn
f extfile(MyFile)
f extmbr(ApplInfo.Member)
dSMACPP pr extpgm('SMACPP')
d QualFileName 20
d MbrName 10
dSMACPP pi
d QualFileName 20
d MbrName 10
dRtvUsrInf pr extproc(
d 'QsyRetrieveUserApplicationInfo')
d RcvVar 1 options(*varsize)
d LenRcvVar 10i 0 const
d RtnRcdFdBk likeds(QSYUAIFI)
d Format 8 const
d UsrPrf 10 const
d ApplID 200 const options(*varsize)
d LenApplID 10i 0 const
d QUSEC likeds(QUSEC)
dUpdUsrInf pr extproc(
d 'QsyUpdateUserApplicationInfo')
d UsrPrf 10 const
d ApplID 200 const options(*varsize)
d LenApplID 10i 0 const
d ApplInfo 1700 const options(*varsize)
d LenApplInfo 10i 0 const
d MinVRM 6 const
d QUSEC likeds(QUSEC)
d/copy qsysinc/qrpglesrc,qsyusrin
d/copy qsysinc/qrpglesrc,qusec
dApplInfo ds 100 qualified
d File 10
d Library 10
d Member 10
d FullScreen 1
dRcvVar ds likeds(QSYI010004)
d based(RcvVarPtr)
dRcvVarApplInfo ds likeds(ApplInfo)
d based(RcvVarInfoPtr)
dMyFile s 21
dRcvVarPtr s *
dRcvVarInfoPtr s *
dApplID s 200 inz(
d 'RPG_DEVELOPER_MY_APPLICATION')
dMinVRM s 6 inz('V5R3M0')
dWait s 1
iMyAppFile ns
i 1 6 2SrcSeq
i 7 12 0SrcDat
i 1332766 SrcDta
/free
QUSBPRV = 0;
// Determine if data exists for this user
RtvUsrInf(QSYI010004 :%size(QSYI010004) :QSYUAIFI :'RUAI0100'
:'*CURRENT' :ApplID :%len(%trimr(ApplID)) :QUSEC);
// New User?
if QSYBAVL15 = 0;
ApplInfo.File = 'QRPGLESRC';
ApplInfo.Library = '*LIBL';
ApplInfo.Member = '*FIRST';
ApplInfo.FullScreen = 'N';
else;
RcvVarPtr = %alloc(QSYBAVL15);
RtvUsrInf(RcvVar :QSYBAVL15 :QSYUAIFI :'RUAI0100'
:'*CURRENT' :ApplID :%len(%trimr(ApplID)) :QUSEC);
RcvVarInfoPtr = RcvVarPtr + RcvVar.QSYDAI;
ApplInfo = RcvVarApplInfo;
dealloc RcvVarPtr;
endif;
// The *USRPRF values are now set, time to check for cmd parameters
select;
when QualFileName = '*PRV'; // do nothing
when ((%subst(QualFileName :1 :10) = '*PRV') and
(%subst(QualFileName :11 :10) <> *blanks));
ApplInfo.Library = %subst(QualFileName :11 :10);
other;
ApplInfo.File = %subst(QualFileName :1 :10);
ApplInfo.Library = %subst(QualFileName :11 :10);
endsl;
if MbrName <> '*PRV';
ApplInfo.Member = MbrName;
endif;
// Now open the file and perform normal functions of MyApplication
MyFile = %trimr(ApplInfo.Library) + '/' + ApplInfo.File;
monitor;
open MyAppFile;
on-error;
dsply ('File ' + %trimr(MyFile) + '.' +
%trimr(ApplInfo.Member) + ' not found');
*inlr = *on;
return;
endmon;
read MyAppFile;
if not %eof(MyAppFile);
dsply %subst(SrcDta :1 :50);
else;
dsply 'Empty file';
endif;
// If the user changes the 'Full Screen Mode', reflect that change
// in ApplInfo.FullScreen so that the most recent setting is saved
// at exit from MyApplication
// When exiting close the file
close MyAppFile;
// When exiting under normal conditions update the *USRPRF
// application information with the most recent settings.
// When exiting under an error condition you may or may not want
// to save these setting -- your call
UpdUsrInf('*CURRENT' :ApplID :%len(%trimr(ApplID))
:ApplInfo :%size(ApplInfo) :MinVRM :QUSEC);
*inlr = *on;
return;
/end-free
The sample application opens a source file member, displays the first 50 source data bytes of the first record found in the member, and then ends. If the member is not found, a message similar to "File VINING/QRPGLESRC.NOTHERE not found" is displayed. If the member exists but contains no records, the message "Empty file" is displayed. This is not an overly robust application but does serve the purpose of demonstrating the use of the User Application APIs.
Following the logical flow of the program, rather than the physical sequence of RPG specifications, SMACPP accepts two parameters from the STRMYAPP command. The first parameter, QualFileName, is the qualified file name of the file to be opened. It is defined as a 20-byte character field where the first 10 bytes are the file name and the second 10 bytes are the library name. The second parameter, MbrName, is the 10-byte member name to be opened from QualFileName.
Moving to the calculation specifications, SMACPP first sets Bytes provided of the error code structure, QUSBPRV, to 0 so that any API detected errors are returned as escape messages. SMACPP then calls the Retrieve User Application Information (QsyRetrieveUserApplicationInfo) API. This API is documented here.
The API defines eight parameters.
The first parameter, Receiver_variable, is where the API will return information related to the user profile later identified by the fifth parameter, User_profile, and the application identified by the sixth parameter, Application_information_ID.
The second parameter, Length_of_receiver_variable, is the length in bytes of the provided Receiver_variable (the first parameter).
The third parameter, Return_records_feedback_information, is a fixed-size 12-byte structure returned by the API. It provides information about the entries returned in the first parameter, Receiver_variable. This is the definition of this structure:
Offset |
Type |
Field |
|
Dec |
Hex |
||
0 |
0 |
BINARY(4) |
Bytes returned |
4 |
4 |
BINARY(4) |
Bytes available |
8 |
8 |
BINARY(4) |
Number of user application information entries |
The QSYSINC-provided structure for this parameter, found in QRPGLESRC.QSYUSRIN, is this:
D*****************************************************************
D*Record structure for Return Records Feedback Information
D*****************************************************************
DQSYUAIFI DS
D* Qsy RUAI Feedback Info
D QSYBRTN15 1 4B 0
D* Bytes Returned
D QSYBAVL15 5 8B 0
D* Bytes Available
D QSYNBRER04 9 12B 0
D*
Number Entries Returned
The first field, Bytes returned (or QSYBRTN15), indicates how many bytes of application-related information were returned in the Receiver_variable. The second field, Bytes available (or QSYBAVL15), indicates how many bytes of application-related information could have been returned in the Receiver_variable. If this field, QSYBAVL15, is set to 0 on return from the API, then no entry was found for the specified user profile and application ID. In other words, the user has not previously used the application, and default values should be used. The third field, Number of user application information entries (or QSYNBRER04), indicates how many complete entries were returned in the Receiver_variable.
The fourth parameter, Format_name, specifies the format that is to be used for returning information in the Receiver_variable. The only format currently supported is RUAI0100, which is defined this way:
Offset |
Type |
Field |
|
Dec |
Hex |
||
0 |
0 |
BINARY(4) |
Length of entry |
4 |
4 |
CHAR(200) |
Application information ID |
204 |
CC |
BINARY(4) |
Displacement to user application information |
208 |
D0 |
BINARY(4) |
Length of user application information |
212 |
D4 |
BINARY(4) |
CCSID of user application information |
216 |
D8 |
CHAR(6) |
First valid release |
CHAR(*) |
User application information |
This is the QSYSINC-provided structure for this format:
D*****************************************************************
D*Record structure for RUAI0100 format
D*****************************************************************
DQSYI010004 DS
D* Qsy RUAI0100
D QSYEL10 1 4B 0
D* Entry Length
D QSYAIID 5 204
D* Application Info ID
D QSYDAI 205 208B 0
D* Displacement Application Inf
D QSYLAI 209 212B 0
D* Length Application Info
D QSYIDOAI 213 216B 0
D* CCSID of Application Info
D QSYFVR 217 222
D* First Valid Release
D*QSYAI00 223 223
D*
D* Varying length
The first field, Length of entry (or QSYEL10), is the length in bytes for the current entry being processed. You may recall from the previous article that the Update User Application Information API can only support an application information entry of up to 1700 bytes. You can, however, have multiple of these entries, so your application does not need to be constrained to retaining only 1700 bytes of application-related information per user. This field allows you to step through each entry by using the length of the current entry, which is essentially a displacement to the next entry.
The second field, Application information ID (or QSYAIID), is the 200-byte application identifier for the current entry. It is by using a generic application information ID that you can retrieve multiple entries with one call to the Retrieve API.
The third field, Displacement to user application information (or QSYDAI), is the byte offset from the start of the current entry to the application-related data returned for this entry.
The fourth field, Length of user application information (or QSYLAI), is the number of bytes returned for the application-related data associated with this entry.
The fifth field, CCSID of user application information (or QSYIDOAI), reflects the job default CCSID that was in use when the Update User Application Information API was used to store the application-related data that is being returned for this entry.
The sixth field, First valid release (or QSYFVR), is the first release level supported by this application entry.
The seventh field, User application information (or QSYAI00), is a commented field that reflects that a variable amount of application-related data will be returned at a variable location in the Receiver variable. The actual location and length are provided to you by the fields QSYDAI and QSYLAI, respectively.
The next four parameters, User_profile through Error_code, are used in the same manner as they were for the Update User Application Information API introduced in the previous article.
So returning to the program flow of SMACPP, the program calls the Retrieve User Application Information API requesting that only minimal information be returned (the %size(QSYI010004) value for the second parameter leaves no room for actual application-related information entries) using format RUAI0100 for the *CURRENT user of application RPG_DEVELOPER_MY_APPLICATION.
SMACPP then examines the value of QSYBAVL15: the number of bytes that are available to be returned for this format, application, and user. If the value is 0, then this user has no prior application-related data stored for RPG_DEVELOPER_MY_APPLICATION, and SMACPP sets default values for this user in the data structure ApplInfo. If the bytes available value is non-zero, then SMACPP allocates sufficient storage to reflect all application-related data associated with the current user and application, calls the Retrieve User Application Information API a second time in order to access the application-related data using the allocated storage, accesses the application-related data by setting the pointer variable RcvVarInfoPtr to the address of the receiver variable using RcvVarPtr, which address the first byte of the previously allocated storage plus the displacement to the application-related data (RcvVar.QSYDAI), moves the retrieved application data from the RcvVarInfoPtr based structure RcvVarApplInfo to the data structure ApplInfo, and then deallocates the storage previously allocated.
At this point, the subfields of the ApplInfo data structure reflect either the default values or the most recently stored values for the current user. It is now time to examine the parameters passed to SMACPP. If all 20 bytes of QualFileName are set to the blank padded value *PRV, then SMACPP does nothing: ApplInfo reflects the previous (or initial) values. If only the first 10 bytes of QualFileName are set to the blank padded value *PRV, then SMACPP moves the library portion of QualFileName to the library subfield of ApplInfo. Otherwise, SMACPP sets both the file and library subfields of ApplInfo to the corresponding values found in QualFileName. The same type of analysis is then done for the MbrName parameter.
Having now established the library and file to be opened, SMACPP sets the variable MyFile to the appropriate value, starts a Monitor for any errors that might occur when opening the file, and opens the file.
The file MyFile is defined as a program-described input-only file with a maximum record length of 32766 bytes (the largest record length supported for a source file though many compilers support a much smaller record length). The file is also defined as being "user open" with the actual file name to be opened determined at run time by the variable MyFile and the actual member to be opened by the subfield ApplInfo.Member. Both of these fields have been previously set by SMACPP.
If an error is encountered when opening the member, an appropriate error message is displayed and SMACPP ends. Note that in this error case SMACPP does not update the application-related data because an update would, in this application scenario, store the name of a file and member that cannot be opened. This stored value would then cause the user, if using the *PRV support of STRMYAPP, to simply fail again next time. I would much rather retain the last successfully used file and member information. This decision, to update or not, is however one that should be made on an application-by-application basis.
If no error is encountered on the open, the monitor block is ended.
SMACPP then reads the first record from MyAppFile and displays either the first 50 bytes of the source found in the record or, if the member contains no records, the message "Empty file." The main point is that you are now into the application logic of RPG_DEVELOPER_MY_APPLICATION.
When the user exits RPG_DEVELOPER_MY_APPLICATION, SMACPP calls the Update User Application Information API in order to store the current values found in the ApplInfo data structure. Now when the user subsequently returns to the application, SMACPP will be able to access the application-related information associated with the most recent use of RPG_DEVELOPER_MY_APPLICATION. If, during normal application usage, the user for instance toggled full-screen mode from "off" to "on," then, as long as this "on" condition is reflected by the subfield ApplInfo.FullScreen and this field is examined by the application logic, the user will still be in "on" mode when RPG_DEVELOPER_MY_APPLICATION is run again at a later time. This approach can be applied to any user preference that the application wishes to support. In this example program, SMACPP is retaining information related to library, file, member, and full-screen mode. In your applications, I suspect you can think of many other attributes that users might want to have retained across application calls.
This concludes the introduction to the User Application APIs and hopefully gives you some ideas on how existing and future applications for your company might be enhanced with improved usability.
If you have other API questions, send them to me at
LATEST COMMENTS
MC Press Online