Les API système, ce que le langage ne sait pas faire
Les deux familles d'API, programmes et procédures, le code erreur qu'elles partagent, puis quatre exemples : une file de données entre deux programmes, une commande lancée depuis le RPG, la description d'un objet et un écran 5250 écrit sans DSPF. En CL, en RPG IV colonné, en full free et en SQL, tout exécuté sur un IBM i 7.5.
En une phrase
Une API système est un programme ou une procédure qu'IBM livre avec le système, et qu'on appelle depuis son propre programme pour faire ce qu'aucune instruction du langage ne fait : échanger des messages par une file de données, lire la description d'un objet, exécuter une commande, écrire sur l'écran.
Deux familles : les programmes et les procédures
La différence tient à la façon de les appeler. Une API programme est un objet *PGM de QSYS : on l'appelle par CALL, comme n'importe quel programme, depuis tous les langages. Une API procédure est une procédure exportée par un programme de service : il faut un programme ILE, qui la lie à la compilation.
| Famille | Objet | Appel | Langages | Exemples |
|---|---|---|---|---|
| API programme | *PGM (OPM) | CALL, ou un prototype EXTPGM | Tous, même le CL | QSNDDTAQ, QRCVDTAQ, QCMDEXC, QUSROBJD |
| API procédure | Procédure d'un *SRVPGM (ILE) | Prototype EXTPROC, programme lié | ILE : RPG avec DFTACTGRP(*NO), C, CL ILE | QsnWrtDta, QsnGetAID (QSNAPI) |
Les noms le disent souvent : en majuscules (QSNDDTAQ) pour un programme, en casse mixte (QsnWrtDta)
pour une procédure. En RPG, les deux s'appellent par un prototype : EXTPGM pour un
programme, EXTPROC pour une procédure (voir PR et PI).
Pour les procédures, pas besoin de déclarer le programme de service : sur la machine des exemples,
QSNAPI est dans le répertoire de liage QUSAPIBD, que le compilateur consulte de
lui-même.
Le code erreur, commun aux API
La plupart des API prennent en dernier paramètre une structure code erreur. Son premier champ décide de ce qui se passe en cas d'erreur :
| Position | Champ | Type RPG | Sens | Rôle |
|---|---|---|---|---|
| 1 | Octets fournis | int(10) | Entrée | Taille de la structure. 0 : l'erreur part en message d'exception. 8 ou plus : elle est rangée ici. |
| 5 | Octets disponibles | int(10) | Sortie | 0 : aucune erreur, le reste de la structure n'est pas modifié. |
| 9 | Identifiant | char(7) | Sortie | Le message, par exemple CPF9801. |
| 16 | Réservé | char(1) | ||
| 17 | Données | char(*) | Sortie | Les variables du message, par exemple le nom de l'objet. |
Le piège classique : oublier d'initialiser les octets fournis. Une valeur au hasard fait croire à l'API
que la structure est plus grande qu'elle n'est. D'où le inz(%size(codeErreur)) des
exemples. Les deux comportements sont montrés plus bas, avec QUSROBJD.
Exemple 1 Une file de données
QSNDDTAQ et QRCVDTAQ : des commandes entre deux programmes
Une file de données (*DTAQ) fait passer des messages d'un programme à un autre, du même
travail ou d'un autre : l'un dépose, l'autre retire, dans l'ordre d'arrivée. Ici, ENVOICL dépose trois
commandes et un programme RPG les lit. La file a été créée par la commande CRTDTAQ,
que lance le programme de l'exemple 2 :
CRTDTAQ DTAQ(JOBIAPI/COMMANDES) MAXLEN(50) TEXT('Commandes a traiter')
CL ENVOICL
/* ENVOICL : dépose trois commandes dans la file COMMANDES */
/* par l'API QSNDDTAQ (un programme : on l'appelle par CALL). */
PGM
DCL VAR(&LONG) TYPE(*DEC) LEN(5 0) VALUE(50)
DCL VAR(&DATA) TYPE(*CHAR) LEN(50)
CHGVAR VAR(&DATA) VALUE('CDE-0001 ACM 3 x Clavier')
CALL PGM(QSNDDTAQ) PARM('COMMANDES' 'JOBIAPI' &LONG &DATA)
CHGVAR VAR(&DATA) VALUE('CDE-0002 BTP 1 x Ecran 27p')
CALL PGM(QSNDDTAQ) PARM('COMMANDES' 'JOBIAPI' &LONG &DATA)
CHGVAR VAR(&DATA) VALUE('CDE-0003 ACM 10 x Souris')
CALL PGM(QSNDDTAQ) PARM('COMMANDES' 'JOBIAPI' &LONG &DATA)
SNDPGMMSG MSG('3 commandes déposées dans COMMANDES')
ENDPGM RPG IV colonné RECOIT4
H* RECOIT4 : lit les commandes en attente dans la file COMMANDES
DLONGUEUR S 5P 0
DDONNEES S 50A
DATTENTE S 5P 0 INZ(0)
DNOMBRE S 10I 0
DTEXTE S 52A
C* CALL et PARM : l'appel d'un programme, a l'ancienne
C* Attente 0 : rend la main tout de suite ; longueur 0 = file vide
C DOU LONGUEUR = 0
C CALL 'QRCVDTAQ'
C PARM 'COMMANDES' FILE 10
C PARM 'JOBIAPI' BIB 10
C PARM LONGUEUR
C PARM DONNEES
C PARM ATTENTE
C IF LONGUEUR > 0
C EVAL NOMBRE = NOMBRE + 1
C DONNEES DSPLY
C ENDIF
C ENDDO
C EVAL TEXTE = 'Commandes lues : ' + %CHAR(NOMBRE)
C TEXTE DSPLY
C EVAL *INLR = *ON Full free RECOITF
**FREE
// RECOITF : lit les commandes en attente dans la file COMMANDES
dcl-pr QRCVDTAQ extpgm('QRCVDTAQ');
file char(10) const;
bibliotheque char(10) const;
longueur packed(5:0);
donnees char(50);
attente packed(5:0) const;
end-pr;
dcl-s longueur packed(5:0);
dcl-s donnees char(50);
dcl-s nombre int(10);
// Attente 0 : l'API rend la main tout de suite ; longueur 0 = file vide
dow '1';
QRCVDTAQ('COMMANDES' : 'JOBIAPI' : longueur : donnees : 0);
if longueur = 0;
leave;
endif;
nombre += 1;
dsply %subst(donnees : 1 : longueur);
enddo;
dsply ('Commandes lues : ' + %char(nombre));
*inlr = *on; CALL 'QRCVDTAQ'et sesPARM- En colonné, l'appel d'un programme à l'ancienne : un PARM par paramètre, dans l'ordre de la documentation. Les littéraux 'COMMANDES' et 'JOBIAPI' vont dans des zones de 10 caractères, définies sur la ligne du PARM.
dcl-pr QRCVDTAQ extpgm('QRCVDTAQ');- En full free, un prototype : le compilateur vérifie le nombre et le type des paramètres.
Le mot-clé
constmarque ceux que l'API ne modifie pas : on peut alors passer des littéraux. longueur packed(5:0)etattente packed(5:0)- Les types de la documentation, à respecter : Packed(5,0). Une attente de 0 rend la main tout de suite, avec une longueur de 0 si la file est vide ; négative, l'API attend sans fin ; positive, elle attend ce nombre de secondes.
CALL QCMD
ADDLIBLE JOBIAPI
CALL ENVOICL
CALL RECOITF
CALL ENVOICL
CALL RECOIT4


