[英]Programming IBM iSeries API QUSLSPL in C#
Can somebody help me with the complete c# code to call QUSLSPL with SPLF0200 format. 有人可以帮我用完整的C#代码调用SPLF0200格式的QUSLSPL吗? I am able to call the program but don't know how to capture/read through the output.
我可以调用该程序,但不知道如何捕获/读取输出。 I am new to this area.
我是这个领域的新手。 Appreciate your help.
感谢您的帮助。
Here is my code. 这是我的代码。
cwbx.ProgramParameters parameters = new cwbx.ProgramParameters();
//user space name
parameters.Append("usrspcnam", cwbrcParameterTypeEnum.cwbrcInout, 20);
StringConverter stringConverterUsrSpaceNm = new cwbx.StringConverter();
stringConverterUsrSpaceNm.Length = 20;
parameters["usrspcnam"].Value = stringConverterUsrSpaceNm.ToBytes("HRAHMAN QGPL ");
//Format
parameters.Append("frmname", cwbrcParameterTypeEnum.cwbrcInout, 8);
StringConverter stringConverterFrmname = new cwbx.StringConverter();
stringConverterFrmname.Length = 8;
parameters["frmname"].Value = stringConverterFrmname.ToBytes("SPLF0200");
//User Name
parameters.Append("usrnam", cwbrcParameterTypeEnum.cwbrcInout, 10);
StringConverter stringConverterUsrnam = new cwbx.StringConverter();
stringConverterUsrnam.Length = 10;
//parameters["usrnam"].Value = stringConverterUsrnam.ToBytes("*CURRENT");
parameters["usrnam"].Value = stringConverterUsrnam.ToBytes(" ");
//qualified output queue
parameters.Append("cola", cwbrcParameterTypeEnum.cwbrcInout, 20);
StringConverter stringConverterCola = new cwbx.StringConverter();
stringConverterCola.Length = 20;
//parameters["cola"].Value = stringConverterCola.ToBytes("*ALL");
parameters["cola"].Value = stringConverterCola.ToBytes(" ");
//form type
parameters.Append("frmtyp", cwbrcParameterTypeEnum.cwbrcInout, 10);
StringConverter stringConverterFrmtyp = new cwbx.StringConverter();
stringConverterFrmtyp.Length = 10;
//parameters["frmtyp"].Value = stringConverterFrmtyp.ToBytes("*ALL");
parameters["frmtyp"].Value = stringConverterFrmtyp.ToBytes(" ");
//user-specific data
parameters.Append("usrdta", cwbrcParameterTypeEnum.cwbrcInout, 10);
StringConverter stringConverterUsrdta = new cwbx.StringConverter();
stringConverterUsrdta.Length = 10;
//parameters["usrdta"].Value = stringConverterUsrdta.ToBytes("*ALL");
parameters["usrdta"].Value = stringConverterUsrdta.ToBytes(" ");
//error
parameters.Append("error", cwbrcParameterTypeEnum.cwbrcInout, 116);
Structure sc2 = new Structure();
sc2.Fields.Append("bytesprov", 4);
sc2.Fields.Append("bytesavail", 4);
sc2.Fields.Append("messageid", 7);
sc2.Fields.Append("err", 1);
sc2.Fields.Append("messagedta", 100);
parameters["error"].Value = sc2.Bytes;
//qualified job name
parameters.Append("qualifiedjobnm", cwbrcParameterTypeEnum.cwbrcInput, 26);
StringConverter stringConverterUsrdta1 = new cwbx.StringConverter();
stringConverterUsrdta1.Length = 26;
parameters["qualifiedjobnm"].Value = stringConverterUsrdta1.ToBytes("* ");
//keys
parameters.Append("keys", cwbrcParameterTypeEnum.cwbrcInput, 44); //44 is 11 keys times 4 bytes per key
LongConverter lc = new cwbx.LongConverter();
Structure keys = new Structure();
keys.Fields.Append("Spooledfilename", 4); //char10 201
keys.Fields["Spooledfilename"].Value = lc.ToBytes(201);
keys.Fields.Append("Username", 4); //char10 203
keys.Fields["Username"].Value = lc.ToBytes(203);
keys.Fields.Append("opqueue", 4); //206
keys.Fields["opqueue"].Value = lc.ToBytes(206);
keys.Fields.Append("userdata", 4); //209
keys.Fields["userdata"].Value = lc.ToBytes(209);
keys.Fields.Append("status", 4); //210
keys.Fields["status"].Value = lc.ToBytes(210);
keys.Fields.Append("totpages", 4); //bin 211
keys.Fields["totpages"].Value = lc.ToBytes(211);
keys.Fields.Append("copies", 4); //bin 213
keys.Fields["copies"].Value = lc.ToBytes(213);
keys.Fields.Append("openeddate", 4); //216
keys.Fields["openeddate"].Value = lc.ToBytes(216);
keys.Fields.Append("opentime", 4); //217
keys.Fields["opentime"].Value = lc.ToBytes(217);
keys.Fields.Append("jobid", 4); //218
keys.Fields["jobid"].Value = lc.ToBytes(218);
keys.Fields.Append("fileid", 4); //219
keys.Fields["fileid"].Value = lc.ToBytes(219);
parameters["keys"].Value = keys.Bytes;
//number of keys to return
parameters.Append("numberoffields", cwbrcParameterTypeEnum.cwbrcInput, 4);
LongConverter LongConverterKeys = new cwbx.LongConverter();
parameters["numberoffields"].Value = LongConverterKeys.ToBytes(11); //11 keys in total
program.Invoke(true, ref parameters);
Now what next? 现在接下来呢? Where and how to read output?
在哪里以及如何读取输出? Appreciate your response.
感谢您的回应。
You picked a humdinger of an API to start out with. 您首先选择了一个悍马。 You have a user space list API with an all-key list format.
您有一个具有全键列表格式的用户空间列表API。 Those are complex.
那些很复杂。 I'll do my best to explain it all.
我会尽力解释这一切。 Buckle up!
系好安全带!
The QUSLSPL API does not return anything except what's in the error structure. 除了错误结构中的内容以外,QUSLSPL API不返回任何内容。 Everything else is an input parameter.
其他所有内容都是输入参数。 To access the spooled file list generated by the API, you must access the user space object.
要访问API生成的假脱机文件列表,必须访问用户空间对象。 In your example, the user space is QGPL/HRAHMAN.
在您的示例中,用户空间为QGPL / HRAHMAN。 Before I get into examining the output of the user space, let's get into understanding how to use a user space.
在研究用户空间的输出之前,让我们开始了解如何使用用户空间。
A user space is just a big old block of bytes stored in a library on the host system with a maximum size of 16,776,704 bytes. 用户空间只是存储在主机系统上的库中的旧字节大块,最大大小为16,776,704字节。 You can use them for more than just list API results, but that's all I really use them for.
您不仅可以列出API结果,还可以使用它们,但这就是我真正使用它们的全部。 The steps for list APIs that require user spaces are as such:
需要用户空间的列表API的步骤如下:
Creating the user space is done via the Create User Space (QUSCRTUS) API. 通过创建用户空间(QUSCRTUS)API完成创建用户空间。 This API is pretty straight-forward.
该API非常简单。 You pass it a qualified name of the user space, some initial values, and the API error structure (so you can handle problems that come up).
您为它传递用户空间的限定名称,一些初始值和API错误结构(以便您处理出现的问题)。 The API definition can be found here: http://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/quscrtus.htm
可以在以下位置找到API定义: http : //www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/quscrtus.htm
The parameters are: 参数为:
After you call the QUSLSPL API, you need to retrieve the data from the user space. 调用QUSLSPL API后,您需要从用户空间检索数据。 For that you use the QUSRTVUS API.
为此,请使用QUSRTVUS API。 This API takes the user space name, the starting position, length, receiver variable, and the API error structure.
该API包含用户空间名称,起始位置,长度,接收器变量和API错误结构。 The API definition is here: http://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/qusrtvus.htm
API定义在这里: http : //www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/qusrtvus.htm
The parameters are: 参数为:
When you're all done, delete the user space using the QUSDLTUS API. 完成后,请使用QUSDLTUS API删除用户空间。 This one is even easier, it takes the fully qualified name and the API error structure.
这甚至更容易,它采用了完全限定的名称和API错误结构。 The API definition is found here: http://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/qusdltus.htm
可在以下位置找到API定义: http : //www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/qusdltus.htm
List APIs return data to the user space in a specific format. 列表API以特定格式将数据返回到用户空间。 It looks like this:
看起来像这样:
What really matters, as far as reading through a list API are the following values in the front of the user space, in that generic header. 就通读列表API而言,真正重要的是该通用标头中用户空间前面的以下值。 Note that these positions are zero-based.
请注意,这些位置是从零开始的。
With this information, you read the user space in chunks. 使用此信息,您可以分块读取用户空间。 Each chunk starts at offset+(current zero-based entry number * size of each entry) and runs for the length of the entry size.
每个块都以offset +(当前从零开始的条目号*每个条目的大小)开始,并以条目大小的长度运行。
Each entry in the list returned from QUSLSPL for format SPLF0200 has two parts. 从QUSLSPL返回的格式为SPLF0200的列表中的每个条目都有两个部分。 The first 4 bytes hold a count of fields returned.
前4个字节保存返回的字段计数。 Then it has the field data structure repeated for each field.
然后,它具有对每个字段重复的字段数据结构。 The size of the field data structure is variable.
字段数据结构的大小是可变的。 You have to loop through it for each field, look at the field key, and use that determine which value got returned.
您必须遍历每个字段,查看字段键,然后使用该键确定要返回的值。 The end result is a two-level loop.
最终结果是两级循环。 The outer loop cycles through each spooled file entry.
外循环遍历每个假脱机文件条目。 The inner loop cycles through each field returned in the SPLF0200 format.
内部循环循环浏览以SPLF0200格式返回的每个字段。
Here is some sample code, based on your original question. 这是一些基于您原始问题的示例代码。 Some notes, first:
首先,请注意以下几点:
Also note that I altered the parameters slightly to bring up the current user's spooled files because, in testing this sample, I didn't want to have to generate spooled data within the current job. 还要注意,我略微更改了参数以显示当前用户的假脱机文件,因为在测试此样本时,我不想在当前作业中生成假脱机数据。
//Define a single StringConverter and LongConverter to re-use
cwbx.StringConverter stringConverter = new cwbx.StringConverter();
cwbx.LongConverter longConverter = new cwbx.LongConverter();
//Type the user space name only once. It's re-used a lot.
String userSpaceName = "HRAHMAN QGPL ";
//Connect to the AS/400
AS400System as400 = new AS400System();
as400.Define("MY_SYSTEM_HOST_ADDRESS");
as400.UserID = "MY_USER";
as400.Password = "MY_PASSWORD";
as400.Connect(cwbcoServiceEnum.cwbcoServiceRemoteCmd);
//Define the error structure once, to be re-used a lot.
Structure sc2 = new Structure();
sc2.Fields.Append("bytesprov", 4);
sc2.Fields.Append("bytesavail", 4);
sc2.Fields.Append("messageid", 7);
sc2.Fields.Append("err", 1);
sc2.Fields.Append("messagedta", 100);
sc2.Fields["bytesavail"].Value = longConverter.ToBytes(sc2.Length);
//Create the user space
cwbx.Program quscrtus = new cwbx.Program();
quscrtus.system = as400;
quscrtus.LibraryName = "QSYS";
quscrtus.ProgramName = "QUSCRTUS";
cwbx.ProgramParameters quscrtusParms = new cwbx.ProgramParameters();
quscrtusParms.Append("UserSpaceName", cwbrcParameterTypeEnum.cwbrcInput, 20).Value = stringConverter.ToBytes(userSpaceName);
quscrtusParms.Append("ExtendedAttr", cwbrcParameterTypeEnum.cwbrcInput, 10).Value = stringConverter.ToBytes("".PadRight(10));
quscrtusParms.Append("InitialSize", cwbrcParameterTypeEnum.cwbrcInput, 4).Value = longConverter.ToBytes(1);
quscrtusParms.Append("InitialValue", cwbrcParameterTypeEnum.cwbrcInput, 1).Value = longConverter.ToBytes(0);
quscrtusParms.Append("Auth", cwbrcParameterTypeEnum.cwbrcInput, 10).Value = stringConverter.ToBytes("*ALL".PadRight(10));
quscrtusParms.Append("Desc", cwbrcParameterTypeEnum.cwbrcInput, 50).Value = stringConverter.ToBytes("QUSLSPL Results".PadRight(50));
quscrtusParms.Append("Replace", cwbrcParameterTypeEnum.cwbrcInput, 10).Value = stringConverter.ToBytes("*YES".PadRight(10));
quscrtusParms.Append("APIError", cwbrcParameterTypeEnum.cwbrcInout, sc2.Length).Value = sc2.Bytes;
quscrtus.Call(quscrtusParms);
sc2.Bytes = quscrtusParms["APIError"].Value;
if (((string)stringConverter.FromBytes(sc2.Fields["messageid"].Value)).Trim().Length > 0)
{
//deal with error
return;
}
//Call the list spooled files API
cwbx.Program quslspl = new cwbx.Program();
quslspl.system = as400;
quslspl.LibraryName = "QSYS";
quslspl.ProgramName = "QUSLSPL";
ProgramParameters quslsplParms = new cwbx.ProgramParameters();
quslsplParms.Append("usrspcnam", cwbrcParameterTypeEnum.cwbrcInput, 20).Value = stringConverter.ToBytes(userSpaceName); //user space name
quslsplParms.Append("frmname", cwbrcParameterTypeEnum.cwbrcInput, 8).Value = stringConverter.ToBytes("SPLF0200"); //Format
quslsplParms.Append("usrnam", cwbrcParameterTypeEnum.cwbrcInput, 10).Value = stringConverter.ToBytes("*CURRENT".PadRight(10)); //User Name
quslsplParms.Append("cola", cwbrcParameterTypeEnum.cwbrcInput, 20).Value = stringConverter.ToBytes("*ALL".PadRight(20)); //qualified output queue
quslsplParms.Append("frmtyp", cwbrcParameterTypeEnum.cwbrcInput, 10).Value = stringConverter.ToBytes("*ALL".PadRight(10)); //form type
quslsplParms.Append("usrdta", cwbrcParameterTypeEnum.cwbrcInput, 10).Value = stringConverter.ToBytes("*ALL".PadRight(10)); //user-specific data
quslsplParms.Append("error", cwbrcParameterTypeEnum.cwbrcInout, sc2.Length).Value = sc2.Bytes; //error
quslsplParms.Append("qualifiedjobnm", cwbrcParameterTypeEnum.cwbrcInput, 26).Value = stringConverter.ToBytes("".PadRight(26)); //qualified job name
//keys. The SPLF0200 structure uses a list of field keys. So we tell the API which keys we want and that's what it returns.
cwbx.Structure keys = new cwbx.Structure();
keys.Fields.Append("Spooledfilename", 4).Value = longConverter.ToBytes(201);
keys.Fields.Append("Username", 4).Value = longConverter.ToBytes(203);
keys.Fields.Append("opqueue", 4).Value = longConverter.ToBytes(206);
keys.Fields.Append("userdata", 4).Value = longConverter.ToBytes(209);
keys.Fields.Append("status", 4).Value = longConverter.ToBytes(210);
keys.Fields.Append("totpages", 4).Value = longConverter.ToBytes(211);
keys.Fields.Append("copies", 4).Value = longConverter.ToBytes(213);
keys.Fields.Append("openeddate", 4).Value = longConverter.ToBytes(216);
keys.Fields.Append("opentime", 4).Value = longConverter.ToBytes(217);
keys.Fields.Append("jobid", 4).Value = longConverter.ToBytes(218);
keys.Fields.Append("fileid", 4).Value = longConverter.ToBytes(219);
quslsplParms.Append("keys", cwbrcParameterTypeEnum.cwbrcInput, keys.Length).Value=keys.Bytes;
quslsplParms.Append("numberoffields", cwbrcParameterTypeEnum.cwbrcInput, 4).Value = longConverter.ToBytes(keys.Fields.Count); //number of keys to return
quslspl.Call(quslsplParms);
sc2.Bytes = quslsplParms["error"].Value;
if (((string)stringConverter.FromBytes(sc2.Fields["messageid"].Value)).Trim().Length > 0)
{
//deal with error
return;
}
//Get the list information from the user space
cwbx.Structure listInfo = new cwbx.Structure();
listInfo.Fields.Append("OffsetToData", 4);
listInfo.Fields.Append("DataSectionSize", 4);
listInfo.Fields.Append("NumberOfEntries", 4);
listInfo.Fields.Append("EntrySize", 4);
//The List information data structure starts at zero-based position 0x7c. The retrieve user space
//API uses 1-based indexing. Retreive the list information from the user space.
cwbx.Program qusrtvus = new cwbx.Program();
qusrtvus.system = as400;
qusrtvus.LibraryName = "QSYS";
qusrtvus.ProgramName = "QUSRTVUS";
cwbx.ProgramParameters qusrtvusParms = new cwbx.ProgramParameters();
qusrtvusParms.Append("UserSpaceName", cwbrcParameterTypeEnum.cwbrcInput, 20).Value = stringConverter.ToBytes(userSpaceName);
qusrtvusParms.Append("StartingPosition", cwbrcParameterTypeEnum.cwbrcInput, 4).Value = longConverter.ToBytes(0x7c + 1);
qusrtvusParms.Append("Length", cwbrcParameterTypeEnum.cwbrcInput, 4).Value = longConverter.ToBytes(listInfo.Length);
qusrtvusParms.Append("Receiver", cwbrcParameterTypeEnum.cwbrcInout, listInfo.Length);
qusrtvusParms.Append("APIError", cwbrcParameterTypeEnum.cwbrcInout, sc2.Length).Value = sc2.Bytes;
qusrtvus.Call(qusrtvusParms);
sc2.Bytes = qusrtvusParms["APIError"].Value;
if (((string)stringConverter.FromBytes(sc2.Fields["messageid"].Value)).Trim().Length > 0)
{
//deal with error
return;
}
listInfo.Bytes = qusrtvusParms["Receiver"].Value;
int offsetToData = longConverter.FromBytes(listInfo.Fields["OffsetToData"].Value);
int numberOfEntries = longConverter.FromBytes(listInfo.Fields["NumberOfEntries"].Value);
int entrySize = longConverter.FromBytes(listInfo.Fields["EntrySize"].Value);
//Define the structure to receive the SPLF0200 Field data. This is described in the QUSLSPL API.
//Note: According to the API documentation, this is the only part that repeats for each key. The first
//four bytes of the SPLF0200 structure is the count of keys returned.
cwbx.Structure SPLF0200Field = new cwbx.Structure(); //individual field value data
SPLF0200Field.Fields.Append("LengthOfInformation", 4);
SPLF0200Field.Fields.Append("KeyField", 4);
SPLF0200Field.Fields.Append("TypeOfData", 1);
SPLF0200Field.Fields.Append("Reserved", 3);
SPLF0200Field.Fields.Append("LengthOfData", 4);
//Loop through each entry in the list and get the field values by key
for (int currentEntry = 0; currentEntry < numberOfEntries; currentEntry++)
{
qusrtvusParms["StartingPosition"].Value = longConverter.ToBytes(offsetToData + (currentEntry * entrySize) + 1);
qusrtvusParms["Length"].Value = longConverter.ToBytes(entrySize);
qusrtvusParms["Receiver"].Length = entrySize;
qusrtvus.Call(qusrtvusParms);
sc2.Bytes = qusrtvusParms["APIError"].Value;
if (((string)stringConverter.FromBytes(sc2.Fields["messageid"].Value)).Trim().Length > 0)
{
//deal with error
return;
}
//According to the SPLF0200 format, the first 4-byte integer is the number of fields returned.
//After that, it's a variable list of key structures.
byte[] entry = qusrtvusParms["Receiver"].Value;
byte[] numberOfFieldsReturnedBytes = new byte[4];
Array.Copy(entry, 0, numberOfFieldsReturnedBytes, 0, 4);
int numberOfFieldsReturned = longConverter.FromBytes(numberOfFieldsReturnedBytes);
int lastBufferEnd = 4;
//Fields to hold the spooled file field elements. Note: In a production environment, I would normally
//create a class to hold all of this, but this is just for sample purposes.
String spooledFileName = "";
String userName = "";
String opqueue = "";
String userdata = "";
String status = "";
int totpages = 0;
int copies = 0;
String openeddate = "";
String opentime = "";
byte[] jobid = new byte[16];
byte[] fileid = new byte[16];
for (int currentField = 0; currentField < numberOfFieldsReturned; currentField++)
{
byte[] SPLF0200FieldBytes = new byte[SPLF0200Field.Length];
Array.Copy(entry, lastBufferEnd, SPLF0200FieldBytes, 0, SPLF0200FieldBytes.Length);
SPLF0200Field.Bytes = SPLF0200FieldBytes;
int fieldDataLength = longConverter.FromBytes(SPLF0200Field.Fields["LengthOfData"].Value);
int fieldInfoLength = longConverter.FromBytes(SPLF0200Field.Fields["LengthOfInformation"].Value);
int fieldKey = longConverter.FromBytes(SPLF0200Field.Fields["KeyField"].Value);
byte[] fieldDataBytes = new byte[fieldDataLength];
Array.Copy(entry, lastBufferEnd + 16, fieldDataBytes, 0, fieldDataLength);
lastBufferEnd = lastBufferEnd + fieldInfoLength;
switch (fieldKey) {
case 201:
spooledFileName = stringConverter.FromBytes(fieldDataBytes);
break;
case 203:
userName = stringConverter.FromBytes(fieldDataBytes);
break;
case 206:
opqueue = stringConverter.FromBytes(fieldDataBytes);
break;
case 209:
userdata = stringConverter.FromBytes(fieldDataBytes);
break;
case 210:
status = stringConverter.FromBytes(fieldDataBytes);
break;
case 211:
totpages = longConverter.FromBytes(fieldDataBytes);
break;
case 213:
copies = longConverter.FromBytes(fieldDataBytes);
break;
case 216:
openeddate = stringConverter.FromBytes(fieldDataBytes);
break;
case 217:
opentime = stringConverter.FromBytes(fieldDataBytes);
break;
case 218:
jobid = fieldDataBytes;
break;
case 219:
fileid = fieldDataBytes;
break;
}
}
//All field elements that the API returned (that we care about) are loaded.
//Now do something with the spooled file fields here.
}
//Delete the user space
cwbx.Program qusdltus = new cwbx.Program();
qusdltus.system = as400;
qusdltus.LibraryName = "QSYS";
qusdltus.ProgramName = "QUSDLTUS";
cwbx.ProgramParameters qusdltusParms = new cwbx.ProgramParameters();
qusdltusParms.Append("UserSpaceName", cwbrcParameterTypeEnum.cwbrcInput, 20).Value = stringConverter.ToBytes(userSpaceName);
qusdltusParms.Append("APIError", cwbrcParameterTypeEnum.cwbrcInout, sc2.Length).Value = sc2.Bytes;
qusdltus.Call(qusdltusParms);
sc2.Bytes = qusdltusParms["APIError"].Value;
if (((string)stringConverter.FromBytes(sc2.Fields["messageid"].Value)).Trim().Length > 0)
{
//deal with error
return;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.