← ST-Computer 12 / 1987

Resource Datei? Nein Danke!

Grundlagen

Sicher sind vielen Lesern schon Programme begegnet, die zwar mit MenĂŒleisten, Dialogen und sonstigen GEM-Objekten arbeiten, aber keine * .RSC Datei benötigen. Typisches Beispiel: Tempus der Editor von CCD. Der folgende Beitrag und das dazugehörende Listing zeigen, wie man in seinen eigenen C-Programmen die Resource Datei in den Programmcode integriert.

Der Sinn der Resource

In letzter Zeit hat sich auf dem Gebiet der BenutzeroberflĂ€chen einiges getan. Ein Personal Computer (im Sinne des Wortes, und nicht eines bestimmten Herstellers) ist ohne Bildschirmgrafik und Maus kaum noch an den Mann oder die Frau zu bringen. Auf die Schnittstelle zum Benutzer (Neuhochdeutsch: Userinterface) wird immer mehr Wert gelegt und so bleibt es nicht mehr den Informatikern ĂŒberlassen sich darĂŒber Gedanken zu machen, wie die Software mit dem Benutzer kommuniziert, sondern zunehmend werden Spezialisten der Fachgebiete Ergonomie und Psychologie zu solchen Aufgaben herangezogen. Software-Ergonomie ist das aktuelle Schlagwort, und wird es wohl auch noch eine Weile bleiben. DarĂŒber darf jedoch die Softwaretechnik nicht vergessen werden. Und genau unter diese Rubrik fĂ€llt das Konzept der Resourcedatei. Der Trend geht deutlich zu einer Trennung zwischen den Funktionen und der BenutzeroberflĂ€che eines Programms. Dies dient im Wesentlichen der PortabilitĂ€t von Programmen. Wer schon einmal versucht hat ein Programm von Rechner X auf Rechner Y zu portieren, dem ist sicher aufgefallen, daß die Probleme zum grĂ¶ĂŸten Teil in der Ein-/Ausgabe auftreten und damit an der Schnittstelle zum Benutzer. Ein weiterer Punkt ist die Übersetzung von einer Landessprache in eine Andere. Speziell in dieser Hinsicht muß man das Konzept von GEM loben. Man kann Programme, deren Benutzerschnittstelle komplett in der Resource-Datei definiert ist, in eine andere Landessprache ĂŒbersetzen, ohne im Besitz des Quelltextes zu sein und ohne neu zu compilieren. Man benötigt dazu lediglich ein Programm zum Editieren der Resource-Dateien von GEM. Ein solches Programm ist das RCS (Resource Construction Set) aus dem Entwicklungspaket fĂŒr den ATARI ST. Es ist fĂŒr 15 Mark bei der ST-Computer erhĂ€ltlich (siehe Public Domain Service).

FĂŒr den Software-Entwickler haben die Resourcen den Vorteil, daß die optische PrĂ€sentation der BenutzeroberflĂ€che interaktiv geĂ€ndert werden kann und bei einer Änderung nicht neu compiliert werden muß. Außerdem wird die Bildschirmausgabe automatisch an die Bildschirmauflösung angepaßt.

Nachdem ich nun einige Argumente fĂŒr die Resourcedateien genannt habe denken Sie sicher „ist doch eine prima Sache, wozu also dieser Artikel?“. Dazu ist zunĂ€chst zu bemerken, daß nicht alles Gold ist, was glĂ€nzt. Sicher hatten sie auch schon die Meldung „Resourcedatei nicht gefunden“ auf Ihrem Bildschirm. Sicher haben Sie sich auch schon geĂ€rgert, daß der Bootvorgang bei Accessories, die eine Resourcedatei benutzen lĂ€nger dauert. Und außerdem ist das Inhaltsverzeichnis einer Diskette kĂŒrzer, wenn nicht jedes Programm zusĂ€tzlich eine Resourcedatei hat. Bestimmt fallen Ihnen auch noch mehr GrĂŒnde ein, warum es unter UmstĂ€nden praktisch ist, wenn die Resourcen im Programm integriert sind. Genug Theorie, jetzt folgt die Praxis.

Voraussetzung ist...

