PDA

View Full Version : api QSPGETSP mit SPFR0300, wie bekommt man aus dem userspace etwas ausgelesen?



Seiten : [1] 2

karin
06-02-18, 15:04
hallo allerseits,

habe gerade etwas zeit zum basteln und wollte mal userspace-auslesen üben.
habe dazu einen userspace erstellt und mit dem API QSPGETSP vermutlich auch befüllt, also es sollten sich nun print-Daten einer existierenden spoolfile darin befinden.
über diverse quellen habe ich auch das aufsetzen und auslesen eines userspaces ins Programm kopiert, aber es tut sich NIX. falsch, es kommt diese Fehlermeldung:
MCH0601
Space offset X'00000000' or X'0000000000000000' is outside current limit
for object @USERSPACE.

bevor ich nun meinen code hier reinkopiere erst mal eine frage: hat irgendjemand hier aus dem Forum jemals schon mal spooldaten über api ausgelesen?

im Internet weisen alle auf den cpysplf hin, interessiert mich alles für diesen trainingsfall nicht. ich möchte rein aus übungszwecken das ding mal mit APIs umsetzen. die Daten, die der userspace auswerfen soll, möchte ich nur mal zum spaß mit dsply anzeigen, mehr nicht.

merci im voraus!!!
//karin

PS: mit der doku kann ich leider nicht viel anfangen, die print-Daten zum Format SPFR0300 sind so umständlich dokumentiert, verstehe nur Bahnhof. vielleicht kann mir da jemand mit einem Beispiel helfen?

Fuerchau
06-02-18, 15:29
Nun, dazu gibt es die USRSPC-API's (den Link findest du bestimmt;-).
Mittels QUSCRTUS lege ich einen USRSPC erst mal an (ich weiß nämlich nicht, ob das Spool-API dies tut).
Nun gibt es das QUSRTVUS-API um die Daten auszulesen.
Am Einfachsten ist es allerdings, im RPGle mit Pointern umzugehen als mit dem API.
Per QUSPTRUS bekommst du einen Pointer für direkten Zugriff auf das USRSPC-Objekt:

dMyUsPtr *
dMyUsHDR ds based(MyUsPtr)

In MyUsHdr kannst du die Felder anlog der API-Beschreibung definieren.

Nun nimm als Beispiel die Adresse "Offset to First Buffer":

dMyFrstBptr *
dMyBuffer ds based(MyFrstBptr)

Mittels "eval MyFrstBptr = MyUsPtr + OffsetfBuffer" weist du die Adresse zu und hast Zugriff auf den Puffer des 1. Satzes.
Da die Informationen geschachtelt sind, ist es eine Rechnerei mitr den ganzen Adressen, aber doch relativ einfach, da du für jeden Typ der Information eine Based-DS nehmen kannst und den dazugehörigen Pointer über den Basis-Ptr und die relative Adresse ermitteln kannst.

karin
07-02-18, 06:23
....
Mittels "eval MyFrstBptr = MyUsPtr + OffsetfBuffer" weist du die Adresse zu und hast Zugriff auf den Puffer des 1. Satzes.
....

yepp, das habe ich alles. die entscheidende stelle, wo es bei mir hakt, und da habe ich vermutlich einen Denkfehler oder was auch immer, ist die stelle, wo ich auf den puffer zugreife.
sieht so aus mein Programm

if open_spoolfile();
if create_userspace();
// Befüllen des User Space
fill_userspace();
// Zugriff auf User Space
GetPointer(USERSPACENAME:UserSpacePointer);
//User Space Informationen verarbeiten
For UserSpaceCounter = 1 to ListHeader.Count;
FieldPointer = UserSpacePointer + ListHeader.Offset
+ (ListHeader.Size * (UserSpaceCounter - 1));
// irgendwas mit den Daten machen
dsplytext = 'DS_SPFR0300.PRINT_DATA= '
+ %editc(DS_SPFR0300.PRINT_DATA:'X') ;
dsply dsplytext ;
endfor;
// Userspace löschen
delete_userspace();
endif;
Close_spoolfile();
endif;


das befüllen sieht so aus (vielleicht etwas übel geschrieben, aber ich arbeite viel mit DSen)
ds_QSPGETSP.Spooled_file_handle
= ds_QSPOPNSP.Spooled_file_handle_returned;
ds_QSPGETSP.Qualified_user_space_name = USERSPACENAME;
ds_QSPGETSP.Format_name = 'SPFR0300';
ds_QSPGETSP.Ordinal_number_of_buffer_to_be_read = 8;
ds_QSPGETSP.End_of_open_spooled_file = '*ERROR';
clear ds_Error_code_ERRC0100;
ds_QSPGETSP.Error_code = ds_Error_code_ERRC0100;
// Einlesen Spoolfile in den Userspace
QSPGETSP(ds_QSPGETSP.Spooled_file_handle
: ds_QSPGETSP.Qualified_user_space_name
: ds_QSPGETSP.Format_name
: ds_QSPGETSP.Ordinal_number_of_buffer_to_be_read
: ds_QSPGETSP.End_of_open_spooled_file
: ds_QSPGETSP.Error_code
);

die Routinen create_userspace(), getpointer(...) und delete_userspace() sehen so aus, als würden sie ordnungsgemäß laufen

hier noch ein paar variablen :

dcl-s UserSpacePointer Pointer;
dcl-s FieldPointer Pointer;
Dcl-Ds ListHeader Based(UserSpacePointer) Qualified;
Offset Int(10) Pos(125);
Count Int(10) Pos(133);
Size Int(10) Pos(137);
End-Ds;
Dcl-Ds ds_SPFR0300 Based(FieldPointer) Qualified;
print_data int(10) pos(1); end-ds;
Dcl-S UserSpaceCounter uns(20) inz;
Dcl-S dsplytext char(50) inz;


wenn ich nun mein Programm laufen lasse, kommen diese Meldungen:

call testspoolf parm('jobname' 'user' '887773' 'TESTSPOOLF' '000001')
Ownership of object @USERSPACE in QTEMP type *USRSPC changed.
DSPLY DS_SPFR0300.PRINT_DATA= 0000000000
Space offset X'00000000' or X'0000000000000000' is outside current limit
for object @USERSPACE.
End of requests.

ich weiß nicht so recht, wie ich den puffer behandeln soll... oder ob im userspace wirklich was drinsteht (wie kann man das prüfen?)

lg karin

jajonowak
07-02-18, 07:12
moin,

da gab es mal einen Befehl dspusrspc in der Bibl. TAATOOL

Fuerchau
07-02-18, 08:05
Die TAATOOLS gibt es (leider) nicht mehr, allerdings kann man sich da auch mit DMPOBJ/DMPSYSOBJ behelfen.
Ggf. ein Grundsätzlicher Fehler:
Die RPG-Zählung bei Positionen in der DS "POS(nn)" beginnt bei 1, die relative Position zu einer Adresse bei 0. Die API-Strukturen beginnen ebenso bei 0.
Ich hoffe, du hast dies berücksichtigt.

Beim Aufruf des Spool-API's gibt es eine Error-Struktur, die man korrekt definieren muss um einen Fehler mitzubekommen. In diesem Fall ist das API bereits gescheitert und im USRSPC steht halt nichts.

ErrorStru DS <= nur schematisch;-)
AvailBytes bin(4) inz(%size(ErrorStru))
ProvBytes bin(4) inz(0)
ErrorId char(7) inz <= CPFxxxx
unused char(1) inz
ErrorData char(512) inz <= eigentlich beliebig, Daten zur CPF

Wenn du
clear ds_Error_code_ERRC0100;
ausführst, löscht du ebenso auch AvailBytes und kein API gibt einen Fehler zurück noch wird einer ausgelöst.
Dies ist vollkommen unnötig.
Ist nach dem API-Call ProvBytes > 0, dann ist ein Fehler aufgetreten, ansonsten sollten Daten im USRSPC stehen.

Auch dieses ist falsch:
FieldPointer = UserSpacePointer + ListHeader.Offset + (ListHeader.Size * (UserSpaceCounter - 1));
Wenn du die Strukturen ansiehst, so enthält jeder Eintrag seine eigene Länge.
Somit bekommt der Fieldpointer die 1. Adresse und muss um die Länge der Beschreibung verschoben werden. Die Anzahl der Einträge steht dann im Header, das ist korrekt.

karin
07-02-18, 09:06
hallo allerseits,

taatool hab ich hier, dspusrspc -> super!!
boardmittel dmpobj -> DANKE!!!

jetzt weiß ich zumindest, daß der userspace korrekt gefüllt ist

werde mich nun den restlichen fehlern widmen...

