Harlekin und das Geheimnis der Module: HPG-Module selbstgemacht, Teil 1

Im letzten Jahr wurde das bekannte Multi-Accessory Harlekin einem umfangreichen Facelifting unterzogen, das sogar Michael Jackson neidisch machen dürfte. Das Kind hieß von nun an Harlekin II und kann durch Module erweitert und dadurch den Wünschen des Benutzers angepaßt werden. Dieser Artikel beschreibt, wie man solche HPG-Module selbst entwickeln kann.

Jeder, der Harlekin besitzt, weiß, daß HPG für „Harlekin ProGram“ steht. Wer Harlekin besitzt und das bisher nicht wußte, sollte vielleicht doch einmal einen Blick in das Handbuch werfen ...

Das Modulkonzept ist bereits vom modularen CPX-Kontrollfeld bekannt. Es dient einerseits dazu, seltener benötigte Module auszulagern, um das Accessory nicht unnötig aufzublähen, andererseits, um Harlekin flexibel zu gestalten und den Benutzerwünschen anpassen zu können. Wer Harlekin besitzt oder die Werbung zu diesem Programm gelesen hat, könnte meinen, daß das Accessory bereits allen Anforderungen gerecht wird und kaum noch sinnvoll zu erweitern ist. In der Tat ist Harlekin sehr flexibel, dennoch fällt einem nach kurzem Überlegen die eine oder andere Funktion ein, um die Harlekin noch ergänzt werden könnte. Zum Beispiel könnte manch ein Accessory als HPG-Modul implementiert werden, so daß kostbare Accessory-Plätze frei würden.

Der Hobby-Programmierer wird dazu nicht nur ermutigt, sondern sogar unterstützt, indem die Harlekin-Entwickler die Dokumentation der Modul-Schnittstelle frei zugänglich gemacht haben. Dementsprechend werden für selbstentwickelte Module auch keine Lizenzgebühren fällig. Aber natürlich dürfen sie nur ohne Harlekin selbst vertrieben werden! Wer ein Modul (auch wenn es nur ein kleines Utility ist) entwickelt hat, das professionellen Ansprüchen genügt, kann es zu MAXON einsenden, gegebenenfalls wird es dann in Zukunft mit Harlekin oder auf einer Erweiterungsdiskette vertrieben!

Laut Handbuch kann man die Dokumentation bei MAXON anfordern; wenn auf Ihrer Harlekin-Diskette die Datei HPG_LIB.LZH/im Ordner HARLEKINA BINYHPG\ jedoch vorhanden ist, besitzen Sie bereits die (vorläufige) Dokumentation. Diese Datei liegt im komprimierten Format vor und kann mit dem bekannten Programm LH ARC entpackt werden. Nach dem Entpacken der Datei befindet sich auf Ihrer Platte oder Diskette neben verschiedenen Beispielprogrammen und den dafür benötigten Bindings und Header-Dateien auch eine englische Beschreibung der Modulschnittstelle einschließlich der zur Verfügung gestellten Funktionen.

Leider ist das Englisch an einigen Stellen nicht gerade leicht verständlich, und der Text enthält auch ansonsten einige Fehler und Ungereimtheiten. Daher wollen wir in diesem Artikel eine Einführung in die Programmierung der HPG-Module geben, um Ihnen einige der Stolpersteine und Schwierigkeiten zu ersparen, mit denen wir bei der Entwicklung unserer Beispiel-Module zu kämpfen hatten. Natürlich konnten wir nicht jede Funktion bis ins kleinste Detail testen, so daß manch ein Geheimnis noch darauf warten mag, von einen abenteuerlustigen Programmiererim Stil von Indiana Jones entdeckt zu werden.

Keine Angst vor Bugs!

An dieser Stelle seien uns ein paar warnende Worte gestattet: die Entwicklung eines umfangreicheren HPG-Moduls kann sich als sehr frustrierend gestalten, da dem Programmierer wie auch bei Accessories und CPX-Modulen kaum Debugging-Hilfen zur Verfügung stehen und sich die Funktionen der Harlekin-Library manchmal nicht ganz so verhalten, wie es sich der Programmierer vielleicht vorstellt. Das kann sich zum Beispiel darin äußern, daß Harlekin ohne nähere Angabe von Gründen die Ausführung eines Funktionsaufrufs mit einer internen Fehlemummer abbricht und verweigert. Dem nicht ganz so erfahrenen Programmierer sei es deshalb ans Herz gelegt, zunächst ein kleineres HPG-Modul zu schreiben, um sich an die Programmierumgebung zu gewöhnen.