das bereits erwĂ€hnte RCS von Digital Research. Dieses Programm ist nĂ€mlich als einziges seiner Art in der Lage, die erzeugten Resourcedateien auch als C Quelltext abzuspeichern. Das bedeutet nicht, daß die Resourcedatei auch mit diesem Programm erstellt werden muß, es wird lediglich benötigt, um die Resourcen in C umzuwandeln. Dazu wĂ€hlt man im 'Global’ MenĂŒ des RCS den Punkt 'Output’ an. In der darauf folgenden Dialogbox klickt man in das KĂ€stchen unter dem Text 'Source File for Resource’. Danach lĂ€dt man seine Resourcedatei und speichert sie sofort wieder ab. Auf der Diskette sollte sich dann eine Datei mit Namen ’RSC.C’ befinden, vorausgesetzt Ihre Resourcedatei heißt ’RSC. RSC’. Als nĂ€chstes startet man einen Editor seiner Wahl und Ă€ndert in dem hier abgedruckten Listing in Zeile 4 und 5 den Vornamen der Dateien ’rsc.h’ und ’rsc.c’ entsprechend dem Namen seiner eigenen Resourcedatei um. Anschließend compiliert man das Ganze und linkt es zu seinem Programm dazu. Alles funktioniert wie vorher, nur daß die Resourcedatei jetzt nicht mehr von Diskette geladen wird, sondern im Programm enthalten ist. Das war’s eigentlich schon. FĂŒr die Interessierten unter den Lesern noch ein paar Worte zu der Funktion der Routine.

So geht’s

In Zeile 21 und 22 wird GEM die Adresse der Objektpointertabelle mitgeteilt. Diese wird z. B. fĂŒr die Funktion RSRC_GADDR benötigt. In der FOR-Schleife 'Do Objects’ werden die Objektkoordinaten vom Zeichenformat in das aktuelle Bildschirmformat umgerechnet. Dazu muß man wissen, daß die Anfangskoordinaten eines Objekts und dessen Höhe und Breite auf ganz besondere Weise abgespeichert sind. Jeder Wert ist in einem 16 Bit Wort unter gebracht, dessen Low- und High-Byte unterschiedliche Bedeutung haben. Betrachten wir einmal die ob_heigh-Komponente eines Objekts. Im Low-Byte steht die Objekthöhe in Zeichen und im High-Byte die Anzahl der einzelnen Pixel. Ein Zeichen ist je nach eingestellter Bildschirmauflösung 8 oder 16 Pixel hoch. Wenn also ein Farbmonitor angeschlossen ist und die Zeichenhöhe 8 Pixel betrĂ€gt, ergibt sich die Objekthöhe zu

Low-Byte * 8 + High-Byte

Analoges gilt fĂŒr die Objekt breite und die X-Y Koordinaten. Im abgedruckten Listing wurde die Multiplikation durch eine Schiebeoperation ersetzt. Die Umrechnung der Koordinaten erfolgt in den Zeilen 30 bis 37.

In dem folgenden Switch-Statement wird in der Objektspezifikation ein Pointer auf die dem Objekttyp zugeordnete Struktur eingetragen. In den 6 For-Schleifen ab Zeile 63 wird das Gleiche fĂŒr die einzelnen Strukturen auf die eine Objektspezifikation zeigen kann gemacht.

Den Linker ĂŒberlistet

Die Routine habe ich ’rsrc_load’ genannt, weil dadurch die Möglichkeit besteht vorhandene Programme ohne eine Änderung am Quelltext, nur durch neues Linken so zu modifizieren, daß keine Resourcedatei mehr benötigt wird. Das funktioniert deshalb, weil der Linker die Funktion ’rsrc_load’ zuerst in einem der Objektfiles sucht und sie nur dann aus der Library holt, wenn er sie nicht gefunden hat. So ist es möglich, durch HinzufĂŒgen oder Weglassen eines Objekts beim Linken zu steuern, ob die Resourcedatei geladen wird, oder im Programm integriert ist.

In KĂŒrze gibt es einen neuen Leckerbissen aus der GEM-KĂŒche. Jedes Fenster bekommt seine eigene MenĂŒleiste. Wie das geht werde ich in einer der nĂ€chsten Ausgaben verraten.