die ds_Error_code_ERRC0100 ist gemäß ibm-doku erstellt, müßte zumindest einigermaßen richtig sein, wenngleich ich das mit dem clear noch nicht verstanden habe warum ich den nicht machen soll. ich dachte, in der error steht dann nach dem prozeduraufruf ein fehler drin, wenn er zurückkommt? und aus Gewohnheit mache ich die felder vor dem prozeduraufruf leer. (nicht gut??)

dcl-ds ds_Error_code_ERRC0100 qualified ;
Bytes_provided int(10) Inz(%size(ds_Error_code_ERRC0100));
Bytes_available int(10) inz;
Exception_ID char(7);
Reserved char(1);
Exception_data varchar(128); -------------> änder ich gleich auf 512
end-ds;

zum rest:

ich vermute, daß die logik, wie ich den fieldpointer errechne, noch nicht richtig ist. könnte daran liegen, daß ich dieses code-schnipsel kopiert habe aus einem Programm, das einen userspace mit völlig anderen Daten ausliest, wo das halt so paßt, hier aber halt eben nicht. werde weiter forschen :-)

lg karin

Pikachu
07-02-18, 09:28
DSPF und EDTF können übrigens auch mit Benutzerbereichen umgehen:

DSPF STMF('/QSYS.LIB/Bibliothek.LIB/Name.USRSPC')
EDTF STMF('/QSYS.LIB/Bibliothek.LIB/Name.USRSPC')

Zu den Fehler-Formaten:
Die Inhalt der einzelnen Felder der Fehler-Formate sind hier im Detail beschrieben (https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_73/apiref/errorcodeformat.htm).

Fuerchau
07-02-18, 11:02
Ein Clear initialisiert mit dem Default.
Ein Reset initialisiert mit den Werten, die durch INZ oder in der *INZSR festgelegt ist.

Mit "Bytes_provided" teilst du dem API mit, wie lang der Puffer ist, den du im Fehlerfall eben zur Verfügung stellst.
Nach dem Clear initialisiert du mit 0, also wir die Errorstruktur nicht gefüllt.

Bei manchen API's kann man die Errorstruktur auch weglassen. In diesem Fall wird eine Escape-Message gesendet, die mit einer Monitor-Gruppe überwacht werden kann.

Die Länge der Exception_data ist vollkommen egal, es kommt halt auf die möglichen Fehler-ID's und die verwendeten Datenfelder an (siehe DSPMSGD, Felddefinitionen).
Willst du die Daten gar nicht auswerten, kann man das Feld auch weglassen.
D.h., die Minimal-Struktur ist 16 Bytes.

DMPOBJ/EDTF können eben auch Hex anzeigen, so dass man die Strukturen mit den relativen Adressen sich genauer anschauen kann.

karin
07-02-18, 13:25
ok, ich habe jetzt ein Ergebnis hinbekommen, nicht schön, aber übungszweck erfüllt.
fehler war tatsächlich die Adressierung des userspaces, diese habe ich geändert und nun sieht es schon ganz gut aus. ich kann die Inhalte des userspace z.b. mit DSPLY anzeigen, mehr brauche ich erst mal nicht.

nun müßte ich noch eine sinnvolle schleife bauen und irgendwas sinnvolles mit dem userspace machen. hhm. wie ziemlich viele leute im Internet schon angedeutet haben, die spooldaten stehen nicht vollends brauchbar im userspace, jetzt müßte man Steuerzeichen rausfieseln und ähnliches. ist mir aber für den übungszweck nicht förderlich, lasse ich also erst mal bleiben.

zumal ich das zusammenspiel von buffern, sizes und Offsets (beim spool-API Satzart SPFR0300) noch nicht durchdrungen habe. die logischen Erklärungen passen nicht zum DSPLY-Ergebnis, da muß es wohl noch ein paar kniffe geben, die sich mir nicht erschließen.

lange rede kurzer sinn: ich habe einiges dazugelernt und bekomme nun wenigstens ein ordentliches grundgerüst für API-Verwendung hin, das war die grundidee der Übung.

danke für alle hinweise!!
lg karin

BenderD
07-02-18, 20:47
... einfacher geht es mit verfügbaren Komponenten (wer die bei sich reinkopiert, hat da etwas nicht verstanden!). Siehe: http://bender-dv.de/Snippets.html#APILIST

D*B