星期四, 11月 02, 2023

2002-09-11 如何讓報表管理自動化?


2002-09-11 如何讓報表管理自動化?

報表管理通常是一般系統管理的工作,AS/400(iSeries) 系統已包含以使用者及使用者自己的報表連結相關
的印表機及輸出佇列(Outq -- Output Queue)的報表管理技術,通常管理人員會允許使用者使用指令
WRKSPLF(Work with Spool Files) 及 WRKOUTQ(Work with Output Queues) 截取報表資料,這些指令讓使
用者管理他們自己的報表,及若某使用者同時擁有 *SPLCTL  特殊權限時,該使用者同時可以管理其他人的
報表,然而使用這些指令仍然無法讓報表管理自動化。使用者仍然需要從一個輸出佇列搬移報表至另一個輸
出佇列或從一台印表機搬移報表至另一台印表機。

為什麼有人想要讓報表管理自動化?因為當報表很多時,如週報月報季報年報累計一段時間後,就會有報表
儲存的需求,因為報表本身於 AS/400(iSeries)系統上並不是一個物件,所以無法利用 SAVE 指令儲存,所
以需要採用某些技巧才將報表儲存起來,當然報表可以利用複製報表至資料庫檔案儲存在 AS/400(iSeries)
或下載至 PC 上,但報表非常多時便無法一一用手動的方式來完成,所以可以利用其他廠商所開發的報表管
理軟體,所以仍需要額外的成本才能完成報表管理自動化的工作,基於成本考量,我將教您如何達成報表管
理自動化的方式。其步驟如下:

1:取得哪些報表放置於輸出佇列中的詳細資料,即報表管理自動化的先決條件是以輸出佇列(Outq)為管理
  單位。

2:使用指令 CPYSPLF 複製報表資料至資料庫檔案(PF -- Physical file)。

3:
  a 若僅需儲存報表於 AS/400(iSeries)上,則定期備份步驟2所產生的資料庫檔案(需要自行定義資
    料庫檔案名稱及其 member 成員名稱,方便於備份及回複管理)。

  b 若僅需儲存報表於 PC 上,則有三種方式:

    一: 使用指令 CPYTOSTMF 複製步驟2所產生的資料庫檔案至 IFS 的一般 PC 檔案即可使用
       SAV/RST 指令備份/回複或

    二: 使用 FTP 方式將步驟2所產生的資料庫檔案傳送到 PC 的 FTP 伺服器或

    三: 於 AS/400(iSeries) 及 PC 端撰寫 Socket 程式,傳送步驟2所產生的資料庫檔案至 PC。

    在這裡我僅以方式一來做例子。

要如何將上述三個步驟組合自動處理而不用人工介入輸入指令呢?

這起始點是如何取得放置於輸出佇列中報表的詳細資料,您可以藉由系統所提供用以連結輸出佇列(Outq)的
資料佇列(DTAQ -- Data Queue)來取得放置於輸出佇列(Outq)中報表的詳細資料,來完成第一個步驟,所以
第一步是藉由下述指令新增一個資料佇列(DTAQ -- Data Queue),

CRTDTAQ DTAQ(lib/AUTOSPLDTAQ) MAXLEN(128)

然後新增一個輸出佇列(Outq),同時指定 DTAQ(Data Queue) 參數連結上述指令所新增的資料佇列(DTAQ --
Data Queue),指令如下,

CRTOUTQ OUTQ(lib/AUTOSPLOUTQ) DTAQ(lib/AUTOSPLDTAQ)

在上述例子中 "lib" 是您所希望放置輸出佇列Outq(Output Queue)及 資料佇列DTAQ(Data Queue) 物件的程
式庫(附註:Outq 及 Dtaq 可以放置於不同的程式庫)。

上述指令在輸出佇列 AUTOSPLOUTQ 及資料佇列 AUTOSPLDTAQ 間建立了一個連結關係,所以當有報表放置於輸
出佇列 AUTOSPLOUTQ 時,同時會有一筆該報表的相關資料放置於資料佇列 AUTOSPLDTAQ 中。

放置於資料佇列 AUTOSPLDTAQ 中資訊的長度有 128 位,包含如下資訊:

    報表資訊放置於資料佇列DTAQ(Data Queue)的資料格式
  ===========================================
  起始位置 長度   說明
  ==== ==== =================================
  1         CHAR(10)  Function "*SPOOL"   表此筆記錄是報表相關資訊(不需要)
    11        CHAR(02)  Record type "01"    表示已放置至輸出佇列的報表狀態為 Ready(不需要)
  13        CHAR(26)  Qualified job name  產生此報表的 Job 全名
             CHAR(10)  Job name
             CHAR(10)  User name
             CHAR(6)   Job number
  39        CHAR(10)  Spool file name     表示已放置至輸出佇列報表的報表名稱
  49        BINARY(4) Spool file number   表示已放置至輸出佇列報表的報表序號
  53        CHAR(20)  Qualified output queue name 表示此報表所放置的輸出佇列名稱全名
              CHAR(10)  Output queue name
                         CHAR(10)  Library of the output queue     
  73        CHAR(56)   56 bytes of filler 此 56 位保留不用(不需要)

  上述資訊可能用於指令 CPYSPLF 及 CPYTOSTMF。