Abb. 1: Die Dialogbox des fertigen HPG-Moduls
Abb. 2: Dieses Icon können Sie nach dem Compilieren in das HPG-Modul einfügen.

Wer allerdings Harlekin-Module auf einem 1-MB-Rechner entwickeln möchte, sei vorgewarnt: Hat man Harlekin und Turbo-C/Pure-C (und sicher auch die meisten anderen Programmierumgebungen) zusammen im Speicher, kann es passieren, daß nicht genügend Speicher zum Compilieren zur Verfügung steht. Mit dem Accessory „The Chameleon“ läßt sich dieses Problem zwar umgehen, jedoch ist die Entwicklung dann recht umständlich.

Modulaufbau

Ein HPG-Modul ist im wesentlichen nichts anderes als ein GEM-Programm, das jedoch bereits vollständig initialisiert ist. Es muß/darf also weder AES und VDI noch das GEMDOS initialisiert werden! Auch dürfen zur Beendigung eines Moduls weder appl_exit() noch Pterm() oder eine ähnliche Funktion aufgerufen werden, denn Harlekin ruft ein HPG-Modul wie ein Unterprogramm auf, das als VOID deklariert ist, und sollte als solches auch nur mit return verlassen werden. Im Gegensatz zur Dokumentation hat der Mauszeiger bei Aufruf eines Moduls übrigens nicht die Form einer Biene, sondern die normale Pfeilform.

Aus den soeben erwähnten Gründen darf beim Linken auch nicht die übliche Start-up-Datei, wie zum Beispiel TCSTART.O bzw. PCSTART.O (je nach Compiler), dazugebunden werden. Stattdessen ist die mitgelieferte Datei HPGSTART.O zu verwenden, die den Zugriff auf die Harlekin-Funktionen erst möglich macht.

Im Gegensatz zu Accessories darf ein HPG-Modul auch keine Resource-Datei nachladen, sondern muß die benötigten Resource-Informationen als RSH-Datei beim Compilieren mit einbinden.

Das Abenteuer beginnt

Am Anfang des Quelltextes für ein HPG-Modul müssen nach den (je nach Compiler) üblichen Include-Dateien zuerst verschiedene Harlekin-eigene Header-Dateien eingebunden werden. Dabei handelt es sich um HPGLIB.H, die unter anderem die Prototypen für die verschiedenen Library-Routinen zur Verfügung stellt. Des weiteren wird die Header-Datei RSHI.H benötigt, die ihrerseits die vom Programmierer erstellte RSH-Datei einbindet. Dazu muß dem Symbol RSC_RSH vor dem Einbinden von RSHI.H der entsprechende Dateiname zugewiesen werden.

Besonders unangenehm für die Entwicklung erweist sich dabei die Datei HPGLIB.H, denn viele Funktionen in der HPG-Library ersetzen eine gleichnamige Betriebssystemfunktion. Leider wurde jedoch darauf verzichtet, ihnen einen neuen (und damit eindeutigen) Namen zu geben. Da sich einige dieser Funktionen zusätzlich auch noch in den Parametern von bereits definierten Funktionen unterscheiden, meldet der Compiler Fehler (Redeclaration Error), wenn eine Svstem-Header-Datei eingebunden wird, in der diese Funktion schon mit den anderen Parametern deklariert w orden ist. Der einzige Ausweg ist dann, die entsprechende System-Header-Datei nicht einzubinden und stattdessen die benötigten Definitionen aus der Header-Datei herauszukopieren und in den Quelltext direkt einzufügen. Einige andere Funktionen wiederum sind auskommentiert worden oder von den Entwicklern nicht dokumentiert. Eine Nachfrage bei der Mermaid Group hat ergeben, daß diese Funktionen nicht benutzt werden sollten. Da die Datei in der gleichen Form auch zur Entwicklung der mitgelieferten Harlekin-Module benutzt wird, sind nämlich nicht alle Funktionen für den Hobbyprogrammierer verwendbar.

Für Benutzer der Header-Datei PORTAB.H stellen die drei Definitionen von BYTE, WORD und LONG ein weiteres Problem dar. Zum einen wird WORD abweichend von allen Konventionen als unsigned int definiert, und zum anderen sind die in HPGLIB.H benutzten Defines in manchen Fällen mit den Typedefs von PORTAB.H unverträglich, was sich beim Compilieren in teilweise unverständlichen Fehlermeldungen äußert. Aus diesem Grund haben wir direkt zu Beginn unserer Quelltexte diese drei Definitionen mittels #undef unschädlich gemacht.