La même file, vue et utilisée en SQL
Avant la lecture, juste après ENVOICL, QSYS2.DATA_QUEUE_ENTRIES montre le contenu de la file sans rien retirer :
SELECT ORDINAL_POSITION, MESSAGE_DATA
FROM TABLE(QSYS2.DATA_QUEUE_ENTRIES(DATA_QUEUE => 'COMMANDES',
DATA_QUEUE_LIBRARY => 'JOBIAPI')) ORDINAL_POSITION | MESSAGE_DATA |
|---|---|
1 | CDE-0001 ACM 3 x Clavier |
2 | CDE-0002 BTP 1 x Ecran 27p |
3 | CDE-0003 ACM 10 x Souris |
SELECT DATA_QUEUE_TYPE, MAXIMUM_MESSAGE_LENGTH, SEQUENCE, CURRENT_MESSAGES
FROM QSYS2.DATA_QUEUE_INFO
WHERE DATA_QUEUE_LIBRARY = 'JOBIAPI' DATA_QUEUE_TYPE | MAXIMUM_MESSAGE_LENGTH | SEQUENCE | CURRENT_MESSAGES |
|---|---|---|---|
STANDARD | 50 | FIFO | 3 |
Les procédures QSYS2.SEND_DATA_QUEUE et QSYS2.RECEIVE_DATA_QUEUE font le travail de QSNDDTAQ et de QRCVDTAQ :
CALL QSYS2.SEND_DATA_QUEUE(MESSAGE_DATA => 'CDE-0004 BTP 2 x Casque',
DATA_QUEUE => 'COMMANDES',
DATA_QUEUE_LIBRARY => 'JOBIAPI') SELECT MESSAGE_DATA
FROM TABLE(QSYS2.RECEIVE_DATA_QUEUE(DATA_QUEUE => 'COMMANDES',
DATA_QUEUE_LIBRARY => 'JOBIAPI')) MESSAGE_DATA |
|---|
CDE-0004 BTP 2 x Casque |
RECEIVE_DATA_QUEUE retire le message : DATA_QUEUE_ENTRIES ne rend ensuite plus aucune ligne. Différence avec ENVOICL : SEND_DATA_QUEUE a déposé exactement la longueur du texte, 26 caractères, alors que QSNDDTAQ en dépose 50, la longueur passée en paramètre.
Exemple 2 Une commande depuis le RPG
QCMDEXC : exécuter une commande CL
Le RPG n'a pas d'instruction pour lancer une commande CL : QCMDEXC le fait. Deux paramètres : la commande,
puis sa longueur en packed(15:5). CMDF crée la file de l'exemple 1 :
**FREE
// CMDF : cree la file COMMANDES par l'API QCMDEXC
dcl-pr QCMDEXC extpgm('QCMDEXC');
commande char(3000) const options(*varsize);
longueur packed(15:5) const;
end-pr;
// Statut du programme : identifiant du dernier message d'erreur
dcl-ds etat psds qualified;
message char(7) pos(40);
end-ds;
dcl-s commande varchar(200);
commande = 'CRTDTAQ DTAQ(JOBIAPI/COMMANDES) MAXLEN(50) '
+ 'TEXT(''Commandes a traiter'')';
monitor;
QCMDEXC(commande : %len(commande));
dsply 'File COMMANDES creee';
on-error;
dsply ('CRTDTAQ refuse : ' + etat.message);
endmon;
*inlr = *on; commande char(3000) const options(*varsize)- La commande est passée telle quelle ; sa vraie longueur est donnée par le second paramètre,
%len(commande). monitor; … on-error;- Une commande qui échoue envoie son message d'erreur au programme.
MONITOR l'intercepte, et l'identifiant
du message se lit dans la structure d'état du programme (
psds, positions 40 à 46).