要記住當有有一份新的報表放置於輸出佇列Outq(Output Queue)中時,而且該報表的狀態是 Ready(RDY),此時
即有一筆報表紀錄放置於資料佇列 DTAQ(Data Queue)中,所以我們需要一個批次工作用以監控是否有新的報表
資訊放置於資料佇列 DTAQ(Data Queue) 中。

下列是用於處理這個程序的 RPGIV 程式片斷,底下是依照報表資訊放置於資料佇列DTAQ(Data Queue)的資料格
式用於接收資料佇列 DTAQ(Data Queue)資料的資料結構:

D SpoolInfo        DS 
D  Function                       10 
D  RecordType                      2 
D  QualJobName                    26 
D   JobName                       10     Overlay(QualJobName:1) 
D   JobUser                       10     Overlay(QualJobName:11) 
D   JobNumber                      6     Overlay(QualJobName:21) 
D  FileName                       10 
D  FileNumber                      9B 0 
D  QualQueueName                  20 
D   QueueName                     10     Overlay(QualQueueName:1)
D   QueueLibrary                  10     Overlay(QualQueueName:11)
D  Filler                         56 

這個資料結構包含從資料佇列 DTAQ(Data Queue) 所取得的資訊,job name,job user,job number,file name
及 file number 是重要的資訊,並提供給指令 CPYSPLF 使用。

下列是要擷取資料佇列 DTAQ(Data Queue) 報表資訊所需要使用的資料欄位範例:

*   Data Queue Variables 
D RcvQueueName    S               10     Inz(‘AUTOSPLDTAQ’)
D RcvQueueLib     S               10     Inz('*LIBL')
D RcvMsgSize      S                5 0   Inz(%Size(RcvMsg)) 
D RcvMsg          S              128 
D RcvWaitTime     S                5 0   Inz(-1)

下列是接收資料佇列 DTAQ(Data Queue) 報表資訊所使用的 RPGIV 運算:

C                    Call        'QRCVDTAQ' 
C                    Parm                      RcvQueueName
C                    Parm                      RcvQueueLib 
C                    Parm                      RcvMsgSize 
C                    Parm                      RcvMsg 
C                    Parm                      RcvWaitTime

欄位 RcvWaitTime 值為 -1,表示接收資料佇列 DTAQ(Data Queue) 報表資訊時,若資料佇列 DTAQ(Data Queue)
沒有報表資訊紀錄時,即一直等待至有資訊時才讀取,等待時並不會耗用系統資源。如果程式還要執行除了處理
資料佇列 DTAQ(Data Queue) 之外的其他工作時,RcvWaitTime 值也可以設定一個以秒為單位的值,以符合您的
需求。

當然這個程序也可以使用 CL 程式而不用 RPGIV 來開發,由於 RPGIV 的字串處理函數功能比 CL 好,所以我選擇
RPGIV。

接著要進行第二個步驟,也就是要使用指令 CPYSPLF 複製報表資料至資料庫檔案。

這個工作類似大部分系統管理人員所要做的,有時候系統管理人員需要拷貝報表資料給公司內部人員或廠商使用,
或將儲存報表資料並拷貝至磁帶後,再將報表及儲存報表的資料庫檔案刪除,才能釋放系統儲存空間,有需要使用
時再回複(restore)回系統。在這裡我想將報表分享給 PC 使用者,所以我將儲存報表的資料庫檔案拷貝至 IFS 的
一個目錄,並將該目錄分享出來,如同一般 PC 的網路磁碟機,PC 使用者可以透過網路磁碟機,直接讀取報表。
您可以使用 Client Access Operation Navigator 將在 IFS 下放置報表的目錄分享出來。

對我而言,RPGIV 處理字串的功能比 CL 好,所以我仍使用 RPGIV 來執行系統指令。我於 RPGIV 中使用系統所提
供的 QCMDEXC 程式來執行系統指令,

在呼叫 QCMDEXC 前需要定義所要使用的二個參數宣告:

D CmdStr           S             512 
D CmdLen           S              15  5

接著呼叫 QCMDEXC 的傳統方式如下:

C                    Eval       CmdStr = ‘WRKSPLF’
C                    Eval       CmdLen = %Len(%Trim(CmdLine)) 
C                    Call       'QCMDEXC' 
C                    Parm                     CmdLine 
C                    Parm                     CmdLength 

"CmdLine" 包含所要執行的指令,及 "CmdLength" 包含所要執行指令的長度。

另一種呼叫 QCMDEXC 的方式是如 C 語言藉由宣告外部函式,我較喜歡此種方式,因為可以使用 RPGIV 的錯誤偵測
功能,下列是宣告外部函式的例子:

D Cmd              PR                   ExtPgm('QCMDEXC')
D                               512     Options(*VarSize)
D                                       Const
D                                15   5 Const 

我使用上述相同的 CmdStr 及 CmdLen 定義。

下列是使用外部函式呼叫 QCMDEXC 的範例:

C                    Eval       CmdStr = 'WRKSPLF’
C                    Eval       CmdLen = %Len(%Trim(CmdStr)) 
C                    CallP(E)   Cmd(CmdStr:CmdLen)
C                    If         %Error
*          (error handling code here)
C                    EndIf 

