VIII. Bôvítômodulok írása C-ben
Автор: Kádár Zsolt
Дата: 22.06.1999
Источник: https://xenia.sote.hu
Язык: Венгерский
Bevezetés
Az eddigi leckék során nagyon sokszor használtuk már az RxFuncAdd függvényt, amellyel DLL-ekben elhelyezkedô függvényeket tettünk elérhetôvé REXX programok számára. A bôvítômodulokat tárgyaló tanfolyamunk utolsó leckéjében azt fogjuk megnézni, hogy hogyan kell a bôvítômodulokat C-ben megírni. A nyelvek közötti különbségekbôl adódik, hogy a C programnak bizonyos szabályoknak kell megfelelni. A legszembetûnôbb különbség az, hogy a REXX a C-vel ellentétben egyetlen adattípust, a karakterláncot ismer. A REXX és C programok együttmûködésekor tehát gondoskodni kell arról, hogy a szükséges adatkonverzió automatikusan végbemenjen. Szerencsére nem kell teljesen a nulláról kezdenünk, mivel az IBM a Devcon CD-ken található Developer's Toolkitben elérhetôvé tette a REXXSAA.H nevû fejlécállományt, amely a feladat egy részét megoldja.
Az RXSTRING adattípus
A fejlécállományban található definíciók közül az egyik leglényegesebb az RXSTRING adattípus, amelyet a REXX karakterláncok C programbeli kezelésére hozták létre. A C program ugyanis ebben az adattípusban kapja meg a REXX program által átadott paramétereket, s természetesen ugyanebben a formában adja vissza az eredményeket is. A C program a mûködése közben persze tetszés szerinti formátumra konvertálhatja az RXSTRING-et. Az alábbiakban megadtuk az RXSTRING definícióját:
typedef struct {
ULONG strlength; /* A sztring hossza */
PCH strptr; /* Mutató a sztringre */
} RXSTRING;
typedef RXSTRING *PRXSTRING; /* Mutató az RXSTRING-re */
A C függvény megírása
Hogy a C-ben írt függvényt a REXX programok is használni tudják, a következô sorrendet kell betartani a függvény megírásakor:
- 1. Csatolni kell a REXX függvényeket specifikáló definíciót:
#define INCL_RXFUNC - 2. Meg kell adni a REXX fejlécállományt:
#include <rexxsaa.h> - 3. Deklarálni kell a függvényt REXX interfészként a REXXFunctionHandler kulcsszóval.
- 4. A függvény elején szükség esetén konvertálni kell az RXSTRING-ben kapott adatokat a megfelelô C típusra.
- 5. A függvény törzsének megírása után vissza kell alakítani a visszaadandó adatokat RXSTRING típusra.
Az alábbiakban bemutatunk egy rövid példaprogramot, amely a Hello függvényt valósítja meg C-ben, amelyet aztán REXX-bôl fogunk meghívni. A függvény nem csinál mást, mint visszaadja a paraméterként átadott karakterláncot a "Hello " és "!" karakterláncok közé ágyazva. Ezáltal a függvényt például REXX-bôl a "World" paraméterrel meghívva a klasszikus "Hello World!' szöveget lehet REXX-bôl a C-ben írt DLL segítségével kinyomtatni. A példa persze kissé erôltetett, hiszen a C bôvítômodul által kínált Hello függvényt REXX-ben is könnyen meg lehetne írni, ám példának tökéletesen megteszi.
/* LECKE08A.C */
/* A szükséges definíciók */
#define INCL_RXFUNC
#define INVALID_ROUTINE 40
#define VALID_ROUTINE 0
/* A szükséges header fájlok */
#include <string.h>
#include "rexxsaa.h"
/* Makró a C függvény által visszaadott RXSTRING elôállítására */
#define BUILDRXSTRING(t, s) { \
strcpy((t)->strptr,(s));\
(t)->strlength = strlen((s)); \
}
/* A függvény prototípusa */
RexxFunctionHandler Hello;
/* A függvény részletezve */
ULONG APIENTRY Hello(
PUCHAR Name, /* A függvény neve */
ULONG argc, /* Az argumentek száma */
RXSTRING argv[], /* Az argumentek */
PSZ Queuename, /* A várakozási sor neve */
PRXSTRING Retstr) /* A visszaadott sztring */
{
UCHAR str[80]; /* Ideiglenes változó */
/* A bevitt paraméterek ellenôrzése */
if (argc !=1) /* Maximum 1 paraméter */
return(INVALID_ROUTINE); /* Hibás használat */
if (!RXVALIDSTRING(argv[0])) /* Érvényes-e a sztring */
return(INVALID_ROUTINE); /* Hibás használat */
if (argv[0].strlength > 70) /* Max. 70 hosszú lehet */
return(INVALID_ROUTINE); /* Hibás használat */
/* A visszaadott sztring elôállítása */
strcat(str, "Hello ");
strcat(str, argv[0].strptr);
strcat(str, "!");
/* A Rexx visszatérési érték elôállítása */
BUILDRXSTRING(Retstr, str);
/* Minden rendben van, így visszatérhetünk */
return(VALID_ROUTINE);
}
A példaprogramot az elsô pontban kötelezôen elôírt RXFUNC definícióval kezdjük, amelyet még két másik követ. A 40-es visszatérési érték azt jelzi a REXX program számára, hogy nem megfelelôen használták a függvényt. A 0-ás visszatérési érték a helyes használatot jelenti. A fejlécállományok definiálásánál megadtuk a Hello függvény számára szükséges string.h fájlt, amelyet a 2. pontban kötelezôen elôírt rexxsaa.h csatolása követ. A következô kódrészlet egy makrót definiál, amely megkönnyíti az RXSTRING típusú értékek elôállítását a C-ben használt karakterláncokból. A folytatásban REXX függvényként deklaráljuk a Hello függvényt, majd részletesen kidolgozzuk. A függvény paraméterlistája kötött; a REXX program által átadott adat az argv[] tömbben található. A következô kódrészlet a bevitt adatok számának és típusának ellenôrzését végzi. Figyeljük meg, hogy használunk egy RXVALIDSTRING makrót, amely azt ellenôrzi, hogy érvényes-e a megadott bemeneti adat. Nagyon sok más, a bemeneti paraméterek feldolgozását segítô függvényt találhatunk még a szintén a Developer's Connection részét képezô RXSTRING.LIB fájlban. Példaként az RXTOI függvényt említhetjük meg, amely RXSTRING-et alakít integerré. Amennyiben a bevitt adatok száma és értéke nem felel meg az általunk definiált feltételeknek, akkor az INVALID_ROUTINE értékkel térünk vissza, ami azt fogja jelenteni a REXX programnak, hogy helytelenül használta a függvényt. Ha sikeresen átestünk az ellenôrzéseken, a három strcat utasítással elvégezzük a tulajdonképpeni munkát, a bemeneti adat beékelését a "Hello " és a "!" karakterláncok közé. A BUILDRXSTRING makró segítségével a kapott karakterláncot visszaalakítjuk RXSTRING-re, hogy az elérhetô legyen a REXX függvény számára és a VALID_ROUTINE visszatérési érték mellett zárjuk a C függvényt.
A DLL elôállítása
Ha kész a C kód, akkor már nincs más hátra, mint elkészíteni a DLL-t. Erre a célra elvileg bármelyik C fordító megfelel; én a Borland C for OS/2 2.0-át használtam erre a célra. A DLL elkészítéséhez szükség van még egy DEF fájlra is, amelyben listázzuk a REXX programok számára elérhetô függvényeket:
LIBRARY LECKE08A INITINSTANCE TERMINSTANCE
DESCRIPTION 'Zsolt Kadar LECKE Utilities - (C) Copyright Crucial Applications 1999'
EXPORTS
HELLO = Hello @1
Ezek után már nincs más hátra, mint létrehozni egy projectet, hozzáadni a létrehozott fájlokat, a target opciónál beállítani, hogy DLL-t akarunk készíteni, amelyhez az általunk készített DEF fájlt akarjuk használni, és a build gombra bökni. Ha minden jól megy, akkor néhány pillanat múlva kész a DLL, amelyet rögtön tesztelhetünk is REXX-bôl.
A DLL használata
A DLL-ben található függvényt elôször regisztrálni kell az RxFuncAdd utasítással, amelynek elsô és harmadik paramétere rendszerint a függvény neve, a második pedig a DLL neve kell, hogy legyen. A DLL-t természetesen be kell másolni egy olyan könyvtárba, amely benne van a LIBPATH-ban, hogy az RxFuncAdd meg tudja találni. A sikeres regisztráció után pedig minden további nélkül meghívhatjuk a Hello függvényt a World paraméterrel, hogy jól megérdemelt munkánk eredményeként feltûnjön a képernyôn a "Hello World!" szöveg.
/* lecke08a.cmd */
Call RxFuncAdd 'Hello', 'LECKE08A', 'Hello'
Say Hello('World')
EXIT
REXX programok hívása C-bôl
Természetesen a dolog fordítottja, vagyis REXX programok meghívása C-bôl is lehetséges. Sôt mi több, nem is olyan nehéz dolog. Mivel a REXX interpreter maga is egy DLL, a C program egy az egyben meg tudja hívni az interpretert a REXX programok futtatásához. A REXXSAA.H fejlécállományban szerepel egy REXXSTART függvény, amely az interpreter indítására szolgál. Az alábbi példaprogram a REXXSTART függvény használatára mutat példát. A REXXDB2.C program elindítja a GETDB.CMD REXX programot, amely egy adatbázis nevét adja vissza a C programnak, amely aztán kinyomtatja azt:
#define INCL_REXXSAA
#include <rexxsaa.h>
#include <stdio.h>
#include <string.h>
int main(void);
int main()
{
RXSTRING arg; /* argument sztring REXX-hez */
RXSTRING rexxretval; /* REXX-beli visszatérési érték */
UCHAR *str = ""; /* REXX-nek átadott sztring */
APIRET rc; /* REXX visszatérési érték */
SHORT rexxrc = 0; /* a függvény visszatérési értéke */
MAKERXSTRING(arg, str, strlen(str)); /* bemeneti paraméter elôállítása */
rc=RexxStart((LONG) 0,
(PRXSTRING) &arg,
(PSZ) "GETDB.CMD",
(PRXSTRING) 0,
(PSZ) 0,
(LONG) RXSUBROUTINE,
(PRXSYSEXIT) 0,
(PSHORT) &rexxrc,
(PRXSTRING) &rexxretval );
Printf("Az adatbázis neve: %s",rexxretval.strptr);
DosFreeMem(rexxretval.strptr);
return 0;
}
REXX GYÍK:
K1. Hol találok további példákat C-ben írt REXX bôvítômodulokra?
V1. Az elôzô leckében már említett hobbes.nmsu.edu ftp site /pub/dev/rexx könyvtárában található shareware/freeware modulok némelyikéhez mellékelték a forráskódot is. Egy ilyen modul például az általunk is tárgyalt RxAsync.
Gyakorlatok:
1. Készítsen olyan bôvítômodult, amely az Ön számára a REXX-bôl legjobban hiányzó függvényt valósítja meg!
2. Készítsen egy C programot, amely a parancssorban megadott REXX programot futtatja le!
| Kádár Zsolt 1999. 06. 22. |