En SQL, la procédure QSYS2.QCMDEXC rend le même service.
Exemple 3 Le code erreur en pratique
QUSROBJD : la description d'un objet
QUSROBJD remplit une zone, le récepteur, avec la description d'un objet, selon un format : OBJD0100 pour l'essentiel, OBJD0200 pour davantage de champs, dont l'attribut et le texte. Le programme décrit le format par une structure, aux positions de la documentation :
**FREE
// OBJDF : description d'un objet par l'API QUSROBJD
dcl-pi *n;
objet char(10);
type char(10);
end-pi;
dcl-pr QUSROBJD extpgm('QUSROBJD');
recepteur char(32767) options(*varsize);
longueur int(10) const;
format char(8) const;
nomQualifie char(20) const;
typeObjet char(10) const;
erreur likeds(codeErreur);
end-pr;
// Debut du format OBJD0200, aux positions donnees par la documentation
dcl-ds objd0200 qualified;
octetsRendus int(10);
octetsDispo int(10);
nom char(10);
bibliotheque char(10);
type char(10);
bibRetour char(10);
asp int(10);
proprietaire char(10);
domaine char(2);
creation char(13);
modification char(13);
attribut char(10);
texte char(50);
end-ds;
// Code erreur : octets fournis > 0, l'API y range l'erreur
// au lieu d'envoyer un message d'exception
dcl-ds codeErreur qualified;
fournis int(10) inz(%size(codeErreur));
disponibles int(10) inz(0);
message char(7);
*n char(1);
donnees char(100);
end-ds;
QUSROBJD(objd0200 : %size(objd0200) : 'OBJD0200'
: objet + '*LIBL' : type : codeErreur);
if codeErreur.disponibles > 0;
dsply ('Erreur ' + codeErreur.message + ' sur ' + %trim(objet));
else;
dsply (%trim(objd0200.bibRetour) + '/' + %trim(objd0200.nom)
+ ' proprietaire ' + objd0200.proprietaire);
dsply objd0200.texte;
endif;
*inlr = *on; La même API, avec un code erreur dont les octets fournis valent 0 :
**FREE
// OBJEXCF : QUSROBJD avec un code erreur de 0 octet fourni
dcl-pi *n;
objet char(10);
type char(10);
end-pi;
dcl-pr QUSROBJD extpgm('QUSROBJD');
recepteur char(32767) options(*varsize);
longueur int(10) const;
format char(8) const;
nomQualifie char(20) const;
typeObjet char(10) const;
erreur likeds(codeErreur);
end-pr;
dcl-ds etat psds qualified;
message char(7) pos(40);
end-ds;
dcl-s recepteur char(100);
// Octets fournis = 0 : l'API envoie l'erreur en message d'exception
dcl-ds codeErreur qualified;
fournis int(10) inz(0);
disponibles int(10) inz(0);
end-ds;
monitor;
QUSROBJD(recepteur : %size(recepteur) : 'OBJD0100'
: objet + '*LIBL' : type : codeErreur);
dsply ('Objet trouve : ' + %trim(objet));
on-error;
dsply ('Exception ' + etat.message + ', statut ' + %char(%status));
endmon;
*inlr = *on; CALL OBJDF PARM(COMMANDES '*DTAQ')
CALL OBJDF PARM(INCONNUE '*DTAQ')
CALL OBJEXCF PARM(INCONNUE '*DTAQ')