在 CallP(Call a Prototype Procedure or Program) 後指定一個 "E" 運算元延伸器,當 CallP 指令執行有錯誤時
,我能擷取錯誤並做適當的處理,這就如同 CLP 中的 MOMMSG(Monitor Message) 功能。您覺得哪一個比較好用?


複製報表資料至資料庫檔案包含二個步驟,首先,新增一個資料庫檔案用以存放報表資料,接著,複製報表資料至資
料庫檔案。我新增一個資料庫檔案於程式館 QTEMP 中,並給予該新增的資料庫檔案一個由時間產生的唯一的名稱,
該名稱您可依據自己的需求定義之,下列是我設定的資料庫檔案名稱的定義:

D TimeStamp        S                Z
D CharTimeStamp    S              26 

我以 CPY 開頭,後加上時間的微秒(microseconds) 部分當成資料庫檔案名稱,這確保有唯一的名稱,我使用 TIME
運算元,放置程式執行至 TIME 運算元的當時系統時間至 TimeStamp 變數中,然後使用內建函數 %CHAR 將 TimeStamp
值轉換成文字,接著使用內建函數 %SUBST 擷取微秒(microseconds)部分,然後新增一個命令字串如下:

CRTPF FILE(CPYxxxxxx) RCDLEN(200) SIZE(*NOMAX) IGCDTA(*YES) AUT(*ALL)

"xxxxxx" 表示時間的微秒(microseconds)部分,而 "200" 表是報表每行的最大長度,IGCDTA(*YES) 表可容納中文 DBCS。

*   Create the file to receive CPYSPLF output in QTEMP. 
C     CrtFile       BegSr

C                   Time                     TimeStamp 
C                   Eval       CharTimeStamp = %Char(TimeStamp)

C                   Eval       CmdStr = 'CRTPF FILE(QTEMP/' + 
C                                       'CPY' + 
C                                       %SubSt(CharTimeStamp:21:6) + 
C                                       ')' + ' ' + 'RCDLEN(200) + 
C                                       SIZE(*NOMAX) + 
C                                       IGCDTA(*YES) + 
C                                       AUT(*ALL)' 
C                   Eval       CmdLen = %Len(%Trim(CmdStr)) 
C                   CallP(E)   Cmd(CmdStr:CmdLen) 
*          (error handling code here)
C                   EndSr 

上述程式片斷新增一個唯一名稱的資料庫檔案於程式館 QTEMP 中。

下一個指令是複製報表資料至資料庫檔案,此時需要使用先前從資料佇列 DTAQ(Data Queue)中收到的資料 ,
當有有一份新的報表放置於輸出佇列Outq(Output Queue)中時,而且該報表的狀態是 Ready(RDY),同時也有一
筆報表紀錄放置於資料佇列 DTAQ(Data Queue)中,而這筆記錄由程式讀入,並放置於一個資料結構中,資料結
構中的資訊可以用來擷取指定的報表,為了便於參照,這裡再將資料佇列 DTAQ(Data Queue)中報表相關資料的
資料格式列出:

D SpoolInfo        DS
D  Function                      10
D  RecordType                     2
D  QualJobName                   26
D   JobName                      10     Overlay(QualJobName:1)
D   JobUser                      10     Overlay(QualJobName:11)
D   JobNumber                     6     Overlay(QualJobName:21)
D  FileName                      10
D  FileNumber                     9B 0
D  QualQueueName                 20 
D   QueueName                    10     Overlay(QualQueueName:1) 
D   QueueLibrary                 10     Overlay(QualQueueName:11)
D  Filler                        56 


複製報表資料至資料庫檔案的指令如下:

CPYSPLF FILE(FILENAME) TOFILE(CPYxxxxxx) JOB(QUALJOBNAME) SPLNBR(FILENUMBER)

"FileName"    表從資料佇列 DTAQ(Data Queue) 所取得的報表名稱,
"CPYxxxxxx"   是前一步驟所新增的資料庫檔案名稱,
"QualJobName" 表從資料佇列 DTAQ(Data Queue) 所取得產生報表 Job,
"FileNumber"  表從資料佇列 DTAQ(Data Queue) 所取得的報表序號。

*   Execute a CPYSPLF to file in QTEMP.
C     CpyFile       BegSr
C 
C                    Eval       ZoneNumber = FileNumber
C                    Move       ZoneNumber    CharNumber
C                    Eval       CmdStr  = 'CPYSPLF FILE(' +
C                                        %Trim(FileName) +')' + ' ' +
C                                        'TOFILE(QTEMP/' +
C                                        'CPY' +
C                                        %SubSt(CharTimeStamp:21:6) +
C                                        ')' +
C                                        ' ' + 'JOB(' +
C                                        %Trim(JobNumber) + '/' +
C                                        %Trim(JobUser) + '/' +
C                                        %Trim(JobName) +
C                                        ')' + ' ' +
C                                        'SPLNBR(' + CharNumber + ')'
C                    Eval       CmdLen = %Len(%Trim(CmdStr))
C                    CallP(E)   Cmd(CmdStr:CmdLen)
*          (error handling code here)
C                    EndSr 

上述程式片斷,複製報表資料至資料庫檔案。