Außerdem definiert HPGLIB.H alle Dateifunktionen neu, weil die Standardbetriebssystemfunktionen oft Malloc()-Aufrufe ausführen, was für ein Accessory jedoch in der Regel nicht zulässig ist. Daraus ergibt sich, daß die Datei STDIO.H nicht eingebunden werden kann, da die oben beschriebene Situation zu vermeiden ist. Wird jetzt aber eine andere Definition aus STDIO.H benötigt, wie zum Beispiel im Listing die Funktion sprintf(), muß diese von Hand deklariert werden.

Eine weitere Schwierigkeit ergibt sich, wenn die Variable errno benötigt wird, die normalerweise in der Standard-Startup-Datei enthalten ist. Dies ist wiederum unter anderem bei sprintf() der Fall, was sich deshalb hervorragend zu Demonstrationszwecken eignet. In HPGSTART.O ist errno jedoch leider nicht enthalten, weshalb diese Variable in diesem Fall zu Programmbeginn global definiert werden muß. Unserem Vorschlag an die Entwickler von Harlekin, diese Variable in HPGSTART.O zu übernehmen, wurde leider nicht entsprochen.

Da wir gerade bei sprintf() sind: Von der Benutzung von printf() (und sei es auch nur zu Debugging-Zwecken) ist unbedingt abzuraten, denn wir haben bei der Benutzung dieser Funktion von merkwürdigen Fehlermeldungen bis hin zum Totalabsturz des Rechners nur schlechte Erfahrungen gemacht. Ein ähnliches Verhalten kann sich zeigen, wenn man andere Compiler- und Linker-Optionen einschaltet als die, die in den mitgelieferten Projektdateien benutzt werden. Schließlich sollten auch die Warnungen des Linkers über doppelt definierte Symbole („Doubly defined symbol“) aus oben genannten Gründen gnädig ignoriert werden. Nachdem wir nun die wichtigsten und größten Stolpersteine für den zukünftigen Modul-Programmierer beschrieben haben, wenden wir uns jetzt den mehr konkreten Dingen zu.

Resourcen

Wie schon erwähnt, darf ein HPG-Modul nicht die AES-Funktion rsrc_load() aufrufen, sondern muß ihre Resource-Informationen als RSH-Datei einbinden. Um auf diese in der gewohnten Weise zugreifen zu können, stellt die HPG-Library die Funktion fix_resource() zur Verfügung, die komfortabel über das Makro FIX_RSC() aufgerufen werden kann. Sie übernimmt die Aufgaben, die sonst rsrc_load() hat, nämlich Umrechnung der Koordinaten, Einträgen der Zeiger etc. Auf die einzelnen Objektbäume der Resource-Datei kann nach Aufruf von FIX_RSC() bequem über die externe Variable tree zugegriffen werden, die im Quelltext folgendermaßen deklariert sein muß:

extern OBJECT *tree[];

Ein Objekt OK_KNOPF des Dialogs DIALOG kann dann z.B. so angesprochen werden:

tree[DIALOG][OK_KNOPF].ob_state = NORMAL;

Der Übersichtlichkeit halber haben wir in unseren Beispielprogrammen einen weiteren Zeiger eingeführt, über den dann wie üblich auf die Elemente einer Dialogbox zugegriffen werden kann. Auf obiges Beispiel bezogen, würde das dann so aussehen:

OBJECT *dialog; 
dialog = tree[DIALOG]; 
dialog[OK_KNOPF].ob_state = NORMAL;

Auch beim Erstellen einer Resource-Datei für ein HPG-Modul sind ein paar Dinge zu beachten. Zunächst sollten alle Dialoge eine Titelzeile wie auch die anderen HPG-Modulen enthalten, die Harlekin nicht selbst anlegt (wie man vielleicht annehmen könnte, da fast alle Module solch eine Titelzeile besitzen). Dazu gehört ebenfalls das Anlegen einer Schließbox, mit der der Dialog beendet werden kann. Damit erhalten Harlekin-Dialoge das Aussehen von Fenstern, auch wenn es sich dabei nicht um solche handelt. Bei der Entwicklung ist bei uns der Fall aufgetreten, daß ein Dialog nicht mit einem EXIT-Objekt beendet werden konnte. Hier war aber Abhilfe durch Setzen des TOUCHEXIT-Flags möglich. Hierbei hat es sich jedoch um einen Einzelfall gehandelt, der in der Regel nicht auftritt und auch den Harlekin-Entwicklern unerklärlich war. Das Exit-Objekt, mit dem der Dialog beendet wurde, wird übrigens von Harlekin automatisch deselektiert.

Wie man vielleicht schon an den vorhandenen HPG-Modulen bemerkt hat, unterstützt Harlekin auch die Macintosh-typischen Radio- und Checkbuttons. Diese kann man ganz einfach im RCS anlegen, indem man ein Objekt vom Typ BOXCHAR in den Dialog einfügt und je nach gewünschtem Knopftyp den Buchstaben ‘o’ (für Radiobutton) oder ‘x’ (für Checkbutton) einträgt. Bei diesen Buttons müssen jedoch unbedingt auch die Flags SELECTABLE und gegebenenfalls RADIOBUTTON gesetzt werden.

Babylonisches Gebab(b)el...

Harlekin besitzt die Fähigkeit, mehrsprachige Module zu unterstützen. Zu diesem Zweck muß die Resource in Englisch erstellt werden. Die deutsche und französische/dänische (je nach Programm/Doku-mentation) Übersetzung muß anschließend im Quelltext erfolgen. Hierzu muß ein Array vom Typ LNGDEF angelegt werden, das folgendermaßen definiert ist:

typedef struct
{
    int tree; 
    int object; 
    char *lngtext[2];
} LNGDEF;

Jeder Eintrag im Array enthält also als erstes den Index des Baumes (bzw. des Dialoges) oder -1, falls kein weiterer Eintrag mehr folgt. Danach folgen der Index des Objektes im Baum und der deutsche und französische Text für das Objekt. Um auf unser obiges Beispiel zurückzukommen, wollen wir hier annehmen, der Knopf habe den englischen Text „Yes“. Das LNGDEF-Array könnte dann wie in Tabelle 1 aussehen.

Nun muß nur noch die Funktion fix_language() aufgerufen werden, um die Übersetzungen in die Resource einzuhängen, falls erforderlich. Das würde dann so aussehen:

fix_language(tree, language);

Da diese Strings im Quelltext statisch angelegt und nur die Zeiger umgesetzt werden, spielt die Länge der Texte in den verschiedenen Sprachen keine Rolle. Es müssen also nicht Leerzeichen eingefügt werden, um alle drei Texte jeweils auf die gleiche Länge zu bringen. Zu beachten ist stattdessen jedoch folgendes: Die Objektbreite (im RCS einzustellen) muß so breit gewählt werden, daß alle Übersetzungen darin Platz finden. Ist dies nicht der Fall, wird der entsprechende Text bei der eingestellten Objektbreite abgeschnitten!

LNGDEF language[] = {
    DIALOG,         /* Der Index des Baumes, kommt vom RCS */
    OK_KNOPF,       /* Der Objektindex gleichen Ursprungs *7
    "Ja", "Oui",    /* Die Übersetzungen */
    -1              /* Das Ende der Liste */
};

Tabelle 1

Speicherverwaltung

Ab hier kann (fast) normal wie mit einem GEM-Programm gearbeitet werden. Jedoch darf der vom Modul benötigte Speicherplatz inklusive Variablen/Daten 25 K nicht überschreiten. Da Harlekin ein Accessory ist, fordert es seinen Speicher nur einmal direkt nach Programmstart an. Diese besagten 25 K können jedoch mittels des Moduls VECTOR.HPG eigenen Erfordernissen angepaßt werden. Auch kann ein Programm in mehrere Module zerlegt werden, die nacheinander ausgeführt werden können. Harlekin stellt hierfür geeignete Mechanismen zur Verfügung, die wir später noch erläutern.

Ein Modul darf auch nicht die Funktion Malloc() benutzen, um weiteren Speicher anzufordern, denn ein im Hintergrund laufendes Hauptprogramm gibt beim Beenden den gesamten angeforderten Speicher frei, also auch den, den das Harlekin-Modul mit Malloc() angefordert hat! Selbst wenn das nicht der Fall wäre, würde durch ein solches Verhalten der Speicher zu stark fragmentiert. Harlekin bietet deshalb verschiedene Möglichkeiten, um an zusätzlichen Speicher zu gelangen. Zum einen kann der ungenutzte Teil der 25K mittels der Funktionen getworkbuf() und freeworkbuf() verwaltet werden. Die Funktion getworkbuf() darf maximal viermal aufgerufen werden. Die so angeforderten Speicherblöcke müssen anschließend unbedingt wieder freigegeben werden! Die Freigabe geschieht dabei automatisch in LIFO-Reihenfolge (last in - first out), denn der Funktion freeworkbuf() kann kein Parameter übergeben werden, mit dem ein Speicherblock gekennzeichnet werden könnte.