Le programme passe *LIBL comme bibliothèque : celle où l'objet a été trouvé revient dans
bibRetour, ici JOBIAPI. Le texte affiché est celui donné à CRTDTAQ.
Exemple 4 Une API procédure
QsnWrtDta : écrire sur l'écran sans DSPF
Les API DSM (Dynamic Screen Manager) pilotent l'écran 5250 directement : effacer,
écrire un texte à une ligne et une colonne, attendre une touche. Ce sont des procédures du programme de
service QSNAPI : le programme est ILE, d'où dftactgrp(*no), et les prototypes utilisent
EXTPROC.
**FREE
// ECRANF : ecrit sur l'ecran 5250 avec les API DSM (procedures ILE)
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-ds codeErreur qualified template;
fournis int(10);
disponibles int(10);
message char(7);
*n char(1);
end-ds;
dcl-pr QsnClrScr int(10) extproc('QsnClrScr');
mode char(1) const options(*omit);
tampon int(10) const options(*omit);
environnement int(10) const options(*omit);
erreur likeds(codeErreur) options(*omit);
end-pr;
dcl-pr QsnWrtDta int(10) extproc('QsnWrtDta');
donnees char(132) const options(*varsize);
longueur int(10) const;
zone int(10) const options(*omit);
ligne int(10) const;
colonne int(10) const;
attributDebut char(1) const options(*omit);
attributFin char(1) const options(*omit);
couleurDebut char(1) const options(*omit);
couleurFin char(1) const options(*omit);
tampon int(10) const options(*omit);
environnement int(10) const options(*omit);
erreur likeds(codeErreur) options(*omit);
end-pr;
dcl-pr QsnGetAID char(1) extproc('QsnGetAID');
touche char(1) options(*omit);
tampon int(10) const options(*omit);
environnement int(10) const options(*omit);
erreur likeds(codeErreur) options(*omit);
end-pr;
// Attributs 5250 : 20 normal (vert), 21 inverse, 22 blanc,
// 30 turquoise, 32 jaune, 28 rouge ; sur un ecran couleur,
// c'est l'attribut de couleur qui compte
dcl-c NORMAL x'20';
dcl-c BLANC x'22';
dcl-c INVERSE x'21';
dcl-c TURQUOISE x'30';
dcl-c JAUNE x'32';
dcl-c ROUGE x'28';
dcl-s texte varchar(80);
dcl-s touche char(1);
// Mode '0' : effacer l'ecran et passer en 24 x 80
QsnClrScr('0' : *omit : *omit : *omit);
texte = 'Ecran ecrit par QsnWrtDta';
QsnWrtDta(texte : %len(texte) : 0 : 2 : 27
: BLANC : NORMAL : BLANC : NORMAL : *omit : *omit : *omit);
texte = ' Pas de DSPF : le programme place lui-meme chaque texte ';
QsnWrtDta(texte : %len(texte) : 0 : 5 : 11
: INVERSE : NORMAL : INVERSE : NORMAL : *omit : *omit : *omit);
texte = 'Ligne 8, colonne 11, en jaune';
QsnWrtDta(texte : %len(texte) : 0 : 8 : 11
: NORMAL : NORMAL : JAUNE : NORMAL : *omit : *omit : *omit);
texte = 'Ligne 10, colonne 30, en rouge';
QsnWrtDta(texte : %len(texte) : 0 : 10 : 30
: NORMAL : NORMAL : ROUGE : NORMAL : *omit : *omit : *omit);
texte = 'Appuyez sur Entree ou sur F3';
QsnWrtDta(texte : %len(texte) : 0 : 22 : 2
: NORMAL : NORMAL : TURQUOISE : NORMAL : *omit : *omit : *omit);
// QsnGetAID attend une touche et rend son code AID
touche = QsnGetAID(*omit : *omit : *omit : *omit);
if touche = x'33';
dsply 'Touche lue : F3';
elseif touche = x'F1';
dsply 'Touche lue : Entree';
else;
dsply 'Touche lue : une autre';
endif;
*inlr = *on; options(*omit)- Les paramètres facultatifs des API DSM (tampon de commandes, environnement, code erreur) sont omis : l'API prend alors l'écran courant et ses valeurs par défaut.
QsnWrtDta(texte : %len(texte) : 0 : ligne : colonne : …)- Le texte, sa longueur, 0 pour « pas d'identifiant de zone » (le texte se place alors par ligne et colonne), la ligne et la colonne, puis les attributs
de début et de fin : monochrome, puis couleur. Sur un écran couleur, c'est l'attribut de couleur qui
compte :
x'21'en couleur donne la vidéo inverse. QsnGetAID- Attend une touche et rend son code AID :
x'F1'pour Entrée,x'33'pour F3.

Touche lue : F3.Pour un vrai écran de saisie, un DSPF reste plus simple à écrire et à maintenir. DSM sert aux outils qui construisent leur écran à l'exécution.
Les messages relevés
| Message | API | Ce qu'on voit | Cause |
|---|---|---|---|
| CPF9870 | QCMDEXC | L'objet COMMANDES de type *DTAQ existe déjà dans la bibliothèque JOBIAPI. | CMDF appelé une seconde fois : CRTDTAQ échoue, MONITOR intercepte le message. |
| CPF9801 | QUSROBJD, code erreur de 116 octets | Aucun message : l'identifiant est rangé dans la structure. | Objet absent. Le programme lit codeErreur.message et continue. |
| CPF9801 | QUSROBJD, code erreur de 0 octet | Objet INCONNUE non trouvé dans la bibliothèque *LIBL. | Le même objet absent, mais en exception : MONITOR l'intercepte (statut 00202) ; sans lui, le programme serait interrompu par l'erreur. |
Sources
Les exemples ont été exécutés sur un IBM i 7.5 (voir la méthode). Les règles viennent de ces sources, consultées le 26 octobre 2026 :
- Send Data Queue (QSNDDTAQ) API, IBM, IBM i 7.5. Paramètres de QSNDDTAQ : nom de la file, bibliothèque, longueur en Packed(5,0), données.
- Receive Data Queue (QRCVDTAQ) API, IBM, IBM i 7.5. Temps d'attente : négatif sans fin, 0 sans attente (longueur rendue à 0), positif en secondes ; longueur reçue jamais supérieure au MAXLEN de CRTDTAQ.
- Error code parameter format, IBM, IBM i 7.5. Format ERRC0100 : octets fournis, octets disponibles, identifiant (7), réservé, données ; octets fournis à 0 : exception ; 8 ou plus : erreur rangée dans la structure.
- Retrieve Object Description (QUSROBJD) API, IBM, IBM i 7.5. Paramètres de QUSROBJD et format OBJD0200 (attribut étendu en position 91, texte en 101).
- Execute Command (QCMDEXC) API, IBM, IBM i 7.5. La commande et sa longueur en Packed(15,5).
- Write Data (QsnWrtDta) API, IBM, IBM i 7.5. Données, longueur, zone, ligne, colonne, attributs de début et de fin (monochrome et couleur).
- SEND_DATA_QUEUE, SEND_DATA_QUEUE_BINARY, SEND_DATA_QUEUE_UTF8, IBM, IBM i 7.5. Procédures SQL équivalentes à QSNDDTAQ.
- RECEIVE_DATA_QUEUE table function, IBM, IBM i 7.5. Fonction SQL équivalente à QRCVDTAQ, qui retire le message par défaut.
- DATA_QUEUE_ENTRIES table function, IBM, IBM i 7.5. Lecture du contenu d'une file sans le retirer.
Questions fréquentes
Qu'est-ce qu'une API système sur IBM i ?
Un programme ou une procédure qu'IBM livre avec le système, et qu'on appelle depuis son propre programme pour faire ce qu'aucune instruction du langage ne fait : déposer un message dans une file de données, lire la description d'un objet, exécuter une commande, écrire sur l'écran.
Quelle différence entre QSNDDTAQ et QsnWrtDta ?
QSNDDTAQ est une API programme (*PGM) : on l'appelle par CALL, depuis n'importe quel langage, même en CL. QsnWrtDta est une API procédure : elle est dans le programme de service QSNAPI, et on l'appelle comme une procédure, depuis un programme ILE (en RPG, DFTACTGRP(*NO)). Sur l'IBM i 7.5 des exemples, QSNAPI est dans le répertoire de liage QUSAPIBD, que le compilateur consulte de lui-même : aucun BNDDIR à déclarer.
À quoi sert le paramètre code erreur ?
La plupart des API le prennent en dernier paramètre. Si son premier champ (octets fournis) vaut 0, l'erreur est envoyée en message d'exception (CPF9801 pour un objet absent). S'il vaut 8 ou plus, l'API range l'erreur dans la structure, sans exception : les octets disponibles sont alors différents de 0 et l'identifiant du message est renseigné.
Comment lire une file de données sans attendre ?
Avec QRCVDTAQ et un temps d'attente de 0 : l'API rend la main tout de suite, et la longueur reçue vaut 0 si la file est vide. Avec une valeur négative, l'API attend sans fin ; avec une valeur positive, elle attend ce nombre de secondes.
Peut-on utiliser une file de données en SQL ?
Oui : QSYS2.SEND_DATA_QUEUE dépose un message, QSYS2.RECEIVE_DATA_QUEUE le retire, et QSYS2.DATA_QUEUE_ENTRIES montre le contenu sans rien retirer. Sur IBM i 7.5, SEND_DATA_QUEUE a déposé exactement la longueur du texte, sans blancs de complément.
Comment exécuter une commande CL depuis un programme RPG ?
Avec l'API QCMDEXC : la commande en premier paramètre, sa longueur en packed(15:5) en second. Une commande qui échoue envoie son message d'erreur au programme : on l'intercepte par MONITOR.