GNavigia und Da­ten­ban­ken

Pro­gram­mie­ren Sie ei­ne Da­ten­ban­kan­bin­dung mit­tels COM

Dies Variante wird so nicht mehr unterstützt.

Wer sich mit dem Com­po­nent Ob­ject Mo­del, kurz «COM», aus­kennt, kann ei­ne un­ab­hän­gi­ge, zur Lauf­zeit nach­lad­ba­re Da­ten­ban­kan­bin­dung für GNavigia schrei­ben. Un­ter .NET geht das oh­ne Zwei­fel  kom­for­ta­bler, ist aber nicht zwin­gend er­for­der­lich. Ei­ne Bei­spie­lan­bin­dung, von der .NET-Pro­gram­me ab­lei­ten kön­nen, liegt GNavigia un­ter dem Na­men GpsDa­ta­ba­seAc­cess bei. Wenn Sie die Be­zeich­nung «Da­ten­ban­kan­bin­dung» sehr weit fas­sen, kön­nen Sie prak­tisch al­le Ar­ten von Aus­wer­tun­gen auf den Da­ten auf­setz­ten.

Das Ob­jekt muss da­zu le­dig­lich ei­nen pa­ra­me­ter­lo­sen Kon­struk­tor so­wie die IGpsDa­ta­ba­seAc­cess Schnitt­stel­le im­ple­men­tie­ren und die Re­gis­trie­rung als COM Ob­jekt um den Un­ter­schlüs­sel

  {8BE02F24-766C-4ba3-A744-42FF0E3F8564}

er­wei­tern. Wer von der o.a. Klas­se ab­lei­tet, er­hält die Er­zeu­gung des Un­ter­schlüs­sels «frei Haus». Vor­sicht: Für Ih­re ei­ge­ne Da­ten­bank­klas­se be­nö­ti­gen Sie ei­ne an­de­re, neue GUID! Ei­ne GUID er­zeugt man mit dem Pro­gramm GUIDGEN.EXE, dass man über Goo­gle auf den Sei­ten von Mi­cro­soft fin­det. Es soll­te bei al­len COM-Ent­wick­lungs­tools da­bei sein! Ggf. ge­ne­riert das Neu­an­le­gen ei­nes .NET Pro­jekts, das für COM re­gis­triert wird, ei­ne sol­che GUID in der Da­tei As­sem­b­lyIn­fo.cs.

Die GUID wird aus­ge­wer­tet, wenn im Me­nü «Ex­tras/Da­ten­ban­kan­bin­dung» ge­wählt wird. Es er­scheint dann ei­ne Lis­te al­ler Ob­jek­te zur Aus­wahl, die die­sen Un­ter­schlüs­sel an­ge­ben. Die Auf­lis­tung dau­ert ei­nen klei­nen Mo­ment. Der dar­ge­stell­te Na­me ist der des COM Ob­jekts, auch als «Prog-ID» be­zeich­net; in­tern wird die GUID ge­spei­chert.

Wenn Sie ei­ne An­bin­dung ge­schrie­ben ha­ben, die zu­min­dest den kor­rek­ten Kon­struk­tor und die er­for­der­li­chen Metho­den im­ple­men­tiert so­wie die o.a. Voraus­set­zun­gen er­füllt, er­scheint nach der Aus­wahl ein wei­te­rer Menü­punkt «Da­ten­bank», der die ab­ge­bil­de­ten Un­ter­menü­punk­te ent­hält.
Zur Re­gis­trie­rung des COM-Objekts muss der Ent­wick­ler über Ad­mi­nis­tra­tor­rech­te ver­fü­gen, da die Ein­trä­ge un­ter HKEY_CLASSES_ROOT er­fol­gen. Wer nicht als Ad­mi­nis­tra­tor ent­wi­ckeln will, der kann, zu­min­dest un­ter .NET, zur ers­ten Re­gis­trie­rung die Ent­wick­lungs­um­ge­bung als Ad­min­stra­tor star­ten und da­nach die Op­ti­on «Für COM re­gis­trie­ren» aus­schal­ten. Die Re­gis­trie­rung ist nur ein­mal nö­tig, um das COM Ob­jekt und das In­ter­face be­kannt zu ma­chen, da­nach er­folgt die Ent­wick­lung als ganz nor­ma­le Klas­sen­bi­blio­thek.

Steue­rung der Da­ten­bank­zu­grif­fe

Die Funk­tio­na­li­tät, die die Schnitt­stel­le IGpsDa­ta­ba­seAc­cess zur Ver­fü­gung stellt, lässt sich am Bes­ten am auf­ge­klapp­ten Me­nü do­ku­men­tie­ren; da­bei lie­fern die Ei­gen­schaf­ten (Pro­per­ties) die Tex­te für die Menü­punk­te, wäh­rend die Metho­den die ei­gent­li­che Da­ten­bank­funk­tio­na­li­tät be­reit­stel­len. GpsI­ni­tia­li­ze, GpsSa­veDa­ta und GpsLoa­dDa­ta wer­den di­rekt aus dem Me­nü auf­ge­ru­fen. GpsConnect und GpsDis­connect wer­den zu ge­ge­be­ner Zeit ge­ru­fen, z.B. wenn der Be­nut­zer die Da­ten­ban­kan­bin­dung wech­selt, in­dem er aus dem Me­nü «Ex­tras/Da­ten­ban­kan­bin­dung» ei­nen an­de­ren Da­ten­ban­k­an­schluss aus­wählt. Le­dig­lich der Menü­punkt «Ab­mel­den von der Da­ten­bank», der in­tern GpsDis­connect auf­ruft, wird al­lein von GNavigia ver­wal­tet.

Ini­tia­li­sie­rung des Menüs

Das Me­nü wird ei­ner­seits aus der An­fra­ge an die Schnitt­stel­len­me­tho­den in­itia­li­siert, an­de­rer­seits aber auch aus In­for­ma­tio­nen aus der Re­gis­trie­rungs­da­ten­bank. Wenn ei­ne gül­ti­ge Da­ten­bank­ver­bin­dung aus­ge­wählt wird, er­scheint sie beim Wie­der­auf­star­ten der Appli­ka­ti­on, in­itia­li­siert aus der Re­gis­trie­rung.

La­den und Spei­chern der Da­ten

Zu­dem merkt sich GNavigia die Her­kunft der Da­ten, wes­halb nur beim erst­ma­li­gen Si­chern und ak­ti­vier­ter Da­ten­bank zwi­schen dem Spei­chern in die Da­ten­bank und dem in ei­ne Da­tei un­ter­schie­den wer­den muss. Wenn Sie sich für ei­ne Da­tei als Spei­cher­ort ent­schie­den ha­ben, kön­nen Sie im­mer noch aus dem Me­nü das Zu­rück­schrei­ben der Da­ten in die Da­ten­bank ver­an­las­sen, wo­durch je­doch nur der ak­tu­el­le Stand ge­si­chert wird. Beim Beant­wor­ten ei­ner Si­cher­heits­ab­fra­ge wird fol­ge­rich­tig nur in die Da­tei ge­schrie­ben.

Die IGpsDa­ta­ba­seAc­cess Schnitt­stel­le

Die IGpsDa­ta­ba­seAc­cess Schnitt­stel­le ist be­wusst ein­fach ge­hal­ten, so­dass COM Ser­ver kei­ne .NET In­ter­na ken­nen müs­sen. Was sie ken­nen müs­sen ist je­doch die in­ter­ne Da­ten­struk­tur von GNavigia, was we­gen der XML-Struk­tur, mit der al­le Da­ten über die Schnitt­stel­le aus­ge­tauscht wer­den, aber sehr fle­xi­bel ge­hand­habt wer­den kann. Das In­ter­face ist wie folgt de­fi­niert:

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 for­ma­le Pa­ra­me­ter «hwnd» ist vom Typ int (Int32) und re­prä­sen­tiert je­nes Win­dowhand­le, das die Ur­ge­stei­ne der Fens­ter­pro­gram­mie­rung seit den aus­ge­hen­den 80er Jah­ren des vo­ri­gen Jahr­hun­derts ken­nen soll­ten. Es hat nur ei­nen ein­zi­gen Wert, näm­lich ei­nen even­tu­ell not­wen­di­gen Dia­log an ei­nem Fens­ter fest­ma­chen zu kön­nen und so die Ket­te der durch mo­da­le Dia­lo­ge ab­ge­schal­te­ten Fens­ter nicht zu un­ter­bre­chen. Der .NET-Pro­gram­mie­rer kann das Hand­le di­rekt nut­zen, in­dem er ein Ob­jekt der  fens­ter­na­hen Klas­se «Tem­po­ra­ryOw­ner» an­legt, die selbst wie­der­um kei­ne an­de­re Auf­ga­be hat, als die Schnitt­stel­le «IWin32Win­dow» be­reit­zu­stel­len, die ih­rer­seits kei­ne an­de­re Auf­ga­be hat, als das Win­dowhand­le ver­füg­bar zu ma­chen. COM Pro­gram­mie­rer ha­ben es an die­ser (und nur an die­ser) Stel­le ein­fa­cher: Sie cas­ten den Wert auf HWND und kön­nen ihn als pa­rent win­dow hand­le be­nut­zen.

Rück­ga­be­wer­te

Wer­fen Sie nie­mals ei­ne Aus­nah­me (Ex­cep­ti­on), die die Schnitt­stel­le ver­lässt. Sor­gen Sie da­für, dass die Aus­nah­men in­ner­halb der Schnitt­stel­le blei­ben und be­nut­zen Sie die vor­ge­se­he­nen XML-Doku­men­te als Rück­ga­be­wer­te, al­so «Re­spon­se» und «Er­rorRe­spon­se». Wer .NET be­nutzt, kann die ent­spre­chen­den Metho­den der  KorKarNet.Uti­li­ties.dll  auf­ru­fen. Da­mit ist das Ver­pa­cken der In­for­ma­tion be­son­ders ein­fach. Al­ler­dings bleibt die Auf­ga­be be­ste­hen, die Da­ten zu ei­nem GNavigia kon­for­men XML-Doku­ment zu­sam­men­zu­stel­len. Das The­ma «GNavigia für Fort­ge­schrit­te­ne» wid­met sich die­sem an­spruchs­vol­len The­ma.

Der har­te Kern der Da­ten­ban­kan­bin­dung

Die Da­ten­ban­kan­bin­dung stellt im Kern zwei Metho­den zur Ver­fü­gung, die die Ar­beit des Da­ten­aus­tauschs über­neh­men:

string GpsSaveData(int hwnd, string xmlDataString);
string GpsLoadData(int hwnd);

Da­ten in der Da­ten­bank spei­chern

Wid­men wir uns zu­nächst dem Spei­chern von Da­ten. Hier macht es sich GNavigia be­son­ders ein­fach, in­dem es ex­akt den­sel­ben Do­ku­mentin­halt in ei­ne Zei­chen­ket­te ver­packt, die das Pro­gramm auch auf Da­tei aus­ge­ben wür­de.

Ob ei­ne Da­ten­ban­kan­wen­dung die In­for­ma­tio­nen über Ob­jek­te und Lay­out aus­wer­ten will oder nur die pri­mären Da­ten (Tracks, Track­punk­te und Weg­punk­te) be­rück­sich­tigt, ist letzt­lich je­der Appli­ka­ti­on selbst über­las­sen. Ei­ne Mi­schung aus da­tei­ge­stütz­ter Lay­out­de­fi­ni­ti­on und da­ten­bank­ge­spei­cher­ter Punkt­in­for­ma­ti­on ist nicht mög­lich. Denk­bar ist, dass die Da­ten­ban­kappli­ka­ti­on die Lay­out­de­fi­ni­ti­on in ei­ner ge­schlos­se­nen Zei­chen­ket­te im XML-For­mat in die Da­ten­bank schreibt. Al­ler­dings ist dann ei­ne Zu­ord­nung von Pri­mär- und Lay­out­da­ten nur durch ei­ne Auf­trags­ver­wal­tung zu rea­li­sie­ren, die hier nicht be­han­delt wird.