(JL)

#include <osbind.h> /* wird fuer Getrez benoetigt */ #include <obdefs.h> /* typdefinitionen fuer AES-Structs */ #include "rac.h" /* .H Datei der Reaource */ #include "rsc.c" /* .C Datei dea Quelltextes der Resource */ #define WHITEBAK NORMAL /* Leider noetig, keine Ahnung wofuer */ #define HIGH 2 /* Returnwert von Getrez fuer 640x400 */ extern int global[]; /* Globale GEM Variablen */ int rsrc_load(RscFile) char *RscFile; /* der Ordnung wegen, wird nicht benutzt */ { int dx, dy, Obj; OBJECT **GEM_rsc; GEM_rsc = (OBJECT **) &global[5]; *GEM_rsc = (OBJECT *) &rs_trindex[0]; dx = dy = 3; if (Getrez() == HIGH) dy = 4; /* * Do Objects */ for(Obj = 0;Obj < NUM_OBS;Obj++) { rs_object[Obj].ob_x = ((rs_object[Obj].ob_x & 0x00ff) << dx) + (rs_object(Obj).ob_x >> 8); rs_object[Obj].ob_y = ((rs_object[Obj].ob_y & 0x00ff) << dy) +(rs_object[Obj].ob_y >> 8); rs_object[Obj].ob_width = ((rs_object[Obj].ob_width & 0x00ff) << dx) +(rs_object[Obj].ob_width >> 8); rs_object[Obj].ob_height =((rs_object[Obj].ob_height & 0x00ff) << dy) + (rs_object[Obj].ob_height >> 8); switch(rs_object[Obj].ob_type) { case G_FTEXT : case G_BOXTEXT : case G_FBOXTEXT : case G_TEXT : { rs_object[Obj].ob_spec = (char *) &rs_tedinfo[(int)rs_object[Obj].ob_spec]; break; } case G_BUTTON : case G_TITLE : case G_STRING : { rs_object[Obj].ob_spec = (char *) rs_strings[(int) rs_object[Obj].ob_spec]; break; } case G_ICON : { rs_object[Obj].ob_spec = (char *) (&rs_iconblk[(int) rs_object[Obj].ob_spec]); break; } case G_IMAGE : { rs_object[Obj].ob_spec = (char *) (&rs_bitblk[(int) rs_object[Obj].ob_spec]); break; } } } /* * Do Textinfos */ for(Obj = 0;Obj < NUM_TI;Obj++) { rs_tedinfo[Obj].te_ptext = ra_strings[(int)rs_tedinfo[Obj].te_ptext]; rs_tedinfo[Obj].te_ptmplt = rs_strings[(int)rs_tedinfo[Obj].te_ptmplt]; rs_tedinfo[Obj].te_pvalid = rs_strings[(int)rs_tedinfo[Obj].te_pvalid]; } /* * Do IconBlocks */ for(Obj = 0;Obj < NUM_IB;Obj++) { rs_iconblk[Obj].ib_pmask = rs_imdope[(int) rs_iconblk[Obj].ib_pmask].image; rs_iconblk[Obj].ib_pdata = rs_imdope[(int) rs_iconblk[Obj].ib_pdata].image; rs_iconblk[Obj].ib_ptext = rs_strings[(int) rs_iconblk[Obj].ib_ptext]; } /* * Do Bitimages */ for(Obj = 0;Obj < NUM_BB;Obj++) { rs_bitblk[Obj].bi_pdata = rs_imdope[(int) rs_bitblk[Obj].bi_pdata].image; } /* * Do FreeStrings */ for(Obj = 0;Obj < NUM_FRSTR;Obj++) { rs_frstr[Obj] = (long) rs_strings[(int) rs_frstr[Obj]]; } /* * Do Freeimages */ for(Obj = 0;Obj < NUM_FRIMG;Obj++) { rs_frimg[Obj] = (long) &rs_bitblk[(int) rs_frimg[Obj]]; } /* * Do TreeIndex */ for(Obj = 0;Obj < NUM_TREE;Obj++) { rs_trindex[Obj] = (long) &rs_object[(int) rs_trindex[Obj]]; } return(1); /* Kein Fehler, woher auch :-) */ }