在 C# 中编程 IBM iSeries API QUSLSPL

本文关键字:iSeries API QUSLSPL IBM 编程 | 更新日期: 2023-09-27 18:03:04

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

这是我的代码。

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

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

在 C# 中编程 IBM iSeries API QUSLSPL

你选择了一个 API 的哼哼声来开始。 您有一个具有全键列表格式的用户空间列表 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

参数为:

  • 完全限定名(字符[20](
  • 扩展属性(字符[10](
  • 初始大小(二进制[4](
  • 初始值(字符[1](
  • 公共权力(字符[10](
  • 文本描述(字符[50](
  • 替换(字符[10](
  • API 错误结构

从用户空间检索数据

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

参数为:

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

删除用户空间

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

列出用户空间中的 API 结构

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

  • 用户区域
  • 泛型标头
  • 输入参数部分
  • 页眉节
  • 列表数据部分

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

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

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

查看 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;
}