在步驟一及步驟二已完成了擷取報表相關資訊及複製報表資料至資料庫檔案,接著步驟三要拷貝含有報表資料的
資料庫檔案至 IFS 分享目錄的 stream file,所謂的 stream file 是一個以位元(Byte)為單位的檔案,他是一
個連續性的檔案,而不是 AS/400(iSeries) 資料庫以欄位為基礎的紀錄格式(record format)檔案,stream file
並沒有欄位,而是像 PC 的純文字格式的檔案,所以是由程式來決定它的結構,stream file 使用於非資料庫結
構的資料,如影像檔,聲音檔,最重要的是文件檔。

使用指令
CPYTOSTMF(Copy to Stream File) 或 CPYTOIMPF(Copy to Import File),拷貝資料庫檔案至 IFS 分享目錄的
stream file,其中 CPYTOIMPF 較適用於拷貝大量資料,下列是執行範例:
 
CPYTOSTMF FROMMBR('/QSYS.LIB/QTEMP.LIB/CPY123456.FILE/CPY123456.MBR')
 
     TOSTMF('/spool/QSYSPRT-201134-0001.txt') STMFOPT(*REPLACE) STMFCODPAG(*PCASCII)
CPYTOSTMF FROMMBR('/QSYS.LIB/QTEMP.LIB/CPY123456.FILE/CPY123456.MBR') 
     TOSTMF('/spool/QSYSPRT-201134-0001.txt') STMFOPT(*REPLACE) STMFCODPAG(950)

CPYTOSTMF FROMMBR('/QSYS.LIB/QTEMP.LIB/CPY123456.FILE/CPY123456.MBR') 
     TOSTMF('/spool/QSYSPRT-201134-0001.txt') STMFOPT(*REPLACE) 
     CVTDTA(*AUTO) DBFCCSID(*FILE) STMFCODPAG(950)
參數 CVTDTA(*AUTO) 及 DBFCCSID(*FILE) 是預設值可以不用設,在此僅列出參考。

或

CPYTOIMPF FROMFILE(QTEMP/CPY123456) TOSTMF('/spool/QSYSPRT-201134-0001.txt') MBROPT(*REPLACE)
     STMFCODPAG(*PCASCII) RCDDLM(*CRLF) STRDLM(*NONE)
CPYTOIMPF FROMFILE(QTEMP/CPY123456) TOSTMF('/spool/QSYSPRT-201134-0001.txt') MBROPT(*REPLACE)
     STMFCODPAG(950) RCDDLM(*CRLF) STRDLM(*NONE)

上述 STMFCODPAG 指的是 PC 的字元頁碼,您可以特別指定 950 是中文 Big5 的字元頁碼,若使用 *PCASCII,
則系統會自行依照相關系統資訊運算出您的 PC 字元頁碼,這會花少許時間,不過使用者不會有延遲的感覺,我傾
像使用較明確的指定 PC 的字元頁碼,這樣較不會混淆。不過我於範例中使用 STMFCODPAG(*PCASCII)。

當轉換中文時,系統會自動將中文控制碼 0E 及 0F 裁掉,所以資料會往左靠,您將需要於轉換前作額外的處理,
如將加一個空白於 0E 前及 0F 後,下列詳細說明整個 0E 及 0F 的處理方式:

位置         .123456789012 
原來資料        .0    0
                  .E中文F123
轉換後的資料      .中文123    ====> 資料會往左靠,造成有中文的報表格式位移

位置         .123456789012
            .0    0
原來資料          .E中文F123 
           . 0    0
原來資料插入空白後    . E中文F 123 <==== 於 0E 前插入一個空白及 0F 後插入一個空白 
轉換後的資料      . 中文 123    ====> 將中文控制碼 0E 及 0F 裁掉後,資料與原來資料格式一樣,
                     所以中文的報表格式正確


我在範例中使用 CPYTOSTMF 執行拷貝的動作,我仍然使用先前所定義的呼叫外部函式的方式如下:


宣告呼叫執行系統指令的系統外部函式:

D Cmd              PR                   ExtPgm('QCMDEXC')
D                               512     Options(*VarSize)
D                                       Const
D                                15   5 Const 


宣告外部函式所要使用的參數定義:

D CmdStr           S             512 
D CmdLen           S              15  5

* single quote 單引號
D Quote            S              1     Inz(X'7D')

 
下列 SndFile 副程序是用於產生指令 CPYTOSTMF 及使用 QCMDEXC 執行指令:

C      SndFile       Begsr
*   Send the spooled file output to the appropriate IFS directory.
C                    Eval       CmdLine = 'CPYTOSTMF + 
C                                        FROMMBR(' + Quote + 
C                                        '/QSYS.LIB/QTEMP.LIB/' + 
C                                        'CPY' + 
C                                         %SubSt(CharTimeStamp:21:6) + 
C                                        '.FILE' + '/' +
C                                        'CPY' +
C                                        %SubSt(CharTimeStamp:21:6) +
C                                        '.MBR' + Quote + ')' + ' ' +
C                                        'TOSTMF(' + Quote +
C                                        '/spool' + ‘/’ +
C                                        %Trim(FileName) + '_' +
C                                        JobNumber + '_' +
C                                        CharNumber +
C                                        Quote + ')' + ' ' +
C                                        'STMFCODPAG(*PCASCII)' + ' ' +
C                                        'STMFOPT(*REPLACE)'
C                    Eval      CmdLen = %Len(%Trim(CmdStr))
C                    CallP(E) Cmd(CmdStr:CmdLen)
*          (error handling code here)
C                    EndSr 


上述程式碼中參數 FROMMBR 指定 CPYSPLF 指令所輸出的資料庫檔案名稱,FROMMBR 參數所指定的格式
不同於 AS/400(iSeries)的傳統檔案格式,我雖指定 AS/400(iSeries) 的傳統檔案,但使用 IFS 的檔
案結構格式,檔名以 "/QSYS.LIB" 開頭表示指定 AS/400(iSeries) 的傳統檔案,接著下一層是
"/QTEMP.LIB",最後加上以 "CPY" 加上時間的微秒部分組合成檔案名稱,且也需要指定檔案成員名稱。
一個於 AS/400(iSeries)的傳統(QSYS)檔案中的物件均需要以 ".LIB",".FILE",".MBR" 結尾,這是
CPYTOSTMF 指令及其他相關 IFS 整合性檔案系統的指令所必須的,就如同 PC 或 Unix 的目錄架構。

這個 TOSTMF(To Stream File) 參數是由一個目錄(在這個例子中是指定 "/spool",但您也可以自行指定)
及報表名稱、Job Number、報表序號組成的檔名所組成。

這個 STMFCODPAG(Stream File Code Page) 有多個參數值,其中二個重要的參數值 *PCASCII 及 *STDASCII
,STDASCII 參數值是使用於 IBM PC 所使用的字元編碼,一般是使用 *PCASCII,所指的是一般 Windows 應
用軟體所使用的格式,而 STMFOPT (File Options) 參數是所拷貝的資料是要加入檔尾或覆蓋原有資料的選項
,並利用呼叫函式 QCMDEXC 執行 CPYTOSTMF 指令,拷貝資料庫檔案的報表內容至 IFS 的目錄中。

您可能也需要設定一個 AS/400 NetServer 的目錄分享,AS/400 NetServer 提供分享 IFS 目錄的功能,來讓
Windows PC 當成網路磁碟機,新增目錄分享只要執行一次,AS/400 會保留目錄分享直到刪除該目錄的分享設
定,此刪除動作並不會刪除該分享目錄的資料而僅刪除該目錄的分享設定。

設定 AS/400 NetServer 目錄分享,可以藉由 Operations Navigator 或 APIs 完成,有許多的 AS/400 NetServer
API 可供使用,底下列出部分 APIs 即其使用方法(附註:V5R2 已提供所有 NetServer API 工具於程式庫
QUSRTOOL 中 http://www-1.ibm.com/servers/eserver/iseries/netserver/qusrtool.htm):

* 新增目錄分享 Add File Server Share (QZLSADFS) 
  CALL QZLSADFS PARM(ROOT '/' x'00000001' x'00000000' 'Root File System Share' x'00000002' x'ffffffff' x'00000000') 
* 更改目錄分享 Change File Server Share (QZLSCHFS) 更改目錄分享
  CALL QZLSCHFS PARM(ROOT '/' x'00000001' x'00000000' 'Root File System Share' x'00000002' x'ffffffff' x'00000000') 

  Add and change file server share. 

  ROOT - 分享名稱 share name 
  '/' - 分享路徑 path name 
  x'00000001' - 分享路徑長度 length of path name 
  x'00000000' - 路徑名稱的字元頁碼 CCSID encoding of path name (0 indicates same as job) 
  'Root File System Share' - 分享說明 text description 
  x'00000002' - 分享權限 permissions (2 指可讀寫 indicates r/w) 
  x'ffffffff' - 同時可以幾個人存取分響目錄 maximum users (-1 只不限制 indicates no max) 
  x'00000000' - used in error code structure 

* Add Print Server Share (QZLSADPS)
  CALL QZLSADPS PARM(OUTQ 'QPRINT QGPL ' 'default iSeries outq' x'00000001' 'IBM 4039 LaserPrinter' x'00000000') 

* Change Print Server Share (QZLSCHPS)
  CALL QZLSCHPS PARM(OUTQ 'QPRINT QGPL ' 'default iSeries outq' x'00000001' 'IBM 4039 LaserPrinter' x'00000000') 

  Add and change print server share. 

  OUTQ - share name 
  'QPRINT QGPL ' - qualified output queue (10 spaces needed for queue, and 10 for library) 
  'default iSeries outq' - text description 
  x'0000001' - spool file type (1 indicates *USERASCII, 2 *AFP, 3 *SCS) 
  'IBM 4039 LaserPrinter' - print driver type (indentifes appropriate print driver for share) 
  x'00000000' - used in error code structure 

* Change Server Guest (QZLSCHSG)
  CALL QZLSCHSG PARM(lowauth x'00000000') 
  
  lowauth - name of guest user profile 
  x'00000000' - used in error code structure 

* Change Server Information (QZLSSCHSI)
  CALL QZLSCHSI PARM(RequestVar x'00000112' ZLSS0100 x'00000000') 

  RequestVar - variable holding input data structure 
  x'00000112' - length of variable data 
  ZLSS0100 - format requested for change (ZLSS0100 indicates server information) 
  x'00000000' - used in error code structure 

* 更改 NetServer 名稱 Change Server Name (QZLSCHSN)
  CALL QZLSCHSN PARM(qas400 smbmania 'demo server' x'00000000') 

  qas400 - server name 
  smbmania - domain name 
  'demo server' - text description
  x'00000000' - used in error code structure 

* 停止NetServer End Server (QZLSENDS)
  CALL QZLSENDS PARM(x'00000000') 

* End Server Session (QZLSENSS)
  CALL QZLSENSS PARM(bucky x'00000000') 
  
  bucky - workstation name 
  x'00000000' - used in error code structure 

* List Server Information (QZLSLSTI)
  CALL QZLSLSTI PARM('OUTDATA TEST ' ZLSL0100 *ALL x'00000000') 

  'OUTDATA TEST ' - name of user space to receive information (10 spaces needed for space name, 10 for library) 
  ZLSL0300 -format of data requested (ZLSL0100 indicates configuration information) 
  *ALL - information qualifier 
  x'00000000' - used in error code structure 


* Open List of Server Information (QZLSOLST)
* 移除目錄分享設定 Remove Server Share (QZLSRMS)
  CALL QZLSRMS PARM(OUTQ x'00000000') 
  
  OUTQ - share name 
  x'00000000' - used in lieu of error code structure 

* 啟動NetServer Start Server (QZLSSTRS)
  CALL QZLSSTRS PARM('0' x'00000000') 
 

這個 QZLSADFS API 使用於設定目錄分享,底下是如何使用 QZLSADFS API 的範例:

* Call the create share API.
C      CreateShare   BegSr

C                    Call     'QZLSADFS'
C                    Parm                    ShrName
C                    Parm                    ShrPath
C                    Parm                    ShrPathLen
C                    Parm                    PathCcsid
C                    Parm                    ShrTextDesc
C                    Parm                    Permissions
C                    Parm                    ShrMaxUsrs
C                    Parm                    ErroeCode

C                    EndSr 

"ShrName" 指的是 Windows 環境中所看到的目錄分享的名稱,"ShrPath" 指的是 IFS 所要分享的目錄
全名,"ShrTextDesc" 是目錄分享的說明,"ShrPathLen" 是分享目錄全名即 "ShrPath" 的長度,執行
這個副程序會指定一個 IFS 的目錄路徑分享,這允許 Windows 使用者從網路芳鄰看到此分享目錄的檔
案,並且可以存取分享目錄下的檔案。

有關 As/400(iSeries) NetServer 詳細資料請參照 http://www-1.ibm.com/servers/eserver/iseries/netserver/

在這篇文章中,我們提到從拷貝報表資料至資料庫檔案,再從資料庫檔案拷貝至 IFS 的分享目錄中,並
設定目錄分享,讓 Windows 使用者可以可以從網路磁碟機存取資料,藉由這些步驟,您能自行整合從
AS/400 的報表至 Windows PC 的文字檔,並將此流程自動化。我想留這個如何自動化的工作給您自行完
成,因為我知道您可以完成。 在此我僅給您一個間單的 Outq 監控的範例 MONOUTQC CLP 範例。


/*                                                             */
/* *********************************************************** */
/* *                                                         * */
/* * PROGRAM MONOUTQC                                        * */
/* *                                                         * */
/* * By Vengoal Chang                                        * */
/* * DATE 8/29/2002                                          * */
/* *                                                         * */
/* *********************************************************** */
/*                                                             */
/*                                                             */
/* MONOUTQC - READ DTAQ AND CONVERT SPOOL FILE                 */
/*                                                             */
/* This Program:                                               */
/* - Wait up to 300 seconds to receive an entry from           */
/*   the data queue                                            */
/* - If no entry read, it check if the program should end      */
/* The program stop if:                                        */
/* - Job was cancel with a ENDJOB command                      */
/* - Subsystem was stop ENDSBS command                         */
/* - System shut down PWRDWNSYS command                        */
/* - If the entry is "STOP" program stop immediately           */
/* - Split the entry in fields                                 */
/* - Call program CVTSSPL to do the spool file conversion     */
/* - Move or Delete the spool file                             */
/* - Return wait for an entry                                  */
/*                                                             */
/*-------------------------------------------------------------*/
/*                                                             */
/* PROGRAM CHANGES                                             */
/*                                                             */
/* VERSION DATE PROGRAMMER DETAIL                              */
/*     YY/MM/DD                                                */
/*                                                             */
/* 1.0 02/08/29 Vengoal INITIAL VERSION                        */
/*                                                             */
/*-------------------------------------------------------------*/

         PGM

         DCL &DTAQNAME *CHAR  10 VALUE(CVTSDTAQ)
         DCL &DTAQLIB  *CHAR  10 VALUE(*LIBL)
         DCL &ENTLEN   *DEC    5 VALUE(128)
         DCL &ENTRY    *CHAR 128
         DCL &WAIT     *DEC    5 VALUE(300)
         DCL &ENDSTS   *CHAR   1
         DCL &SPLFIL   *CHAR  10
         DCL &JOBNAM   *CHAR  10
         DCL &JOBUSR   *CHAR  10
         DCL &JOBNBR   *CHAR   6
         DCL &SPLNBRB  *CHAR   4 /* BINARY */
         DCL &SPLNBRD  *DEC    6 /* DECIMAL */
         DCL &SPLNBR   *CHAR   6 /* CHARACTER */
         DCL &OUTQN    *CHAR  10
         DCL &OUTQL    *CHAR  10
         DCL &USRDTA   *CHAR  10

/* ----------------------------------------------------------------- */
/* RECEIVE AN ENTRY FROM THE DTAQ (FIRST IN FIRST OUT)               */
/* ----------------------------------------------------------------- */
         RCVDTAQ: CALL PGM(QRCVDTAQ) PARM(&DTAQNAME &DTAQLIB +
                                          &ENTLEN &ENTRY &WAIT)

/* ----------------------------------------------------------------- */
/* CHECK IF AN ENTRY WAS RECEIVE OR TIMEOUT                          */
/* ----------------------------------------------------------------- */
         IF COND(&ENTLEN *EQ 0) THEN(GOTO CMDLBL(TIMEOUT))

/* ----------------------------------------------------------------- */
/* CHECK IF THE ENTRY RECEIVE IS THE "STOP" COMMAND                  */
/* ----------------------------------------------------------------- */
         IF COND(%SST(&ENTRY 1 4) *EQ 'STOP') THEN(GOTO +
                                                   CMDLBL(END))

/* ----------------------------------------------------------------- */
/* READ THE FIELD FROM THE RECEIVE ENTRY                             */
/* ----------------------------------------------------------------- */
         CHGVAR &JOBNAM VALUE(%SST(&ENTRY 13 10))
         CHGVAR &JOBUSR VALUE(%SST(&ENTRY 23 10))
         CHGVAR &JOBNBR VALUE(%SST(&ENTRY 33 6))
         CHGVAR &SPLFIL VALUE(%SST(&ENTRY 39 10))
         CHGVAR &SPLNBRB VALUE(%SST(&ENTRY 49 4))
         CHGVAR &SPLNBRD VALUE(%BIN(&SPLNBRB))
         CHGVAR &SPLNBR &SPLNBRD

/* ----------------------------------------------------------------- */
/* CALL PROGRAM CVTSPL TO WORK WITH THE SPOOL                      */
/* 您需要依自己的需求自行撰寫 CVTSPL                                 */
/* 於 CVTSPL 中可以 CPYSPLF Copy spooled file TO DB                  */
/* 並 CPYTOSTMF Copy to Stream File                                */
/* ----------------------------------------------------------------- */      
         
         CALL PGM(CVTSPL) PARM(&ENTRY &OUTQN &OUTQL +
                                 &USRDTA)

/* ----------------------------------------------------------------- */
/* Move or Delete the spool file                                     */
/* ----------------------------------------------------------------- */
         IF COND(&OUTQN *EQ '*DELETE') THEN(DLTSPLF +
                           FILE(&SPLFIL) +
                           JOB(&JOBNBR/&JOBUSR/&JOBNAM) +
                           SPLNBR(&SPLNBR) SELECT(*ALL))
         ELSE CMD(CHGSPLFA FILE(&SPLFIL) +
                           JOB(&JOBNBR/&JOBUSR/&JOBNAM) +
                           SPLNBR(&SPLNBR) SELECT(*ALL) +
                           OUTQ(&OUTQL/&OUTQN) USRDTA(&USRDTA))

/* ----------------------------------------------------------------- */
/* GO READ NEXT ENTRY IN THE DTAQ                                    */
/* ----------------------------------------------------------------- */
         GOTO CMDLBL(RCVDTAQ)

/* ----------------------------------------------------------------- */
/* TIME OUT (CHECK IF THE JOB MUST END)                              */
/* ----------------------------------------------------------------- */
TIMEOUT: RTVJOBA ENDSTS(&ENDSTS)
         IF COND(&ENDSTS *EQ '1') THEN(GOTO CMDLBL(END))
         ELSE CMD(GOTO CMDLBL(RCVDTAQ))
         GOTO CMDLBL(RCVDTAQ)

/* ----------------------------------------------------------------- */
/* ERROR HANDLING                                                    */
/*                                                                   */
/* ----------------------------------------------------------------- */
ERROR:
         GOTO CMDLBL(RCVDTAQ)
END:     ENDPGM




新增 OS/400 的目錄分享指令範例

使用範例:
分享 OS/400 CD Drive 給 Windows 使用者
 
ADDSHARE SHARENAME(AS400CD) PATHNAME('/QOPT') TEXTDESC('AS400 CD DRIVER')
-----------------------------------------------------------------------
CMD Creation

CRTCMD CMD(yourlib/ADDSHARE) PGM(yourlib/ADDSHARE) +
    SRCFILE(yourlib/yourPFSourceFile) SRCMBR(ADDSHARECM)

-----------------------------------------------------------------------
ADDSHARECM.CMD Source

CMD
             PARM       KWD(SHARENAME) TYPE(*CHAR) LEN(12) +
                          CHOICE('New Share Name (MAX:12 chars)') +
                          PMTCTL(*PMTRQS) PROMPT('Share Name')
             PARM       KWD(PATHNAME) TYPE(*CHAR) LEN(20) +
                          CHOICE('First char must be slash U/U') +
                          PMTCTL(*PMTRQS) PROMPT('Share Path') /* +
                          'First char must be slash U/U' */
             PARM       KWD(TEXTDESC) TYPE(*CHAR) LEN(50) +
                          CHOICE('Share Comment') PMTCTL(*PMTRQS) +
                          PROMPT('Share comment') /* 'Share comment' */
             PARM       KWD(PERMS) TYPE(*CHAR) LEN(4) RTNVAL(*NO) +
                          RSTD(*YES) DFT(1) VALUES(1 2) +
                          CHOICE('Permissions (1: R/O, 2:R/W)') +
                          PMTCTL(*PMTRQS) PROMPT('Permissons') /* +
                          '1: READ/ONLY 2:READ/WRITE' */
             PARM       KWD(MAXUSERS) TYPE(*CHAR) LEN(4) RSTD(*NO) +
                          DFT(-1) RANGE(-1 255) CHOICE('Max users +
                          (-1 to 255,-1:NOMAX)') PMTCTL(*PMTRQS) +
                          PROMPT('Max users')
-----------------------------------------------------------------------
ADDSHARE.CLP Source

/*****************************************************************/
/*                                                               */
/* ADD WINDOWS SHARE FOR AS/400                                  */
/*                                21.02.2002 MAB13               */
/*****************************************************************/
PGM PARM(&SHARENAME &PATHNAME &TEXTDESC &PERMS &MAXUSERS)

DCL VAR(&SHARENAME ) TYPE(*CHAR) LEN(12)

DCL VAR(&PATHNAME )  TYPE(*CHAR) LEN(20)
DCL VAR(&PATHNAMEL)  TYPE(*CHAR) LEN(4)

DCL VAR(&CCSPATHN)   TYPE(*CHAR) LEN(4)
DCL VAR(&TEXTDESC)   TYPE(*CHAR) LEN(50)
DCL VAR(&PERMS)      TYPE(*CHAR) LEN(4)
DCL VAR(&PERMSP)     TYPE(*CHAR) LEN(4)

DCL VAR(&MAXUSERS)   TYPE(*CHAR) LEN(4)
DCL VAR(&MAXUSERSP)  TYPE(*CHAR) LEN(4)

DCL VAR(&ERRORCODE)  TYPE(*CHAR) LEN(255)

DCL &LENGTH *DEC LEN(2) VALUE(20)
DCL &LENGTHC *CHAR LEN(4)


CHGVAR     VAR(%BIN(&CCSPATHN)) VALUE(0)
CHGVAR     VAR(%BIN(&MAXUSERSP)) VALUE(&MAXUSERS)
CHGVAR     VAR(%BIN(&PERMSP)) VALUE(&PERMS)

LOOP:
IF (%SUBSTRING(&PATHNAME &LENGTH 1) *EQ ' ') (DO)
    CHGVAR VAR(&LENGTH) VALUE(&LENGTH - 1)
    IF (&LENGTH *EQ 0) GOTO CMDLBL(EXIT)
    GOTO CMDLBL(LOOP)
ENDDO

CHGVAR VAR(&LENGTHC) VALUE(&LENGTH)
CHGVAR VAR(%BIN(&PATHNAMEL)) VALUE(&LENGTHC)


CALL       PGM(QZLSADFS) +
                PARM(&SHARENAME  +
                     &PATHNAME   +
                     &PATHNAMEL  +
                     &CCSPATHN   +
                     &TEXTDESC   +
                     &PERMSP     +
                     &MAXUSERS   +
                     &ERRORCODE)

IF (&ERRORCODE *NE '*') +
   SNDPGMMSG MSG('ERROR CODE:' *CAT &ERRORCODE)
   ELSE SNDPGMMSG MSG('SHARED RESOURCES SUCCESSFULY ADDED')
EXIT:
ENDPGM

-----------------------------------------------------------------------

Add File Server Share (QZLSADFS) API Parameters

 Required Parameter Group: 

1  Share name  Input  CHAR(12)  
2  Path name  Input  CHAR(*)  
3  Length of path name  Input  BINARY(4)  
4  CCSID encoding of path name  Input  BINARY(4)  
5  Text description  Input  CHAR(50)  
6  Permissions  Input  BINARY(4)  
7  Maximum users  Input  BINARY(4)  
8  Error code  I/O  CHAR(*)  
-----------------------------------------------------------------------
API Error Messages
CPF3C1E E  Required parameter &1 omitted.  
CPF3C36 E  Number of parameters, &1, entered for this API was not valid.  
CPF3CF1 E  Error code parameter not valid.  
CPF3CF2 E  Error(s) occurred during running of &1 API.  
CPFA0D4 E  File system error occurred.  
CPFB682 E  API &1 failed with reason code &2.  
CPFB683 E  Data conversion failed for API &1.  
CPFB684 E  User does not have the correct authority for API &1.  
CPFB68A E  Error occurred while working with shared resource &2.  
CPFB68B E  Character is not valid for value &3.  
CPFB68D E  Length specified in parameter &2 for API &1 not valid.  
CPFB693 E  Data conversion failed for &5 API.  
CPIB685 E  Error occurred on AS/400 Support for Windows Network Neighborhood (AS/400 NetServer) request.  

更詳細資訊請參照手冊 OS/400 Printer Device Programming V4R4
http://publib.boulder.ibm.com/cgi-bin/bookmgr/books/qb3auj03/COVER

AS/400 印表機相關列印的手冊
http://www.printers.ibm.com/R5PSC.NSF/Web/4man



沒有留言: