GNavigia und Datenbanken
Programmieren Sie eine Datenbankanbindung mittels COM


Wer sich mit dem Component Object Model, kurz «COM», auskennt, kann eine unabhängige, zur Laufzeit nachladbare Datenbankanbindung für GNavigia schreiben. Unter .NET geht das ohne Zweifel komfortabler, ist aber nicht zwingend erforderlich. Eine Beispielanbindung, von der .NET-Programme ableiten können, liegt GNavigia unter dem Namen GpsDatabaseAccess bei. Wenn Sie die Bezeichnung «Datenbankanbindung» sehr weit fassen, können Sie praktisch alle Arten von Auswertungen auf den Daten aufsetzten.
Das Objekt muss dazu lediglich einen parameterlosen Konstruktor sowie die IGpsDatabaseAccess Schnittstelle implementieren und die Registrierung als COM Objekt um den Unterschlüssel
{8BE02F24-766C-4ba3-A744-42FF0E3F8564} erweitern. Wer von der o.a. Klasse ableitet, erhält die Erzeugung des Unterschlüssels «frei Haus». Vorsicht: Für Ihre eigene Datenbankklasse benötigen Sie eine andere, neue GUID! Eine GUID erzeugt man mit dem Programm GUIDGEN.EXE, dass man über Google auf den Seiten von Microsoft findet. Es sollte bei allen COM-Entwicklungstools dabei sein! Ggf. generiert das Neuanlegen eines .NET Projekts, das für COM registriert wird, eine solche GUID in der Datei AssemblyInfo.cs.
Die GUID wird ausgewertet, wenn im Menü «Extras/Datenbankanbindung» gewählt wird. Es erscheint dann eine Liste aller Objekte zur Auswahl, die diesen Unterschlüssel angeben. Die Auflistung dauert einen kleinen Moment. Der dargestellte Name ist der des COM Objekts, auch als «Prog-ID» bezeichnet; intern wird die GUID gespeichert.

Zur Registrierung des COM-Objekts muss der Entwickler über Administratorrechte verfügen, da die Einträge unter HKEY_CLASSES_ROOT erfolgen. Wer nicht als Administrator entwickeln will, der kann, zumindest unter .NET, zur ersten Registrierung die Entwicklungsumgebung als Adminstrator starten und danach die Option «Für COM registrieren» ausschalten. Die Registrierung ist nur einmal nötig, um das COM Objekt und das Interface bekannt zu machen, danach erfolgt die Entwicklung als ganz normale Klassenbibliothek.
Steuerung der Datenbankzugriffe
Die Funktionalität, die die Schnittstelle IGpsDatabaseAccess
zur Verfügung stellt, lässt
sich am Besten am aufgeklappten Menü dokumentieren; dabei liefern
die
Eigenschaften (Properties) die Texte für die Menüpunkte,
während die
Methoden die eigentliche Datenbankfunktionalität bereitstellen. GpsInitialize,
GpsSaveData und GpsLoadData werden
direkt aus dem Menü
aufgerufen. GpsConnect und GpsDisconnect werden zu
gegebener Zeit
gerufen, z.B. wenn der Benutzer die Datenbankanbindung wechselt, indem
er aus dem Menü «Extras/Datenbankanbindung» einen
anderen
Datenbankanschluss auswählt. Lediglich der Menüpunkt
«Abmelden von der
Datenbank», der intern GpsDisconnect aufruft, wird allein von
GNavigia verwaltet.Initialisierung des Menüs
Das Menü wird einerseits aus der Anfrage an die Schnittstellenmethoden initialisiert, andererseits aber auch aus Informationen aus der Registrierungsdatenbank. Wenn eine gültige Datenbankverbindung ausgewählt wird, erscheint sie beim Wiederaufstarten der Applikation, initialisiert aus der Registrierung.Laden und Speichern der Daten
Zudem merkt sich GNavigia die Herkunft der Daten, weshalb nur beim
erstmaligen Sichern und aktivierter Datenbank zwischen dem Speichern in
die Datenbank und dem in eine Datei unterschieden werden muss. Wenn Sie
sich für eine Datei als Speicherort entschieden haben, können
Sie immer
noch aus dem Menü das Zurückschreiben der Daten in die
Datenbank
veranlassen, wodurch jedoch nur der aktuelle Stand gesichert wird. Beim
Beantworten einer Sicherheitsabfrage wird folgerichtig nur in die Datei geschrieben.Die IGpsDatabaseAccess Schnittstelle
Die IGpsDatabaseAccess Schnittstelle ist bewusst einfach gehalten, sodass COM Server keine .NET Interna kennen müssen. Was sie kennen müssen ist jedoch die interne Datenstruktur von GNavigia, was wegen der XML-Struktur, mit der alle Daten über die Schnittstelle ausgetauscht werden, aber sehr flexibel gehandhabt werden kann. Das Interface ist wie folgt definiert:public interface IGpsDatabaseAccess
{
// Read only property: The database name
string GpsDatabaseName { get;}
// Read only property: An appropriate title
string GpsDatabaseTitle { get;}
// Read only property: A kind of tooltip
string GpsDatabaseHint { get;}
// Read only property: Menu item text for GpsInitialize
string GpsInitializeMenuText { get;}
// Read only property: Menu item text for GpsSaveData
string GpsSaveDataMenuText { get;}
// Read only property: Menu item text for GpsLoadData
string GpsLoadDataMenuText { get;}
// Menue called method to initialize database access.
// returns: XmlDocuments.Response() if successfull
string GpsInitialize(int hwnd);
// Menue called method to connect to the database.
// returns: XmlDocuments.Response() if successfull
string GpsConnect(int hwnd);
// Menue called method to disconnect from the database
// returns: XmlDocuments.Response() if successfull
string GpsDisconnect(int hwnd);
// Menue called method to save data to database.
// returns: XmlDocuments.Response() if successfull
string GpsSaveData(int hwnd, string xmlDataString);
// Menue called method to load data from database.
// returns: An XML Data Document String if successfull where the
// string is a fully qualified XML document.
// Mind the schema definition!
string GpsLoadData(int hwnd);
}
Der formale Parameter «hwnd» ist vom Typ int (Int32) und repräsentiert jenes Windowhandle, das die Urgesteine der Fensterprogrammierung seit den ausgehenden 80er Jahren des vorigen Jahrhunderts kennen sollten. Es hat nur einen einzigen Wert, nämlich einen eventuell notwendigen Dialog an einem Fenster festmachen zu können und so die Kette der durch modale Dialoge abgeschalteten Fenster nicht zu unterbrechen. Der .NET-Programmierer kann das Handle direkt nutzen, indem er ein Objekt der fensternahen Klasse «TemporaryOwner» anlegt, die selbst wiederum keine andere Aufgabe hat, als die Schnittstelle «IWin32Window» bereitzustellen, die ihrerseits keine andere Aufgabe hat, als das Windowhandle verfügbar zu machen. COM Programmierer haben es an dieser (und nur an dieser) Stelle einfacher: Sie casten den Wert auf HWND und können ihn als parent window handle benutzen.
Rückgabewerte
Werfen Sie niemals eine Ausnahme (Exception), die die Schnittstelle verlässt. Sorgen Sie dafür, dass die Ausnahmen innerhalb der Schnittstelle bleiben und benutzen Sie die vorgesehenen XML-Dokumente als Rückgabewerte, also «Response» und «ErrorResponse». Wer .NET benutzt, kann die entsprechenden Methoden der KorKarNet.Utilities.dll aufrufen. Damit ist das Verpacken der Information besonders einfach. Allerdings bleibt die Aufgabe bestehen, die Daten zu einem GNavigia konformen XML-Dokument zusammenzustellen. Das Thema «GNavigia für Fortgeschrittene» widmet sich diesem anspruchsvollen Thema.Der harte Kern der Datenbankanbindung
Die Datenbankanbindung stellt im Kern zwei
Methoden zur Verfügung, die die Arbeit des Datenaustauschs übernehmen:string GpsSaveData(int hwnd, string xmlDataString);
string GpsLoadData(int hwnd);
Daten in der Datenbank speichern
Widmen wir uns zunächst dem Speichern von Daten. Hier macht es sich GNavigia besonders einfach, indem es exakt denselben Dokumentinhalt in eine Zeichenkette verpackt, die das Programm auch auf Datei ausgeben würde.Ob eine Datenbankanwendung die Informationen über Objekte und Layout auswerten will oder nur die primären Daten (Tracks, Trackpunkte und Wegpunkte) berücksichtigt, ist letztlich jeder Applikation selbst überlassen. Eine Mischung aus dateigestützter Layoutdefinition und datenbankgespeicherter Punktinformation ist nicht möglich. Denkbar ist, dass die Datenbankapplikation die Layoutdefinition in einer geschlossenen Zeichenkette im XML-Format in die Datenbank schreibt. Allerdings ist dann eine Zuordnung von Primär- und Layoutdaten nur durch eine Auftragsverwaltung zu realisieren, die hier nicht behandelt wird.
Der Rückgabewert der Methode GpsSaveData ist eine XML-Zeichenkette, die die Liste der neu in die Datenbank eingetragenen Punkte enthält. Diese bekommen beim Insert eine neue, datenbankinterne ID, hier als global gültige ID (GUID) bezeichnet, die GNavigia mitgeteilt werden muss. Diese Aufgabe übernimmt das Tag «Identifier» in der Antwort auf die Anfrage:
<Identifier iid="312" guid="AXZ67900jsds00" />
Darin ist «iid» die GNavigia-ID des Punktes und «guid» der globally unique identifier, den Sie als Benutzer vergeben haben, um das Objekt in der Datenbank identifizieren zu können, sollte also datenbankweit eindeutig sein! Sie erhalten Aufschluss über die syntaktisch korrekte Ausgabe/Platzierung der GUID, indem Sie das Programm mit dem Parameter
-guid
auf der Kommandozeile aufrufen und eine Datei mit mindestens einem Wegpunkt, Track, Trackpunkt, Objekt, Textobjekt und einer Objektreferenz speichern. Ansonsten wird eine leere, undefinierte GUID nicht in die Datei geschrieben. Bei dieser Simulation erhält die GUID den Wert "#Invalid", der später beim Einlesen der Datei wieder in einen leeren Wert überführt wird.
Daten aus der Datenbank laden
Prinzipiell ist das Ladeformat identisch
mit dem Speicherformat, doch liegen beim Laden nur die erfassten,
externen Informationen vor, sodass die Daten kompakter auftreten. Dabei
handelt es sich um das bereits zuvor erwähnte XML-Dokument, das
durch
eine
Schemadatei validiert werden kann. Die Schemadatei ist allerdings
noch nicht realisiert. Wenn Sie sich die Datenstruktur im Abschnitt
«GNavigia
für
Fortgeschrittene» genauer ansehen, werden Sie feststellen,
dass Sie
für die Nachbildung der Datendateien eine wie auch immer geartete
Auftragsverwaltung benötigen, die die primären Beobachtungen
und die
Objektbildung, die Sie im Laufe der Zeit vornehmen, zu einer ladbaren Datenstruktur zusammenstellt.Eigene Einstellungen transportieren
Damit Sie Einstellungen und eigene Vorgaben aus der Lademethode in die
Speichermethode übertragen können, können Sie in die
Ladedatei eine
Eigendatenkennung eintragen. XML-Elemente, die sich zwischen den Markierungen<Database>
</Database>
befinden, werden vom Programm als Ganzes gelesen, aber nicht interpretiert. Beim Ausgeben der Daten als Datei oder beim Zurückschreiben in die Datenbank wird dieses Tag wieder ausgegeben. Damit ist es möglich, ohne den Gebrauch globaler Variablen Daten zwischen den Methoden zum Laden und Speichern zu transportieren.
Hilfsfunktionen
Beispiel für die Verwendung der Klasse TemporaryOwner:
string IDatabaseAccess.GpsSaveData(int hwnd, string xmlDataString);{
MessageBox.Show(new TemporaryOwner(hwnd),
String.Format("The method received a string of {0} bytes.",
xmlDataString.Length));
return null;
}