Die andere Methode, an Speicher zu gelangen, stellen die Funktionen set_tmpbuf_size() sowie get_tmpbuf_size() dar. Sie zapfen den zentralen Memorypool von Harlekin, in dem der gesamte verbleibende Speicher aller anderen HPG-Module verwaltet wird, direkt an.

Ein neues Modul

Damit dieser Teil nicht allzu theoretisch bleibt, folgt als Demonstration das Listing eines kleinen HPG-Moduls, das die Belegung der Festplattenpartitionen anzeigt (siehe Abbildung l). Dieses Modul ist als Basis für eigene Experimente gedacht und noch beliebig erweiterbar. Das Programm wurde mit Turbo-C entwickelt; aus oben angeführten Gründen sollte dabei auf jeden Fall die abgedruckte Projektdatei benutzt werden! Das Icon für das Modul ist in Abbildung 2 zu sehen. Es kann im Harlekin-eigenen Modul HPGEDIT eingegeben und dort ins frisch compilierte Modul eingefügt werden.

Im nächsten Teil werden die restlichen Funktionen beschrieben, und ein nützliches neues HPG-Modul darf natürlich auch nicht fehlen.

Uwe Hax & Oliver Scholz

/*
 * DFREE.H
 * Objektindizes, wie vom RCS geliefert
 *
 * von Oliver Scholz, Januar 1992
 * (c) 1992 MAXON Computer
 */

#define DFREE 0     /* TREE */
#define CLOSE 1     /* OBJECT in TREE #0 */
#define OFFSET 3    /* OBJECT in TREE #0 */
#define CNAME 4     /* OBJECT in TREE #0 */
#define DNAME 5     /* OBJECT in TREE #0 */
#define ENAME 6     /* OBJECT in TREE #0 */
#define GNAME 7     /* OBJECT in TREE #0 */
#define FNAME 8     /* OBJECT in TREE #0 */
#define CGREY 9     /* OBJECT in TREE #0 */
#define CBAR 10     /* OBJECT in TREE #0 */
#define DGREY 11    /* OBJECT in TREE #0 */
#define DBAR 12     /* OBJECT in TREE #0 */
#define EGREY 13    /* OBJECT in TREE #0 */
#define EBAR 14     /* OBJECT in TREE #0 */
#define FGREY 15    /* OBJECT in TREE #0 */
#define FBAR 16     /* OBJECT in TREE #0 */
#define GGREY 17    /* OBJECT in TREE #0 */
#define GBAR 18     /* OBJECT in TREE #0 */
#define HGREY 19    /* OBJECT in TREE #0 */
#define HBAR 20     /* OBJECT in TREE #0 */
#define HNAME 21    /* OBJECT in TREE #0 */
#define IGREY 22    /* OBJECT in TREE #0 */
#define IBAR 23     /* OBJECT in TREE #0 */
#define JGREY 24    /* OBJECT in TREE #0 */
#define JBAR 25     /* OBJECT in TREE »0 */
#define INAME 26    /* OBJECT in TREE #0 */
#define JNAME 27    /* OBJECT in TREE #0 */
#define FREEC 28    /* OBJECT in TREE #0 */
#define FREED 29    /* OBJECT in TREE #0 */
#define FREEE 30    /* OBJECT in TREE #0 */
#define FREEF 31    /* OBJECT in TREE #0 */
#define FREEG 32    /* OBJECT in TREE #0 */
#define FREEH 33    /* OBJECT in TREE #0 */
#define FREEI 34    /* OBJECT in TREE #0 */
#define FREEJ 35    /* OBJECT in TREE #0 */
#define TOTALC 36   /* OBJECT in TREE »0 */
#define TOTALD 37   /* OBJECT in TREE #0 */
#define TOTALE 38   /* OBJECT in TREE #0 */
#define TOTALF 39   /* OBJECT in TREE #0 */
#define TOTALG 40   /* OBJECT in TREE #0 */
#define TOTALH 41   /* OBJECT in TREE #0 */
#define TOTALI 42   /* OBJECT in TREE #0 */
#define TOTALJ 43   /* OBJECT in TREE #0 */
#define TITLE 44    /* OBJECT in TREE #0 */
#define DRIVE 45    /* OBJECT in TREE #0 */
#define USAGE 46    /* OBJECT in TREE #0 */
#define FREE 47     /* OBJECT in TREE #0 */

; DFREE.PRJ
;
; von Oliver Scholz, Januar 1992
;


