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. |