使用C#编写IBM iSeries API QUSLSPL

有人可以用完整的c#代码帮助我调用SPLF0200格式的QUSLSPL。 我能够调用该程序,但不知道如何捕获/读取输出。 我是这个领域的新手。 感谢您的帮助。

这是我的代码。

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

接下来呢? 在哪里以及如何阅读输出? 感谢您的回复。

你选择了一个API的humdinger开始。 您有一个具有全键列表格式的用户空间列表API。 那些很复杂。 我会尽力解释一切。 系好安全带!

除了错误结构中的内容之外,QUSLSPL API不会返回任何内容。 其他一切都是输入参数。 要访问API生成的假脱机文件列表,您必须访问用户空间对象。 在您的示例中,用户空间是QGPL / HRAHMAN。 在开始研究用户空间的输出之前,让我们先了解如何使用用户空间。

什么是用户空间?

用户空间只是存储在主机系统上的库中的一个大的旧字节块,最大大小为16,776,704字节。 你可以使用它们而不仅仅是列出API结果,但这就是我真正使用它们的全部内容。 需要用户空间的列表API的步骤如下:

  1. 创建用户空间。
  2. 调用API。
  3. 检查API中的错误。
  4. 找到每个条目的大小。
  5. 找到列表数据的开头。
  6. 遍历用户空间中的条目。
  7. 删除用户空间。

创建用户空间

创建用户空间是通过创建用户空间(QUSCRTUS)API完成的。 这个API非常简单。 您传递了一个用户空间的限定名称,一些初始值和API错误结构(这样您就可以处理出现的问题)。 可以在此处找到API定义: http : //www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/quscrtus.htm

参数是:

  • 完全限定名称(char [20])
  • 扩展属性(char [10])
  • 初始大小(二进制[4])
  • 初始值(char [1])
  • 公共权力机构(char [10])
  • 文字说明(char [50])
  • 替换(char [10])
  • API错误结构

从用户空间检索数据

调用QUSLSPL API后,需要从用户空间检索数据。 为此,您使用QUSRTVUS API。 此API获取用户空间名称,起始位置,长度,接收器变量和API错误结构。 API定义位于: http : //www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/qusrtvus.htm

参数是:

  • 完全合格的名称(char [20])
  • 起始位置(二进制[4])注意:这是从1开始的,而不是从零开始的。
  • 要返回的数据长度(二进制[4])
  • 接收器变量(*)
  • API错误结构

删除用户空间

完成所有操作后,使用QUSDLTUS API删除用户空间。 这个更容易,它采用完全限定名称和API错误结构。 可在此处找到API定义: http : //www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/apis/qusdltus.htm

列出用户空间中的API结构

List API以特定格式将数据返回给用户空间。 它看起来像这样:

  • 用户区域
  • 通用标头
  • 输入参数部分
  • 标题部分
  • 列表数据部分

真正重要的是,只要通过列表API读取,就可以在该通用标头中的用户空间前面使用以下值。 请注意,这些位置是从零开始的。

  • 位置0x7c:偏移到列表数据部分
  • 位置0x84:列表条目数
  • 位置0x88:每个条目的大小

使用此信息,您可以读取块中的用户空间。 每个块从偏移量+(当前从零开始的条目号*每个条目的大小)开始,并以条目大小的长度运行。

看看QUSLSPL的结果

从QUSLSPL返回的格式为SPLF0200的列表中的每个条目都有两部分。 前4个字节包含返回的字段数。 然后,它为每个字段重复了字段数据结构。 字段数据结构的大小是可变的。 您必须为每个字段循环遍历它,查看字段键,并使用它确定返回的值。 最终结果是两级循环。 外部循环遍历每个假脱机文件条目。 内循环循环遍历SPLF0200格式返回的每个字段。

以下是一些示例代码,基于您的原始问题。 一些注意事项,首先:

  • 我没有在API调用周围进行错误检查或尝试/捕获逻辑,但生产程序会有。
  • 我可能会将用户空间API调用放入他们自己的类中以获得可重用性。
  • 我更改了如何设置输入参数值以更加简化。
  • 我使用单个StringConverter和LongConverter进行所有转换。

另请注意,我稍微更改了参数以显示当前用户的假脱机文件,因为在测试此示例时,我不想在当前作业中生成假脱机数据。

 //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; }