C:\HARLEKIN\BIN\HPG\DFREE.HPG 
.C[-K -M -G] .L[-V -S=0]
=
HPGSTART.O 
DFREE.C 
TCFLTLIB.LIB 
TCSTDLIB.LIB 
TCTOSLIB.LIB 
TCGEMLIB.LIB

/*
 * DFREE.RSH
 *
 * von Oliver Scho1z, Januar 1992 
 *
 */

#define TOOBJ 0 
#define FREEBB 0 
#define FREEIMG 0 
#define FREESTR 37

BYTE *rs_strings[] =
{
    "STRING", "C:", "D:", "E:", "G:", "F:",
    "H:", "I:", "J;" ,
    "999.99", "999.99", "999.99", "999.99", 
    "999.99", "999.99", "999.99", "999.99", 
    "999.99", "999.99", "999.99", "999.99", 
    "999.99", "999.99", "999.99", "999.99",
    " Hard Disk Usage Information ", "", "", 
    "Drive", "", "",
    "Usage", "", "",
    "Free MBs", "", ""
};

LONG rs_frstr[] = { o };

BITBLK rs_bitblk[] = { 0 };

LONG rs_frimg[] = { 0 } ;

ICONBLK rs_iconblk[] = { 0 };

TEDINFO rs_tedinfo[] =
{
    25L, 26L, 27L, 3, 6, 2, 0x11C1, 0x0, 255, 30,1,
    28L, 29L, 30L, 3, 6, 0, 0x1180, 0x0, 255, 6,1,
    31L, 32L, 33L, 3, 6, 0, 0x1180, 0x0, 255, 6,1,
    34L, 35L, 36L, 3, 6, 0, 0x1180, 0x0, -1, 9,1
};

OBJECT rs_object[] =
{
    -1, 1, 47, G_BOX, NONE, OUTLINED, 0x21101L, 
    0,0, 570,15,
    2, -1, -1, G_BOXCHAR, 0x5, NORMAL, 0x5FF1100L, 
    0,0, 770,1,
    44, 3, 43, G_BOX, NONE, NORMAL, 0xFF1101L, 
    513,2, 1079,2060,
    4, -1, -1, G_STRING, HIDETREE, NORMAL, 
    0x0L, 1025,3585, 6,1,
    5, -1, -1, G_STRING, NONE, NORMAL, 0x1L,
    2,257, 3,1,
    6, -1, -1, G_STRING, NONE, NORMAL, 0x2L,
    2,1538, 3,1,
    7, -1, -1, G_STRING, NONE, NORMAL, 0x3L,
    2,2819, 3,1,
    8, -1, -1, G_STRING, NONE, NORMAL, 0x4L,
    2,1286, 3,1,
    9, -1, -1, G_STRING, NONE, NORMAL, 0x5L,
    2,5, 3,1,
    11, 10, 10, G_BOX, NONE, NORMAL, 0XFF1141L, 
    525,513, 546,3840,
    9, -1, -1, G_BOX, NONE, NORMAL, 0xFF1111L,
    0,0, 1793,3840,
    13, 12, 12, G_BOX, NONE, NORMAL, 0xFF1141L, 
    525,1794, 546,3840,
    11, -1, -1, G_BOX, NONE, NORMAL, 0xFF1111L, 
    0,0, 1793,3840,
    15, 14, 14, G_BOX, NONE, NORMAL, 0xFF1141L, 
    525,3075, 546,3840,
    13, -1, -1, G_BOX, NONE, NORMAL, 0xFF1111L,
    0,0, 1793,3840,
    17, 16, 16, G_BOX, NONE, NORMAL, 0xFF1141L, 
    525,261, 546,3840,
    15, -1, -1, G_BOX, NONE, NORMAL, 0xFF1111L,
    0,0, 1793,3840,
    19, 18, 18, G_BOX, NONE, NORMAL, 0xFF1141L, 
    525,1542, 546,3840,
    17, -1, -1, G_BOX, NONE, NORMAL, 0xFF1111L,
    0,0, 1793,3840,
    21, 20, 20, G_BOX, NONE, NORMAL, 0XFF1141L, 
    525,2823, 546,3840,
    19, -1, -1, G_BOX, NONE, NORMAL, 0xFF1111L,
    0,0, 1793,3840,
    22, -1, -1, G_STRING, NONE, NORMAL, 0x6L,
    2,2567, 3,1,
    24, 23, 23, G_BOX, NONE, NORMAL, 0xFF1141L, 
    525,9, 546,3840,
    22, -1, -1, G_BOX, NONE, NORMAL, 0xFF1111L,
    0,0, 1793,3840,
    26, 25, 25, G_BOX, NONE, NORMAL, 0xFF1141L, 
    525,1290, 546,3840,
    24, -1, -1, G_BOX, NONE, NORMAL, 0xFF1111L,
    0,0, 1793,3840,
    27, -1, -1, G_STRING, NONE, NORMAL, 0x7L,
    2,3848, 3,1,
    28, -1, -1, G_STRING, NONE, NORMAL, 0x8L,
    2,1034, 3,1,
    29, -1, -1, G_STRING, NONE, NORMAL, 0x9L,
    1328,257, 6,1,
    30, -1, -1, G_STRING, NONE, NORMAL, 0xAL,
    1328,1538, 6,1,
    31, -1, -1, G_STRING, NONE, NORMAL, 0xBL,
    1328,2819, 6,1,
    32, -1, -1, G_STRING, NONE, NORMAL, 0xCL,
    1328,5, 6,1,
    33, -1, -1, G_STRING, NONE, NORMAL, 0xDL,
    1328,1286, 6,1,
    34, -1, -1, G_STRING, NONE, NORMAL, 0xEL,
    1328,2567, 6,1,
    35, -1, -1, G_STRING, NONE, NORMAL, 0xFL,
    1328,3848, 6,1,
    36, -1, -1, G_STRING, NONE, NORMAL, 0x10L,
    1328,1034, 6,1,
    37, -1, -1, G_STRING, NONE, NORMAL, 0x11L,
    1285,257, 6,1,
    38, -1, -1, G_STRING, NONE, NORMAL, 0x12L,
    1285,1538, 6,1,
    39, -1, -1, G_STRING, NONE, NORMAL, 0x13L,
    1285,2819, 6,1,
    40, -1, -1, G_STRING, NONE, NORMAL, 0x14L,
    1285,5, 6,1,
    41, -1, -1, G_STRING, NONE, NORMAL, 0x15L,
    1285,1286, 6,1,
    42, -1, -1, G_STRING, NONE, NORMAL, 0x16L,
    1285,2567, 6,1,
    43, -1, -1, G_STRING, NONE, NORMAL, 0x17L,
    1285,3848, 6,1,
    2, -1, -1, G_STRING, NONE, NORMAL, 0x18L,
    1285,1034, 6,1,
    45, -1, -1, G_BOXTEXT, NONE, NORMAL, 0x0L, 
    770,0, 1847,1,
    46, -1, -1, G_TEXT, NONE, NORMAL, 0x1L,
    3,1793, 1800,1,
    47, -1, -1, G_TEXT, NONE, NORMAL, 0x2L,
    280,1793, 782,1,
    0, -1, -1, G_TEXT, LASTOB, NORMAL, 0x3L, 
    816,1537, 8,1};