Der Rück­ga­be­wert der Metho­de GpsSa­veDa­ta ist ei­ne XML-Zei­chen­ket­te, die die Lis­te der neu in die Da­ten­bank ein­ge­tra­ge­nen Punk­te ent­hält. Die­se be­kom­men beim In­sert ei­ne neue, da­ten­ban­kin­ter­ne ID, hier als glo­bal gül­ti­ge ID (GUID) be­zeich­net, die GNavigia mit­ge­teilt wer­den muss. Die­se Auf­ga­be über­nimmt das Tag «Iden­ti­fier» in der Ant­wort auf die An­fra­ge:

 <Identifier iid="312" guid="AXZ67900jsds00" />

Da­rin ist «iid» die GNa­vi­gia-ID des Punk­tes und «guid» der glo­bal­ly un­i­que iden­ti­fier, den Sie als Be­nut­zer ver­ge­ben ha­ben, um das Ob­jekt in der Da­ten­bank iden­ti­fi­zie­ren zu kön­nen, soll­te al­so da­ten­bank­weit ein­deu­tig sein! Sie er­hal­ten Auf­schluss über die syn­tak­tisch kor­rek­te Aus­ga­be/Plat­zie­rung der GUID, in­dem Sie das Pro­gramm mit dem Pa­ra­me­ter

-guid

auf der Kom­man­do­zei­le auf­ru­fen und ei­ne Da­tei mit min­des­tens ei­nem Weg­punkt, Track, Track­punkt, Ob­jekt, Text­ob­jekt und ei­ner Ob­jek­tre­fe­renz spei­chern. An­sons­ten wird ei­ne lee­re, un­de­fi­nier­te GUID nicht in die Da­tei ge­schrie­ben. Bei die­ser Si­mu­la­ti­on er­hält die GUID den Wert "#Invalid", der spä­ter beim Ein­le­sen der Da­tei wie­der in ei­nen lee­ren Wert über­führt wird.

Da­ten aus der Da­ten­bank la­den

Prin­zi­pi­ell ist das La­de­for­mat iden­tisch mit dem Spei­cher­for­mat, doch lie­gen beim La­den nur die er­fass­ten, ex­ter­nen In­for­ma­tio­nen vor, so­dass die Da­ten kom­pak­ter auf­tre­ten. Da­bei han­delt es sich um das be­reits zu­vor er­wähn­te XML-Doku­ment, das durch ei­ne Sche­ma­da­tei va­li­diert wer­den kann. Die  Sche­ma­da­tei ist al­ler­dings noch nicht rea­li­siert. Wenn Sie sich die Da­ten­struk­tur im Ab­schnitt «GNavigia für Fort­ge­schrit­te­ne» ge­nau­er an­se­hen, wer­den Sie fest­stel­len, dass Sie für die Nach­bil­dung der Da­ten­da­tei­en ei­ne wie auch im­mer ge­ar­te­te Auf­trags­ver­wal­tung be­nö­ti­gen, die die pri­mären Beo­b­ach­tun­gen und die Ob­jekt­bil­dung, die Sie im Lau­fe der Zeit vor­neh­men, zu ei­ner lad­ba­ren Da­ten­struk­tur zu­sam­men­stellt.

Ei­ge­ne Ein­stel­lun­gen trans­por­tie­ren

Da­mit Sie Ein­stel­lun­gen und ei­ge­ne Vor­ga­ben aus der La­de­me­tho­de in die Spei­cher­me­tho­de über­tra­gen kön­nen, kön­nen Sie in die La­de­da­tei ei­ne Ei­gen­da­ten­ken­nung ein­tra­gen. XML-Ele­men­te, die sich zwi­schen den Mar­kie­run­gen

<Database>
</Database>

be­fin­den, wer­den vom Pro­gramm als Gan­zes ge­le­sen, aber nicht in­ter­pre­tiert. Beim Aus­ge­ben der Da­ten als Da­tei oder beim Zu­rück­schrei­ben in die Da­ten­bank wird die­ses Tag wie­der aus­ge­ge­ben. Da­mit ist es mög­lich, oh­ne den Ge­brauch glo­ba­ler Va­ria­blen Da­ten zwi­schen den Metho­den zum La­den und Spei­chern zu trans­por­tie­ren.

Hilfs­funk­tio­nen

Bei­spiel für die Ver­wen­dung der Klas­se Tem­po­ra­ryOw­ner:

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;
}