LONG rs_trindex(] = { 0L };

struct foobar 
{
    WORD    dummy;
    WORD    *image;
} rs_imdope[] = { 0 };

#define NUM_STRINGS 37 
#define NUM_FRSTR 0 
#define NUM_IMAGES 0 
#define NUM_BB 0 
#define NUM_FRIMG 0 
#define NUM_IB 0 
#define NUM_TI 4 
#define NUM_OBS 48 
#define NUM_TREE 1

/*
 * Demonstrationsprogramm zur Programmierung
 * eines HPG Moduls:
 * Grafische Darstellung des Belegungsgrades
 * der Harddisk Partitionen
 *
 * Version 1.0
 ***************************************************
 * von Oliver Scholz, Januar 1992
 * (c) 1992 MAXON Computer 
 */

#include <portab.h>
#include <stdlib.h>
#include <tos.h>
#include <string.h>

/*
 * aus <stdio.h>: (kann nicht included werden;
 */

WORD sprintf(BYTE *string,
        const BYTE *format, ... );
WORD errno; /* Startup-Code fehlt */

#include "hpglib.h"

/*
 * Objektdefinitionen, vom RCS erstellt 
 */
#include "dfree.h"

/*
 * Name der Resourcedatei 
 */
#define RSC_RSH "dfree.rsh"

#include "rshi.h"

/*
 * Definitionen abschalten, siehe Text 
 */
#undef WORD 
#undef BYTE 
#undef LONG

/*
 * Die Texte der Objekte, hier leider nur
 * Englisch/Deutsch, die dänische/französische
 * Übersetzung darf der Leser nach Geschmack 
 * selbst einfügen...
 * (erste praktische Übung...)
 */
static LNGDEF language[] =
{
    DFREE, TITLE,
    " Auslastung der Harddisk-Partitionen ", "",
    DFREE, DRIVE, "Laufwerk", "",
    DFREE, USAGE, "Belegungsgrad", "",
    DFREE, FREE, "Freie MB", "",
    -1
};

#define MAXDRXVE 8

WORD names[MAXDRIVE ] = 
{
    CNAME, DNAME, ENAME, FNAME,
    GNAME, HNAME, INAME, JNAME
};

WORD gauges[MAXDRIVE] =
{
    CBAR, DBAR, EBAR, FBAR,
    GBAR, HBAR, IBAR, JBAR
};

WORD backgd[MAXDRIVE] =
{
    CGREY, DGREY, EGREY, FGREY,
    GGREY, HGREY, IGREY, JGREY
} ;

WORD _free[MAXDRIVE] =
{
    FREEC, FREED, FREEE, FREEF,
    FREEG, FREEH, FREEI, FREEJ
};

WORD total[MAXDRIVE] =
{
    TOTALC, TOTALD, TOTALE, TOTALF,
    TOTALG, TOTALH, TOTALI, TOTALJ
};

OBJECT *dfree;

LONG read_drvbits (VOID);
VOID main (VOID);

/*
 * Das Hauptprogramm.. (endlich!)
 */

VOID main (VOID)
{
    WORD button,i,mask;
    WORD drvbits = (WORD)read, drvbits();
    DISKINFO info;
    float mb;
    char buffer[16];

    FIX_RSC();
    /*
     * eingestellte Sprache eintragen 
     */
    fix_language(tree,language);

    /*
     * Adresse des Objektbaumes holen 
     */
    dfree = tree[DFREE];

    /*
     * Laufwerk C maskieren 
     */
    mask = 0x4;

    for (i = 0; i < MAXDRIVE; i++)
    {
        /*
         * Laufwerk vorhanden ?
         */

        if (!(drvbits & mask))
        {
            /*
             * Nein: dazugehörige Objekte verstecken 
             */
            dfree[names[i]].ob_flags |= HIDETREE; 
            dfree[gauges[i]].ob_flags |= HIDETREE; 
            dfree[backgd[i]].ob_flags |= HIDETREE; 
            dfree[_free[i]].ob_flags |= HIDETREE; 
            dfree[total[i]] ob_flags |= HIDETREE;
        }
        else
        {
            /*
             * Ja: Objekte zeigen 
             */
            dfree[names[i]].ob_flags &= ~HIDETREE; 
            dfree[gauges[i]].ob_flags &= ~HIDETREE; 
            dfree[backgd[i]].ob_flags &= ~HIDETREE; 
            dfree[_free[i]].ob_flags &= ~HIDETREE; 
            dfree[total[i]] ob_flags &= ~HIDETREE;

            /*
             * Diskinformationen lesen 
             */
            if (!Dfree(&info, i + 3))
            {
                /*
                 * Balkenbreite berechnen und
                 * einstellen 
                 */
                dfree[gauges[i]].ob_width = (WORD)
                    ((info.b_total - info.b_free)
                    * dfree[backgd[i]]-ob_width 
                    / info.b_total);

                mb = (float)info.b_free * info.b_secsiz * 
                            info.b_clsiz / 1024 / 1024;

                sprintf(buffer,"%6.2f",mb); 
                strncpy(dfree[_free[i]].ob_spec.free_string,buffer,6);

                mb = (float)info.b_total * info.b_secsiz 
                     * info.b_clsiz / 1024 / 1024;

                sprintf(buffer,"%6.2f",mb); 
                strncpy(dfree[total[i]].ob_spec.free_string,buffer,6);
            }
        }

        /*
         * Maske für nächstes Laufwerk 
         */
        mask = mask « 1;
    }

    /*
     * Maus abschalten und Dialogbox zeichnen 
     */
    mouse_off(); 
    obopen(dfree); 
    mouse_on();

    do
    {
        /*
         * Dialog abarbeiten, Doppelclick ignorieren 
         */
        button = obdoform(dfree, 0) & 0x7fff;
    }
    while (button != CLOSE);

    /*
     * Dialogbox schließen, zurück zum Harlekin 
     */
    obclose(dfree);

    /*
     * _keine_ exit()-Aufrufe verwenden !
     */
}

/*
 * drvbits-Variable lesen 
 */
LONG read_drvbits (VOID)
{
    LONG ssp;
    LONG value;

    ssp=Super(0L);
    value = *(LONG *)0x4C2L;
    Super((VOID *)ssp);

    return(value);
}


Aus: ST-Computer 04 / 1992, Seite 112

Links

Copyright-Bestimmungen: siehe Über diese Seite