<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>http://wiki.omnibussimulator.de/omsiwikineu.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Holmexx</id>
	<title>OMSIWiki - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.omnibussimulator.de/omsiwikineu.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Holmexx"/>
	<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Spezial:Beitr%C3%A4ge/Holmexx"/>
	<updated>2026-06-19T12:15:49Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.31.0</generator>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=777</id>
		<title>Hauptseite</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=777"/>
		<updated>2012-11-26T05:54:59Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font style=&amp;quot;font-size:1.2em;&amp;quot;&amp;gt;&lt;br /&gt;
'''Herzlich willkommen auf der deutschen Version von OMSIWiki!'''&lt;br /&gt;
&lt;br /&gt;
Hier geht's direkt zu einer der Hauptkategorien:&lt;br /&gt;
&lt;br /&gt;
* [[FAQs - Häufig gestellte Fragen]]&lt;br /&gt;
* [[:Kategorie:Busfahren in OMSI|Busfahren in OMSI]]&lt;br /&gt;
* Entwicklung von Addons:&lt;br /&gt;
** [[:Kategorie:Nachschlagewerk für Addon-Entwickler|Nachschlagewerk]]&lt;br /&gt;
** [[:Kategorie:Tutorials für Addon-Entwickler|Tutorials]]&lt;br /&gt;
** [[:Kategorie:Tipps und Tricks für Addon-Entwickler|Tipps und Tricks]]&lt;br /&gt;
* [[:Kategorie:Anschlussprojekte|Anschlussprojekte (z.B. Addon-Manager, OAT)]]&lt;br /&gt;
* [[:Kategorie:Addon-Präsentationen|Addon-Präsentationen]]&lt;br /&gt;
* [[:Kategorie:Hintergrundinformationen|Hintergrundinformationen]]&lt;br /&gt;
&lt;br /&gt;
'''Achtung: Vor dem Verfassen eigener Beiträge bitte zuerst die Regeln lesen!''' Weiter unten gibt es noch eine Ultra-Kurzanleitung für Neulinge.&lt;br /&gt;
&lt;br /&gt;
''Aktuell in Arbeit:''&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Tutorial zum programmieren eines [[OMSI Plugin Framework|OMSI-Plugins in C++]] (Fortschritt: ####------) --[[Benutzer:Holmexx|Holmexx]] 06:54, 26. Nov. 2012 (MET) &lt;br /&gt;
* Übersetzen der Artikel, zuletzt [[Repainting of OMSI buses (also over panes)]] --[[Benutzer:Dario|Dario]] 12:04, 17. Jul. 2012 (MEST)&lt;br /&gt;
* [[Fahrpläne erstellen]] --[[Benutzer:Felix (Keyway)|Felix (Keyway)]] 16:21, 31. Dez. 2011 (MET) ----- Weitergeführt von [[Benutzer:Dario|Dario]] 11:33, 18. Jul. 2012 (MEST)&lt;br /&gt;
* ''(aktuell pausiert)'' [[Fahrzeug-SDK]] (c) von Rüdiger, Einbau ins OMSIWiki von --[[Benutzer:Marcel Kuhnt|Marcel Kuhnt]] 16:12, 2. Dez. 2011 (MET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Wir Entwickler von OMSI haben OMSIWiki eingerichtet, um eine bessere Plattform für alle Arten von Informationen rund um OMSI zu erhalten. Folgende Themengebiete sind von uns vorläufig vorgesehen:&lt;br /&gt;
&lt;br /&gt;
* Präsentation von Hintergrundinformationen über das Addon-Design von unserer Seite (Objekt- und Fahrzeugbar, Soundengine, Scriptengine usw.)&lt;br /&gt;
* Tipps und Tricks oder auch ganze Tutorials von Usern z.B. zum Erstellen von Repaints oder Mapbau würden unsere Kernthemen abrunden. Entweder als Ergänzung unserer oder als weiterreichende Artikel.&lt;br /&gt;
* Die Bedienung von OMSI und insbesondere der Busse könnte ein weiterer Themenkomplex sein. Zwar gibt es natürlich ein Handbuch für OMSI, dennoch gibt es vieleicht die eine oder andere Sache, die ausführlicher erklärt werden soll. Hier werden wir uns allerdings etwas zurückhalten.&lt;br /&gt;
* Weiterhin könnten hier bewährte Anschlussprojekte zu OMSI präsentiert werden, z.B. OAT oder der Addon-Manager. Höchstwahrscheinlich werden die zugehörigen Artikel dann von den Leitern oder treuesten Fans dieser Projekte geschrieben, wir werden uns hier ebenfalls zurückhalten.&lt;br /&gt;
* Ähnlich hierzu haben wir nichts gegen eine hochqualitative Präsentation von komplexen Addons; denkbar wäre hier z.B. die Bedienungsanleitung eines Addon-Busses oder die Beschreibung und Hinweise für die Fahrt durch eine Addon-Karte mit Fahrplänen und/oder Karten. Wo wir hier allerdings die Grenze setzen, steht noch nicht fest. Insbesondere sollen hier keine &amp;quot;Mini-Artikel&amp;quot; entstehen, wo nur ein Screenshot von einem Repaint und ein Download-Link präsentiert wird!&lt;br /&gt;
* Selbstverständlich dürfen hier auch gerne Hintergrundinformationen zu unserer Strecke oder unseren Bussen oder aber zu Addons gegeben werden (wie sah Spandau in der Realität 1989 aus? Wie wurde damals in Berlin Bus gefahren?). Es sollte sich aber um abgeschlossene und ernsthaft geschriebene Artikel handeln und es sollte definitiv ein Bezug zu OMSI vorhanden sein! Also keine schnell hingeschriebenen Tagesberichte von irgendeinem Busunternehmen, was keiner kennt und was auch nicht in OMSI mindestens als Addon simuliert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Regeln ==&lt;br /&gt;
&lt;br /&gt;
=== Ist das Thema hier erwünscht? ===&lt;br /&gt;
&lt;br /&gt;
Der Idee von OMSIWiki entsprechend sollte jeder Artikel letztlich in eine der oben genannten Kategorien passen!&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Goldene Regel&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
Zunächst die '''&amp;quot;goldene Regel&amp;quot;''': Bevor ein Artikel verfasst oder geändert wird, sollte stets geschaut werden, ob sich an den Regeln etwas geändert hat! Gerade in der Anfangszeit wird es sicher vorkommen, dass sich Regeln ändern oder neue hinzukommen.&lt;br /&gt;
&lt;br /&gt;
=== Erwünscht ===&lt;br /&gt;
&lt;br /&gt;
* Wenn ihr einen kleinen oder großen Fehler entdeckt (auch in einem unserer Artikel!), dann darf ihn jeder korrigieren! Aber nur, wenn ihr euch dabei auch sicher seid.&lt;br /&gt;
* Ihr findet einen Artikel z.B. im Addon-Handbuch zu trocken? Dann dürft ihr gerne ein kleines Beispiel ergänzen! Von mir weiß ich z.B., dass die Anschauung und Klarheit leidet, wenn ich viele und lange Texte schreibe!&lt;br /&gt;
* Ihr findet einen Fachbegriff, der nicht erklärt wird? Wenn es ein bisher nicht erklärter Begriff von OMSI ist, dürft ihr gerne einen Artikel anfertigen und ihn mit dem Fachbegriff verlinken; handelt es sich um einen allgemeinen Fachbegriff, dann reicht meist ein externer Link zu einem entsprechenden Artikel z.B. in der Wikipedia aus.&lt;br /&gt;
* Um zu vermeiden, dass euch bereits jemand anderes &amp;quot;dazwischen funkt&amp;quot;, obwohl euer Artikel noch gar nicht fertig ist, ergänzt bitte hierzu oben den Hinweis: &amp;quot;''Hinweis: Dieser Artikel befindet sich noch im Aufbau!''&amp;quot;. Dadurch wird auch vermieden, dass der unter Umständen erst halbfertige Artikel schon von jemandem übersetzt wird, sodass nach Fertigstellung der deutschen Version die englische noch unvollständig ist.&lt;br /&gt;
* Wenn euer Artikel auch ein englischsprachiges Pendant hat, dann verknüpft ihn bitte! Ein Blick ans Ende des Quelltextes ''dieser'' Seite zeigt euch, wie das geht! Hat er jedoch ''kein'' Pendant und muss demnach in der englischen OMSIWiki noch angelegt werden, so wäre ein Hinweis ganz oben nicht schlecht: &amp;quot;''Hinweis: Dieser Artikel wurde noch nicht ins Englische übersetzt!''&amp;quot; oder &amp;quot;''Hinweis: Die englische Version muss noch aktualisiert werden!''&amp;quot;&lt;br /&gt;
* Wenn ihr Spaß am Übersetzen habt, dann könnt ihr eine sehr wertvolle Hilfe für OMSIWiki sein! Wenn ihr einen dieser Hinweise entdeckt, scheut euch nicht, den Artikel in die englische OMSIWiki einzupflegen! Ihr solltet danach aber den Original-Autor informieren (damit er die Gelegenheit hat, einmal drüber zu schauen) und dann natürlich die beidseitige Verlinkung mit der deutschen Seite vornehmen und den Hinweis entfernen.&lt;br /&gt;
&lt;br /&gt;
=== Unerwünscht ===&lt;br /&gt;
&lt;br /&gt;
* '''Ganz wichtig: Der Name des Artikels muss wohlüberlegt gewählt werden, weil man den nicht mal eben ändern kann! Wer hier grob fahrlässig schlampt, fliegt raus!'''&lt;br /&gt;
* Schlechter Schreibstil! Was im Chat normal ist und im Forum zwangsweise geduldet wird, ist hier tabu: Bitte gebt euch etwas Mühe, wenn ihr hier einen Artikel verfasst!&lt;br /&gt;
* Werbung für unbekannte, kleine Projekte, Foren, virtuelle Gesellschaften etc. Der Sinn von OMSIWiki ist nicht die Werbung für Projekte! Es soll eine Informationsplattform sein!&lt;br /&gt;
&lt;br /&gt;
Hier dazu was Passendes zum schmunzeln: [http://meta.wikimedia.org/wiki/Wikipedia_Anti-Regeln Wikipedia-Anti-Regeln]&lt;br /&gt;
&lt;br /&gt;
=== Absprachen ===&lt;br /&gt;
&lt;br /&gt;
* Vor Beginn der Arbeit bitte oben bei &amp;quot;Aktuell in Arbeit&amp;quot; eine Zeile mit der geplanten Arbeit und eurer Signatur ergänzen. Nach Fertigstellung diesen wieder entfernen. Sollte jedoch dann gar kein Punkt mehr übrigbleiben, dann ein &amp;quot; * ''Nichts'' &amp;quot; stehen lassen.&lt;br /&gt;
* Wenn ihr größere Korrekturen an unseren Artikeln vornehmt, wär es natürlich gut, wenn ihr uns zumindest nachher darüber informiert, damit wir den Überblick behalten.&lt;br /&gt;
* Bevor ein neuer Artikel verfasst wird, kann es nicht schaden, kurz eine E-Mail an uns Administratoren zu schicken mit euren Planungen.&lt;br /&gt;
* Das Einführen neuer Kategorien hat grundstätzlich in Absprache mit den Administratoren zu geschehen.&lt;br /&gt;
&lt;br /&gt;
* Beachtet auch die Möglichkeit, mit den Autoren auf der Diskussionsseite zu diskutieren! Wie der &amp;quot;Quellcode&amp;quot; einer Diskussionsseite aussieht, seht ihr hier: [[Diskussion:OMSI_Addon_Tester_(OAT)]]. Und nicht vergessen: Die Signatur könnt ihr automatisch erzeugen mit &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;!&lt;br /&gt;
&lt;br /&gt;
=== Multilingualität ===&lt;br /&gt;
&lt;br /&gt;
OMSIWiki ist zweisprachig ausgelegt: Englisch und Deutsch. Wie beim großen Vorbild, der Wikipedia, können die Artikel beider Sprachen miteinander verbunden werden. Dies erfolgt auch auf selbem Wege wie bei Wikipedia. Selbstverständlich ist es erstrebenswert, beide Teile der OMSIWiki auf gleichem Stand zu halten - auch wenn das natürlich praktisch nie ganz der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
=== Zugriff ===&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Wikipedia müsst ihr angemeldet sein, um hier Schreibzugriff zu erhalten. Ich denke, dies ist nicht zu viel verlangt und hilft uns eine gewisse Kontrolle über das Verfassen von Artikeln zu behalten.&lt;br /&gt;
&lt;br /&gt;
== Ultra-Kurzhandbuch ==&lt;br /&gt;
&lt;br /&gt;
Ein paar Hinweise für Neulinge, die sich davor scheuen, das ganze Handbuch zu lesen. Wie &amp;quot;baut&amp;quot; man einen OMSIWiki-Artikel?&lt;br /&gt;
&lt;br /&gt;
* Signatur: Gibt's überm Editor-Fenster einen Button, sonst &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
* Anlegen einer neuen Seite: Nachdem ihr im Forum oder uns Bescheid gegeben habt, gebt ihr den ''wohlüberlegten'' Titel der neuen Seite ins ''Suche''-Feld ein. Es erscheint dann der Vorschlag, ob man diese Seite enlegen möchte? Ein &amp;quot;ja&amp;quot; führt dich dann zum leeren Editorfenster.&lt;br /&gt;
* Eine sinnvolle Gliederung kann folgendermaßen erstellt werden:&lt;br /&gt;
 == Hauptüberschrift ==&lt;br /&gt;
 === Subüberschrift ===&lt;br /&gt;
 ==== Sub-Sub-Überschrift ==== usw.&lt;br /&gt;
* Aufzählungen wie diese werden folgendermaßen durchgeführt:&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 ** Sub-Aufzählungspunkt&lt;br /&gt;
* Ein # statt einem * führt zu numerierten Aufzählungen.&lt;br /&gt;
* Fett- und Kursivschreibung wird mittels Apostrophen markiert:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
''Kursiv''&lt;br /&gt;
'''Fett'''&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Die Zuweisung einer Kategorie (im Beispiel der Kategorie &amp;quot;Busfahren in OMSI&amp;quot;) erfolgt ganz am Ende des Artikels mit &amp;lt;nowiki&amp;gt;[[Kategorie:Busfahren in OMSI]]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Weitere Informationen: [http://meta.wikimedia.org/wiki/Hilfe:Handbuch?uselang=de meta.wikimedia.org/wiki/Hilfe:Handbuch]&lt;br /&gt;
&lt;br /&gt;
== Historie ==&lt;br /&gt;
&lt;br /&gt;
* 8. September 2011 - Marcel Kuhnt: Einrichten der deutschen OMSIWiki und Verlinkung mit der englischen.&lt;br /&gt;
* 13. September 2011 - Marcel Kuhnt: OMSIWiki öffentlich angekündigt.&lt;br /&gt;
&lt;br /&gt;
== Links rund ums Thema OMSI ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.omnibussimulator.de www.omnibussimulator.de] - offizielle Seite von OMSI, dem Omnibussimulator&lt;br /&gt;
* [http://www.omnibussimulator.de/forum/ www.omnibussimulator.de/forum/] - offizielles OMSI-Forum&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&lt;br /&gt;
&lt;br /&gt;
[[Technische Informationen zum MediaWiki]]&lt;br /&gt;
&lt;br /&gt;
[[en:Main Page]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=776</id>
		<title>OMSI Plugin Framework IV</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=776"/>
		<updated>2012-11-26T05:51:00Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das OMSI Plugin Framework ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des '''''OMSI Plugin Frameworks''''' übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt [[#Die_Arbeitsweise_des_Frameworks|Arbeitsweise]] näher erläutert.&lt;br /&gt;
&lt;br /&gt;
Das '''''OMSI Plugin Framework''''' besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen gibt es eine ausführliche [http://omsi.sovoma.de/index.html Online-Dokumentation] (in exzellentem Denglisch ;-) verfasst).&lt;br /&gt;
&lt;br /&gt;
Da es kaum möglich ist, von Anfang an ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den '''''OMSI Plugin Log Viewer''''' und das '''''OMSI Plugin Variables Display'''''. Das sind zwei eigenständige Programme, deren Bedienung in einem [[OMSI_Plugin_Framework_V|extra Kapitel]] erläutert wird.&lt;br /&gt;
&lt;br /&gt;
Außerdem erweitert das '''''OMSI Plugin Framework''''' das ''Microsoft Visual Studio '' noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe, aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und Trigger in einer für den C++-Compiler nutzbaren Form.&lt;br /&gt;
&lt;br /&gt;
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable für das Visual Studio vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte DLL und die dazu passende .opl-Datei automatisch in den '''''plugins'''''-Ordner des OMSI zu kopieren.&lt;br /&gt;
&lt;br /&gt;
=== Die Arbeitsweise des Frameworks ===&lt;br /&gt;
&lt;br /&gt;
Sobald der OMSI Deine DLL geladen hat, ist Dein Plugin sozusagen Bestandteil des OMSI selbst. Die Aufrufe der 4 Funktionen geschehen somit im Context des OMSI. Um nun der [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]] Rechnung zu tragen, hat das Plugin beim Aufruf der Funktion [[OMSI_Plugin_Framework_III#Die_Funktion_Start|Start]] einen weiteren Thread gestartet, der die Aufrufe der Funktionen [[OMSI_Plugin_Framework_III#Die_Funktion_AccessVariable|AccessVariable]] und [[OMSI_Plugin_Framework_III#Die_Funktion_AccessTrigger|AccessTrigger]] bearbeitet. Das hat für Variablen, auf die nur lesend zugegriffen werden soll den Vorteil, das nur sehr wenig CPU-Zeit für die direkte Bearbeitung der Funktionsaufrufe beansprucht wird. &lt;br /&gt;
Writable-Variablen und Trigger können davon natürlich nicht profitieren, da ja hier immer auf das Ergebnis der Verarbeitung in Deinem Plugin gewartet werden muss. Für Readonly-Variablen ist noch ein weiterer Beschleunigungsmechanismus implementiert: die Bearbeitungsfunktion in Deinem Plugin wird nur dann aufgerufen, wenn sich der Wert der Variablen seit dem letzten Aufruf verändert hat.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle ein paar Anmerkungen zum Multithreading. Multithreading ist keinesfalls das Allheilmittel gegen schlechte Frameraten. Ganz im Gegenteil. Wenn man es mit dem Multithreading übertreibt, kann man sogar ganz schnell das umgekehrte Ergebnis erreichen: das Programm wird noch langsamer. Der Grund dafür ist, dass der Prozessor genügend Reserven haben muss, um tatsächlich mehrere Threads parallel auszuführen. Ein Threadwechsel kostet - wie soll es auch anders sein - natürlich auch wieder zusätzliche CPU-Zeit. Mit anderen Worten: auf einem älteren AMD Athlon-XP ein Multithread-Programm auszuführen, bringt gar nichts. Erst wenn der Prozessor wenigstens einen zweiten CPU-Kern hat, kann die Ausführung des Programmes deutlich beschleunigt werden. Wir gehen aber jetzt einfach mal davon aus, dass heutzutage mindestens Dual-Cores oder besser in einem Rechner stecken. Wenn ein Spieler den OMSI tatsächlich noch auf einer alten Single-Core-Maschine laufen lässt, wird er a) ja sowieso wenig Freude am OMSI haben und b) sollte er sich überlegen, ob er dann noch Plugins installiert. Das ist der knallharte Kompromiss, den wir mit diesem Framework eingehen.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Arbeitsweise. Bei Aufrufen von '''AccessVariable''' und '''AccessTrigger''' legt das Plugin eine entsprechende ''Nachricht'' in der internen Nachrichtenwarteschlange ab und weckt dann den zusätzlichen Thread auf. Bis dahin verbraucht dieser Thread keinerlei CPU-Zeit. Ist die Variable ''readonly'', wird die Kontrolle sofort wieder an den OMSI übergeben. Das geht sehr schnell und belastet den OMSI nur wenig. Der jetzt aktivierte zusätzliche Thread startet nun, parallel zum OMSI, die Verarbeitung der Variaben, indem er die Funktion '''''OnMessage''''' in Deinem Plugin aufruft und legt sich danach wieder schlafen. Bei einer Writable-Variablen und einem Trigger wird ebenfalls '''''OnMessage''''' aufgerufen, allerdings muss der OMSI nun auf das Ende der Bearbeitung warten. Diese Schleife wiederholt sich solange, bis der Spieler das Spiel beendet. Von diesen internen Dingen bekommst Du in Deiner '''''OnMessage'''''-Funktion nichts mit. Das eben ist genau der Vorteil eines Frameworks.&lt;br /&gt;
&lt;br /&gt;
=== Die Klassen im Detail ===&lt;br /&gt;
&lt;br /&gt;
==== CWaitableObject, CEvent, CMutex und CThread ====&lt;br /&gt;
&lt;br /&gt;
Diese 4 Klassen kapseln Windows-Elemente in einer C++-Klasse. Dies vereinfacht den Zugriff auf diese Elemente. '''CWaitableObject''' ist dabei die Basis für die anderen drei Klassen. Der Name leitet sich davon ab, dass Programmcode im wahrsten Sinne des Wortes auf solche Elemente warten kann. Das wird über die Funktion '''''WaitFor''''' in den Klassen realisiert. In '''CWaitableObject''' ist diese Funktion noch ''abstract'', erst '''CEvent''', '''CMutex''' und '''CThread''' erfüllen sie mit Leben. Der Partner für &lt;br /&gt;
'''''WaitFor''''' ist die Funktion '''''Release'''''. Nach jedem '''''WaitFor''''' muss man '''''Release''''' aufrufen (außer bei einem Thread), sonst kann es zu einem sogenannten ''Deadlock'' im Programm kommen. Ein ''Deadlock'' bedeutet, das zwei (oder mehr) Threads auf die Freigabe ein und derselben Resource warten. Passiert so etwas, kommt das Programm zum Stillstand. Für den Anwender sieht es so aus, als ob das Programm abgestürzt sei. Technisch stimmt das zwar nicht, aber das spielt für den Anwender keine Rolle. Er kann nicht mehr weiter spielen, arbeiten usw. Solche ''race conditions'', also das gegenseitige Warten auf eine Resource sind die große Schwierigkeit bei der Multithread-Programmierung. Sie sind mitunter schwer zu entdecken und eine häufige Ursache - neben den Endlosschleifen - für vermeintliche Programmabstürze. Wie kann es nun zu solchen ''race conditions'' kommen? Betrachten wir das mal konkret am Beispiel des '''''OMSI Plugin Framework'''''. Kernelement ist hier eine sogenannte Warteschlange für Nachrichten. Eine Warteschlange ist nichts anderes, als eine Datenstruktur, die auf der einen Seite Elemente entgegen nimmt und am anderen Ende der Schlange wieder ausliefert (FIFO-Prinzip: first in, first out). In einer Single-Thread-Umgebung ist eine solche Warteschlange kein Problem. Anders aber in einer Multithread-Umgebung. Nehmen wir mal den Fall, der OMSI hat gerade '''''AccessVariable''''' aufgerufen. Unter der Herrschaft des Hauptthreads wird nun ein Element an das Ende der Warteschlange gepackt. Noch bevor der Hauptthread damit fertig ist, also die Gesamtanzahl der Nachrichten in der Schlange noch nicht erhöht hat, greift der Nebenthread ebenfalls auf die Warteschlange zu und fragt die Anzahl der Nachrichten ab. Er würde z.B. fälschlicherweise 0 geliefert bekommen. Das ist allerdings der harmlosere Fall. Betrachten wir das Ganze jetzt mal von der anderen Seite. Der Nebenthread holt gerade die erste Nachricht aus der Warteschlange ab und entfernt sie aus der Schlange. Just in diesem Moment packt der Hauptthread eine neue Nachricht am anderen Ende in die Warteschlange hinein. Der Nebenthread bekommt davon aber gar nichts mit. Er räumt fein säuberlich den Platz für die eben entfernte&lt;br /&gt;
Nachricht. Im Speicher sieht es dann so aus:&lt;br /&gt;
&lt;br /&gt;
Vor dem Abholen der Nachricht durch den Nebenthread&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_1|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|&lt;br /&gt;
&lt;br /&gt;
Nebenthread hat Nachricht geholt, aber noch nicht vollständig aufgeräumt (die Anzahl an Nachrichten beträgt noch 4)&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|freier_Platz_2|&lt;br /&gt;
&lt;br /&gt;
Hauptthread packt neue Nachricht in die Schlange. Da der Nebenthread die Anzahl noch nicht angepasst hat, geht der Hauptthread davon aus, dass noch 4 Nachrichten in der&lt;br /&gt;
Schlange sind&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|neue_Nachricht|&lt;br /&gt;
&lt;br /&gt;
Und schon ist es passiert. Der Inhalt von ''freier Platz_1'' ist völlig zufällig und kann später, wenn diese ''Nachricht'' durch den Nebenthread abgeholt wird, nur zu irgendwelchem Unfug führen. Das muss also unter allen Umständen vermieden werden. Da kommt nun die Klasse '''CMutex''' ins Spiel. Der Name leitet sich vom englischen ''mutually exclusive'' (sich gegenseitig ausschließend) ab. Mit einem Mutex wird das vorherige Szenario nun wie folgt abgewickelt: Bevor ein Thread Zugriff auf die Warteschlange nimmt, ruft er die '''''WaitFor'''''-Funktion des Mutex auf. Hat eine anderer Thread das bereits vor ihm getan, wird Windows ihm den Zutritt verweigern und der Thread muss warten (daher der Name). Er muss nun solange warten, bis der erste Thread '''''Release''''' aufruft. Vergißt Du nun, die Funktion '''''Release''''' aufzurufen, wird folgendes passieren: Irgendwann ist dieser Thread ja wieder dran und ruft wieder '''''WaitFor''''' auf. Da aber der andere Thread durch das vergessene '''''Release''''' noch immer in '''''WaitFor''''' wartet und sich damit sozusagen einen Platz in der ersten Reihe reserviert hat, wird Windows nun auch diesem Thread den Zutritt verwehren. Da haben &lt;br /&gt;
wir eine ''race condition'', die zu einem ''deadlock'' geführt hat. Thread 1 wartet darauf, das Thread 2 fertig wird und umgekehrt.&lt;br /&gt;
&lt;br /&gt;
Zusammen mit dem Mutex ergibt sich nun auch eine Verwendung für '''CEvent'''. Ein Event wird in der Programmierung ganz allgemein dazu benutzt, einem Thread irgendetwas zu signalisieren. Und soetwas müssen wir auch im Framework tun. Da ja der Nebenthread die meiste Zeit seines Lebens schläft, wäre es nicht so gut, wenn der Hauptthread einfach die Nachricht in die Warteschlange packt und dann noch womöglich auf die Bearbeitung wartet. Das könnte ein ziemlich langes Warten werden, da so ein Thread einen äußerst festen Schlaf hat. Aber da gibt es ja die Events. Der Schlafzustand des Nebenthreads ist nämlich an ein solches Event gebunden, da er die Funktion '''''WaitFor''''' des Events aufgerufen hat. Nachdem der Hauptthread die Nachricht in die Warteschlange gepackt hat (Zutritt bekommt er ja ohne weiteres, da der Nebenthread ja schläft), ruft er die Funktion '''''Raise''''' des Events auf. Dadurch wird der Nebenthread augenblicklich unsanft aus dem Schlummer gerissen und setzt seine Arbeit fort. Der gleiche Mechanismus wird auch für die Writable-Variablen und Trigger verwendet. Der Hauptthread packt die entsprechende Nachricht in die Warteschlange und legt sich nun seinerseits schlafen. Sobald der Nebenthread die Variable oder den Trigger bearbeitet hat, ruft er wiederum die Funktion '''''Raise''''' eines weiteren Events auf, um damit den Hauptthread wieder zu erwecken.&lt;br /&gt;
&lt;br /&gt;
Abschließend in diesem Abschnitt noch ein paar Worte zur Klasse '''CThread'''. Ein Thread ist nichts anderes als ein Stück Programmcode. Jedes Programm hat mindestens einen Thread. Damit ein Thread ausführbar ist, muss er eine Hauptfunktion besitzen. Der Thread läuft nun solange, bis die Hauptfunktion endet. War das der letzte (oder einzige) Thread des Programmes, endet dann auch das Programm selbst. Da Windows mit C++-Klassen rein gar nichts anfangen kann, ist die Hauptfunktion in zwei Teile aufgegliedert. Der erste Teil, die Funktion '''''ThreadFunction''''' ist der Teil, den Windows zu Gesicht bekommt. Glücklicherweise kann man einer Threadfunktion einen Parameter mitgeben. Dieser Parameter ist im Framework nun ein Zeiger auf die Instanz der Klasse '''CThread'''. Über diesen Zeiger ruft die Funktion '''''ThreadFunction''''' nun den zweiten Teil der Hauptfunktion auf, die Funktion '''''MainLoop'''''. Wie der Name schon andeutet, ist das nun die wirkliche Hauptfunktion. Im Framework wird die Hauptfunktion durch das Setzen des Feldes&lt;br /&gt;
'''''m_bTerminate''''' auf '''true''' beendet. '''CThread''' besitzt, da sie ja von '''CWaitableObject''' abgeleitet ist, auch eine '''''WaitFor'''''-Funktion. Dadurch könnte z.B. ein anderer Thread auf die Beendigung dieses Threads warten. Anders als beim '''CMutex''' muss hier aber kein '''''Release''''' aufgerufen werden. Das übernimmt Windows freundlicherweise für uns. Die Beendigung eines Threads löst automatisch ein ''Release'' aus.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework V|[zum Kapitel 5]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=775</id>
		<title>OMSI Plugin Framework IV</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=775"/>
		<updated>2012-11-26T05:49:01Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das OMSI Plugin Framework ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des '''''OMSI Plugin Frameworks''''' übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt [[#Die_Arbeitsweise_des_Frameworks|Arbeitsweise]] näher erläutert.&lt;br /&gt;
&lt;br /&gt;
Das '''''OMSI Plugin Framework''''' besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen gibt es eine ausführliche [http://omsi.sovoma.de/index.html Online-Dokumentation] (in exzellentem Denglisch ;-) verfasst).&lt;br /&gt;
&lt;br /&gt;
Da es kaum möglich ist, von Anfang an ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den '''''OMSI Plugin Log Viewer''''' und das '''''OMSI Plugin Variables Display'''''. Das sind zwei eigenständige Programme, deren Bedienung in einem [[OMSI_Plugin_Framework_V|extra Kapitel]] erläutert wird.&lt;br /&gt;
&lt;br /&gt;
Außerdem erweitert das '''''OMSI Plugin Framework''''' das ''Microsoft Visual Studio '' noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe, aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und Trigger in einer für den C++-Compiler nutzbaren Form.&lt;br /&gt;
&lt;br /&gt;
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable für das Visual Studio vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte DLL und die dazu passende .opl-Datei automatisch in den '''''plugins'''''-Ordner des OMSI zu kopieren.&lt;br /&gt;
&lt;br /&gt;
=== Die Arbeitsweise des Frameworks ===&lt;br /&gt;
&lt;br /&gt;
Sobald der OMSI Deine DLL geladen hat, ist Dein Plugin sozusagen Bestandteil des OMSI selbst. Die Aufrufe der 4 Funktionen geschehen somit im Context des OMSI. Um nun der [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]] Rechnung zu tragen, hat das Plugin beim Aufruf der Funktion [[OMSI_Plugin_Framework_III#Die_Funktion_Start|Start]] einen weiteren Thread gestartet, der die Aufrufe der Funktionen [[OMSI_Plugin_Framework_III#Die_Funktion_AccessVariable|AccessVariable]] und [[OMSI_Plugin_Framework_III#Die_Funktion_AccessTrigger|AccessTrigger]] bearbeitet. Das hat für Variablen, auf die nur lesend zugegriffen werden soll den Vorteil, das nur sehr wenig CPU-Zeit für die direkte Bearbeitung der Funktionsaufrufe beansprucht wird. &lt;br /&gt;
Writable-Variablen und Trigger können davon natürlich nicht profitieren, da ja hier immer auf das Ergebnis der Verarbeitung in Deinem Plugin gewartet werden muss. Für Readonly-Variablen ist noch ein weiterer Beschleunigungsmechanismus implementiert: die Bearbeitungsfunktion in Deinem Plugin wird nur dann aufgerufen, wenn sich der Wert der Variablen seit dem letzten Aufruf verändert hat.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle ein paar Anmerkungen zum Multithreading. Multithreading ist keinesfalls das Allheilmittel gegen schlechte Frameraten. Ganz im Gegenteil. Wenn man es mit dem Multithreading übertreibt, kann man sogar ganz schnell das umgekehrte Ergebnis erreichen: das Programm wird noch langsamer. Der Grund dafür ist, dass der Prozessor genügend Reserven haben muss, um tatsächlich mehrere Threads parallel auszuführen. Ein Threadwechsel kostet - wie soll es auch anders sein - natürlich auch wieder zusätzliche CPU-Zeit. Mit anderen Worten: auf einem älteren AMD Athlon-XP ein Multithread-Programm auszuführen, bringt gar nichts. Erst wenn der Prozessor wenigstens einen zweiten CPU-Kern hat, kann die Ausführung des Programmes deutlich beschleunigt werden. Wir gehen aber jetzt einfach mal davon aus, dass heutzutage mindestens Dual-Cores oder besser in einem Rechner stecken. Wenn ein Spieler den OMSI tatsächlich noch auf einer alten Single-Core-Maschine laufen lässt, wird er a) ja sowieso wenig Freude am OMSI haben und b) sollte er sich überlegen, ob er dann noch Plugins installiert. Das ist der knallharte Kompromiss, den wir mit diesem Framework eingehen.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Arbeitsweise. Bei Aufrufen von '''AccessVariable''' und '''AccessTrigger''' legt das Plugin eine entsprechende ''Nachricht'' in der internen Nachrichtenwarteschlange ab und weckt dann den zusätzlichen Thread auf. Bis dahin verbraucht dieser Thread keinerlei CPU-Zeit. Ist die Variable ''readonly'', wird die Kontrolle sofort wieder an den OMSI übergeben. Das geht sehr schnell und belastet den OMSI nur wenig. Der jetzt aktivierte zusätzliche Thread startet nun, parallel zum OMSI, die Verarbeitung der Variaben, indem er die Funktion '''''OnMessage''''' in Deinem Plugin aufruft und legt sich danach wieder schlafen. Bei einer Writable-Variablen und einem Trigger wird ebenfalls '''''OnMessage''''' aufgerufen, allerdings muss der OMSI nun auf das Ende der Bearbeitung warten. Diese Schleife wiederholt sich solange, bis der Spieler das Spiel beendet. Von diesen internen Dingen bekommst Du in Deiner '''''OnMessage'''''-Funktion nichts mit. Das eben ist genau der Vorteil eines Frameworks.&lt;br /&gt;
&lt;br /&gt;
=== Die Klassen im Detail ===&lt;br /&gt;
&lt;br /&gt;
==== CWaitableObject, CEvent, CMutex und CThread ====&lt;br /&gt;
&lt;br /&gt;
Diese 4 Klassen kapseln Windows-Elemente in einer C++-Klasse. Dies vereinfacht den Zugriff auf diese Elemente. '''CWaitableObject''' ist dabei die Basis für die anderen drei Klassen. Der Name leitet sich davon ab, dass Programmcode im wahrsten Sinne des Wortes auf solche Elemente warten kann. Das wird über die Funktion '''''WaitFor''''' in den Klassen realisiert. In '''CWaitableObject''' ist diese Funktion noch ''abstract'', erst '''CEvent''', '''CMutex''' und '''CThread''' erfüllen sie mit Leben. Der Partner für &lt;br /&gt;
'''''WaitFor''''' ist die Funktion '''''Release'''''. Nach jedem '''''WaitFor''''' muss man '''''Release''''' aufrufen (außer bei einem Thread), sonst kann es zu einem sogenannten ''Deadlock'' im Programm kommen. Ein ''Deadlock'' bedeutet, das zwei (oder mehr) Threads auf die Freigabe ein und derselben Resource warten. Passiert so etwas, kommt das Programm zum Stillstand. Für den Anwender sieht es so aus, als ob das Programm abgestürzt sei. Technisch stimmt das zwar nicht, aber das spielt für den Anwender keine Rolle. Er kann nicht mehr weiter spielen, arbeiten usw. Solche ''race conditions'', also das gegenseitige Warten auf eine Resource sind die große Schwierigkeit bei der Multithread-Programmierung. Sie sind mitunter schwer zu entdecken und eine häufige Ursache - neben den Endlosschleifen - für vermeintliche Programmabstürze. Wie kann es nun zu solchen ''race conditions'' kommen? Betrachten wir das mal konkret am Beispiel des '''''OMSI Plugin Framework'''''. Kernelement ist hier eine sogenannte Warteschlange für Nachrichten. Eine Warteschlange ist nichts anderes, als eine Datenstruktur, die auf der einen Seite Elemente entgegen nimmt und am anderen Ende der Schlange wieder ausliefert (FIFO-Prinzip: first in, first out). In einer Single-Thread-Umgebung ist eine solche Warteschlange kein Problem. Anders aber in einer Multithread-Umgebung. Nehmen wir mal den Fall, der OMSI hat gerade '''''AccessVariable''''' aufgerufen. Unter der Herrschaft des Hauptthreads wird nun ein Element an das Ende der Warteschlange gepackt. Noch bevor der Hauptthread damit fertig ist, also die Gesamtanzahl der Nachrichten in der Schlange noch nicht erhöht hat, greift der Nebenthread ebenfalls auf die Warteschlange zu und fragt die Anzahl der Nachrichten ab. Er würde z.B. fälschlicherweise 0 geliefert bekommen. Das ist allerdings der harmlosere Fall. Betrachten wir das Ganze jetzt mal von der anderen Seite. Der Nebenthread holt gerade die erste Nachricht aus der Warteschlange ab und entfernt sie aus der Schlange. Just in diesem Moment packt der Hauptthread eine neue Nachricht am anderen Ende in die Warteschlange hinein. Der Nebenthread bekommt davon aber gar nichts mit. Er räumt fein säuberlich den Platz für die eben entfernte&lt;br /&gt;
Nachricht. Im Speicher sieht es dann so aus:&lt;br /&gt;
&lt;br /&gt;
Vor dem Abholen der Nachricht durch den Nebenthread&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_1|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|&lt;br /&gt;
&lt;br /&gt;
Nebenthread hat Nachricht geholt, aber noch nicht vollständig aufgeräumt (die Anzahl an Nachrichten beträgt noch 4)&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|freier_Platz_2|&lt;br /&gt;
&lt;br /&gt;
Hauptthread packt neue Nachricht in die Schlange. Da der Nebenthread die Anzahl noch nicht angepasst hat, geht der Hauptthread davon aus, dass noch 4 Nachrichten in der&lt;br /&gt;
Schlange sind&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|neue_Nachricht|&lt;br /&gt;
&lt;br /&gt;
Und schon ist es passiert. Der Inhalt von ''freier Platz_1'' ist völlig zufällig und kann später, wenn diese ''Nachricht'' durch den Nebenthread abgeholt wird, nur zu irgendwelchem Unfug führen. Das muss also unter allen Umständen vermieden werden. Da kommt nun die Klasse '''CMutex''' ins Spiel. Der Name leitet sich vom englischen ''mutually exclusive'' (sich gegenseitig ausschließend) ab. Mit einem Mutex wird das vorherige Szenario nun wie folgt abgewickelt: Bevor ein Thread Zugriff auf die Warteschlange nimmt, ruft er die '''''WaitFor'''''-Funktion des Mutex auf. Hat eine anderer Thread das bereits vor ihm getan, wird Windows ihm den Zutritt verweigern und der Thread muss warten (daher der Name). Er muss nun solange warten, bis der erste Thread '''''Release''''' aufruft. Vergißt Du nun, die Funktion '''''Release''''' aufzurufen, wird folgendes passieren: Irgendwann ist dieser Thread ja wieder dran und ruft wieder '''''WaitFor''''' auf. Da aber der andere Thread durch das vergessene '''''Release''''' noch immer in '''''WaitFor''''' wartet und sich damit sozusagen einen Platz in der ersten Reihe reserviert hat, wird Windows nun auch diesem Thread den Zutritt verwehren. Da haben &lt;br /&gt;
wir eine ''race condition'', die zu einem ''deadlock'' geführt hat. Thread 1 wartet darauf, das Thread 2 fertig wird und umgekehrt.&lt;br /&gt;
&lt;br /&gt;
Zusammen mit dem Mutex ergibt sich nun auch eine Verwendung für '''CEvent'''. Ein Event wird in der Programmierung ganz allgemein dazu benutzt, einem Thread irgendetwas zu signalisieren. Und soetwas müssen wir auch im Framework tun. Da ja der Nebenthread die meiste Zeit seines Lebens schläft, wäre es nicht so gut, wenn der Hauptthread einfach die Nachricht in die Warteschlange packt und dann noch womöglich auf die Bearbeitung wartet. Das könnte ein ziemlich langes Warten werden, da so ein Thread einen äußerst festen Schlaf hat. Aber da gibt es ja die Events. Der Schlafzustand des Nebenthreads ist nämlich an ein solches Event gebunden, da er die Funktion '''''WaitFor''''' des Events aufgerufen hat. Nachdem der Hauptthread die Nachricht in die Warteschlange gepackt hat (Zutritt bekommt er ja ohne weiteres, da der Nebenthread ja schläft), ruft er die Funktion '''''Raise''''' des Events auf. Dadurch wird der Nebenthread augenblicklich unsanft aus dem Schlummer gerissen und setzt seine Arbeit fort. Der gleiche Mechanismus wird auch für die Writable-Variablen und Trigger verwendet. Der Hauptthread packt die entsprechende Nachricht in die Warteschlange und legt sich nun seinerseits schlafen. Sobald der Nebenthread die Variable oder den Trigger bearbeitet hat, ruft er wiederum die Funktion '''''Raise''''' eines weiteren Events auf, um damit den Hauptthread wieder zu erwecken.&lt;br /&gt;
&lt;br /&gt;
Abschließend in diesem Abschnitt noch ein paar Worte zur Klasse CThread. Ein Thread ist nichts anderes als ein Stück Programmcode. Jedes Programm hat mindestens einen Thread. Damit ein Thread ausführbar ist, muss er eine Hauptfunktion besitzen. Der Thread läuft nun solange, bis die Hauptfunktion endet. War das der letzte (oder einzige) Thread des Programmes, endet dann auch das Programm selbst. Da Windows mit C++-Klassen rein gar nichts anfangen kann, ist die Hauptfunktion in zwei Teile aufgegliedert. Der erste Teil, die Funktion '''''ThreadFunction''''' ist der Teil, den Windows zu Gesicht bekommt. Glücklicherweise kann man einer Threadfunktion einen Parameter mitgeben. Dieser Parameter ist im Framework nun ein Zeiger auf die Instanz der Klasse '''CThread'''. Über diesen Zeiger ruft die Funktion '''''ThreadFunction''''' nun den zweiten Teil der Hauptfunktion auf, die Funktion '''''MainLoop'''''. Wie der Name schon andeutet, ist das nun die wirkliche Hauptfunktion. Im Framework wird die Hauptfunktion durch das Setzen des Feldes&lt;br /&gt;
'''''m_bTerminate''''' auf '''true''' beendet. '''CThread''' besitzt, da sie ja von '''CWaitableObject''' abgeleitet ist, auch eine '''''WaitFor'''''-Funktion. Dadurch könnte z.B. ein anderer Thread auf die Beendigung dieses Threads warten. Anders als beim '''CMutex''' muss hier aber kein '''''Release''''' aufgerufen werden. Das übernimmt Windows freundlicherweise für uns. Die Beendigung eines Threads löst automatisch ein ''Release'' aus.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework V|[zum Kapitel 5]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=774</id>
		<title>OMSI Plugin Framework IV</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=774"/>
		<updated>2012-11-26T05:24:31Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das OMSI Plugin Framework ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des '''''OMSI Plugin Frameworks''''' übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt [[#Die_Arbeitsweise_des_Frameworks|Arbeitsweise]] näher erläutert.&lt;br /&gt;
&lt;br /&gt;
Das '''''OMSI Plugin Framework''''' besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen gibt es eine ausführliche [http://omsi.sovoma.de/index.html Online-Dokumentation] (in exzellentem Denglisch ;-) verfasst).&lt;br /&gt;
&lt;br /&gt;
Da es kaum möglich ist, von Anfang an ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den '''''OMSI Plugin Log Viewer''''' und das '''''OMSI Plugin Variables Display'''''. Das sind zwei eigenständige Programme, deren Bedienung in einem [[OMSI_Plugin_Framework_V|extra Kapitel]] erläutert wird.&lt;br /&gt;
&lt;br /&gt;
Außerdem erweitert das '''''OMSI Plugin Framework''''' das ''Microsoft Visual Studio '' noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe, aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und Trigger in einer für den C++-Compiler nutzbaren Form.&lt;br /&gt;
&lt;br /&gt;
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable für das Visual Studio vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte DLL und die dazu passende .opl-Datei automatisch in den '''''plugins'''''-Ordner des OMSI zu kopieren.&lt;br /&gt;
&lt;br /&gt;
=== Die Arbeitsweise des Frameworks ===&lt;br /&gt;
&lt;br /&gt;
Sobald der OMSI Deine DLL geladen hat, ist Dein Plugin sozusagen Bestandteil des OMSI selbst. Die Aufrufe der 4 Funktionen geschehen somit im Context des OMSI. Um nun der [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]] Rechnung zu tragen, hat das Plugin beim Aufruf der Funktion [[OMSI_Plugin_Framework_III#Die_Funktion_Start|Start]] einen weiteren Thread gestartet, der die Aufrufe der Funktionen [[OMSI_Plugin_Framework_III#Die_Funktion_AccessVariable|AccessVariable]] und [[OMSI_Plugin_Framework_III#Die_Funktion_AccessTrigger|AccessTrigger]] bearbeitet. Das hat für Variablen, auf die nur lesend zugegriffen werden soll den Vorteil, das nur sehr wenig CPU-Zeit für die direkte Bearbeitung der Funktionsaufrufe beansprucht wird. &lt;br /&gt;
Writable-Variablen und Trigger können davon natürlich nicht profitieren, da ja hier immer auf das Ergebnis der Verarbeitung in Deinem Plugin gewartet werden muss. Für Readonly-Variablen ist noch ein weiterer Beschleunigungsmechanismus implementiert: die Bearbeitungsfunktion in Deinem Plugin wird nur dann aufgerufen, wenn sich der Wert der Variablen seit dem letzten Aufruf verändert hat.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle ein paar Anmerkungen zum Multithreading. Multithreading ist keinesfalls das Allheilmittel gegen schlechte Frameraten. Ganz im Gegenteil. Wenn man es mit dem Multithreading übertreibt, kann man sogar ganz schnell das umgekehrte Ergebnis erreichen: das Programm wird noch langsamer. Der Grund dafür ist, dass der Prozessor genügend Reserven haben muss, um tatsächlich mehrere Threads parallel auszuführen. Ein Threadwechsel kostet - wie soll es auch anders sein - natürlich auch wieder zusätzliche CPU-Zeit. Mit anderen Worten: auf einem älteren AMD Athlon-XP ein Multithread-Programm auszuführen, bringt gar nichts. Erst wenn der Prozessor wenigstens einen zweiten CPU-Kern hat, kann die Ausführung des Programmes deutlich beschleunigt werden. Wir gehen aber jetzt einfach mal davon aus, dass heutzutage mindestens Dual-Cores oder besser in einem Rechner stecken. Wenn ein Spieler den OMSI tatsächlich noch auf einer alten Single-Core-Maschine laufen lässt, wird er a) ja sowieso wenig Freude am OMSI haben und b) sollte er sich überlegen, ob er dann noch Plugins installiert. Das ist der knallharte Kompromiss, den wir mit diesem Framework eingehen.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Arbeitsweise. Bei Aufrufen von '''AccessVariable''' und '''AccessTrigger''' legt das Plugin eine entsprechende ''Nachricht'' in der internen Nachrichtenwarteschlange ab und weckt dann den zusätzlichen Thread auf. Bis dahin verbraucht dieser Thread keinerlei CPU-Zeit. Ist die Variable ''readonly'', wird die Kontrolle sofort wieder an den OMSI übergeben. Das geht sehr schnell und belastet den OMSI nur wenig. Der jetzt aktivierte zusätzliche Thread startet nun, parallel zum OMSI, die Verarbeitung der Variaben, indem er die Funktion '''''OnMessage''''' in Deinem Plugin aufruft und legt sich danach wieder schlafen. Bei einer Writable-Variablen und einem Trigger wird ebenfalls '''''OnMessage''''' aufgerufen, allerdings muss der OMSI nun auf das Ende der Bearbeitung warten. Diese Schleife wiederholt sich solange, bis der Spieler das Spiel beendet. Von diesen internen Dingen bekommst Du in Deiner '''''OnMessage'''''-Funktion nichts mit. Das eben ist genau der Vorteil eines Frameworks.&lt;br /&gt;
&lt;br /&gt;
=== Die Klassen im Detail ===&lt;br /&gt;
&lt;br /&gt;
==== CWaitableObject, CEvent, CMutex und CThread ====&lt;br /&gt;
&lt;br /&gt;
Diese 4 Klassen kapseln Windows-Elemente in einer C++-Klasse. Dies vereinfacht den Zugriff auf diese Elemente. '''CWaitableObject''' ist dabei die Basis für die anderen drei Klassen. Der Name leitet sich davon ab, dass Programmcode im wahrsten Sinne des Wortes auf solche Elemente warten kann. Das wird über die Funktion '''''WaitFor''''' in den Klassen realisiert. In '''CWaitableObject''' ist diese Funktion noch ''abstract'', erst '''CEvent''', '''CMutex''' und '''CThread''' erfüllen sie mit Leben. Der Partner für &lt;br /&gt;
'''''WaitFor''''' ist die Funktion '''''Release''''''. Nach jedem '''''WaitFor''''' muss man '''''Release''''' aufrufen (außer bei einem Thread), sonst kann es zu einem sogenannten ''Deadlock'' im Programm kommen. Ein ''Deadlock'' bedeutet, das zwei (oder mehr) Threads auf die Freigabe ein und derselben Resource warten. Passiert so etwas, kommt das Programm zum Stillstand. Für den Anwender sieht es so aus, als ob das Programm abgestürzt sei. Technisch stimmt das zwar nicht, aber das spielt für den Anwender keine Rolle. Er kann nicht mehr weiter spielen, arbeiten usw. Solche ''race conditions'', also das gegenseitige Warten auf eine Resource sind die große Schwierigkeit bei der Multithread-Programmierung. Sie sind mitunter schwer zu entdecken und eine häufige Ursache - neben den Endlosschleifen - für vermeintliche Programmabstürze. Wie kann es nun zu solchen ''race conditions'' kommen? Betrachten wir das mal konkret am Beispiel des '''''OMSI Plugin Framework'''''. Kernelement ist hier eine sogenannte Warteschlange für Nachrichten. Eine Warteschlange ist nichts anderes, als eine Datenstruktur, die auf der einen Seite Elemente entgegen nimmt und am anderen Ende der Schlange wieder ausliefert (FIFO-Prinzip: first in, first out). In einer Single-Thread-Umgebung ist eine solche Warteschlange kein Problem. Anders aber in einer Multithread-Umgebung. Nehmen wir mal den Fall, der OMSI hat gerade '''''AccessVariable''''' aufgerufen. Unter der Herrschaft des Hauptthreads wird nun ein Element an das Ende der Warteschlange gepackt. Noch bevor der Hauptthread damit fertig ist, also die Gesamtanzahl der Nachrichten in der Schlange noch nicht erhöht hat, greift der Nebenthread ebenfalls auf die Warteschlange zu und fragt die Anzahl der Nachrichten ab. Er würde z.B. fälschlicherweise 0 geliefert bekommen. Das ist allerdings der harmlosere Fall. Betrachten wir das Ganze jetzt mal von der anderen Seite. Der Nebenthread holt gerade die erste Nachricht aus der Warteschlange ab und entfernt sie aus der Schlange. Just in diesem Moment packt der Hauptthread eine neue Nachricht am anderen Ende in die Warteschlange hinein. Der Nebenthread bekommt davon aber gar nichts mit. Er räumt fein säuberlich den Platz für die eben entfernte&lt;br /&gt;
Nachricht. Im Speicher sieht es dann so aus:&lt;br /&gt;
&lt;br /&gt;
Vor dem Abholen der Nachricht durch den Nebenthread&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_1|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|&lt;br /&gt;
&lt;br /&gt;
Nebenthread hat Nachricht geholt, aber noch nicht vollständig aufgeräumt (die Anzahl an Nachrichten beträgt noch 4)&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|freier_Platz_2|&lt;br /&gt;
&lt;br /&gt;
Hauptthread packt neue Nachricht in die Schlange. Da der Nebenthread die Anzahl noch nicht angepasst hat, geht der Hauptthread davon aus, dass noch 4 Nachrichten in der&lt;br /&gt;
Schlange sind&lt;br /&gt;
&lt;br /&gt;
:|Nachricht_2|Nachricht_3|Letzte_Nachricht|freier_Platz_1|neue_Nachricht|&lt;br /&gt;
&lt;br /&gt;
Und schon ist es passiert. Der Inhalt von ''freier Platz_1'' ist völlig zufällig und kann später, wenn diese ''Nachricht'' durch den Nebenthread abgeholt wird, nur zu irgendwelchem Unfug führen. Das muss also unter allen Umständen vermieden werden. Da kommt nun die Klasse '''CMutex''' ins Spiel. Der Name leitet sich vom englischen ''mutually exclusive'' (sich gegenseitig ausschließend) ab. Mit einem Mutex wird das vorherige Szenario nun wie folgt abgewickelt: Bevor ein Thread Zugriff auf die Warteschlange nimmt, ruft er die '''''WaitFor'''''-Funktion des Mutex auf. Hat eine anderer Thread das bereits vor ihm getan, wird Windows ihm den Zutritt verweigern und der Thread muss warten (daher der Name). Er muss nun solange warten, bis der erste Thread '''''Release''''' aufruft. Vergißt Du nun, die Funktion '''''Release''''' aufzurufen, wird folgendes passieren: Irgendwann ist dieser Thread ja wieder dran und ruft wieder '''''WaitFor''''' auf. Da aber der andere Thread durch das vergessene '''''Release''''' noch immer in '''''WaitFor''''' wartet und sich damit sozusagen einen Platz in der ersten Reihe reserviert hat, wird Windows nun auch diesem Thread den Zutritt verwehren. Da haben &lt;br /&gt;
wir eine ''race condition'', die zu einem ''deadlock'' geführt hat. Thread 1 wartet darauf, das Thread 2 fertig wird und umgekehrt.&lt;br /&gt;
&lt;br /&gt;
Zusammen mit dem Mutex ergibt sich nun auch eine Verwendung für '''CEvent'''. Ein Event wird in der Programmierung ganz allgemein dazu benutzt, einem Thread irgendetwas zu signalisieren. Und soetwas müssen wir auch im Framework tun. Da ja der Nebenthread die meiste Zeit seines Lebens schläft, wäre es nicht so gut, wenn der Hauptthread einfach die Nachricht in die Warteschlange packt und dann noch womöglich auf die Bearbeitung wartet. Das könnte ein ziemlich langes Warten werden, da so ein Thread einen äußerst festen Schlaf hat. Aber da gibt es ja die Events. Der Schlafzustand des Nebenthreads ist nämlich an ein solches Event gebunden. Nachdem der Hauptthread die Nachricht in die Warteschlange gepackt hat (Zutritt bekommt er ja ohne weiteres, da der Nebenthread ja schläft), ruft er die Funktion '''''Raise''''' des Events auf. Dadurch wird der Nebenthread augenblicklich unsanft aus dem Schlummer gerissen und setzt seine Arbeit fort. Der gleiche Mechanismus wird auch für die Writable-Variablen und Trigger verwendet. Der Hauptthread packt die entsprechende Nachricht in die Warteschlange und legt sich nun seinerseits schlafen. Sobald der Nebenthread die Variable oder den Trigger bearbeitet hat, ruft er wiederum die Funktion '''''Raise''''' eines weiteren Events auf, um damit den Hauptthread wieder zu erwecken.&lt;br /&gt;
&lt;br /&gt;
Abschließend in diesem Abschnitt noch ein paar Worte zur Klasse CThread. Ein Thread ist nichts anderes als ein Stück Programmcode. Jedes Programm hat mindestens einen Thread. Damit ein Thread ausführbar ist, muss er eine Hauptfunktion besitzen. Der Thread läuft nun solange, bis die Hauptfunktion endet. War das der letzte (oder einzige) Thread des Programmes, endet dann auch das Programm selbst. Da Windows mit C++-Klassen rein gar nichts anfangen kann, ist die Hauptfunktion in zwei Teile aufgegliedert. Der erste Teil, die Funktion '''''ThreadFunction''''' ist der Teil, den Windows zu Gesicht bekommt. Glücklicherweise kann man einer Threadfunktion einen Parameter mitgeben. Dieser Parameter ist im Framework nun ein Zeiger auf die Instanz der Klasse '''CThread'''. Über diesen Zeiger ruft die Funktion '''''ThreadFunction''''' nun den zweiten Teil der Hauptfunktion auf, die Funktion '''''MainLoop'''''. Wie der Name schon andeutet, ist das nun die wirkliche Hauptfunktion. Im Framework wird die Hauptfunktion durch das Setzen des Feldes&lt;br /&gt;
'''''m_bTerminate''''' auf '''true''' beendet. '''CThread''' besitzt, da sie ja von '''CWaitableObject''' abgeleitet ist, auch eine '''''WaitFor'''''-Funktion. Dadurch könnte z.B. ein anderer Thread auf die Beendigung dieses Threads warten. Anders als beim '''CMutex''' muss hier aber kein '''''Release''''' aufgerufen werden. Das übernimmt Windows freundlicherweise für uns. Die Beendigung eines Threads löst automatisch ein ''Release'' aus.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework V|[zum Kapitel 5]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=773</id>
		<title>OMSI Plugin Framework IV</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=773"/>
		<updated>2012-11-25T21:08:46Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das OMSI Plugin Framework ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des '''''OMSI Plugin Frameworks''''' übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt [[#Die_Arbeitsweise_des_Frameworks|Arbeitsweise]] näher erläutert.&lt;br /&gt;
&lt;br /&gt;
Das '''''OMSI Plugin Framework''''' besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen gibt es eine ausführliche [http://omsi.sovoma.de/index.html Online-Dokumentation] (in exzellentem Denglisch ;-) verfasst).&lt;br /&gt;
&lt;br /&gt;
Da es kaum möglich ist, von Anfang an ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den '''''OMSI Plugin Log Viewer''''' und das '''''OMSI Plugin Variables Display'''''. Das sind zwei eigenständige Programme, deren Bedienung in einem [[OMSI_Plugin_Framework_V|extra Kapitel]] erläutert wird.&lt;br /&gt;
&lt;br /&gt;
Außerdem erweitert das '''''OMSI Plugin Framework''''' das ''Microsoft Visual Studio '' noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe, aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und Trigger in einer für den C++-Compiler nutzbaren Form.&lt;br /&gt;
&lt;br /&gt;
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable für das Visual Studio vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte DLL und die dazu passende .opl-Datei automatisch in den '''''plugins'''''-Ordner des OMSI zu kopieren.&lt;br /&gt;
&lt;br /&gt;
=== Die Arbeitsweise des Frameworks ===&lt;br /&gt;
&lt;br /&gt;
Sobald der OMSI Deine DLL geladen hat, ist Dein Plugin sozusagen Bestandteil des OMSI selbst. Die Aufrufe der 4 Funktionen geschehen somit im Context des OMSI. Um nun der [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]] Rechnung zu tragen, hat das Plugin beim Aufruf der Funktion [[OMSI_Plugin_Framework_III#Die_Funktion_Start|Start]] einen weiteren Thread gestartet, der die Aufrufe der Funktionen [[OMSI_Plugin_Framework_III#Die_Funktion_AccessVariable|AccessVariable]] und [[OMSI_Plugin_Framework_III#Die_Funktion_AccessTrigger|AccessTrigger]] bearbeitet. Das hat für Variablen, auf die nur lesend zugegriffen werden soll den Vorteil, das nur sehr wenig CPU-Zeit für die direkte Bearbeitung der Funktionsaufrufe beansprucht wird. Writable-Variablen und Trigger können davon natürlich nicht profitieren, da ja hier immer auf das Ergebnis der Verarbeitung in Deinem Plugin gewartet werden muss. Für Readonly-Variablen ist noch ein weiterer Beschleunigungsmechanismus implementiert: die Bearbeitungsfunktion in Deinem Plugin wird nur dann aufgerufen, wenn sich der Wert der Variablen seit dem letzten Aufruf verändert hat.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle ein paar Anmerkungen zum Multithreading. Multithreading ist keinesfalls das Allheilmittel gegen schlechte Frameraten. Ganz im Gegenteil. Wenn man es mit dem Multithreading übertreibt, kann man sogar ganz schnell das umgekehrte Ergebnis erreichen: das Programm wird noch langsamer. Der Grund dafür ist, dass der Prozessor genügend Reserven haben muss, um tatsächlich mehrere Threads parallel auszuführen. Ein Threadwechsel kostet - wie soll es auch anders sein - natürlich auch wieder zusätzliche CPU-Zeit. Mit anderen Worten: auf einem älteren AMD Athlon-XP ein Multithread-Programm auszuführen, bringt gar nichts. Erst wenn der Prozessor wenigstens einen zweiten CPU-Kern hat, kann die Ausführung des Programmes deutlich beschleunigt werden. Wir gehen aber jetzt einfach mal davon aus, dass heutzutage mindestens Dual-Cores oder besser in einem Rechner stecken. Wenn ein Spieler den OMSI tatsächlich noch auf einer alten Single-Core-Maschine laufen lässt, wird er a) ja sowieso wenig Freude am OMSI haben und b) sollte er sich überlegen, ob er dann noch Plugins installiert. Das ist der knallharte Kompromiss, den wir mit diesem Framework eingehen.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Arbeitsweise. Bei Aufrufen von '''AccessVariable''' und '''AccessTrigger''' legt das Plugin eine entsprechende ''Nachricht'' in der internen Nachrichtenwarteschlange ab und weckt dann den zusätzlichen Thread auf. Bis dahin verbraucht dieser Thread keinerlei CPU-Zeit. Ist die Variable ''readonly'', wird die Kontrolle sofort wieder an den OMSI übergeben. Das geht sehr schnell und belastet den OMSI nur wenig. Der jetzt aktivierte zusätzliche Thread startet nun, parallel zum OMSI, die Verarbeitung der Variaben, indem er die Funktion '''''OnMessage''''' in Deinem Plugin aufruft und legt sich danach wieder schlafen. Bei einer Writable-Variablen und einem Trigger wird ebenfalls '''''OnMessage''''' aufgerufen, allerdings muss der OMSI nun auf das Ende der Bearbeitung warten. Diese Schleife wiederholt sich solange, bis der Spieler das Spiel beendet. Von diesen internen Dingen bekommst Du in Deiner '''''OnMessage'''''-Funktion nichts mit. Das eben ist genau der Vorteil eines Frameworks.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework V|[zum Kapitel 5]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=772</id>
		<title>OMSI Plugin Framework IV</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=772"/>
		<updated>2012-11-25T15:00:20Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das OMSI Plugin Framework ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des '''''OMSI Plugin Frameworks''''' übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt [[#Die_Arbeitsweise_des_Frameworks|Arbeitsweise]] näher erläutert.&lt;br /&gt;
&lt;br /&gt;
Das '''''OMSI Plugin Framework''''' besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen gibt es eine ausführliche [http://omsi.sovoma.de/index.html Online-Dokumentation] (in exzellentem Denglisch ;-) verfasst).&lt;br /&gt;
&lt;br /&gt;
Da es kaum möglich ist, von Anfang an ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den '''''OMSI Plugin Log Viewer''''' und das '''''OMSI Plugin Variables Display'''''. Das sind zwei eigenständige Programme, deren Bedienung in einem [[OMSI_Plugin_Framework_V|extra Kapitel]] erläutert wird.&lt;br /&gt;
&lt;br /&gt;
Außerdem erweitert das '''''OMSI Plugin Framework''''' das ''Microsoft Visual Studio '' noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe, aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und Trigger in einer für den C++-Compiler nutzbaren Form.&lt;br /&gt;
&lt;br /&gt;
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable für das Visual Studio vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte DLL und die dazu passende .opl-Datei automatisch in den '''''plugins'''''-Ordner des OMSI zu kopieren.&lt;br /&gt;
&lt;br /&gt;
=== Die Arbeitsweise des Frameworks ===&lt;br /&gt;
&lt;br /&gt;
Sobald der OMSI Deine DLL geladen hat, ist Dein Plugin sozusagen Bestandteil des OMSI selbst. Die Aufrufe der 4 Funktionen geschehen somit im Context des OMSI. Um nun der [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]] Rechnung zu tragen, hat das Plugin beim Aufruf der Funktion [[OMSI_Plugin_Framework_III#Die_Funktion_Start|Start]] einen weiteren Thread gestartet, der die Aufrufe der Funktionen [[OMSI_Plugin_Framework_III#Die_Funktion_AccessVariable|AccessVariable]] und [[OMSI_Plugin_Framework_III#Die_Funktion_AccessTrigger|AccessTrigger]] bearbeitet. Das hat für Variablen, auf die nur lesend zugegriffen werden soll den Vorteil, das nur sehr wenig CPU-Zeit für die direkte Bearbeitung der Funktionsaufrufe beansprucht wird. Writable-Variablen und Trigger können davon natürlich nicht profitieren, da ja hier immer auf das Ergebnis der Verarbeitung in Deinem Plugin gewartet werden muss. Für Readonly-Variablen ist noch ein weiterer Beschleunigungsmechanismus implementiert: die Bearbeitungsfunktion in Deinem Plugin wird nur dann aufgerufen, wenn sich der Wert der Variablen seit dem letzten Aufruf verändert hat.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle ein paar Anmerkungen zum Multithreading. Multithreading ist keinesfalls das Allheilmittel gegen schlechte Frameraten. Ganz im Gegenteil. Wenn man es mit dem Multithreading übertreibt, kann man sogar ganz schnell das umgekehrte Ergebnis erreichen: das Programm wird noch langsamer. Der Grund dafür ist, dass der Prozessor genügend Reserven haben muss, um tatsächlich mehrere Threads parallel auszuführen. Ein Threadwechsel kostet - wie soll es auch anders sein - natürlich auch wieder zusätzliche CPU-Zeit. Mit anderen Worten: auf einem älteren AMD Athlon-XP ein Multithread-Programm auszuführen, bringt gar nichts. Erst wenn der Prozessor wenigstens einen zweiten CPU-Kern hat, kann die Ausführung des Programmes deutlich beschleunigt werden. Wir gehen aber jetzt einfach mal davon aus, dass heutzutage mindestens Dual-Cores oder besser in einem Rechner stecken. Wenn ein Spieler den OMSI tatsächlich noch auf einer alten Single-Core-Maschine laufen lässt, wird er a) ja sowieso wenig Freude am OMSI haben und b) sollte er sich überlegen, ob er dann noch Plugins installiert. Das ist der knallharte Kompromiss, den wir mit diesem Framework eingehen.&lt;br /&gt;
&lt;br /&gt;
Weiter gehts mit der Arbeitsweise. Bei Aufrufen von '''AccessVariable''' und '''AccessTrigger''' legt das Plugin eine entsprechende ''Nachricht'' in der internen Nachrichtenwarteschlange ab und weckt dann den zusätzlichen Thread auf. Bis dahin verbraucht dieser Thread keinerlei CPU-Zeit. Ist die Variable ''readonly'', wird die Kontrolle sofort wieder an den OMSI übergeben. Das geht sehr schnell und belastet den OMSI nur wenig. Der jetzt aktivierte zusätzliche Thread startet nun, parallel zum OMSI, die Verarbeitung der Variaben, indem er die Funktion '''''OnMessage''''' in Deinem Plugin aufruft und legt sich danach wieder schlafen. Bei einer Writable-Variablen und einem Trigger wird ebenfalls '''''OnMessage''''' aufgerufen, allerdings muss der OMSI nun auf das Ende der Bearbeitung warten. Diese Schleife wiederholt sich solange, bis der Spieler das Spiel beendet.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework V|[zum Kapitel 5]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=771</id>
		<title>OMSI Plugin Framework IV</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=771"/>
		<updated>2012-11-24T18:48:20Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das OMSI Plugin Framework ==&lt;br /&gt;
&lt;br /&gt;
:Falls das hier wirklich schon jemand liest: Es ist bereits halb acht abends, aber ich fange trotzdem schon mal an. Morgen (25.11.2012) geht es weiter. Versprochen!&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des '''''OMSI Plugin Frameworks''''' übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt [[#Die_Arbeitsweise_des_Frameworks|Arbeitsweise]] näher erläutert.&lt;br /&gt;
&lt;br /&gt;
Das '''''OMSI Plugin Framework''''' besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen gibt es eine ausführliche [http://omsi.sovoma.de/index.html Online-Dokumentation] (in exzellentem Denglisch ;-) verfasst).&lt;br /&gt;
&lt;br /&gt;
Da es kaum möglich ist, von Anfang ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den '''''OMSI Plugin Log Viewer''''' und das '''''OMSI Plugin Variables Display'''''. Das sind zwei eigenständige Programme, deren Bedienung in einem [[OMSI_Plugin_Framework_V|extra Kapitel]] erläutert wird.&lt;br /&gt;
&lt;br /&gt;
Außerdem erweitert das '''''OMSI Plugin Framework''''' das ''Microsoft Visual Studio '' noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe, aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und Trigger in einer für den C++-Compiler nutzbaren Form.&lt;br /&gt;
&lt;br /&gt;
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable für das Visual Studio vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte DLL und die dazu passende .opl-Datei automatisch in den '''''plugins'''''-Ordner des OMSI zu kopieren.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework V|[zum Kapitel 5]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=770</id>
		<title>OMSI Plugin Framework IV</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=770"/>
		<updated>2012-11-24T18:43:49Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: 1. Entwurf&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das OMSI Plugin Framework ==&lt;br /&gt;
&lt;br /&gt;
:Falls das hier wirklich schon jemand liest: Es ist bereits halb acht abends, aber ich fange trotzdem schon mal an. Morgen (25.11.2012) geht es weiter. Versprochen!&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des '''''OMSI Plugin Frameworks''''' übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt [[#Die_Arbeitsweise_des_Frameworks|Arbeitsweise]] näher erläutert.&lt;br /&gt;
&lt;br /&gt;
Das '''''OMSI Plugin Framework''''' besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen gibt es eine ausführliche [http://omsi.sovoma.de/index.php Online-Dokumentation] (in exzellentem Denglisch ;-) verfasst).&lt;br /&gt;
&lt;br /&gt;
Da es kaum möglich ist, von Anfang ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den '''''OMSI Plugin Log Viewer''''' und das '''''OMSI Plugin Variables Display'''''. Das sind zwei eigenständige Programme, deren Bedienung in einem [[OMSI_Plugin_Framework_V|extra Kapitel]] erläutert wird.&lt;br /&gt;
&lt;br /&gt;
Außerdem erweitert das '''''OMSI Plugin Framework''''' das ''Microsoft Visual Studio '' noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe, aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und Trigger in einer für den C++-Compiler nutzbaren Form.&lt;br /&gt;
&lt;br /&gt;
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable für das Visual Studio vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte DLL und die dazu passende .opl-Datei automatisch in den '''''plugins'''''-Ordner des OMSI zu kopieren.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework V|[zum Kapitel 5]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=769</id>
		<title>OMSI Plugin Framework IV</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_IV&amp;diff=769"/>
		<updated>2012-11-24T18:36:54Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Die Seite wurde neu angelegt: „== Das OMSI Plugin Framework ==  :Falls das hier wirklich schon jemand liest: Es ist bereits halb acht abends, aber ich fange trotzdem schon mal an. Morgen (25.11…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Das OMSI Plugin Framework ==&lt;br /&gt;
&lt;br /&gt;
:Falls das hier wirklich schon jemand liest: Es ist bereits halb acht abends, aber ich fange trotzdem schon mal an. Morgen (25.11.2012) geht es weiter. Versprochen!&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich den Aufbau und die Arbeitsweise des Frameworks detailliert beschreiben. Vielleicht hast Du dich die ganze Zeit schon&lt;br /&gt;
gefragt, wozu so ein Framework-Dingens überhaupt gut ist. Ganz allgemein gesagt, soll Dich ein Framework von immer wiederkehrenden Standardaufgaben&lt;br /&gt;
entlasten und Dir eine einheitliche Schnittstelle bieten, mit der Du bestimmte Aufgaben erledigen kannst. Im Falle des '''''OMSI Plugin Frameworks'''''&lt;br /&gt;
übernimmt es auch noch einen etwas schwierigeren Teil der Programmierung, das sogenannte Multithreading. Was es damit auf sich hat, wird im Abschnitt&lt;br /&gt;
[[#Die_Arbeitsweise_des_Frameworks|Arbeitsweise]] näher erläutert.&lt;br /&gt;
&lt;br /&gt;
Das '''''OMSI Plugin Framework''''' besteht aus einer handvoll C++-Klassen, die Deine Variablen und Trigger übersichtlich organisieren, den Umgang mit&lt;br /&gt;
den 4 Funktionen der Plugin-Schnittstelle regeln und eine einheitliche Schnittstelle zur Bearbeitung der Variablen und Trigger schaffen. Für diese Klassen&lt;br /&gt;
gibt es eine ausführliche [http://omsi.sovoma.de/index.php Online-Dokumentation] (in exzellentem Denglisch ;-) verfasst).&lt;br /&gt;
&lt;br /&gt;
Da es kaum möglich ist, von Anfang ein Plugin völlig fehlerfrei zu programmieren (das geht Profis auch nicht anders), gibt es zwei Debug-Hilfen, den &lt;br /&gt;
'''''OMSI Plugin Log Viewer''''' und das '''''OMSI Plugin Variables Display'''''. Das sind zwei eigenständige Programme, deren Bedienung in einem &lt;br /&gt;
[[OMSI_Plugin_Framework_V|extra Kapitel]] erläutert wird.&lt;br /&gt;
&lt;br /&gt;
Außerdem erweitert das '''''OMSI Plugin Framework''''' das ''Microsoft Visual Studio '' noch um einen weiteren Compiler. Dieser Compiler hat die Aufgabe,&lt;br /&gt;
aus einer sehr einfach aufgebauten Textdatei, die die Variablen- und Triggerdeklaration enthält, zum Einen die .opl-Datei für den OMSI zu generieren und&lt;br /&gt;
zum Anderen zwei weitere Dateien zu erzeugen, die direkt in den Code Deines Plugins einfließen. Diese beiden Dateien enthalten dann Deine Variablen und &lt;br /&gt;
Trigger in einer für den C++-Compiler nutzbaren Form.&lt;br /&gt;
&lt;br /&gt;
Das ist noch nicht alles. Weiterhin ist eine neue Umgebungsvariable vorbereitet, mit der es besonders einfach ist, nach jeder Compilierung die erzeugte&lt;br /&gt;
DLL und die dazu passende .opl-Datei automatisch in den '''''plugins'''''-Ordner des OMSI zu kopieren.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework V|[zum Kapitel 5]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_III&amp;diff=768</id>
		<title>OMSI Plugin Framework III</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_III&amp;diff=768"/>
		<updated>2012-11-24T17:55:32Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: einen einzigen Satz verbessert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Die Plugin-Schnittstelle ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich die Arbeitsweise der Plugin-Schnittstelle des OMSI noch etwas tiefer beleuchten, vor allem mehr im Zusammenhang mit der Programmiersprache C++.&lt;br /&gt;
&lt;br /&gt;
Das allgemeine Prinzip wird ja bereits in [[Plug-in-Schnittstelle|diesem Artikel]] erklärt. Auch wenn das Plugin in C++ programmiert wird, ändert sich an den grundlegenden Dingen nichts. Lediglich der im Artikel beschriebene Weg, ein Formular zu öffnen, ist absolut Delphi-typisch und in C++ so nicht möglich. Der Parameter, der beim Aufruf der Funktion '''''Start''''' mitgegeben wird, ist nicht nur einfach ein 'Delphi'-Parameter, er ist auch noch von der verwendeten Delphi-Version abhängig. Deshalb wird dieser Parameter im '''''OMSI Plugin Framework''''' nicht benutzt, auch wenn darüber ein Zugriff auf das Hauptfenster-Handle in C++ möglich wäre.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Lifecycle.jpg|200px|thumb|right|Lebenszyklus eines Plugins]]&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Möglichkeiten, DLLs in ein Programm einzubinden. Die erste Möglichkeit ist, die DLL schon während der Programmierung sozusagen fest mit dem Programm zu verbinden. Diese DLLs müssen beim Programmstart vorhanden sein, sonst schlägt das Starten des Programmes fehl. Diese Möglichkeit benutzt man im z.B. für die System-DLLs. In der Natur eines Plugins liegt es aber, dass es ganz einfach gar nicht da sein kann. Also scheidet die eben erwähnte Möglichkeit zum Einbinden einer DLL aus. Deshalb macht der OMSI von der zweiten Möglichkeit Gebrauch. Ein Programm kann über den Aufruf einer Systemfunktion '''''LoadLibrary''''' zu jeder beliebigen Zeit DLLs nachladen. '''''LoadLibrary''''' sucht aber nur (im Wesentlichen) an drei Stellen automatisch nach einer DLL: in dem Ordner, in dem sich auch das Programm selbst befindet, im '''''Windows'''''-Ordner und im '''''Windows\system(32)'''''-Ordner. Wenn sie dort nicht fündig wird, liefert die Funktion einen Fehler zurück. Also muss der OMSI ''wissen'', wo sich die DLL befindet. Dafür wurde der Ordner &amp;lt;i&amp;gt;&amp;amp;lt;OMSI_Installationsordner&amp;amp;gt;&amp;lt;/i&amp;gt;\'''''plugins''''' festgelegt.&lt;br /&gt;
&lt;br /&gt;
=== Lebenszyklus eines Plugins ===&lt;br /&gt;
&lt;br /&gt;
Plugin-DLLs werden bereits kurz nach dem Start des OMSI geladen und ihre '''''Start'''''-Funktion aufgerufen. Wenn nach dem Start des OMSI das erste mal der Auswahldialog für die Karte, gespeichertes Spiel usw. erscheint, ist das Plugin schon aktiviert, aber im Ruhezustand. Zu diesem Zeitpunkt existiert noch keine Karte und kein Bus, da der Spieler ja die Karte erst noch auswählen muss. Auch nachdem der Spieler eine Karte ausgwählt und der OMSI Diese geladen hat, schläft das Plugin immer noch weiter. Es erwacht erst, sobald der OMSI den Bus des Spielers geladen hat. Solange ein Spieler-Bus existiert werden nun die '''''AccessVariable'''''- und '''''AccessTrigger'''''-Funktionen durch den OMSI aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Kurz vor Beendigung des OMSI ruft Dieser noch die Funktion '''''Finalize''''' auf. Damit endet der Lebenszyklus des Plugins.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion Start ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Start&amp;lt;/span&amp;gt;(AOwner: TComponent); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Start&amp;lt;/span&amp;gt;(void* aOwner);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion '''''Start''''' wird (wie im vorherigen Abschnitt beschrieben) einmalig vor Beginn des eigentlichen Spiels durch den OMSI aufgerufen und ist daher nicht zeitkritisch. In die Funktion '''''Start''''' gehören alle grundlegenden Initialisierungen, die Dein Plugin benötigt. Wenn man mal davon absieht, dass sich die Ladezeit des OMSI verlängert, hast Du hier Zeit, die Dinge zu tun, die Du als Vorbereitung für die eigentliche Arbeit im Plugin benötigst.&lt;br /&gt;
&lt;br /&gt;
Wie im Abschnitt [[#Allgemeines|Allgemeines]] bereits erläutert, solltest Du es vermeiden, den Parameter dieser Funktion zu verwenden. Falls Du sehr daran interessiert bist, an das Handle des Hauptfensters zu gelangen, sei hier ganz grob der Weg beschrieben, wie das möglich wäre: Du müsstest Dir zunächst die technische Dokumentation der Komponente '''''TComponent''''' (bzw. '''''TForm''''', denn eine '''''TForm''''' ist dieser Parameter tatsächlich) passend zu der Delphi-Version besorgen, mit der der OMSI programmiert wurde. Anhand der Dokumentation kannst du dann die Klasse in C++ ''nachbauen''. Wenn Du das geschafft hast, kannst Du nun den Parameter verwenden. Das Ganze ist - wie gesagt - durchaus möglich, aber mehr ein Hack als vernünftige Programmierung.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion AccessVariable ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessVariable&amp;lt;/span&amp;gt;(varindex: word; var value: single; var write: boolean); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessVariable&amp;lt;/span&amp;gt;(unsigned short varindex, float* value, bool* write);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Solange der Spieler über einen Bus verfügt, werden in jedem Frame alle in der .opl-Datei deklarierten Variablen nacheinander genau in der Reihenfolge der Deklaration über diese Funktion an Dein Plugin zur Bearbeitung übergeben.&lt;br /&gt;
&lt;br /&gt;
Der erste Parameter ist dabei der Index der Variablen in der .opl-Datei. Die Zuordnung, welche Variable was ist, musst Du in Deinem Plugin selbst wieder herstellen. Der zweite Parameter ist ein Zeiger auf einen '''''float'''''-Wert. Das ist der aktuelle Wert der Variablen. Der Wert wird deshalb als Zeigertyp übergeben, damit Du den Wert im Plugin auch ändern kannst. Der dritte Parameter schließlich ist ein Zeiger auf einen '''''bool'''''-Wert. Darüber gibst Du dem OMSI Rückmeldung, ob Du den Inhalt der Variablen verändert hast. Wenn Du die Variable nur lesend benutzt, brauchst Du nichts weiter tun. Der Wert, auf den dieser Zeiger zeigt, ist immer mit '''''false''''' vorbelegt.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;unbewiesene_aussage&amp;amp;gt;&lt;br /&gt;
:&amp;lt;span style=&amp;quot;color:blue;font-style:italic&amp;quot;&amp;gt;Beim Ändern des Wertes einer Variablen musst Du auch bedenken, dass ein Script, welches ebenfalls dieselbe Variable ändert, Deinen Wert wieder überschreibt.&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;lt;/unbewiesene_aussage&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dadurch, das diese Funktion für '''''jede''''' Variable in '''''jedem''''' Frame aufgerufen wird, ergibt sich, das diese Funktion äußerst zeitkritisch ist. Über die Ausführungsdauer der Funktion in Deinem Plugin beeinflusst Du direkt die Framerate des OMSI (siehe [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]]).&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion AccessTrigger ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessTrigger&amp;lt;/span&amp;gt;(triggerindex: word; var active: boolean); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessTrigger&amp;lt;/span&amp;gt;(unsigned short triggerindex, bool* active);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ähnlich wie bei der Funktion '''''AccessVariable''''' wird auch '''''AccessTrigger''''' in jedem Frame für jeden in der .opl-Datei deklarierten Trigger genau in der Reihenfolge der Deklaration aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Der erste Parameter ist dabei der Index des Triggers in der .opl-Datei. Die Zuordnung, welcher Trigger wer ist, musst Du in Deinem Plugin selbst wieder herstellen. Der zweite Parameter ist ein Zeiger auf einen '''''bool'''''-Wert. Darüber gibst Du dem OMSI Rückmeldung, ob er den Trigger auslösen soll oder nicht. Wenn der Trigger nicht ausgelöst werden soll, brauchst Du nichts weiter tun. Der Wert, auf den dieser Zeiger zeigt, ist immer mit '''''false''''' vorbelegt.&lt;br /&gt;
&lt;br /&gt;
Genau wie '''''AccessVariable''''' ist auch diese Funktion zeitkritisch, da sie für '''''jeden''''' Trigger in '''''jedem''''' Frame aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn Du in Deinem Plugin den Trigger nicht auslöst, kann er trotzdem von einem Script ausgelöst werden.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion Finalize ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Finalize&amp;lt;/span&amp;gt;; stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Finalize&amp;lt;/span&amp;gt;();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion '''''Finalize''''' wird einmalig beim Beenden des OMSI aufgerufen und ist nicht zeitkritisch. In diese Funktion gehören alle Aufräumarbeiten, die in Deinem Plugin nötig sind.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework II|[zum Kapitel 2]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework IV|[zum Kapitel 4]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=767</id>
		<title>Hauptseite</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=767"/>
		<updated>2012-11-23T21:49:37Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Fortschritt Artikel OMSI Plugin Framework dokumentiert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font style=&amp;quot;font-size:1.2em;&amp;quot;&amp;gt;&lt;br /&gt;
'''Herzlich willkommen auf der deutschen Version von OMSIWiki!'''&lt;br /&gt;
&lt;br /&gt;
Hier geht's direkt zu einer der Hauptkategorien:&lt;br /&gt;
&lt;br /&gt;
* [[FAQs - Häufig gestellte Fragen]]&lt;br /&gt;
* [[:Kategorie:Busfahren in OMSI|Busfahren in OMSI]]&lt;br /&gt;
* Entwicklung von Addons:&lt;br /&gt;
** [[:Kategorie:Nachschlagewerk für Addon-Entwickler|Nachschlagewerk]]&lt;br /&gt;
** [[:Kategorie:Tutorials für Addon-Entwickler|Tutorials]]&lt;br /&gt;
** [[:Kategorie:Tipps und Tricks für Addon-Entwickler|Tipps und Tricks]]&lt;br /&gt;
* [[:Kategorie:Anschlussprojekte|Anschlussprojekte (z.B. Addon-Manager, OAT)]]&lt;br /&gt;
* [[:Kategorie:Addon-Präsentationen|Addon-Präsentationen]]&lt;br /&gt;
* [[:Kategorie:Hintergrundinformationen|Hintergrundinformationen]]&lt;br /&gt;
&lt;br /&gt;
'''Achtung: Vor dem Verfassen eigener Beiträge bitte zuerst die Regeln lesen!''' Weiter unten gibt es noch eine Ultra-Kurzanleitung für Neulinge.&lt;br /&gt;
&lt;br /&gt;
''Aktuell in Arbeit:''&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Tutorial zum programmieren eines [[OMSI Plugin Framework|OMSI-Plugins in C++]] (Fortschritt: ###-------) --[[Benutzer:Holmexx|Holmexx]] 22:49, 23. Nov. 2012 (MET) &lt;br /&gt;
* Übersetzen der Artikel, zuletzt [[Repainting of OMSI buses (also over panes)]] --[[Benutzer:Dario|Dario]] 12:04, 17. Jul. 2012 (MEST)&lt;br /&gt;
* [[Fahrpläne erstellen]] --[[Benutzer:Felix (Keyway)|Felix (Keyway)]] 16:21, 31. Dez. 2011 (MET) ----- Weitergeführt von [[Benutzer:Dario|Dario]] 11:33, 18. Jul. 2012 (MEST)&lt;br /&gt;
* ''(aktuell pausiert)'' [[Fahrzeug-SDK]] (c) von Rüdiger, Einbau ins OMSIWiki von --[[Benutzer:Marcel Kuhnt|Marcel Kuhnt]] 16:12, 2. Dez. 2011 (MET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Wir Entwickler von OMSI haben OMSIWiki eingerichtet, um eine bessere Plattform für alle Arten von Informationen rund um OMSI zu erhalten. Folgende Themengebiete sind von uns vorläufig vorgesehen:&lt;br /&gt;
&lt;br /&gt;
* Präsentation von Hintergrundinformationen über das Addon-Design von unserer Seite (Objekt- und Fahrzeugbar, Soundengine, Scriptengine usw.)&lt;br /&gt;
* Tipps und Tricks oder auch ganze Tutorials von Usern z.B. zum Erstellen von Repaints oder Mapbau würden unsere Kernthemen abrunden. Entweder als Ergänzung unserer oder als weiterreichende Artikel.&lt;br /&gt;
* Die Bedienung von OMSI und insbesondere der Busse könnte ein weiterer Themenkomplex sein. Zwar gibt es natürlich ein Handbuch für OMSI, dennoch gibt es vieleicht die eine oder andere Sache, die ausführlicher erklärt werden soll. Hier werden wir uns allerdings etwas zurückhalten.&lt;br /&gt;
* Weiterhin könnten hier bewährte Anschlussprojekte zu OMSI präsentiert werden, z.B. OAT oder der Addon-Manager. Höchstwahrscheinlich werden die zugehörigen Artikel dann von den Leitern oder treuesten Fans dieser Projekte geschrieben, wir werden uns hier ebenfalls zurückhalten.&lt;br /&gt;
* Ähnlich hierzu haben wir nichts gegen eine hochqualitative Präsentation von komplexen Addons; denkbar wäre hier z.B. die Bedienungsanleitung eines Addon-Busses oder die Beschreibung und Hinweise für die Fahrt durch eine Addon-Karte mit Fahrplänen und/oder Karten. Wo wir hier allerdings die Grenze setzen, steht noch nicht fest. Insbesondere sollen hier keine &amp;quot;Mini-Artikel&amp;quot; entstehen, wo nur ein Screenshot von einem Repaint und ein Download-Link präsentiert wird!&lt;br /&gt;
* Selbstverständlich dürfen hier auch gerne Hintergrundinformationen zu unserer Strecke oder unseren Bussen oder aber zu Addons gegeben werden (wie sah Spandau in der Realität 1989 aus? Wie wurde damals in Berlin Bus gefahren?). Es sollte sich aber um abgeschlossene und ernsthaft geschriebene Artikel handeln und es sollte definitiv ein Bezug zu OMSI vorhanden sein! Also keine schnell hingeschriebenen Tagesberichte von irgendeinem Busunternehmen, was keiner kennt und was auch nicht in OMSI mindestens als Addon simuliert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Regeln ==&lt;br /&gt;
&lt;br /&gt;
=== Ist das Thema hier erwünscht? ===&lt;br /&gt;
&lt;br /&gt;
Der Idee von OMSIWiki entsprechend sollte jeder Artikel letztlich in eine der oben genannten Kategorien passen!&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Goldene Regel&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
Zunächst die '''&amp;quot;goldene Regel&amp;quot;''': Bevor ein Artikel verfasst oder geändert wird, sollte stets geschaut werden, ob sich an den Regeln etwas geändert hat! Gerade in der Anfangszeit wird es sicher vorkommen, dass sich Regeln ändern oder neue hinzukommen.&lt;br /&gt;
&lt;br /&gt;
=== Erwünscht ===&lt;br /&gt;
&lt;br /&gt;
* Wenn ihr einen kleinen oder großen Fehler entdeckt (auch in einem unserer Artikel!), dann darf ihn jeder korrigieren! Aber nur, wenn ihr euch dabei auch sicher seid.&lt;br /&gt;
* Ihr findet einen Artikel z.B. im Addon-Handbuch zu trocken? Dann dürft ihr gerne ein kleines Beispiel ergänzen! Von mir weiß ich z.B., dass die Anschauung und Klarheit leidet, wenn ich viele und lange Texte schreibe!&lt;br /&gt;
* Ihr findet einen Fachbegriff, der nicht erklärt wird? Wenn es ein bisher nicht erklärter Begriff von OMSI ist, dürft ihr gerne einen Artikel anfertigen und ihn mit dem Fachbegriff verlinken; handelt es sich um einen allgemeinen Fachbegriff, dann reicht meist ein externer Link zu einem entsprechenden Artikel z.B. in der Wikipedia aus.&lt;br /&gt;
* Um zu vermeiden, dass euch bereits jemand anderes &amp;quot;dazwischen funkt&amp;quot;, obwohl euer Artikel noch gar nicht fertig ist, ergänzt bitte hierzu oben den Hinweis: &amp;quot;''Hinweis: Dieser Artikel befindet sich noch im Aufbau!''&amp;quot;. Dadurch wird auch vermieden, dass der unter Umständen erst halbfertige Artikel schon von jemandem übersetzt wird, sodass nach Fertigstellung der deutschen Version die englische noch unvollständig ist.&lt;br /&gt;
* Wenn euer Artikel auch ein englischsprachiges Pendant hat, dann verknüpft ihn bitte! Ein Blick ans Ende des Quelltextes ''dieser'' Seite zeigt euch, wie das geht! Hat er jedoch ''kein'' Pendant und muss demnach in der englischen OMSIWiki noch angelegt werden, so wäre ein Hinweis ganz oben nicht schlecht: &amp;quot;''Hinweis: Dieser Artikel wurde noch nicht ins Englische übersetzt!''&amp;quot; oder &amp;quot;''Hinweis: Die englische Version muss noch aktualisiert werden!''&amp;quot;&lt;br /&gt;
* Wenn ihr Spaß am Übersetzen habt, dann könnt ihr eine sehr wertvolle Hilfe für OMSIWiki sein! Wenn ihr einen dieser Hinweise entdeckt, scheut euch nicht, den Artikel in die englische OMSIWiki einzupflegen! Ihr solltet danach aber den Original-Autor informieren (damit er die Gelegenheit hat, einmal drüber zu schauen) und dann natürlich die beidseitige Verlinkung mit der deutschen Seite vornehmen und den Hinweis entfernen.&lt;br /&gt;
&lt;br /&gt;
=== Unerwünscht ===&lt;br /&gt;
&lt;br /&gt;
* '''Ganz wichtig: Der Name des Artikels muss wohlüberlegt gewählt werden, weil man den nicht mal eben ändern kann! Wer hier grob fahrlässig schlampt, fliegt raus!'''&lt;br /&gt;
* Schlechter Schreibstil! Was im Chat normal ist und im Forum zwangsweise geduldet wird, ist hier tabu: Bitte gebt euch etwas Mühe, wenn ihr hier einen Artikel verfasst!&lt;br /&gt;
* Werbung für unbekannte, kleine Projekte, Foren, virtuelle Gesellschaften etc. Der Sinn von OMSIWiki ist nicht die Werbung für Projekte! Es soll eine Informationsplattform sein!&lt;br /&gt;
&lt;br /&gt;
Hier dazu was Passendes zum schmunzeln: [http://meta.wikimedia.org/wiki/Wikipedia_Anti-Regeln Wikipedia-Anti-Regeln]&lt;br /&gt;
&lt;br /&gt;
=== Absprachen ===&lt;br /&gt;
&lt;br /&gt;
* Vor Beginn der Arbeit bitte oben bei &amp;quot;Aktuell in Arbeit&amp;quot; eine Zeile mit der geplanten Arbeit und eurer Signatur ergänzen. Nach Fertigstellung diesen wieder entfernen. Sollte jedoch dann gar kein Punkt mehr übrigbleiben, dann ein &amp;quot; * ''Nichts'' &amp;quot; stehen lassen.&lt;br /&gt;
* Wenn ihr größere Korrekturen an unseren Artikeln vornehmt, wär es natürlich gut, wenn ihr uns zumindest nachher darüber informiert, damit wir den Überblick behalten.&lt;br /&gt;
* Bevor ein neuer Artikel verfasst wird, kann es nicht schaden, kurz eine E-Mail an uns Administratoren zu schicken mit euren Planungen.&lt;br /&gt;
* Das Einführen neuer Kategorien hat grundstätzlich in Absprache mit den Administratoren zu geschehen.&lt;br /&gt;
&lt;br /&gt;
* Beachtet auch die Möglichkeit, mit den Autoren auf der Diskussionsseite zu diskutieren! Wie der &amp;quot;Quellcode&amp;quot; einer Diskussionsseite aussieht, seht ihr hier: [[Diskussion:OMSI_Addon_Tester_(OAT)]]. Und nicht vergessen: Die Signatur könnt ihr automatisch erzeugen mit &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;!&lt;br /&gt;
&lt;br /&gt;
=== Multilingualität ===&lt;br /&gt;
&lt;br /&gt;
OMSIWiki ist zweisprachig ausgelegt: Englisch und Deutsch. Wie beim großen Vorbild, der Wikipedia, können die Artikel beider Sprachen miteinander verbunden werden. Dies erfolgt auch auf selbem Wege wie bei Wikipedia. Selbstverständlich ist es erstrebenswert, beide Teile der OMSIWiki auf gleichem Stand zu halten - auch wenn das natürlich praktisch nie ganz der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
=== Zugriff ===&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Wikipedia müsst ihr angemeldet sein, um hier Schreibzugriff zu erhalten. Ich denke, dies ist nicht zu viel verlangt und hilft uns eine gewisse Kontrolle über das Verfassen von Artikeln zu behalten.&lt;br /&gt;
&lt;br /&gt;
== Ultra-Kurzhandbuch ==&lt;br /&gt;
&lt;br /&gt;
Ein paar Hinweise für Neulinge, die sich davor scheuen, das ganze Handbuch zu lesen. Wie &amp;quot;baut&amp;quot; man einen OMSIWiki-Artikel?&lt;br /&gt;
&lt;br /&gt;
* Signatur: Gibt's überm Editor-Fenster einen Button, sonst &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
* Anlegen einer neuen Seite: Nachdem ihr im Forum oder uns Bescheid gegeben habt, gebt ihr den ''wohlüberlegten'' Titel der neuen Seite ins ''Suche''-Feld ein. Es erscheint dann der Vorschlag, ob man diese Seite enlegen möchte? Ein &amp;quot;ja&amp;quot; führt dich dann zum leeren Editorfenster.&lt;br /&gt;
* Eine sinnvolle Gliederung kann folgendermaßen erstellt werden:&lt;br /&gt;
 == Hauptüberschrift ==&lt;br /&gt;
 === Subüberschrift ===&lt;br /&gt;
 ==== Sub-Sub-Überschrift ==== usw.&lt;br /&gt;
* Aufzählungen wie diese werden folgendermaßen durchgeführt:&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 ** Sub-Aufzählungspunkt&lt;br /&gt;
* Ein # statt einem * führt zu numerierten Aufzählungen.&lt;br /&gt;
* Fett- und Kursivschreibung wird mittels Apostrophen markiert:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
''Kursiv''&lt;br /&gt;
'''Fett'''&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Die Zuweisung einer Kategorie (im Beispiel der Kategorie &amp;quot;Busfahren in OMSI&amp;quot;) erfolgt ganz am Ende des Artikels mit &amp;lt;nowiki&amp;gt;[[Kategorie:Busfahren in OMSI]]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Weitere Informationen: [http://meta.wikimedia.org/wiki/Hilfe:Handbuch?uselang=de meta.wikimedia.org/wiki/Hilfe:Handbuch]&lt;br /&gt;
&lt;br /&gt;
== Historie ==&lt;br /&gt;
&lt;br /&gt;
* 8. September 2011 - Marcel Kuhnt: Einrichten der deutschen OMSIWiki und Verlinkung mit der englischen.&lt;br /&gt;
* 13. September 2011 - Marcel Kuhnt: OMSIWiki öffentlich angekündigt.&lt;br /&gt;
&lt;br /&gt;
== Links rund ums Thema OMSI ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.omnibussimulator.de www.omnibussimulator.de] - offizielle Seite von OMSI, dem Omnibussimulator&lt;br /&gt;
* [http://www.omnibussimulator.de/forum/ www.omnibussimulator.de/forum/] - offizielles OMSI-Forum&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&lt;br /&gt;
&lt;br /&gt;
[[Technische Informationen zum MediaWiki]]&lt;br /&gt;
&lt;br /&gt;
[[en:Main Page]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_III&amp;diff=766</id>
		<title>OMSI Plugin Framework III</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_III&amp;diff=766"/>
		<updated>2012-11-23T21:47:23Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Die Plugin-Schnittstelle ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich die Arbeitsweise der Plugin-Schnittstelle des OMSI noch etwas tiefer beleuchten, vor allem mehr im Zusammenhang mit der Programmiersprache C++.&lt;br /&gt;
&lt;br /&gt;
Das allgemeine Prinzip wird ja bereits in [[Plug-in-Schnittstelle|diesem Artikel]] erklärt. Auch wenn das Plugin in C++ programmiert wird, ändert sich an den grundlegenden Dingen nichts. Lediglich der im Artikel beschriebene Weg, ein Formular zu öffnen, ist absolut Delphi-typisch und in C++ so nicht möglich. Der Parameter, der beim Aufruf der Funktion '''''Start''''' mitgegeben wird, ist nicht nur einfach ein 'Delphi'-Parameter, er ist auch noch von der verwendeten Delphi-Version abhängig. Deshalb wird dieser Parameter im '''''OMSI Plugin Framework''''' nicht benutzt, auch wenn darüber ein Zugriff auf das Hauptfenster-Handle in C++ möglich wäre.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Lifecycle.jpg|200px|thumb|right|Lebenszyklus eines Plugins]]&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Möglichkeiten, DLLs in ein Programm einzubinden. Die erste Möglichkeit ist, die DLL schon während der Programmierung sozusagen fest mit dem Programm zu verbinden. Diese DLLs müssen beim Programmstart vorhanden sein, sonst schlägt das Starten des Programmes fehl. Diese Möglichkeit benutzt man im z.B. für die System-DLLs. In der Natur eines Plugins liegt es aber, dass es ganz einfach gar nicht da sein kann. Also scheidet die eben erwähnte Möglichkeit zum Einbinden einer DLL aus. Deshalb macht der OMSI von der zweiten Möglichkeit Gebrauch. Ein Programm kann über den Aufruf einer Systemfunktion '''''LoadLibrary''''' zu jeder beliebigen Zeit DLLs nachladen. '''''LoadLibrary''''' sucht aber nur (im Wesentlichen) an drei Stellen automatisch nach einer DLL: in dem Ordner, in dem sich auch das Programm selbst befindet, im '''''Windows'''''-Ordner und im '''''Windows\system(32)'''''-Ordner. Wenn sie dort nicht fündig wird, liefert die Funktion einen Fehler zurück. Also muss der OMSI ''wissen'', wo sich die DLL befindet. Dafür wurde der Ordner &amp;lt;i&amp;gt;&amp;amp;lt;OMSI_Installationsordner&amp;amp;gt;&amp;lt;/i&amp;gt;\'''''plugins''''' festgelegt.&lt;br /&gt;
&lt;br /&gt;
=== Lebenszyklus eines Plugins ===&lt;br /&gt;
&lt;br /&gt;
Plugin-DLLs werden bereits kurz nach dem Start des OMSI geladen und ihre '''''Start'''''-Funktion aufgerufen. Wenn nach dem Start des OMSI das erste mal der Auswahldialog für die Karte, gespeichertes Spiel usw. erscheint, ist das Plugin schon aktiviert, aber im Ruhezustand. Zu diesem Zeitpunkt existiert noch keine Karte und kein Bus, da der Spieler ja die Karte erst noch auswählen muss. Auch nachdem der Spieler eine Karte ausgwählt und der OMSI Diese geladen hat, schläft das Plugin immer noch weiter. Es erwacht erst, sobald der OMSI den Bus des Spielers geladen hat. Solange ein Spieler-Bus existiert werden nun die '''''AccessVariable'''''- und '''''AccessTrigger'''''-Funktionen durch den OMSI aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Kurz vor Beendigung des OMSI ruft Dieser noch die Funktion '''''Finalize''''' auf. Damit endet der Lebenszyklus des Plugins.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion Start ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Start&amp;lt;/span&amp;gt;(AOwner: TComponent); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Start&amp;lt;/span&amp;gt;(void* aOwner);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion '''''Start''''' wird (wie im vorherigen Abschnitt beschrieben) einmalig vor Beginn des eigentlichen Spiels durch den OMSI aufgerufen und ist daher nicht zeitkritisch. In die Funktion '''''Start''''' gehören alle grundlegenden Initialisierungen, die Dein Plugin benötigt. Wenn man mal davon absieht, dass sich die Ladezeit des OMSI verlängert, hast Du hier Zeit, die Dinge zu tun, die Du als Vorbereitung für die eigentliche Arbeit im Plugin benötigst.&lt;br /&gt;
&lt;br /&gt;
Wie im Abschnitt [[#Allgemeines|Allgemeines]] bereits erläutert, solltest Du es vermeiden, den Parameter dieser Funktion zu verwenden. Falls Du sehr daran interessiert bist, an das Handle des Hauptfensters zu gelangen, sei hier ganz grob der Weg beschrieben, wie das möglich wäre: Du müsstest Dir zunächst die technische Dokumentation der Komponente '''''TComponent''''' (bzw. '''''TForm''''', denn eine '''''TForm''''' ist dieser Parameter tatsächlich) passend zu der Delphi-Version besorgen, mit der der OMSI programmiert wurde. Anhand der Dokumentation kannst du dann die Klasse in C++ ''nachbauen''. Wenn Du das geschafft hast, kannst Du nun den Parameter verwenden. Das Ganze ist - wie gesagt - durchaus möglich, aber mehr ein Hack als vernünftige Programmierung.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion AccessVariable ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessVariable&amp;lt;/span&amp;gt;(varindex: word; var value: single; var write: boolean); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessVariable&amp;lt;/span&amp;gt;(unsigned short varindex, float* value, bool* write);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Solange der Spieler über einen Bus verfügt, werden in jedem Frame alle in der .opl-Datei deklarierten Variablen nacheinander genau in der Reihenfolge der Deklaration über diese Funktion an Dein Plugin zur Bearbeitung übergeben.&lt;br /&gt;
&lt;br /&gt;
Der erste Parameter ist dabei der Index der Variablen in der .opl-Datei. Die Zuordnung, welche Variable was ist, musst Du in Deinem Plugin selbst wieder herstellen. Der zweite Parameter ist ein Zeiger auf einen '''''float'''''-Wert. Das ist der aktuelle Wert der Variablen. Der Wert wird deshalb als Zeigertyp übergeben, damit Du den Wert im Plugin auch ändern kannst. Der dritte Parameter schließlich ist ein Zeiger auf einen '''''bool'''''-Wert. Darüber gibst Du dem OMSI Rückmeldung, ob Du den Inhalt der Variablen verändert hast. Wenn Du die Variable nur lesend benutzt, brauchst Du nichts weiter tun. Der Wert, auf den dieser Zeiger zeigt, ist immer mit '''''false''''' vorbelegt.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;unbewiesene_aussage&amp;amp;gt;&lt;br /&gt;
:&amp;lt;span style=&amp;quot;color:blue;font-style:italic&amp;quot;&amp;gt;Beim Ändern des Wertes einer Variablen musst Du auch bedenken, dass ein Script, welches ebenfalls dieselbe Variable ändert, Deinen Wert wieder überschreibt.&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;lt;/unbewiesene_aussage&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dadurch, das diese Funktion für '''''jede''''' Variable in '''''jedem''''' Frame aufgerufen wird, ergibt sich, das diese Funktion äußerst zeitkritisch ist. Über die Ausführungsdauer der Funktion in Deinem Plugin beeinflusst Du direkt die Framerate des OMSI (siehe [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]]).&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion AccessTrigger ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessTrigger&amp;lt;/span&amp;gt;(triggerindex: word; var active: boolean); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessTrigger&amp;lt;/span&amp;gt;(unsigned short triggerindex, bool* active);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ähnlich wie bei der Funktion '''''AccessVariable''''' wird auch '''''AccessTrigger''''' in jedem Frame für jeden in der .opl-Datei deklarierten Trigger genau in der Reihenfolge der Deklaration aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Der erste Parameter ist dabei der Index des Triggers in der .opl-Datei. Die Zuordnung, welcher Trigger wer ist, musst Du in Deinem Plugin selbst wieder herstellen. Der zweite Parameter ist ein Zeiger auf einen '''''bool'''''-Wert. Darüber gibst Du dem OMSI Rückmeldung, ob er den Trigger auslösen soll oder nicht. Wenn Du den Trigger nicht auslösen möchtest, brauchst Du nichts weiter tun. Der Wert, auf den dieser Zeiger zeigt, ist immer mit '''''false''''' vorbelegt.&lt;br /&gt;
&lt;br /&gt;
Genau wie '''''AccessVariable''''' ist auch diese Funktion zeitkritisch, da sie für '''''jeden''''' Trigger in '''''jedem''''' Frame aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn Du in Deinem Plugin den Trigger nicht auslöst, kann er trotzdem von einem Script ausgelöst werden.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion Finalize ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Finalize&amp;lt;/span&amp;gt;; stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Finalize&amp;lt;/span&amp;gt;();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion '''''Finalize''''' wird einmalig beim Beenden des OMSI aufgerufen und ist nicht zeitkritisch. In diese Funktion gehören alle Aufräumarbeiten, die in Deinem Plugin nötig sind.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework II|[zum Kapitel 2]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework IV|[zum Kapitel 4]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Datei:Lifecycle.jpg&amp;diff=765</id>
		<title>Datei:Lifecycle.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Datei:Lifecycle.jpg&amp;diff=765"/>
		<updated>2012-11-23T21:38:08Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_III&amp;diff=764</id>
		<title>OMSI Plugin Framework III</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_III&amp;diff=764"/>
		<updated>2012-11-23T21:37:49Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Die Plugin-Schnittstelle ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich die Arbeitsweise der Plugin-Schnittstelle des OMSI noch etwas tiefer beleuchten, vor allem mehr im Zusammenhang mit&lt;br /&gt;
der Programmiersprache C++.&lt;br /&gt;
&lt;br /&gt;
Das allgemeine Prinzip wird ja bereits in [[Plug-in-Schnittstelle|diesem Artikel]] erklärt. Auch wenn das Plugin in C++ programmiert wird, ändert&lt;br /&gt;
sich an den grundlegenden Dingen nichts. Lediglich der im Artikel beschriebene Weg, ein Formular zu öffnen, ist absolut Delphi-typisch und in C++&lt;br /&gt;
so nicht möglich. Der Parameter, der beim Aufruf der Funktion '''''Start''''' mitgegeben wird, ist nicht nur einfach ein 'Delphi'-Parameter, er ist&lt;br /&gt;
auch noch von der verwendeten Delphi-Version abhängig. Deshalb wird dieser Parameter im '''''OMSI Plugin Framework''''' nicht benutzt, auch wenn&lt;br /&gt;
darüber ein Zugriff auf das Hauptfenster-Handle in C++ möglich wäre.&lt;br /&gt;
&lt;br /&gt;
=== Lebenszyklus eines Plugins ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Lifecycle.jpg|200px|thumb|right|Lebenszyklus eines Plugins]]&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Möglichkeiten, DLLs in ein Programm einzubinden. Die erste Möglichkeit ist, die DLL schon während der Programmierung sozusagen fest mit&lt;br /&gt;
dem Programm zu verbinden. Diese DLLs müssen beim Programmstart vorhanden sein, sonst schlägt das Starten des Programmes fehl. Diese Möglichkeit benutzt&lt;br /&gt;
man im z.B. für die System-DLLs (und davon hat Windows eine reichliche Anzahl). In der Natur eines Plugins liegt es aber, dass es ganz einfach gar nicht&lt;br /&gt;
da sein kann. Also scheidet die eben erwähnte Möglichkeit zum Einbinden einer DLL aus. Deshalb macht der OMSI von der zweiten Möglichkeit Gebrauch. Ein&lt;br /&gt;
Programm kann über den Aufruf einer Systemfunktion '''''LoadLibrary''''' zu jeder beliebigen Zeit DLLs nachladen. '''''LoadLibrary''''' sucht aber nur&lt;br /&gt;
(im Wesentlichen) an drei Stellen automatisch nach einer DLL: in dem Ordner, in dem sich auch das Programm selbst befindet, im '''''Windows'''''-Ordner&lt;br /&gt;
und im '''''Windows\system(32)'''''-Ordner. Wenn sie dort nicht fündig wird, liefert die Funktion einen Fehler zurück. Also muss der OMSI ''wissen'', wo &lt;br /&gt;
sich die DLL befindet. Dafür wurde der Ordner &amp;lt;i&amp;gt;&amp;amp;lt;OMSI_Installationsordner&amp;amp;gt;&amp;lt;/i&amp;gt;\'''''plugins''''' festgelegt.&lt;br /&gt;
&lt;br /&gt;
Plugin-DLLs werden bereits kurz nach dem Start des OMSI geladen und ihre '''''Start'''''-Funktion aufgerufen. Wenn nach dem Start des OMSI das erste mal&lt;br /&gt;
der Auswahldialog für die Karte, gespeichertes Spiel usw. erscheint, ist das Plugin schon aktiviert, aber im Ruhezustand. Zu diesem Zeitpunkt existiert &lt;br /&gt;
noch keine Karte und kein Bus, da der Spieler ja die Karte erst noch auswählen muss. Auch nachdem der Spieler eine Karte ausgwählt und der OMSI Diese &lt;br /&gt;
geladen hat, schläft das Plugin immer noch weiter. Es erwacht erst, sobald der OMSI den Bus des Spielers geladen hat. Solange ein Spieler-Bus existiert&lt;br /&gt;
werden nun die '''''AccessVariable'''''- und '''''AccessTrigger'''''-Funktionen durch den OMSI aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Kurz vor Beendigung des OMSI ruft Dieser noch die Funktion '''''Finalize''''' auf. Damit endet der Lebenszyklus des Plugins.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion Start ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Start&amp;lt;/span&amp;gt;(AOwner: TComponent); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Start&amp;lt;/span&amp;gt;(void* aOwner);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion '''''Start''''' wird (wie im vorherigen Abschnitt beschrieben) einmalig vor Beginn des eigentlichen Spiels durch den OMSI aufgerufen und ist &lt;br /&gt;
daher nicht zeitkritisch. In die Funktion '''''Start''''' gehören alle grundlegenden Initialisierungen, die Dein Plugin benötigt. Wenn man mal davon absieht,&lt;br /&gt;
dass sich die Ladezeit des OMSI verlängert, hast Du hier Zeit, die Dinge zu tun, die Du als Vorbereitung für die eigentliche Arbeit im Plugin benötigst.&lt;br /&gt;
&lt;br /&gt;
Wie im Abschnitt [[#Allgemeines|Allgemeines]] bereits erläutert, solltest Du es vermeiden, den Parameter dieser Funktion zu verwenden. Falls Du sehr daran &lt;br /&gt;
interessiert bist, an das Handle des Hauptfensters zu gelangen, sei hier ganz grob der Weg beschrieben, wie das möglich wäre: Du müsstest Dir zunächst die &lt;br /&gt;
technische Dokumentation der Komponente '''''TComponent''''' (bzw. '''''TForm''''', denn eine '''''TForm''''' ist dieser Parameter tatsächlich) passend zu der &lt;br /&gt;
Delphi-Version besorgen, mit der der OMSI programmiert wurde. Anhand der Dokumentation kannst du dann die Klasse in C++ ''nachbauen''. Wenn Du das geschafft&lt;br /&gt;
hast, kannst Du nun den Parameter verwenden. Das Ganze ist - wie gesagt - durchaus möglich, aber mehr ein Hack als vernünftige Programmierung.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion AccessVariable ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessVariable&amp;lt;/span&amp;gt;(varindex: word; var value: single; var write: boolean); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessVariable&amp;lt;/span&amp;gt;(unsigned short varindex, float* value, bool* write);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Solange der Spieler über einen Bus verfügt, werden in jedem Frame alle in der .opl-Datei deklarierten Variablen nacheinander genau in der Reihenfolge der&lt;br /&gt;
Deklaration über diese Funktion an Dein Plugin zur Bearbeitung übergeben.&lt;br /&gt;
&lt;br /&gt;
Der erste Parameter ist dabei der Index der Variablen in der .opl-Datei. Die Zuordnung, welche Variable was ist, musst Du in Deinem Plugin selbst wieder &lt;br /&gt;
herstellen. Der zweite Parameter ist ein Zeiger auf einen '''''float'''''-Wert. Das ist der aktuelle Wert der Variablen. Der Wert wird deshalb als Zeigertyp&lt;br /&gt;
übergeben, damit Du den Wert im Plugin auch ändern kannst. Der dritte Parameter schließlich ist ein Zeiger auf einen '''''bool'''''-Wert. Darüber gibst Du dem &lt;br /&gt;
OMSI Rückmeldung, ob Du den Inhalt der Variablen verändert hast. Wenn Du die Variable nur lesend benutzt, brauchst Du nichts weiter tun. Der Wert, auf den&lt;br /&gt;
dieser Zeiger zeigt, ist immer mit '''''false''''' vorbelegt.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;unbewiesene_aussage&amp;amp;gt;&lt;br /&gt;
:&amp;lt;span style=&amp;quot;color:blue;font-style:italic&amp;quot;&amp;gt;Beim Ändern des Wertes einer Variablen musst Du auch bedenken, dass ein Script, welches ebenfalls dieselbe Variable ändert, Deinen Wert wieder überschreibt.&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;lt;/unbewiesene_aussage&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dadurch, das diese Funktion für '''''jede''''' Variable in '''''jedem''''' Frame aufgerufen wird, ergibt sich, das diese Funktion äußerst zeitkritisch ist. Über&lt;br /&gt;
die Ausführungsdauer der Funktion in Deinem Plugin beeinflusst Du direkt die Framerate des OMSI (siehe [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]]).&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion AccessTrigger ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessTrigger&amp;lt;/span&amp;gt;(triggerindex: word; var active: boolean); stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;AccessTrigger&amp;lt;/span&amp;gt;(unsigned short triggerindex, bool* active);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ähnlich wie bei der Funktion '''''AccessVariable''''' wird auch '''''AccessTrigger''''' in jedem Frame für jeden in der .opl-Datei deklarierten Trigger genau in der&lt;br /&gt;
Reihenfolge der Deklaration aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Der erste Parameter ist dabei der Index des Triggers in der .opl-Datei. Die Zuordnung, welcher Trigger wer ist, musst Du in Deinem Plugin selbst wieder &lt;br /&gt;
herstellen. Der zweite Parameter ist ein Zeiger auf einen '''''bool'''''-Wert. Darüber gibst Du dem OMSI Rückmeldung, ob Du er den Trigger auslösen oder nicht.&lt;br /&gt;
Wenn Du den Trigger nicht auslösen möchtest, brauchst Du nichts weiter tun. Der Wert, auf den dieser Zeiger zeigt, ist immer mit '''''false''''' vorbelegt.&lt;br /&gt;
&lt;br /&gt;
Genau wie '''''AccessVariable''''' ist auch diese Funktion zeitkritisch, da sie für '''''jeden''''' Trigger in '''''jedem''''' Frame aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Auch wenn Du in Deinem Plugin den Trigger nicht auslöst, kann er trotzdem von einem Script ausgelöst werden.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion Finalize ===&lt;br /&gt;
&lt;br /&gt;
Gegenüberstellung Funktionsdeklaration Pascal / C++&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;{ Pascal }&amp;lt;/span&amp;gt;&lt;br /&gt;
 procedure &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Finalize&amp;lt;/span&amp;gt;; stdcall;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// C++&amp;lt;/span&amp;gt;&lt;br /&gt;
 void __stdcall &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;Finalize&amp;lt;/span&amp;gt;();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion '''''Finalize''''' wird einmalig beim Beenden des OMSI aufgerufen und ist nicht zeitkritisch. In diese Funktion gehören alle Aufräumarbeiten, die in&lt;br /&gt;
Deinem Plugin nötig sind.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework II|[zum Kapitel 2]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework IV|[zum Kapitel 4]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_III&amp;diff=763</id>
		<title>OMSI Plugin Framework III</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_III&amp;diff=763"/>
		<updated>2012-11-23T15:47:24Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Die Seite wurde neu angelegt: „== Die Plugin-Schnittstelle ==  === Allgemeines ===  In diesem Kapitel werde ich die Arbeitsweise der Plugin-Schnittstelle des OMSI noch etwas tiefer beleuchten, …“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Die Plugin-Schnittstelle ==&lt;br /&gt;
&lt;br /&gt;
=== Allgemeines ===&lt;br /&gt;
&lt;br /&gt;
In diesem Kapitel werde ich die Arbeitsweise der Plugin-Schnittstelle des OMSI noch etwas tiefer beleuchten, vor allem mehr im Zusammenhang mit&lt;br /&gt;
der Programmiersprache C++.&lt;br /&gt;
&lt;br /&gt;
Das allgemeine Prinzip wird ja bereits in [[Plug-in-Schnittstelle|diesem Artikel]] erklärt. Auch wenn das Plugin in C++ programmiert wird, ändert&lt;br /&gt;
sich an den grundlegenden Dingen nichts. Lediglich der im Artikel beschriebene Weg, ein Formular zu öffnen, ist absolut Delphi-typisch und in C++&lt;br /&gt;
so nicht möglich. Der Parameter, der beim Aufruf der Funktion '''''Start''''' mitgegeben wird, ist nicht nur einfach ein 'Delphi'-Parameter, er ist&lt;br /&gt;
auch noch von der verwendeten Delphi-Version abhängig. Deshalb wird dieser Parameter im '''''OMSI Plugin Framework''''' nicht benutzt, auch wenn&lt;br /&gt;
darüber ein Zugriff auf das Hauptfenster-Handle in C++ möglich wäre.&lt;br /&gt;
&lt;br /&gt;
=== Lebenszyklus eines Plugins ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Möglichkeiten, DLLs in ein Programm einzubinden. Die erste Möglichkeit ist, die DLL schon während der Programmierung sozusagen fest mit&lt;br /&gt;
dem Programm zu verbinden. Diese DLLs müssen beim Programmstart vorhanden sein, sonst schlägt das Starten des Programmes fehl. Diese Möglichkeit benutzt&lt;br /&gt;
man im z.B. für die System-DLLs (und davon hat Windows eine reichliche Anzahl). In der Natur eines Plugins liegt es aber, dass es ganz einfach gar nicht&lt;br /&gt;
da sein kann. Also scheidet die eben erwähnte Möglichkeit zum Einbinden einer DLL aus. Deshalb macht der OMSI von der zweiten Möglichkeit Gebrauch. Ein&lt;br /&gt;
Programm kann über den Aufruf einer Systemfunktion '''''LoadLibrary''''' zu jeder beliebigen Zeit DLLs nachladen. '''''LoadLibrary''''' sucht aber nur&lt;br /&gt;
(im Wesentlichen) an drei Stellen automatisch nach einer DLL: in dem Ordner, in dem sich auch das Programm selbst befindet, im '''''Windows'''''-Ordner&lt;br /&gt;
und im '''''Windows\system(32)'''''-Ordner. Wenn sie dort nicht fündig wird, liefert die Funktion einen Fehler zurück. Also muss der OMSI ''wissen'', wo &lt;br /&gt;
sich die DLL befindet. Dafür wurde der Ordner &amp;lt;i&amp;gt;&amp;amp;lt;OMSI_Installationsordner&amp;amp;gt;&amp;lt;/i&amp;gt;\'''''plugins''''' festgelegt.&lt;br /&gt;
&lt;br /&gt;
Plugin-DLLs werden bereits kurz nach dem Start des OMSI geladen und ihre '''''Start'''''-Funktion aufgerufen. Wenn nach dem Start des OMSI das erste mal&lt;br /&gt;
der Auswahldialog für die Karte, gespeichertes Spiel usw. erscheint, ist das Plugin schon aktiviert, aber im Ruhezustand. Zu diesem Zeitpunkt existiert &lt;br /&gt;
noch keine Karte und kein Bus, da der Spieler ja die Karte erst noch auswählen muss. Auch nachdem der Spieler eine Karte ausgwählt und der OMSI Diese &lt;br /&gt;
geladen hat, schläft das Plugin immer noch weiter. Es erwacht erst, sobald der OMSI den Bus des Spielers geladen hat. Solange ein Spieler-Bus existiert&lt;br /&gt;
werden nun die '''''AccessVariable'''''- und '''''AccessTrigger'''''-Funktionen durch den OMSI aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Kurz vor Beendigung des OMSI ruft Dieser noch die Funktion '''''Finalize''''' auf. Damit endet der Lebenszyklus des Plugins.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion '''Start''' ===&lt;br /&gt;
&lt;br /&gt;
Die Funktion '''''Start''''' wird (wie im vorherigen Abschnitt beschrieben) einmalig vor Beginn des eigentlichen Spiels durch den OMSI aufgerufen und ist &lt;br /&gt;
daher nicht zeitkritisch. In die Funktion '''''Start''''' gehören alle grundlegenden Initialisierungen, die Dein Plugin benötigt. Wenn man mal davon absieht,&lt;br /&gt;
dass sich die Ladezeit des OMSI verlängert, hast Du hier Zeit, die Dinge zu tun, die Du als Vorbereitung für die eigentliche Arbeit im Plugin benötigst.&lt;br /&gt;
&lt;br /&gt;
Wie im Abschnitt [[#Allgemeines]] bereits erläutert, solltest Du es vermeiden, den Parameter dieser Funktion zu verwenden. Falls Du sehr daran interessiert&lt;br /&gt;
bist, an das Handle des Hauptfensters zu gelangen, sei hier ganz grob der Weg beschrieben, wie das möglich wäre: Du müsstest Dir zunächst die technische&lt;br /&gt;
Dokumentation der Komponente '''''TComponent''''' (bzw. '''''TForm''''', denn eine '''''TForm''''' ist dieser Parameter tatsächlich) passend zu der &lt;br /&gt;
Delphi-Version besorgen, mit der der OMSI programmiert wurde. Anhand der Dokumentation kannst du dann die Klasse in C++ ''nachbauen''. Wenn Du das geschafft&lt;br /&gt;
hast, kannst Du nun den Parameter verwenden. Das Ganze ist - wie gesagt - durchaus möglich, aber mehr ein Hack als vernünftige Programmierung.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion '''AccessVariable''' ===&lt;br /&gt;
&lt;br /&gt;
Solange der Spieler über einen Bus verfügt, werden in jedem Frame alle in der .opl-Datei deklarierten Variablen nacheinander genau in der Reihenfolge der&lt;br /&gt;
Deklaration über diese Funktion an Dein Plugin zur Bearbeitung übergeben.&lt;br /&gt;
&lt;br /&gt;
Der erste Parameter ist dabei der Index der Variablen in der .opl-Datei. Die Zuordnung, welche Variable was ist, musst Du in Deinem Plugin selbst wieder &lt;br /&gt;
herstellen. Der zweite Parameter ist ein Zeiger auf einen '''''float'''''-Wert. Das ist der aktuelle Wert der Variablen. Der Wert wird deshalb als Zeigertyp&lt;br /&gt;
übergeben, damit Du den Wert im Plugin auch ändern kannst. Der dritte Parameter schließlich ist ein Zeiger auf einen '''''bool'''''-Wert. Darüber gibst Du dem &lt;br /&gt;
OMSI Rückmeldung, ob Du den Inhalt der Variablen verändert hast. Wenn Du die Variable nur lesend benutzt, brauchst Du nichts weiter tun. Der Wert, auf den&lt;br /&gt;
dieser Zeiger zeigt, ist immer mit '''''false''''' vorbelegt.&lt;br /&gt;
&lt;br /&gt;
Dadurch, das diese Funktion für '''''jede''''' Variable in '''''jedem''''' Frame aufgerufen wird, ergibt sich, das diese Funktion äußerst zeitkritisch ist. Über&lt;br /&gt;
die Ausführungsdauer der Funktion in Deinem Plugin beeinflusst Du direkt die Framerate des OMSI (siehe [[OMSI_Plugin_Framework_II#Die_Regel_Nummer_1|Regel Nummer 1]]).&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion '''AccessTrigger''' ===&lt;br /&gt;
&lt;br /&gt;
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla lacus metus, lacinia at tempus vitae, ultrices eget diam. Phasellus eu interdum nisi. Etiam&lt;br /&gt;
viverra dui sed lectus tristique at semper risus faucibus. Sed vitae neque vel libero vulputate tempus vel non est. Suspendisse viverra justo vitae enim&lt;br /&gt;
iaculis consectetur. Aenean vulputate neque a metus semper vel sollicitudin erat lacinia. Integer volutpat mi vitae lectus tempus faucibus. Aenean rhoncus,&lt;br /&gt;
eros eu pulvinar eleifend, ante leo placerat est, quis blandit ante risus non nisl. Praesent bibendum lorem ut felis pretium bibendum. Vestibulum a velit quam.&lt;br /&gt;
Donec semper tellus in nisi gravida iaculis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus nibh nibh, sodales&lt;br /&gt;
non commodo pellentesque, pharetra et lacus. Nam leo urna, tempus vel mattis id, pretium vitae turpis. Vestibulum ante ipsum primis in faucibus orci luctus et&lt;br /&gt;
ultrices posuere cubilia Curae; Donec nulla ipsum, tristique vitae vehicula in, sodales sit amet turpis.&lt;br /&gt;
&lt;br /&gt;
=== Die Funktion '''Finalize''' ===&lt;br /&gt;
&lt;br /&gt;
Die Funktion '''''Finalize''''' wird einmalig beim Beenden des OMSI aufgerufen und ist nicht zeitkritisch. In diese Funktion gehören alle Aufräumarbeiten, die in&lt;br /&gt;
Deinem Plugin nötig sind.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework II|[zum Kapitel 2]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework IV|[zum Kapitel 4]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Plug-in-Schnittstelle&amp;diff=762</id>
		<title>Plug-in-Schnittstelle</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Plug-in-Schnittstelle&amp;diff=762"/>
		<updated>2012-11-23T13:42:13Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Missverständliche Formulierung verändert, Tippfehler beseitigt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Allgemeines Prinzip =&lt;br /&gt;
&lt;br /&gt;
Es besteht die Möglichkeit, für den OMSI Plugin-DLLs zu programmieren, welche Lese- und Schreibzugriff auf die [[System-_und_vordefinierte_lokalen_Variablen#Fahrzeuge|Fahrzeugvariablen]] haben und [[Scriptsystem#Trigger|Fahrzeug-Trigger]] auslösen können.&lt;br /&gt;
&lt;br /&gt;
Jedes Plugin besteht aus einer [[Konfigurationsdatei]] mit der Dateiendung *.opl und einer zugehörigen DLL. Beide Dateien müssen im Verzeichnis &amp;quot;OMSI\plugins&amp;quot; liegen.&lt;br /&gt;
&lt;br /&gt;
= Beschreibung des Beispiels =&lt;br /&gt;
&lt;br /&gt;
In OMSI enthalten ist bereits ein Beispiel-Plugin enthalten. Um es zu aktivieren, muss die Datei &amp;quot;test.txt&amp;quot; im &amp;quot;&amp;lt;OMSI&amp;gt;\plugins&amp;quot;-Verzeichnis in &amp;quot;test.opl&amp;quot; umbenannt werden.&lt;br /&gt;
&lt;br /&gt;
== Funktionsumfang ==&lt;br /&gt;
&lt;br /&gt;
Dieses Plugin hat drei Funktionen: Einen Tacho (analog und digital) ganz oben, einen Sollwertregler für den roten Heizungsregler (obwohl da falscherweise &amp;quot;Rollband-Sollwert&amp;quot; steht) und einen Türtaster &amp;quot;Button1&amp;quot; (der aber trotzdem nur funktioniert, wenn die Haltestellenbremse aktiv und die Elektrik an ist).&lt;br /&gt;
&lt;br /&gt;
[[Datei:Beispiel-Plugin.jpg|600px|thumb|right|Oberfläche des Beispiel-Plugins]]&lt;br /&gt;
&lt;br /&gt;
== Aufbau der *opl-Datei ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
To activate, rename this file to &amp;quot;test.opl&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[dll]&lt;br /&gt;
Test.dll&lt;br /&gt;
&lt;br /&gt;
[varlist]&lt;br /&gt;
2&lt;br /&gt;
Velocity&lt;br /&gt;
cockpit_heizregler_temp&lt;br /&gt;
&lt;br /&gt;
[triggers]&lt;br /&gt;
1&lt;br /&gt;
bus_doorfront0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zeile ist nur eine Kommentarzeile. Der [dll]-Befehl gibt den Dateinamen der zugehörigen DLL an.&lt;br /&gt;
&lt;br /&gt;
Der [varlist]-Befehl beginnt mit der Anzahl der zu erwartenden (lokalen) Fahrzeugvariablen. Hierbei können auch User-Variablen eines bestimmten Busses angegeben werden. Wenn der tatsächlich gefahrene Bus dann diese Variable nicht hat, dann werden die zugehörigen Zugriffe natürlich nicht durchgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Variable mit dem Index 0 ist also bei dieser DLL &amp;quot;Velocity&amp;quot;, die Variable mit dem Index 1 ist &amp;quot;cockpit_heizregler_temp&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Der [triggers]-Befehl beginnt ebenfalls mit der Anzahl der zu erwartenden Fahrzeugtrigger. In diesem Fall ist dies nur ein Trigger: &amp;quot;bus_doorfront0&amp;quot; mit dem Index 0.&lt;br /&gt;
&lt;br /&gt;
== Aufbau der DLL ==&lt;br /&gt;
&lt;br /&gt;
Anhand der Beispiel-DLL wird nun erklärt, wie der zugehörige Delphi-Code aussehen soll. Im Allgemeinen sollte es möglich sein, auch mit anderen Programmiersprachen passende DLLs zu programmieren. Ausprobiert habe ich dies allerdings nicht.&lt;br /&gt;
&lt;br /&gt;
Die DLL besteht aus zwei Units. Erklärt wird aber nur die Hauptunit (Test.dpr) (die zweite Unit enthält nur einige wenige nicht-relevante Implementierungen für die Form):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
library Test;&lt;br /&gt;
&lt;br /&gt;
uses&lt;br /&gt;
  SysUtils,&lt;br /&gt;
  Dialogs,&lt;br /&gt;
  Classes,&lt;br /&gt;
  TestU in 'TestU.pas' {Form1};&lt;br /&gt;
&lt;br /&gt;
{$R *.res}&lt;br /&gt;
&lt;br /&gt;
procedure Start( AOwner: TComponent ); stdcall;&lt;br /&gt;
begin&lt;br /&gt;
        form1 := TForm1.Create( AOwner );&lt;br /&gt;
        form1.Show;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure Finalize; stdcall;&lt;br /&gt;
begin&lt;br /&gt;
        form1.Free;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure AccessVariable( varindex: word; var value: single; var write: boolean ); stdcall;&lt;br /&gt;
begin&lt;br /&gt;
        case varindex of&lt;br /&gt;
                0:&lt;br /&gt;
                begin&lt;br /&gt;
                        form1.Label2.Caption := floattostrF( value, ffFixed, 5, 1 ) + ' km/h';&lt;br /&gt;
                        form1.Gauge1.Progress := round( value );&lt;br /&gt;
                        write := false;                        &lt;br /&gt;
                end;&lt;br /&gt;
                1:&lt;br /&gt;
                begin&lt;br /&gt;
                        value := form1.TrackBar1.Position / 30;&lt;br /&gt;
                        write := true;&lt;br /&gt;
                end;&lt;br /&gt;
        end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure AccessTrigger( triggerindex: word; var active: boolean ); stdcall;&lt;br /&gt;
begin&lt;br /&gt;
        case triggerindex of&lt;br /&gt;
                0:&lt;br /&gt;
                begin&lt;br /&gt;
                        active := form1.button1_pressed;&lt;br /&gt;
                end;&lt;br /&gt;
        end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
exports&lt;br /&gt;
        AccessVariable,&lt;br /&gt;
        AccessTrigger,        &lt;br /&gt;
        Start,&lt;br /&gt;
        Finalize;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zunächst ist der letzte Abschnitt &amp;quot;exports&amp;quot; zu beachten: Die vier gelisteten Prozeduren sollen von der DLL angeboten werden: ''AccessVariable'', ''AccessTrigger'', ''Start'' und ''Finalize''.&lt;br /&gt;
&lt;br /&gt;
Die vier Prozeduren haben folgenden Aufbau:&lt;br /&gt;
&lt;br /&gt;
=== Aufbau der Prozedur ''Start'' ===&lt;br /&gt;
&lt;br /&gt;
''Start( AOwner: TComponent )'' wird am Anfang aufgerufen und ermöglicht es der DLL, sich zu initialisieren. In diesem Fall wird ''Form1'' erzeugt und der gleichnamigen Variable zugeordnet, welche sich jedoch in der Unit ''TestU'' befindet. Als zweiter Schritt wird der ''Show''-Befehl aufgerufen, um die ''Form1'' anzuzeigen. ''Start'' übergibt den Parameter &amp;quot;AOwner&amp;quot;, welcher der Handler des Hauptprogramms von OMSI darstellt.&lt;br /&gt;
&lt;br /&gt;
=== Aufbau der Prozedur ''Finalize'' ===&lt;br /&gt;
&lt;br /&gt;
''Finalize'' dagegen wird beim Schließen aufgerufen. Hier wird schlicht das Objekt ''Form1'' zerstört.&lt;br /&gt;
&lt;br /&gt;
=== Aufbau der Prozedur ''AccessVariable'' ===&lt;br /&gt;
&lt;br /&gt;
Im Betrieb ruft OMSI diese Prozedur für alle in der *.opl-Datei gelisteten lokalen Variablen auf. Sie übergibt dabei stets den Index der Variable (''varindex''). Die Prozedur kann nun ihrerseits die Variablen ''value'' und ''write'' schreiben.&lt;br /&gt;
&lt;br /&gt;
Bei einem Lesezugriff kann die Prozedur wie im Beispiel unter &amp;quot;0:&amp;quot; die Variable über ''value'' einfach auslesen. Es ist aber wie unter &amp;quot;1&amp;quot; auch möglich, dem Wert von ''value'' einen neuen Wert zuzuweisen. Dann aber muss die Variable ''write'' auch auf ''wahr'' gesetzt werden, damit der Wert von OMSI übernommen wird. Im Beispiel wird die ''TrackBar'' ausgelesen und der Wert auf den Wert von ''value'' geschrieben.&lt;br /&gt;
&lt;br /&gt;
=== Aufbau der Prozedur ''AccessTrigger'' ===&lt;br /&gt;
&lt;br /&gt;
Diese Prozedur arbeitet recht ähnlich. Hier allerdings wird die Triggerliste durchgearbeitet. Die DLL kann bei Aufruf dieser Funktion den Wert ''active'' auf ''true'' setzen; dann löst OMSI den gewünschten Trigger aus.&lt;br /&gt;
&lt;br /&gt;
= Ausführliches Tutorial =&lt;br /&gt;
&lt;br /&gt;
Ein ausführliches Tutorial zur Nutzung dieser Schnittstelle - allerdings mit der Programmiersprache C++ - ist hier im Wiki in der Kategorie [[OMSI Plugin Framework|Tutorials]] zu finden.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Nachschlagewerk_für_Addon-Entwickler]]&lt;br /&gt;
&lt;br /&gt;
[[en:Plug-In Interface]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=761</id>
		<title>OMSI Plugin Framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=761"/>
		<updated>2012-11-23T13:32:39Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Rechtschreibfehler beseitigt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Inhaltsverzeichnis ==&lt;br /&gt;
&lt;br /&gt;
* [[#Vorwort|Vorwort]]&lt;br /&gt;
* [[OMSI Plugin Framework I|Kapitel 1]] - Allgemeines&lt;br /&gt;
** Voraussetzungen und Installation&lt;br /&gt;
* [[OMSI Plugin Framework II|Kapitel 2]] - Die graue Theorie&lt;br /&gt;
** ein bisschen Theorie muss sein&lt;br /&gt;
* [[OMSI Plugin Framework III|Kapitel 3]] - Die Plugin-Schnittstelle&lt;br /&gt;
** die Arbeitsweise der Plugin-Schnittstelle&lt;br /&gt;
* [[OMSI Plugin Framework IV|Kapitel 4]] - Das OMSI Plugin Framework&lt;br /&gt;
** detaillierte Beschreibung des Frameworks&lt;br /&gt;
* [[OMSI Plugin Framework V|Kapitel 5]] - Die OMSI Plugin Framework Debug-Hilfen&lt;br /&gt;
** Beschreibung der Debug-Hilfen zum Debuggen eines Plugins&lt;br /&gt;
* [[OMSI Plugin Framework VI|Kapitel 6]] - Ein Beispielprojekt&lt;br /&gt;
** Beispielprojekt für eine (fast) vollautomatische Klimaanlage&lt;br /&gt;
* [http://omsi.sovoma.de Online-Hilfe]&lt;br /&gt;
** die vollständige Dokumentation zum Framework&lt;br /&gt;
&lt;br /&gt;
== Vorwort zum Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Liebe angehende Plugin-Programmierer,&lt;br /&gt;
&lt;br /&gt;
dieses Tutorial zum '''''OMSI Plugin Framework''''' ist - wie man so schön neudeutsch sagt, &amp;quot;Working under progress&amp;quot;. Ich stelle das unfertige Tutorial hauptsächlich aus zwei Gründen bereits zur Verfügung:&amp;lt;br&amp;gt;1.) damit diejenigen unter euch, die schon über ausreichende Programmiererfahrung verfügen und ohne viele weitere Erklärungen auskommen, schon mal loslegen können und&amp;lt;br&amp;gt;2.) damit jeder schon während ich die einzelnen Kapitel schreibe, über das Forum Ideen, Verbesserungsvorschläge, Fragen zu Unklarheiten usw. einbringen kann.&lt;br /&gt;
&lt;br /&gt;
Bitte, werdet nicht ungeduldig, wenn mir nicht jeden Tag ein neues Kapitel aus der Feder tropft. Ich habe so nebenbei noch eine 'richtige' Arbeit bei der Berliner Feuerwehr und ... äh, da war doch noch was ... irgendwas war da noch ... was war denn da bloß noch ... ach ja, 'ne Familie ist da ja auch noch.&lt;br /&gt;
&lt;br /&gt;
In diesem Sinne, viel Spass beim programmieren und diskutieren&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Holmexx|Holmexx]] ([[Benutzer Diskussion:Holmexx|Diskussion]]) 07:07, 19. Nov. 2012 (CET)&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Vielleicht hat der/die Eine oder Andere ja schon mal mit dem Gedanken gespielt, sich an ein Plugin heranzuwagen, das Vorhaben aber dann verworfen, weil er/sie gedacht, programmieren ist was für Profis und viel zu schwer. Die Erstellung eines Plugins für den OMSI ist - auch mit geringer Programmiererfahrung - gar nicht so schwierig wie es auf den ersten Blick aussieht. Das Entscheidende wird ja schon hier im [http://www.omnibussimulator.de/omsiwiki.de/index.php?title=Plug-in-Schnittstelle OMSI-Wiki] erklärt. Allerdings beziehen sich diese Erklärungen auf die Programmiersprache Pascal, die einstmals mit Borlands Delphi weite Verbreitung fand. Borland ist seit langem Geschichte und damit Delphi schon fast in Vergessenheit geraten. Die Firma [http://www.embarcadero.com/de/products/delphi Embarcadero] vertreibt zwar Delphi wieder, die Preise dort werden aber jeden Hobbyprogrammierer abschrecken. Die Alternative kommt von Microsoft. Dort kann man sich [http://www.microsoft.com/germany/express/download/default.aspx Visual Studio Express] kostenlos herunterladen. Für die Plugin-Programmierung benötigst Du '''Visual C++ 2010 EXPRESS'''. Wenn Du nun noch über wenigstens grundlegende Kenntnisse in der Programmiersprache C++ verfügst, kann es ja losgehen. Aber halt, warum C++? Geht nicht auch C# oder Visual Basic? Aus technischer Sicht ist es absolut möglich, ein Plugin in C# oder VB zu entwickeln. Allerdings stehen sich mit C#/VB und OMSI zwei Welten gegenüber. Die erste &lt;br /&gt;
Welt ist die des &amp;quot;Managed Code&amp;quot; und die Andere die des &amp;quot;Unmanaged Code&amp;quot;. Um beide Welten zusammen zu bringen, brauchst Du eine Wrapper-DLL. Und die kannst Du nur mit - Du ahnst es bereits - C/C++ programmieren, auch noch verbunden mit einem dramatisch erhöhten Schwierigkeitsgrad. Außerdem macht COM-Programmierung keinen Spaß, sondern ist einfach nur schmerzhaft. Ein weiteres Hindernis ist die Architektur eines &amp;quot;Managed Code&amp;quot;-Programmes. Managed Code ist auf maximale Sicherheit ausgelegt, nicht auf Performance. Es ist ungefähr so, als ob Du mit einer voll gepanzerten Limousine bei der DTM antrittst. Dein Auto ist zwar unkaputtbar, schade ist nur, dass die anderen Fahrer schon beim ersten Bier sitzen nach dem Rennen, während Du noch 6 Runden zu fahren hast. Bleiben wir also lieber bei C++.&lt;br /&gt;
&lt;br /&gt;
Um die Sache, insbesondere für Programmiernovizen, noch etwas zu vereinfachen, habe ich dieses Framework entwickelt, mit dem sich - hoffentlich ;-) - schnell und einfach Plugins programmieren lassen. Ich habe mich ganz bewusst für die Programmiersprache C++ entschieden, obwohl mit dem OpenSource-Projekt [http://www.lazarus.freepascal.org Lazarus] ein gut gelungener Delphi-Klon existiert und man damit sogar in reinrassigem Pascal im Delphi-Stil programmieren könnte. Aber C++ ist doch noch etwas systemnaher als Pascal und bietet dem Plugin-Programmierer Möglichkeiten, die in Pascal nur recht umständlich oder sogar überhaupt nicht möglich wären (z.B. Klassen-Templates, Verwendung von Makros).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorials für Addon-Entwickler]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSIWiki:Aktuelle_Ereignisse&amp;diff=760</id>
		<title>OMSIWiki:Aktuelle Ereignisse</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSIWiki:Aktuelle_Ereignisse&amp;diff=760"/>
		<updated>2012-11-19T19:15:22Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Dies ist nur ein Vorschlag zur Gliederung dieser Seite. Seiten die in Arbeit sind, weiterhin auf der [[Hauptseite]] eintragen!'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hier sind alle aktuellen Ereignisse des OMSI-Wikis aufgelistet. Wenn ein neuer Artikel angelegt werden soll, dann bitte unter Artikel =&amp;gt; Aktuell in Arbeit eintragen. &lt;br /&gt;
&lt;br /&gt;
== Artikel ==&lt;br /&gt;
&lt;br /&gt;
=== Aktuell in Arbeit ===&lt;br /&gt;
&lt;br /&gt;
* Tutorial zum programmieren eines [[OMSI Plugin Framework|OMSI-Plugins in C++]] (Fortschritt: ##--------) --[[Benutzer:Holmexx|Holmexx]] 20:15, 19. Nov. 2012 (MET)&lt;br /&gt;
&lt;br /&gt;
== Kategorien ==&lt;br /&gt;
&lt;br /&gt;
=== Aktuell in Arbeit ===&lt;br /&gt;
&lt;br /&gt;
''Derzeit sind keine Artikel in Arbeit''&lt;br /&gt;
&lt;br /&gt;
== Projektseiten ==&lt;br /&gt;
&lt;br /&gt;
=== Aktuell in Arbeit ===&lt;br /&gt;
&lt;br /&gt;
''Derzeit sind keine Artikel in Arbeit''&lt;br /&gt;
&lt;br /&gt;
== Hilfeseiten ==&lt;br /&gt;
&lt;br /&gt;
=== Aktuell in Arbeit ===&lt;br /&gt;
&lt;br /&gt;
''Derzeit sind keine Artikel in Arbeit''&lt;br /&gt;
&lt;br /&gt;
[[en:Current events]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_II&amp;diff=759</id>
		<title>OMSI Plugin Framework II</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_II&amp;diff=759"/>
		<updated>2012-11-19T18:33:42Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Verschönerungen in den Beispielen (farbliche Hervorhebungen)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Die graue Theorie ==&lt;br /&gt;
&lt;br /&gt;
Keine Angst, Du musst Dich jetzt nicht durch seitenlange, staubtrockene Texte wühlen, aber um ein bisschen Theorie kommen wir nicht drumherum. Dieses Kapitel soll auch keine umfassende Einführung in die Programmiersprache C/C++ und in die Spieleprogrammierung sein, sondern eher Anfängern und Unerfahrenen ein paar Tipps geben, damit sie wenigstens die größten Fettnäpfchen auslassen können.&lt;br /&gt;
&lt;br /&gt;
=== Die Regel Nummer 1 ===&lt;br /&gt;
&lt;br /&gt;
Das Plugin, dass Du entwickeln willst, ist ja Bestandteil eines Spieles (nämlich des OMSI) und damit bist Du nun quasi Spieleprogrammierer. Ein Spieleprogrammierer muss sich aber einigen Regeln unterwerfen. Die Regel Nummer 1 heißt: Performance, Performance und noch mal Performance. Ein ungeschickt programmiertes Plugin kann die Framerate des OMSI (die ja schon recht knapp ist) in absolut frostige Tiefen drücken. Das musst Du Dir während der ganzen Programmierung ständig vor Augen halten. Wenn Du z.B. für ein Problem mehrere Lösungswege gefunden hast, solltest Du Dir wirklich die Mühe machen, sie alle nacheinander auszuprobieren. Das kostet viel Zeit, ist aber letztendlich die einzige Möglichkeit, die performanteste Lösung zu finden.&lt;br /&gt;
&lt;br /&gt;
Wie Du in den weiteren Abschnitten noch feststellen wirst, ist es aber abseits der Regel Nummer 1 kaum möglich, eine starre Richtlinie aufzustellen. Du wirst immer einen Kompromiss eingehen müssen. Welches Ergebnis das Beste ist, kannst Du nur durch umfangreiche Tests herausfinden. Und diese Tests solltest Du z.B. von einem Freund durchführen lassen, der von Programmierung gar keine Ahnung hat. Das hat im Wesentlichen zwei Gründe: zum Einen sind Programmierer kurioserweise bei ihren Tests kaum in der Lage, ihre eigenen Fehler zu finden (kein Scherz) und zum Anderen wirst Du verwundert sein auf welche Ideen Benutzer kommen, an die Du bei der Programmierung nicht mal im Traum gedacht hast und die - selbstverständlich - zu Fehlern mit Programmabsturz führen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeitsspeicher ===&lt;br /&gt;
&lt;br /&gt;
Eine andere Regel ist, den zur Verfügung stehenden Arbeitspeicher klug einzusetzen. Heutzutage, wo die meisten Computer in aller Regel über mehrere Gigabyte Speicher verfügen, ist das zwar nicht mehr ganz so eng wie früher, wo wirklich noch um jedes einzelne '''Byte''' gekämpft werden musste. Aus den Augen verlieren darf man das Thema trotzdem nicht. Das Schlimmste was passieren kann, ist, das einem Prozess der Arbeitsspeicher ausgeht. Dann muss Windows nämlich Speicher frei machen, indem es Bereiche des Arbeitsspeichers in die sogenannte Auslagerungsdatei auslagert. Und das ist '''''die''''' Performancebremse überhaupt. Wenn das, vielleicht auch noch mehrfach, passiert, wird das Spiel zu einer reinen Diashow verkommen. Performance und Arbeitsspeicher sind zwei Dinge, die eng miteinander verzahnt sind. Meistens ist es performanter, temporäre (zeitweilige, nur zu diesem Zweck angelegte) Variablen anzulegen und mit diesen eine Aufgabe zu lösen. Wenn aber das Anlegen der temporären Variablen dazu führt, das ersteinmal neuer Arbeitspeicher bei Windows angefordert werden muss, hat sich der ganze Performancevorteil in Nichts aufgelöst. Das gilt insbesondere für das Anlegen von (besonders) großen Datenstrukturen im sogenannten Stack. Der Stack ist in seiner Größe nämlich begrenzt. Er kann zwar vergrößert werden, aber das ist performancetechnisch so teuer, das es ein einem Spiel praktisch nicht vorkommen sollte. Falls so etwas in Deinem Code passiert, ist schlicht und ergreifend das Codedesign falsch und muss unbedingt überarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Datenstrukturen, die Du mehrfach benötigst, legst Du natürlich in der Initialisierungphase an (also bei Aufruf der Funktion '''''Start''''' durch den OMSI) und nicht kurz vor jeder Verwendung. Letzteres würde zwar (vielleicht) den Arbeitsspeicherverbrauch des Programmes reduzieren, kostet aber wertvolle CPU-Zeit (siehe Regel Nummer 1).&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung ===&lt;br /&gt;
&lt;br /&gt;
Ein weiteres Thema ist die Fehlerbehandlung. Gerade bei der Fehlerbehandlung ist es wichtig, einen gesunden Kompromiss zwischen Absturzsicherheit des Programmes und Performance zu finden. Selbstverständlich möchte jeder, das es nicht zu Programmabstürzen kommt - schon gar nicht in einem Spiel. Überlegungen dazu sind deshalb so wichtig, weil ein gravierender Fehler in Deinem Plugin den gesamten OMSI ins Byte-Nirvana reißen wird. &lt;br /&gt;
&lt;br /&gt;
Eine Technik zur Fehlerbehandlung die C++ bietet, ist die Möglichkeit, Codeabschnitte in try/except-Klammern einzufassen. Ganz allgemein sieht das so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;__try&amp;lt;/span&amp;gt;&lt;br /&gt;
 {&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// hier kommt der Code, der zu einem Fehler führt, z.B.:&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; x = 5;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; y = 0;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; z = x / y;  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Super-Idee, diese Division durch 0 ;-)&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Code, der jetzt noch hier kommt, wird nie mehr ausgeführt, da die &lt;br /&gt;
    // vorherige Zeile zu einer Division-durch-0-Exception führt&amp;lt;/span&amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;__except&amp;lt;/span&amp;gt; ( EXCEPTION_EXECUTE_HANDLER )&lt;br /&gt;
 {&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// mache irgendetwas, um den Fehler wieder gerade zu biegen&amp;lt;/span&amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// hier gehts ganz normal weiter, als ob nichts passiert wäre&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das hemmungslose Benutzen von try/except und Performance sind allerdings zwei Dinge, die schlecht zusammen passen. Try/except kostet nämlich CPU-Zeit und sollte nur an klug überlegten Stellen eingesetzt werden. Wenn Du in Deinem Code eine Funktion aufrufst die Du nicht selbst geschrieben hast und wo die Dokumentation schon sagt, das im Fehlerfall die oder die Exception auftreten kann, musst Du natürlich try/except verwenden. In selbst geschriebenem Code solltest Du Exceptions vermeiden. Besser ist es, wenn die Funktion im Fehlerfall einen Fehlercode zurückliefert. Dazu zwei Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;int&amp;lt;/span&amp;gt; NichtSoGuteFunktion(&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;int&amp;lt;/span&amp;gt; irgend_ein_wichtiger_wert)&lt;br /&gt;
 {&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;if&amp;lt;/span&amp;gt; (irgend_ein_wichtiger_wert != wert_den_ich_hier_erwarte)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;throw new&amp;lt;/span&amp;gt; exception_xy ( ... );  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// sicher, aber teuer&amp;lt;/span&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// weitere Verarbeitung&lt;br /&gt;
    // ...&amp;lt;/span&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;return&amp;lt;/span&amp;gt; ergebnis;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein besserer Ansatz könnte so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;enum&amp;lt;/span&amp;gt; MeineFehlerwerte&lt;br /&gt;
 {&lt;br /&gt;
    Bescheuerter_Fehler      = -1,&lt;br /&gt;
    Zu_wenig_Kaffee_Fehler   = -2,&lt;br /&gt;
    Zu_viel_Pizza_Fehler     = -3,&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// usw.&amp;lt;/span&amp;gt;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;int&amp;lt;/span&amp;gt; BessereFunktion(&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;int&amp;lt;/span&amp;gt; irgend_ein_wichtiger_wert, &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;int*&amp;lt;/span&amp;gt; zeiger_auf_variable_die_ergebnis_speichert)&lt;br /&gt;
 {&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;if&amp;lt;/span&amp;gt; (irgend_ein_wichtiger_wert != wert_den_ich_hier_erwarte)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;return&amp;lt;/span&amp;gt; Bescheuerter_Fehler;  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// genau so sicher, aber VIEL billiger&amp;lt;/span&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// weitere Verarbeitung&lt;br /&gt;
    // ...&amp;lt;/span&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    *zeiger_auf_variable_die_ergebnis_speichert = ergebnis;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;return&amp;lt;/span&amp;gt; ERROR_SUCCESS; &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// ERROR_SUCCESS ist vordefiniert und hat den Wert 0&amp;lt;/span&amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
Eine Andere, ganz große Kasperfalle ist die Verwendung von nicht initialisierten Variablen, allen voran, die Zeigervariablen. Diese Fehler sind später außerdem relativ schwierig zu entdecken. Im Gegensatz zu z.B. Visual Basic werden bei C/C++ Variablen bei ihrer Deklaration nicht mit einem Wert vorbelegt. Deshalb ist es ganz wichtig, alle Variablen vor ihrer ersten Verwendung mit einem bestimmten Wert zu initialisieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;int&amp;lt;/span&amp;gt; variable;           &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Variable hat einen zufälligen Inhalt, ist aber meistens weniger gefährlich&amp;lt;/span&amp;gt;&lt;br /&gt;
  &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;char*&amp;lt;/span&amp;gt; zeiger_variable;  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Variable hat einen zufälligen Inhalt, Verwendung führt totsicher zum Programmabsturz&amp;lt;/span&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// irgendwo später im Code:&amp;lt;/span&amp;gt;&lt;br /&gt;
  &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;if&amp;lt;/span&amp;gt; (zeiger_variable != NULL) { ... }  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Absturz ist sicher, da ohne Initialisierung zeiger_variable niemals NULL ist !!!&amp;lt;/span&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// deshalb immer so:&amp;lt;/span&amp;gt;&lt;br /&gt;
  &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;int&amp;lt;/span&amp;gt; variable = 0;&lt;br /&gt;
  &amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;char*&amp;lt;/span&amp;gt; zeiger_variable = NULL;&lt;br /&gt;
 &lt;br /&gt;
  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// irgendwo später im Code:&amp;lt;/span&amp;gt;&lt;br /&gt;
  if (zeiger_variable != NULL) { ... }  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Alles o.k., da durch Initialisierung zeiger_variable NULL sein kann&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das teuflische an der Sache ist, das die in den Kommentaren als ''totsicher'' und ''niemals'' deklarierten Dinge gar nicht so totsicher sind. Natürlich kann es sein, das der Speicher, der der Variablen durch den Compiler zugewiesen wird, rein zufällig tatsächlich NULL ist. Und laut Murphy's Law ist das bei den ersten drei Programmtests auch so. Beim vierten Test aber plötzlich nicht mehr und das Programm stürzt ab. Und dann geht die verzweifelte Fehlersuche los ...&lt;br /&gt;
&lt;br /&gt;
=== Objektorientierte Programmierung vs. prozedurale Programmierung ===&lt;br /&gt;
&lt;br /&gt;
So manch Hardcore-Spieleprogrammierer wird die Nase rümpfen und denken, objektorientierte Programmierung (wird im OMSI Plugin Framework verwendet), das geht gar nicht, das macht man doch nicht. Ich muss leider zugeben, so ganz unrecht haben sie nicht. Objektorientierte Programmierung erzeugt nämlich einen gewissen Overhead, der CPU-Zeit kostet. Und das ist ja bekanntlich die teuerste Resource, die uns zur Verfügung steht. Aber wie Du eingangs ja schon festgstellt hast, must Du auch hier einen Kompromiss eingehen. Auf der einen Seite steht der Overhead durch die Verwendung von Klassen, auf der anderen Seite steht ein einfacherer, übersichtlicherer Code, der besonders Programmieranfängern den Einstieg erleichtern wird. Wenn Du schon über ausreichend Programmiererfahrung verfügst, kannst Du ja mal versuchen, das Framework in eine rein prozedurale Variante zu überführen. Du wirst feststellen, dass das gar nicht so einfach ist und möglicherweise Anfänger ziemlich überfordert.&lt;br /&gt;
&lt;br /&gt;
Der Overhead bei der Verwendung von Klassen entsteht dadurch, dass jedem Methodenaufruf ein unsichtbarer Parameter (der sogenannte '''this'''-Zeiger) mitgegeben wird. In Pseudo-Assembler sieht das etwa so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;push&amp;lt;/span&amp;gt;  parameter_1&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;push&amp;lt;/span&amp;gt;  parameter_2&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;; usw.&amp;lt;/span&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;mov&amp;lt;/span&amp;gt;   &amp;lt;span style=&amp;quot;color:magenta&amp;quot;&amp;gt;ecx&amp;lt;/span&amp;gt;, this  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;; &amp;lt;-- der zusätzliche Assembler-Befehl&amp;lt;/span&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;call&amp;lt;/span&amp;gt;  method_xy&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;; ...&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Gleiche gilt für die Verwendung der Felder einer Klasse. Auch der Zugriff erfolgt über den '''this'''-Zeiger. Ein etwas größerer Overhead entsteht noch, wenn die Klasse virtuelle Methoden verwendet. Dann muss nämlich noch eine Tabelle für die virtuellen Methoden angelegt werden und der Aufruf der Methoden erfolgt dann indirekt über diese Tabelle.&lt;br /&gt;
Alles zusammen genommen denke ich aber, das der Overhead für unsere modernen Prozessoren gering ist und die Vorteile der objektorientierten Programmierung überwiegen. Die Praxis gibt mir dabei recht. Das Plugin zur Darstellung eines IBIS auf einem Logitech G13 ist objektorientiert programmiert und ich konnte kein Leistungseinbuße des OMSI feststellen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=758</id>
		<title>Hauptseite</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=758"/>
		<updated>2012-11-19T08:55:21Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font style=&amp;quot;font-size:1.2em;&amp;quot;&amp;gt;&lt;br /&gt;
'''Herzlich willkommen auf der deutschen Version von OMSIWiki!'''&lt;br /&gt;
&lt;br /&gt;
Hier geht's direkt zu einer der Hauptkategorien:&lt;br /&gt;
&lt;br /&gt;
* [[FAQs - Häufig gestellte Fragen]]&lt;br /&gt;
* [[:Kategorie:Busfahren in OMSI|Busfahren in OMSI]]&lt;br /&gt;
* Entwicklung von Addons:&lt;br /&gt;
** [[:Kategorie:Nachschlagewerk für Addon-Entwickler|Nachschlagewerk]]&lt;br /&gt;
** [[:Kategorie:Tutorials für Addon-Entwickler|Tutorials]]&lt;br /&gt;
** [[:Kategorie:Tipps und Tricks für Addon-Entwickler|Tipps und Tricks]]&lt;br /&gt;
* [[:Kategorie:Anschlussprojekte|Anschlussprojekte (z.B. Addon-Manager, OAT)]]&lt;br /&gt;
* [[:Kategorie:Addon-Präsentationen|Addon-Präsentationen]]&lt;br /&gt;
* [[:Kategorie:Hintergrundinformationen|Hintergrundinformationen]]&lt;br /&gt;
&lt;br /&gt;
'''Achtung: Vor dem Verfassen eigener Beiträge bitte zuerst die Regeln lesen!''' Weiter unten gibt es noch eine Ultra-Kurzanleitung für Neulinge.&lt;br /&gt;
&lt;br /&gt;
''Aktuell in Arbeit:''&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Tutorial zum programmieren eines [[OMSI Plugin Framework|OMSI-Plugins in C++]] (Fortschritt: ##--------) --[[Benutzer:Holmexx|Holmexx]] 07:49, 19. Nov. 2012 (MET) &lt;br /&gt;
* Übersetzen der Artikel, zuletzt [[Repainting of OMSI buses (also over panes)]] --[[Benutzer:Dario|Dario]] 12:04, 17. Jul. 2012 (MEST)&lt;br /&gt;
* [[Fahrpläne erstellen]] --[[Benutzer:Felix (Keyway)|Felix (Keyway)]] 16:21, 31. Dez. 2011 (MET) ----- Weitergeführt von [[Benutzer:Dario|Dario]] 11:33, 18. Jul. 2012 (MEST)&lt;br /&gt;
* ''(aktuell pausiert)'' [[Fahrzeug-SDK]] (c) von Rüdiger, Einbau ins OMSIWiki von --[[Benutzer:Marcel Kuhnt|Marcel Kuhnt]] 16:12, 2. Dez. 2011 (MET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Wir Entwickler von OMSI haben OMSIWiki eingerichtet, um eine bessere Plattform für alle Arten von Informationen rund um OMSI zu erhalten. Folgende Themengebiete sind von uns vorläufig vorgesehen:&lt;br /&gt;
&lt;br /&gt;
* Präsentation von Hintergrundinformationen über das Addon-Design von unserer Seite (Objekt- und Fahrzeugbar, Soundengine, Scriptengine usw.)&lt;br /&gt;
* Tipps und Tricks oder auch ganze Tutorials von Usern z.B. zum Erstellen von Repaints oder Mapbau würden unsere Kernthemen abrunden. Entweder als Ergänzung unserer oder als weiterreichende Artikel.&lt;br /&gt;
* Die Bedienung von OMSI und insbesondere der Busse könnte ein weiterer Themenkomplex sein. Zwar gibt es natürlich ein Handbuch für OMSI, dennoch gibt es vieleicht die eine oder andere Sache, die ausführlicher erklärt werden soll. Hier werden wir uns allerdings etwas zurückhalten.&lt;br /&gt;
* Weiterhin könnten hier bewährte Anschlussprojekte zu OMSI präsentiert werden, z.B. OAT oder der Addon-Manager. Höchstwahrscheinlich werden die zugehörigen Artikel dann von den Leitern oder treuesten Fans dieser Projekte geschrieben, wir werden uns hier ebenfalls zurückhalten.&lt;br /&gt;
* Ähnlich hierzu haben wir nichts gegen eine hochqualitative Präsentation von komplexen Addons; denkbar wäre hier z.B. die Bedienungsanleitung eines Addon-Busses oder die Beschreibung und Hinweise für die Fahrt durch eine Addon-Karte mit Fahrplänen und/oder Karten. Wo wir hier allerdings die Grenze setzen, steht noch nicht fest. Insbesondere sollen hier keine &amp;quot;Mini-Artikel&amp;quot; entstehen, wo nur ein Screenshot von einem Repaint und ein Download-Link präsentiert wird!&lt;br /&gt;
* Selbstverständlich dürfen hier auch gerne Hintergrundinformationen zu unserer Strecke oder unseren Bussen oder aber zu Addons gegeben werden (wie sah Spandau in der Realität 1989 aus? Wie wurde damals in Berlin Bus gefahren?). Es sollte sich aber um abgeschlossene und ernsthaft geschriebene Artikel handeln und es sollte definitiv ein Bezug zu OMSI vorhanden sein! Also keine schnell hingeschriebenen Tagesberichte von irgendeinem Busunternehmen, was keiner kennt und was auch nicht in OMSI mindestens als Addon simuliert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Regeln ==&lt;br /&gt;
&lt;br /&gt;
=== Ist das Thema hier erwünscht? ===&lt;br /&gt;
&lt;br /&gt;
Der Idee von OMSIWiki entsprechend sollte jeder Artikel letztlich in eine der oben genannten Kategorien passen!&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Goldene Regel&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
Zunächst die '''&amp;quot;goldene Regel&amp;quot;''': Bevor ein Artikel verfasst oder geändert wird, sollte stets geschaut werden, ob sich an den Regeln etwas geändert hat! Gerade in der Anfangszeit wird es sicher vorkommen, dass sich Regeln ändern oder neue hinzukommen.&lt;br /&gt;
&lt;br /&gt;
=== Erwünscht ===&lt;br /&gt;
&lt;br /&gt;
* Wenn ihr einen kleinen oder großen Fehler entdeckt (auch in einem unserer Artikel!), dann darf ihn jeder korrigieren! Aber nur, wenn ihr euch dabei auch sicher seid.&lt;br /&gt;
* Ihr findet einen Artikel z.B. im Addon-Handbuch zu trocken? Dann dürft ihr gerne ein kleines Beispiel ergänzen! Von mir weiß ich z.B., dass die Anschauung und Klarheit leidet, wenn ich viele und lange Texte schreibe!&lt;br /&gt;
* Ihr findet einen Fachbegriff, der nicht erklärt wird? Wenn es ein bisher nicht erklärter Begriff von OMSI ist, dürft ihr gerne einen Artikel anfertigen und ihn mit dem Fachbegriff verlinken; handelt es sich um einen allgemeinen Fachbegriff, dann reicht meist ein externer Link zu einem entsprechenden Artikel z.B. in der Wikipedia aus.&lt;br /&gt;
* Um zu vermeiden, dass euch bereits jemand anderes &amp;quot;dazwischen funkt&amp;quot;, obwohl euer Artikel noch gar nicht fertig ist, ergänzt bitte hierzu oben den Hinweis: &amp;quot;''Hinweis: Dieser Artikel befindet sich noch im Aufbau!''&amp;quot;. Dadurch wird auch vermieden, dass der unter Umständen erst halbfertige Artikel schon von jemandem übersetzt wird, sodass nach Fertigstellung der deutschen Version die englische noch unvollständig ist.&lt;br /&gt;
* Wenn euer Artikel auch ein englischsprachiges Pendant hat, dann verknüpft ihn bitte! Ein Blick ans Ende des Quelltextes ''dieser'' Seite zeigt euch, wie das geht! Hat er jedoch ''kein'' Pendant und muss demnach in der englischen OMSIWiki noch angelegt werden, so wäre ein Hinweis ganz oben nicht schlecht: &amp;quot;''Hinweis: Dieser Artikel wurde noch nicht ins Englische übersetzt!''&amp;quot; oder &amp;quot;''Hinweis: Die englische Version muss noch aktualisiert werden!''&amp;quot;&lt;br /&gt;
* Wenn ihr Spaß am Übersetzen habt, dann könnt ihr eine sehr wertvolle Hilfe für OMSIWiki sein! Wenn ihr einen dieser Hinweise entdeckt, scheut euch nicht, den Artikel in die englische OMSIWiki einzupflegen! Ihr solltet danach aber den Original-Autor informieren (damit er die Gelegenheit hat, einmal drüber zu schauen) und dann natürlich die beidseitige Verlinkung mit der deutschen Seite vornehmen und den Hinweis entfernen.&lt;br /&gt;
&lt;br /&gt;
=== Unerwünscht ===&lt;br /&gt;
&lt;br /&gt;
* '''Ganz wichtig: Der Name des Artikels muss wohlüberlegt gewählt werden, weil man den nicht mal eben ändern kann! Wer hier grob fahrlässig schlampt, fliegt raus!'''&lt;br /&gt;
* Schlechter Schreibstil! Was im Chat normal ist und im Forum zwangsweise geduldet wird, ist hier tabu: Bitte gebt euch etwas Mühe, wenn ihr hier einen Artikel verfasst!&lt;br /&gt;
* Werbung für unbekannte, kleine Projekte, Foren, virtuelle Gesellschaften etc. Der Sinn von OMSIWiki ist nicht die Werbung für Projekte! Es soll eine Informationsplattform sein!&lt;br /&gt;
&lt;br /&gt;
Hier dazu was Passendes zum schmunzeln: [http://meta.wikimedia.org/wiki/Wikipedia_Anti-Regeln Wikipedia-Anti-Regeln]&lt;br /&gt;
&lt;br /&gt;
=== Absprachen ===&lt;br /&gt;
&lt;br /&gt;
* Vor Beginn der Arbeit bitte oben bei &amp;quot;Aktuell in Arbeit&amp;quot; eine Zeile mit der geplanten Arbeit und eurer Signatur ergänzen. Nach Fertigstellung diesen wieder entfernen. Sollte jedoch dann gar kein Punkt mehr übrigbleiben, dann ein &amp;quot; * ''Nichts'' &amp;quot; stehen lassen.&lt;br /&gt;
* Wenn ihr größere Korrekturen an unseren Artikeln vornehmt, wär es natürlich gut, wenn ihr uns zumindest nachher darüber informiert, damit wir den Überblick behalten.&lt;br /&gt;
* Bevor ein neuer Artikel verfasst wird, kann es nicht schaden, kurz eine E-Mail an uns Administratoren zu schicken mit euren Planungen.&lt;br /&gt;
* Das Einführen neuer Kategorien hat grundstätzlich in Absprache mit den Administratoren zu geschehen.&lt;br /&gt;
&lt;br /&gt;
* Beachtet auch die Möglichkeit, mit den Autoren auf der Diskussionsseite zu diskutieren! Wie der &amp;quot;Quellcode&amp;quot; einer Diskussionsseite aussieht, seht ihr hier: [[Diskussion:OMSI_Addon_Tester_(OAT)]]. Und nicht vergessen: Die Signatur könnt ihr automatisch erzeugen mit &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;!&lt;br /&gt;
&lt;br /&gt;
=== Multilingualität ===&lt;br /&gt;
&lt;br /&gt;
OMSIWiki ist zweisprachig ausgelegt: Englisch und Deutsch. Wie beim großen Vorbild, der Wikipedia, können die Artikel beider Sprachen miteinander verbunden werden. Dies erfolgt auch auf selbem Wege wie bei Wikipedia. Selbstverständlich ist es erstrebenswert, beide Teile der OMSIWiki auf gleichem Stand zu halten - auch wenn das natürlich praktisch nie ganz der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
=== Zugriff ===&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Wikipedia müsst ihr angemeldet sein, um hier Schreibzugriff zu erhalten. Ich denke, dies ist nicht zu viel verlangt und hilft uns eine gewisse Kontrolle über das Verfassen von Artikeln zu behalten.&lt;br /&gt;
&lt;br /&gt;
== Ultra-Kurzhandbuch ==&lt;br /&gt;
&lt;br /&gt;
Ein paar Hinweise für Neulinge, die sich davor scheuen, das ganze Handbuch zu lesen. Wie &amp;quot;baut&amp;quot; man einen OMSIWiki-Artikel?&lt;br /&gt;
&lt;br /&gt;
* Signatur: Gibt's überm Editor-Fenster einen Button, sonst &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
* Anlegen einer neuen Seite: Nachdem ihr im Forum oder uns Bescheid gegeben habt, gebt ihr den ''wohlüberlegten'' Titel der neuen Seite ins ''Suche''-Feld ein. Es erscheint dann der Vorschlag, ob man diese Seite enlegen möchte? Ein &amp;quot;ja&amp;quot; führt dich dann zum leeren Editorfenster.&lt;br /&gt;
* Eine sinnvolle Gliederung kann folgendermaßen erstellt werden:&lt;br /&gt;
 == Hauptüberschrift ==&lt;br /&gt;
 === Subüberschrift ===&lt;br /&gt;
 ==== Sub-Sub-Überschrift ==== usw.&lt;br /&gt;
* Aufzählungen wie diese werden folgendermaßen durchgeführt:&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 ** Sub-Aufzählungspunkt&lt;br /&gt;
* Ein # statt einem * führt zu numerierten Aufzählungen.&lt;br /&gt;
* Fett- und Kursivschreibung wird mittels Apostrophen markiert:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
''Kursiv''&lt;br /&gt;
'''Fett'''&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Die Zuweisung einer Kategorie (im Beispiel der Kategorie &amp;quot;Busfahren in OMSI&amp;quot;) erfolgt ganz am Ende des Artikels mit &amp;lt;nowiki&amp;gt;[[Kategorie:Busfahren in OMSI]]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Weitere Informationen: [http://meta.wikimedia.org/wiki/Hilfe:Handbuch?uselang=de meta.wikimedia.org/wiki/Hilfe:Handbuch]&lt;br /&gt;
&lt;br /&gt;
== Historie ==&lt;br /&gt;
&lt;br /&gt;
* 8. September 2011 - Marcel Kuhnt: Einrichten der deutschen OMSIWiki und Verlinkung mit der englischen.&lt;br /&gt;
* 13. September 2011 - Marcel Kuhnt: OMSIWiki öffentlich angekündigt.&lt;br /&gt;
&lt;br /&gt;
== Links rund ums Thema OMSI ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.omnibussimulator.de www.omnibussimulator.de] - offizielle Seite von OMSI, dem Omnibussimulator&lt;br /&gt;
* [http://www.omnibussimulator.de/forum/ www.omnibussimulator.de/forum/] - offizielles OMSI-Forum&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&lt;br /&gt;
&lt;br /&gt;
[[Technische Informationen zum MediaWiki]]&lt;br /&gt;
&lt;br /&gt;
[[en:Main Page]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_II&amp;diff=757</id>
		<title>OMSI Plugin Framework II</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_II&amp;diff=757"/>
		<updated>2012-11-19T08:39:56Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: unklare Formulierung verbessert (Abschnitt Arbeitsspeicher)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Die graue Theorie ==&lt;br /&gt;
&lt;br /&gt;
Keine Angst, Du musst Dich jetzt nicht durch seitenlange, staubtrockene Texte wühlen, aber um ein bisschen Theorie kommen wir nicht drumherum. Dieses Kapitel soll auch keine umfassende Einführung in die Programmiersprache C/C++ und in die Spieleprogrammierung sein, sondern eher Anfängern und Unerfahrenen ein paar Tipps geben, damit sie wenigstens die größten Fettnäpfchen auslassen können.&lt;br /&gt;
&lt;br /&gt;
=== Die Regel Nummer 1 ===&lt;br /&gt;
&lt;br /&gt;
Das Plugin, dass Du entwickeln willst, ist ja Bestandteil eines Spieles (nämlich des OMSI) und damit bist Du nun quasi Spieleprogrammierer. Ein Spieleprogrammierer muss sich aber einigen Regeln unterwerfen. Die Regel Nummer 1 heißt: Performance, Performance und noch mal Performance. Ein ungeschickt programmiertes Plugin kann die Framerate des OMSI (die ja schon recht knapp ist) in absolut frostige Tiefen drücken. Das musst Du Dir während der ganzen Programmierung ständig vor Augen halten. Wenn Du z.B. für ein Problem mehrere Lösungswege gefunden hast, solltest Du Dir wirklich die Mühe machen, sie alle nacheinander auszuprobieren. Das kostet viel Zeit, ist aber letztendlich die einzige Möglichkeit, die performanteste Lösung zu finden.&lt;br /&gt;
&lt;br /&gt;
Wie Du in den weiteren Abschnitten noch feststellen wirst, ist es aber abseits der Regel Nummer 1 kaum möglich, eine starre Richtlinie aufzustellen. Du wirst immer einen Kompromiss eingehen müssen. Welches Ergebnis das Beste ist, kannst Du nur durch umfangreiche Tests herausfinden. Und diese Tests solltest Du z.B. von einem Freund durchführen lassen, der von Programmierung gar keine Ahnung hat. Das hat im Wesentlichen zwei Gründe: zum Einen sind Programmierer kurioserweise bei ihren Tests kaum in der Lage, ihre eigenen Fehler zu finden (kein Scherz) und zum Anderen wirst Du verwundert sein auf welche Ideen Benutzer kommen, an die Du bei der Programmierung nicht mal im Traum gedacht hast und die - selbstverständlich - zu Fehlern mit Programmabsturz führen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeitsspeicher ===&lt;br /&gt;
&lt;br /&gt;
Eine andere Regel ist, den zur Verfügung stehenden Arbeitspeicher klug einzusetzen. Heutzutage, wo die meisten Computer in aller Regel über mehrere Gigabyte Speicher verfügen, ist das zwar nicht mehr ganz so eng wie früher, wo wirklich noch um jedes einzelne '''Byte''' gekämpft werden musste. Aus den Augen verlieren darf man das Thema trotzdem nicht. Das Schlimmste was passieren kann, ist, das einem Prozess der Arbeitsspeicher ausgeht. Dann muss Windows nämlich Speicher frei machen, indem es Bereiche des Arbeitsspeichers in die sogenannte Auslagerungsdatei auslagert. Und das ist '''''die''''' Performancebremse überhaupt. Wenn das, vielleicht auch noch mehrfach, passiert, wird das Spiel zu einer reinen Diashow verkommen. Performance und Arbeitsspeicher sind zwei Dinge, die eng miteinander verzahnt sind. Meistens ist es performanter, temporäre (zeitweilige, nur zu diesem Zweck angelegte) Variablen anzulegen und mit diesen eine Aufgabe zu lösen. Wenn aber das Anlegen der temporären Variablen dazu führt, das ersteinmal neuer Arbeitspeicher bei Windows angefordert werden muss, hat sich der ganze Performancevorteil in Nichts aufgelöst. Das gilt insbesondere für das Anlegen von (besonders) großen Datenstrukturen im sogenannten Stack. Der Stack ist in seiner Größe nämlich begrenzt. Er kann zwar vergrößert werden, aber das ist performancetechnisch so teuer, das es ein einem Spiel praktisch nicht vorkommen sollte. Falls so etwas in Deinem Code passiert, ist schlicht und ergreifend das Codedesign falsch und muss unbedingt überarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Datenstrukturen, die Du mehrfach benötigst, legst Du natürlich in der Initialisierungphase an (also bei Aufruf der Funktion '''''Start''''' durch den OMSI) und nicht kurz vor jeder Verwendung. Letzteres würde zwar (vielleicht) den Arbeitsspeicherverbrauch des Programmes reduzieren, kostet aber wertvolle CPU-Zeit (siehe Regel Nummer 1).&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung ===&lt;br /&gt;
&lt;br /&gt;
Ein weiteres Thema ist die Fehlerbehandlung. Gerade bei der Fehlerbehandlung ist es wichtig, einen gesunden Kompromiss zwischen Absturzsicherheit des Programmes und Performance zu finden. Selbstverständlich möchte jeder, das es nicht zu Programmabstürzen kommt - schon gar nicht in einem Spiel. Überlegungen dazu sind deshalb so wichtig, weil ein gravierender Fehler in Deinem Plugin den gesamten OMSI ins Byte-Nirvana reißen wird. &lt;br /&gt;
&lt;br /&gt;
Eine Technik zur Fehlerbehandlung die C++ bietet, ist die Möglichkeit, Codeabschnitte in try/except-Klammern einzufassen. Ganz allgemein sieht das so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;__try&amp;lt;/span&amp;gt;&lt;br /&gt;
 {&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// hier kommt der Code, der zu einem Fehler führt, z.B.:&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; x = 5;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; y = 0;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; z = x / y;  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Super-Idee, diese Division durch 0 ;-)&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Code, der jetzt noch hier kommt, wird nie mehr ausgeführt, da die &lt;br /&gt;
    // vorherige Zeile zu einer Division-durch-0-Exception führt&amp;lt;/span&amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;__except&amp;lt;/span&amp;gt; ( EXCEPTION_HANDLER )&lt;br /&gt;
 {&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// mache irgendetwas, um den Fehler wieder gerade zu biegen&amp;lt;/span&amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// hier gehts ganz normal weiter, als ob nichts passiert wäre&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das hemmungslose Benutzen von try/except und Performance sind allerdings zwei Dinge, die schlecht zusammen passen. Try/except kostet nämlich CPU-Zeit und sollte nur an klug überlegten Stellen eingesetzt werden. Wenn Du in Deinem Code eine Funktion aufrufst die Du nicht selbst geschrieben hast und wo die Dokumentation schon sagt, das im Fehlerfall die oder die Exception auftreten kann, musst Du natürlich try/except verwenden. In selbst geschriebenem Code solltest Du Exceptions vermeiden. Besser ist es, wenn die Funktion im Fehlerfall einen Fehlercode zurückliefert. Dazu zwei Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 int NichtSoGuteFunktion(int irgend_ein_wichtiger_wert)&lt;br /&gt;
 {&lt;br /&gt;
    if (irgend_ein_wichtiger_wert != wert_den_ich_hier_erwarte)&lt;br /&gt;
    {&lt;br /&gt;
        throw new exception_xy ( ... );  // sicher, aber teuer&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // weitere Verarbeitung&lt;br /&gt;
    // ...&lt;br /&gt;
 &lt;br /&gt;
    return ergebnis;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein besserer Ansatz könnte so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 enum MeineFehlerwerte&lt;br /&gt;
 {&lt;br /&gt;
    Bescheuerter_Fehler      = -1,&lt;br /&gt;
    Zu_wenig_Kaffee_Fehler   = -2,&lt;br /&gt;
    Zu_viel_Pizza_Fehler     = -3,&lt;br /&gt;
    // usw.&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 int BessereFunktion(int irgend_ein_wichtiger_wert, int* zeiger_auf_variable_die_ergebnis_speichert)&lt;br /&gt;
 {&lt;br /&gt;
    if (irgend_ein_wichtiger_wert != wert_den_ich_hier_erwarte)&lt;br /&gt;
    {&lt;br /&gt;
        return Bescheuerter_Fehler;  // genau so sicher, aber VIEL billiger&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // weitere Verarbeitung&lt;br /&gt;
    // ...&lt;br /&gt;
 &lt;br /&gt;
    *zeiger_auf_variable_die_ergebnis_speichert = ergebnis;&lt;br /&gt;
    return ERROR_SUCCESS; // ERROR_SUCCESS ist vordefiniert und hat den Wert 0&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
Eine Andere, ganz große Kasperfalle ist die Verwendung von nicht initialisierten Variablen, allen voran, die Zeigervariablen. Diese Fehler sind später außerdem relativ schwierig zu entdecken. Im Gegensatz zu z.B. Visual Basic werden bei C/C++ Variablen bei ihrer Deklaration nicht mit einem Wert vorbelegt. Deshalb ist es ganz wichtig, alle Variablen vor ihrer ersten Verwendung mit einem bestimmten Wert zu initialisieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
  int variable;           // Variable hat einen zufälligen Inhalt, ist aber meistens weniger gefährlich&lt;br /&gt;
  char* zeiger_variable;  // Variable hat einen zufälligen Inhalt, Verwendung führt totsicher zum Programmabsturz&lt;br /&gt;
 &lt;br /&gt;
  // irgendwo später im Code:&lt;br /&gt;
  if (zeiger_variable != NULL) { ... }  // Absturz ist sicher, da ohne Initialisierung zeiger_variable niemals NULL ist !!!&lt;br /&gt;
 &lt;br /&gt;
  // deshalb immer so:&lt;br /&gt;
  int variable = 0;&lt;br /&gt;
  char* zeiger_variable = NULL;&lt;br /&gt;
 &lt;br /&gt;
  // irgendwo später im Code:&lt;br /&gt;
  if (zeiger_variable != NULL) { ... }  // Alles o.k., da durch Initialisierung zeiger_variable NULL sein kann&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das teuflische an der Sache ist, das die in den Kommentaren als ''totsicher'' und ''niemals'' deklarierten Dinge gar nicht so totsicher sind. Natürlich kann es sein, das der Speicher, der der Variablen durch den Compiler zugewiesen wird, rein zufällig tatsächlich NULL ist. Und laut Murphy's Law ist das bei den ersten drei Programmtests auch so. Beim vierten Test aber plötzlich nicht mehr und das Programm stürzt ab. Und dann geht die verzweifelte Fehlersuche los ...&lt;br /&gt;
&lt;br /&gt;
=== Objektorientierte Programmierung vs. prozedurale Programmierung ===&lt;br /&gt;
&lt;br /&gt;
So manch Hardcore-Spieleprogrammierer wird die Nase rümpfen und denken, objektorientierte Programmierung (wird im OMSI Plugin Framework verwendet), das geht gar nicht, das macht man doch nicht. Ich muss leider zugeben, so ganz unrecht haben sie nicht. Objektorientierte Programmierung erzeugt nämlich einen gewissen Overhead, der CPU-Zeit kostet. Und das ist ja bekanntlich die teuerste Resource, die uns zur Verfügung steht. Aber wie Du eingangs ja schon festgstellt hast, must Du auch hier einen Kompromiss eingehen. Auf der einen Seite steht der Overhead durch die Verwendung von Klassen, auf der anderen Seite steht ein einfacherer, übersichtlicherer Code, der besonders Programmieranfängern den Einstieg erleichtern wird. Wenn Du schon über ausreichend Programmiererfahrung verfügst, kannst Du ja mal versuchen, das Framework in eine rein prozedurale Variante zu überführen. Du wirst feststellen, dass das gar nicht so einfach ist und möglicherweise Anfänger ziemlich überfordert.&lt;br /&gt;
&lt;br /&gt;
Der Overhead bei der Verwendung von Klassen entsteht dadurch, dass jedem Methodenaufruf ein unsichtbarer Parameter (der sogenannte '''this'''-Zeiger) mitgegeben wird. In Pseudo-Assembler sieht das etwa so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;push&amp;lt;/span&amp;gt;  parameter_1&lt;br /&gt;
 push  parameter_2&lt;br /&gt;
 ; usw.&lt;br /&gt;
 mov   ecx, this  ; &amp;lt;-- der zusätzliche Assembler-Befehl&lt;br /&gt;
 call  method_xy&lt;br /&gt;
 ; ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Gleiche gilt für die Verwendung der Felder einer Klasse. Auch der Zugriff erfolgt über den '''this'''-Zeiger. Ein etwas größerer Overhead entsteht noch, wenn die Klasse virtuelle Methoden verwendet. Dann muss nämlich noch eine Tabelle für die virtuellen Methoden angelegt werden und der Aufruf der Methoden erfolgt dann indirekt über diese Tabelle.&lt;br /&gt;
Alles zusammen genommen denke ich aber, das der Overhead für unsere modernen Prozessoren gering ist und die Vorteile der objektorientierten Programmierung überwiegen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=756</id>
		<title>OMSI Plugin Framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=756"/>
		<updated>2012-11-19T08:02:23Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Inhaltsverzeichnis ==&lt;br /&gt;
&lt;br /&gt;
* [[#Vorwort|Vorwort]]&lt;br /&gt;
* [[OMSI Plugin Framework I|Kapitel 1]] - Allgemeines&lt;br /&gt;
** Voraussetzungen und Installation&lt;br /&gt;
* [[OMSI Plugin Framework II|Kapitel 2]] - Die graue Theorie&lt;br /&gt;
** ein bisschen Theorie muss sein&lt;br /&gt;
* [[OMSI Plugin Framework III|Kapitel 3]] - Die Plugin-Schnittstelle&lt;br /&gt;
** die Arbeitsweise der Plugin-Schnittstelle&lt;br /&gt;
* [[OMSI Plugin Framework IV|Kapitel 4]] - Das OMSI Plugin Framework&lt;br /&gt;
** detaillierte Beschreibung des Frameworks&lt;br /&gt;
* [[OMSI Plugin Framework V|Kapitel 5]] - Der OMSI Plugin Log Viewer&lt;br /&gt;
** Beschreibung der Debug-Hilfe zum Debuggen eines Plugins&lt;br /&gt;
* [[OMSI Plugin Framework VI|Kapitel 6]] - Ein Beispielprojekt&lt;br /&gt;
** Beispielprojekt für eine (fast) vollautomatische Klimaanlage&lt;br /&gt;
* [http://omsi.sovoma.de Online-Hilfe]&lt;br /&gt;
** die vollständige Dokumentation zum Framework&lt;br /&gt;
&lt;br /&gt;
== Vorwort zum Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Liebe angehende Plugin-Programmierer,&lt;br /&gt;
&lt;br /&gt;
dieses Tutorial zum '''''OMSI Plugin Framework''''' ist - wie man so schön neudeutsch sagt, &amp;quot;Working under progress&amp;quot;. Ich stelle das unfertige Tutorial hauptsächlich aus zwei Gründen bereits zur Verfügung:&amp;lt;br&amp;gt;1.) damit diejenigen unter euch, die schon über ausreichende Programmiererfahrung verfügen und ohne viele weitere Erklärungen auskommen, schon mal loslegen können und&amp;lt;br&amp;gt;2.) damit jeder schon während ich die einzelnen Kapitel schreibe, über das Forum Ideen, Verbesserungsvorschläge, Fragen zu Unklarheiten usw. einbringen kann.&lt;br /&gt;
&lt;br /&gt;
Bitte, werdet nicht ungeduldig, wenn mir nicht jeden Tag ein neues Kapitel aus der Feder tropft. Ich habe so nebenbei noch eine 'richtige' Arbeit bei der Berliner Feuerwehr und ... äh, da war doch noch was ... irgendwas war da noch ... was war denn da bloß noch ... ach ja, 'ne Familie ist da ja auch noch.&lt;br /&gt;
&lt;br /&gt;
In diesem Sinne, viel Spass beim programmieren und diskutieren&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Holmexx|Holmexx]] ([[Benutzer Diskussion:Holmexx|Diskussion]]) 07:07, 19. Nov. 2012 (CET)&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Vielleicht hat der/die Eine oder Andere ja schon mal mit dem Gedanken gespielt, sich an ein Plugin heranzuwagen, das Vorhaben aber dann verworfen, weil er/sie gedacht, programmieren ist was für Profis und viel zu schwer. Die Erstellung eines Plugins für den OMSI ist - auch mit geringer Programmiererfahrung - gar nicht so schwierig wie es auf den ersten Blick aussieht. Das Entscheidende wird ja schon hier im [http://www.omnibussimulator.de/omsiwiki.de/index.php?title=Plug-in-Schnittstelle OMSI-Wiki] erklärt. Allerdings beziehen sich diese Erklärungen auf die Programmiersprache Pascal, die einstmals mit Borlands Delphi weite Verbreitung fand. Borland ist seit langem Geschichte und damit Delphi schon fast in Vergessenheit geraten. Die Firma [http://www.embarcadero.com/de/products/delphi Embarcadero] vertreibt zwar Delphi wieder, die Preise dort werden aber jeden Hobbyprogrammierer abschrecken. Die Alternative kommt von Microsoft. Dort kann man sich [http://www.microsoft.com/germany/express/download/default.aspx Visual Studio Express] kostenlos herunterladen. Für die Plugin-Programmierung benötigst Du '''Visual C++ 2010 EXPRESS'''. Wenn Du nun noch über wenigstens grundlegende Kenntnisse in der Programmiersprache C++ verfügst, kann es ja losgehen. Aber halt, warum C++? Geht nicht auch C# oder Visual Basic? Aus technischer Sicht ist es absolut möglich, ein Plugin in C# oder VB zu entwickeln. Allerdings stehen sich mit C#/VB und OMSI zwei Welten gegenüber. Die erste &lt;br /&gt;
Welt ist die des &amp;quot;Managed Code&amp;quot; und die Andere die des &amp;quot;Unmanaged Code&amp;quot;. Um beide Welten zusammen zu bringen, brauchst Du eine Wrapper-DLL. Und die kannst Du nur mit - Du ahnst es bereits - C/C++ programmieren, auch noch verbunden mit einem dramatisch erhöhten Schwierigkeitsgrad. Außerdem macht COM-Programmierung keinen Spaß, sondern ist einfach nur schmerzhaft. Ein weiteres Hindernis ist die Architektur eines &amp;quot;Managed Code&amp;quot;-Programmes. Managed Code ist auf maximale Sicherheit ausgelegt, nicht auf Performance. Es ist ungefähr so, als ob Du mit einer voll gepanzerten Limousine bei der DTM antrittst. Dein Auto ist zwar unkaputtbar, schade ist nur, dass die anderen Fahrer schon beim ersten Bier sitzen nach dem Rennen, während Du noch 6 Runden zu fahren hast. Bleiben wir also lieber bei C++.&lt;br /&gt;
&lt;br /&gt;
Um die Sache, insbesondere für Programmiernovizen, noch etwas zu vereinfachen, habe ich dieses Framework entwickelt, mit dem sich - hoffentlich ;-) - schnell und einfach Plugins programmieren lassen. Ich habe mich ganz bewusst für die Programmiersprache C++ entschieden, obwohl mit dem OpenSource-Projekt [http://www.lazarus.freepascal.org Lazarus] ein gut gelungener Delphi-Klon existiert und man damit sogar in reinrassigem Pascal im Delphi-Stil programmieren könnte. Aber C++ ist doch noch etwas systemnaher als Pascal und bietet dem Plugin-Programmierer Möglichkeiten, die in Pascal nur recht umständlich oder sogar überhaupt nicht möglich wären (z.B. Klassen-Templates, Verwendung von Makros).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorials für Addon-Entwickler]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_II&amp;diff=755</id>
		<title>OMSI Plugin Framework II</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_II&amp;diff=755"/>
		<updated>2012-11-19T07:57:46Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Schriftgöße und -farben angepasst (muss fortgesetzt werden)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Die graue Theorie ==&lt;br /&gt;
&lt;br /&gt;
Keine Angst, Du musst Dich jetzt nicht durch seitenlange, staubtrockene Texte wühlen, aber um ein bisschen Theorie kommen wir nicht drumherum. Dieses Kapitel soll auch keine umfassende Einführung in die Programmiersprache C/C++ und in die Spieleprogrammierung sein, sondern eher Anfängern und Unerfahrenen ein paar Tipps geben, damit sie wenigstens die größten Fettnäpfchen auslassen können.&lt;br /&gt;
&lt;br /&gt;
=== Die Regel Nummer 1 ===&lt;br /&gt;
&lt;br /&gt;
Das Plugin, dass Du entwickeln willst, ist ja Bestandteil eines Spieles (nämlich des OMSI) und damit bist Du nun quasi Spieleprogrammierer. Ein Spieleprogrammierer muss sich aber einigen Regeln unterwerfen. Die Regel Nummer 1 heißt: Performance, Performance und noch mal Performance. Ein ungeschickt programmiertes Plugin kann die Framerate des OMSI (die ja schon recht knapp ist) in absolut frostige Tiefen drücken. Das musst Du Dir während der ganzen Programmierung ständig vor Augen halten. Wenn Du z.B. für ein Problem mehrere Lösungswege gefunden hast, solltest Du Dir wirklich die Mühe machen, sie alle nacheinander auszuprobieren. Das kostet viel Zeit, ist aber letztendlich die einzige Möglichkeit, die performanteste Lösung zu finden.&lt;br /&gt;
&lt;br /&gt;
Wie Du in den weiteren Abschnitten noch feststellen wirst, ist es aber abseits der Regel Nummer 1 kaum möglich, eine starre Richtlinie aufzustellen. Du wirst immer einen Kompromiss eingehen müssen. Welches Ergebnis das Beste ist, kannst Du nur durch umfangreiche Tests herausfinden. Und diese Tests solltest Du z.B. von einem Freund durchführen lassen, der von Programmierung gar keine Ahnung hat. Das hat im Wesentlichen zwei Gründe: zum Einen sind Programmierer kurioserweise bei ihren Tests kaum in der Lage, ihre eigenen Fehler zu finden (kein Scherz) und zum Anderen wirst Du verwundert sein auf welche Ideen Benutzer kommen, an die Du bei der Programmierung nicht mal im Traum gedacht hast und die - selbstverständlich - zu Fehlern mit Programmabsturz führen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeitsspeicher ===&lt;br /&gt;
&lt;br /&gt;
Eine andere Regel ist, den zur Verfügung stehenden Arbeitspeicher klug einzusetzen. Heutzutage, wo die meisten Computer in aller Regel über mehrere Gigabyte Speicher verfügen, ist das zwar nicht mehr ganz so eng wie früher, wo wirklich noch um jedes einzelne '''Byte''' gekämpft werden musste. Aus den Augen verlieren darf man das Thema trotzdem nicht. Das Schlimmste was passieren kann, ist, das einem Prozess der Arbeitsspeicher ausgeht. Dann muss Windows nämlich Speicher frei machen, indem es Bereiche des Arbeitsspeichers in die sogenannte Auslagerungsdatei auslagert. Und das ist '''''die''''' Performancebremse überhaupt. Wenn das, vielleicht auch noch mehrfach, passiert, wird das Spiel zu einer reinen Diashow verkommen. Performance und Arbeitsspeicher sind zwei Dinge, die eng miteinander verzahnt sind. Meistens ist es performanter, temporäre (zeitweilige, nur zu diesem Zweck angelegte) Variablen anzulegen und mit diesen eine Aufgabe zu lösen. Wenn aber das Anlegen der temporären Variablen dazu führt, das ersteinmal neuer Arbeitspeicher bei Windows angefordert werden muss, hat sich der ganze Performancevorteil in Nichts aufgelöst. Das gilt insbesondere für das Anlegen von (besonders) großen Datenstrukturen im sogenannten Stack. Der Stack ist in seiner Größe nämlich begrenzt. Er kann zwar vergrößert werden, aber das ist performancetechnisch so teuer, das es ein einem Spiel praktisch nicht vorkommen sollte. Falls so etwas in Deinem Code passiert, ist schlicht und ergreifend das Codedesign falsch und muss unbedingt überarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Datenstrukturen, die Du mehrfach benötigst, legst Du natürlich in der Initialisierungphase an (also bei Aufruf der Funktion '''''Start''''' durch den OMSI) und nicht kurz vor jeder Verwendung. Das würde zwar (vielleicht) den Arbeitsspeicherverbrauch des Programmes reduzieren, kostet aber wertvolle CPU-Zeit (siehe Regel Nummer 1).&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung ===&lt;br /&gt;
&lt;br /&gt;
Ein weiteres Thema ist die Fehlerbehandlung. Gerade bei der Fehlerbehandlung ist es wichtig, einen gesunden Kompromiss zwischen Absturzsicherheit des Programmes und Performance zu finden. Selbstverständlich möchte jeder, das es nicht zu Programmabstürzen kommt - schon gar nicht in einem Spiel. Überlegungen dazu sind deshalb so wichtig, weil ein gravierender Fehler in Deinem Plugin den gesamten OMSI ins Byte-Nirvana reißen wird. &lt;br /&gt;
&lt;br /&gt;
Eine Technik zur Fehlerbehandlung die C++ bietet, ist die Möglichkeit, Codeabschnitte in try/except-Klammern einzufassen. Ganz allgemein sieht das so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;__try&amp;lt;/span&amp;gt;&lt;br /&gt;
 {&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// hier kommt der Code, der zu einem Fehler führt, z.B.:&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; x = 5;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; y = 0;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;float&amp;lt;/span&amp;gt; z = x / y;  &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Super-Idee, diese Division durch 0 ;-)&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// Code, der jetzt noch hier kommt, wird nie mehr ausgeführt, da die &lt;br /&gt;
    // vorherige Zeile zu einer Division-durch-0-Exception führt&amp;lt;/span&amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;__except&amp;lt;/span&amp;gt; ( EXCEPTION_HANDLER )&lt;br /&gt;
 {&lt;br /&gt;
    &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// mache irgendetwas, um den Fehler wieder gerade zu biegen&amp;lt;/span&amp;gt;&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;// hier gehts ganz normal weiter, als ob nichts passiert wäre&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das hemmungslose Benutzen von try/except und Performance sind allerdings zwei Dinge, die schlecht zusammen passen. Try/except kostet nämlich CPU-Zeit und sollte nur an klug überlegten Stellen eingesetzt werden. Wenn Du in Deinem Code eine Funktion aufrufst die Du nicht selbst geschrieben hast und wo die Dokumentation schon sagt, das im Fehlerfall die oder die Exception auftreten kann, musst Du natürlich try/except verwenden. In selbst geschriebenem Code solltest Du Exceptions vermeiden. Besser ist es, wenn die Funktion im Fehlerfall einen Fehlercode zurückliefert. Dazu zwei Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 int NichtSoGuteFunktion(int irgend_ein_wichtiger_wert)&lt;br /&gt;
 {&lt;br /&gt;
    if (irgend_ein_wichtiger_wert != wert_den_ich_hier_erwarte)&lt;br /&gt;
    {&lt;br /&gt;
        throw new exception_xy ( ... );  // sicher, aber teuer&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // weitere Verarbeitung&lt;br /&gt;
    // ...&lt;br /&gt;
 &lt;br /&gt;
    return ergebnis;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein besserer Ansatz könnte so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 enum MeineFehlerwerte&lt;br /&gt;
 {&lt;br /&gt;
    Bescheuerter_Fehler      = -1,&lt;br /&gt;
    Zu_wenig_Kaffee_Fehler   = -2,&lt;br /&gt;
    Zu_viel_Pizza_Fehler     = -3,&lt;br /&gt;
    // usw.&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 int BessereFunktion(int irgend_ein_wichtiger_wert, int* zeiger_auf_variable_die_ergebnis_speichert)&lt;br /&gt;
 {&lt;br /&gt;
    if (irgend_ein_wichtiger_wert != wert_den_ich_hier_erwarte)&lt;br /&gt;
    {&lt;br /&gt;
        return Bescheuerter_Fehler;  // genau so sicher, aber VIEL billiger&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // weitere Verarbeitung&lt;br /&gt;
    // ...&lt;br /&gt;
 &lt;br /&gt;
    *zeiger_auf_variable_die_ergebnis_speichert = ergebnis;&lt;br /&gt;
    return ERROR_SUCCESS; // ERROR_SUCCESS ist vordefiniert und hat den Wert 0&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
Eine Andere, ganz große Kasperfalle ist die Verwendung von nicht initialisierten Variablen, allen voran, die Zeigervariablen. Diese Fehler sind später außerdem relativ schwierig zu entdecken. Im Gegensatz zu z.B. Visual Basic werden bei C/C++ Variablen bei ihrer Deklaration nicht mit einem Wert vorbelegt. Deshalb ist es ganz wichtig, alle Variablen vor ihrer ersten Verwendung mit einem bestimmten Wert zu initialisieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
  int variable;           // Variable hat einen zufälligen Inhalt, ist aber meistens weniger gefährlich&lt;br /&gt;
  char* zeiger_variable;  // Variable hat einen zufälligen Inhalt, Verwendung führt totsicher zum Programmabsturz&lt;br /&gt;
 &lt;br /&gt;
  // irgendwo später im Code:&lt;br /&gt;
  if (zeiger_variable != NULL) { ... }  // Absturz ist sicher, da ohne Initialisierung zeiger_variable niemals NULL ist !!!&lt;br /&gt;
 &lt;br /&gt;
  // deshalb immer so:&lt;br /&gt;
  int variable = 0;&lt;br /&gt;
  char* zeiger_variable = NULL;&lt;br /&gt;
 &lt;br /&gt;
  // irgendwo später im Code:&lt;br /&gt;
  if (zeiger_variable != NULL) { ... }  // Alles o.k., da durch Initialisierung zeiger_variable NULL sein kann&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das teuflische an der Sache ist, das die in den Kommentaren als ''totsicher'' und ''niemals'' deklarierten Dinge gar nicht so totsicher sind. Natürlich kann es sein, das der Speicher, der der Variablen durch den Compiler zugewiesen wird, rein zufällig tatsächlich NULL ist. Und laut Murphy's Law ist das bei den ersten drei Programmtests auch so. Beim vierten Test aber plötzlich nicht mehr und das Programm stürzt ab. Und dann geht die verzweifelte Fehlersuche los ...&lt;br /&gt;
&lt;br /&gt;
=== Objektorientierte Programmierung vs. prozedurale Programmierung ===&lt;br /&gt;
&lt;br /&gt;
So manch Hardcore-Spieleprogrammierer wird die Nase rümpfen und denken, objektorientierte Programmierung (wird im OMSI Plugin Framework verwendet), das geht gar nicht, das macht man doch nicht. Ich muss leider zugeben, so ganz unrecht haben sie nicht. Objektorientierte Programmierung erzeugt nämlich einen gewissen Overhead, der CPU-Zeit kostet. Und das ist ja bekanntlich die teuerste Resource, die uns zur Verfügung steht. Aber wie Du eingangs ja schon festgstellt hast, must Du auch hier einen Kompromiss eingehen. Auf der einen Seite steht der Overhead durch die Verwendung von Klassen, auf der anderen Seite steht ein einfacherer, übersichtlicherer Code, der besonders Programmieranfängern den Einstieg erleichtern wird. Wenn Du schon über ausreichend Programmiererfahrung verfügst, kannst Du ja mal versuchen, das Framework in eine rein prozedurale Variante zu überführen. Du wirst feststellen, dass das gar nicht so einfach ist und möglicherweise Anfänger ziemlich überfordert.&lt;br /&gt;
&lt;br /&gt;
Der Overhead bei der Verwendung von Klassen entsteht dadurch, dass jedem Methodenaufruf ein unsichtbarer Parameter (der sogenannte '''this'''-Zeiger) mitgegeben wird. In Pseudo-Assembler sieht das etwa so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;span style=&amp;quot;font-weight:bold&amp;quot;&amp;gt;push&amp;lt;/span&amp;gt;  parameter_1&lt;br /&gt;
 push  parameter_2&lt;br /&gt;
 ; usw.&lt;br /&gt;
 mov   ecx, this  ; &amp;lt;-- der zusätzliche Assembler-Befehl&lt;br /&gt;
 call  method_xy&lt;br /&gt;
 ; ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Gleiche gilt für die Verwendung der Felder einer Klasse. Auch der Zugriff erfolgt über den '''this'''-Zeiger. Ein etwas größerer Overhead entsteht noch, wenn die Klasse virtuelle Methoden verwendet. Dann muss nämlich noch eine Tabelle für die virtuellen Methoden angelegt werden und der Aufruf der Methoden erfolgt dann indirekt über diese Tabelle.&lt;br /&gt;
Alles zusammen genommen denke ich aber, das der Overhead für unsere modernen Prozessoren gering ist und die Vorteile der objektorientierten Programmierung überwiegen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_I&amp;diff=754</id>
		<title>OMSI Plugin Framework I</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_I&amp;diff=754"/>
		<updated>2012-11-19T07:49:16Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Schriftgröße angepasst&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
Beginnen wir mit einer Definition:&lt;br /&gt;
 &amp;lt;tt style=&amp;quot;font-size:1.4em&amp;quot;&amp;gt;Ein Programmierer ist eine Maschine, die riesige Mengen Kaffee, Pizza und Schokolade zu Programmcode verarbeitet.&amp;lt;/tt&amp;gt;&lt;br /&gt;
Wenn Du also dazu in der Lage bist, hast Du die erste Hürde schon mal genommen. Und die Zweite gleich mit: Du kannst nämlich sogar über uralte Kalauer - naja, wenigstens schmunzeln. So, jetzt wirds aber ernst. Um ein brauchbares Plugin zu produzieren, solltest Du &lt;br /&gt;
&lt;br /&gt;
* über Basiswissen in der Programmiersprache C/C++ verfügen&lt;br /&gt;
* zumindestens ganz grob wissen, was man unter objektorientierter Programmierung versteht (und wenn nicht: am Ende dieses Tutorials weißt Du es)&lt;br /&gt;
* wissen, wozu Klassen in C++ gut sind und wie man mit ihnen umgeht&lt;br /&gt;
&lt;br /&gt;
Das wäre für den Anfang schon mal gar nicht schlecht. Da Du zum Debuggen Deines Plugins den Debugger des Visual Studios nicht verwenden kannst, gehört zum OMSI Plugin Framework auch eine Debug-Hilfe - der '''''OMSI Plugin Log Viewer''''' (mir ist kein längerer Titel eingefallen, deshalb muss es so gehen). Um den Log Viewer sinnvoll einsetzen zu können, musst Du einen zweiten Bildschirm an Deinem Computer haben oder - noch besser - einen weiteren Windows-Computer in Deinem lokalen Netzwerk. Als Programmierwerkzeug eignet sich das bereits im Vorwort erwähnte '''''Visual Studio Express''''' (und natürlich auch alle seine großen Brüder und Schwestern) hervorragend. Der Log Viewer und das Setup-Programm des ''OMSI Plugin Frameworks'' benötigen das Microsoft '''''.Net-Framework 4'''''. Und last but not least benötigst Du natürlich ;-) das '''''OMSI Plugin Framework'''''.&lt;br /&gt;
&lt;br /&gt;
Die Voraussetzungen noch einmal zusammengefasst:&lt;br /&gt;
# &amp;lt;del&amp;gt;Master-Abschluss in IT-Wissenschaften (Promotion wird empfohlen)&amp;lt;/del&amp;gt; :-D&lt;br /&gt;
# zweiter Bildschirm oder Netzwerk-Computer mit mindestens Windows-XP&lt;br /&gt;
# [http://www.microsoft.com/de-de/download/details.aspx?id=17718 Download] des Microsoft .Net Framework 4&lt;br /&gt;
# [http://www.microsoft.com/germany/express/download/default.aspx Download] des Microsoft Visual Studio (Express)&lt;br /&gt;
# [http://omsi.sovoma.de/downloads/opf.zip Download] des OMSI Plugin Framework&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:new_projekt.png|100px|thumb|right|Bild 1]]&lt;br /&gt;
[[Datei:omsi_plugin_project.png|100px|thumb|right|Bild 2]]&lt;br /&gt;
[[Datei:project_created.png|100px|thumb|right|Bild 3]]&lt;br /&gt;
&lt;br /&gt;
Als erstes solltest Du das '''''.Net Framework 4''''' installieren, falls es auf Deinem Computer noch nicht vorhanden ist. Starte also die Installation des '''''.Net Framework 4''''' und erledige in aller Ruhe Deinen Wochenend-Einkauf. Ein herzliches ''Danke schön'' an Microsoft an dieser Stelle für diesen exzellenten Installer. Ach ja, falls Du die automatischen Updates für Windows eingeschaltet hast, wird Dich früher oder später noch das Service Pack 1 für das '''''.Net Framework 4''''' überraschen. Auch dessen Installation dauert so 1-2 Microsoft-Minuten. &lt;br /&gt;
&lt;br /&gt;
Die Installation des '''''Visual Studio Express''''' dagegen ist völlig unkompliziert und in kurzer Zeit erledigt. Nachdem diese Installation abgeschlossen ist, solltest Du als nächstes das '''''OMSI Plugin Framework''''' installieren. Entpacke dazu das heruntergeladene Archiv in einen Ordner Deiner Wahl und starte '''opfsetup.exe'''. Die '''opfsetup.exe''' muss mit Administratorrechten laufen, da zum Einbinden der Projektvorlage ins Visual Studio u.a. Einträge in der Windows-Registry und im ''Programme''-Ordner gemacht werden, welcher für sogenannte ''eingeschränkte Benutzer'' nicht beschreibbar ist. Außerdem wird Windows noch meckern, dass der Herausgeber des Programmes unbekannt ist. Aus Windows-Sicht stimmt das auch, weil die digitale Signatur fehlt. Aber ich will einfach nicht mehrere 100 Dollar pro Jahr ausgeben, nur um ein paar mal meine eigenen Programme digital signieren zu können. Du darfst mir aber vertrauen: '''opfsetup.exe''' ist kein bösartiges Programm, sofern Du es mit dem obigen Link heruntergeladen hast. Das ist nämlich mein eigener Server und der ist ungezieferfrei! Die Installation des Frameworks sollte nach dem Klick auf &amp;quot;Installieren&amp;quot; im Bruchteil einer Sekunde erledigt sein.&lt;br /&gt;
&lt;br /&gt;
Wenn Du den Log Viewer auf einem anderen Computer im Netzwerk laufen lassen willst, musst Du die Leiden mit dem '''''.Net Framework 4''''' auf diesem Computer noch einmal ertragen. Auch auf diesem Computer musst Du das '''''OMSI Plugin Framework''''' herunterladen und entpacken. Natürlich muss '''opfsetup.exe''' auf diesem Computer '''''nicht''''' ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Wenn Du das alles durchgestanden hast, muss nur noch der Log Viewer '''NICHT''' installiert werden. Im Ernst, für den Log Viewer ist keine Installation notwendig. Falls Du den Log Viewer mal in einen anderen Ordner oder auf einen anderen Computer (auf dem das .Net Framework 4 schon existiert) verfrachten willst, musst Du nur darauf achten, das die beiden Dateien ''OMSIPluginLogViewer.exe'' und ''Ionic.Zip.dll'' zusammen bleiben. Das ist alles.&lt;br /&gt;
&lt;br /&gt;
Wenn alles geklappt hat, machen wir doch mal den großen Test. Starte Visual Studio, habe ein bisschen Geduld (nur der allererste Start dauert etwas) und klicke im Start-Bildschirm auf '''Neues Projekt''' (Bild 1). Es öffnet sich der Einstellungsdialog für ein neues Projekt. Klicke im linken Teil unterhalb von '''Visual C++''' auf den Ordner '''OMSI'''. In diesem Ordner gibt es nur eine Projektvorlage, ein OMSI Plugin (Bild 2). Gib dem neuen Projekt noch einen Namen (Eingabefeld '''Name''' am unteren Rand), die anderen Eingabefelder kannst Du so belassen, wie sie sind. Klicke nun auf '''OK''', um das Projekt anzulegen. Es erscheint noch ein Zwischendialog, in dem es aber nichts einzustellen gibt. Klicke nochmals auf '''Erstellen'''. Nach kurzer Zeit sollte Dein Bildschirm wie auf dem Bild 3 aussehen.&lt;br /&gt;
&lt;br /&gt;
Damit belassen wir es ersteinmal. Es sollte nur ein Test sein, ob die Installation insgesamt funktioniert hat.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework II|[zum Kapitel 2]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Plug-in-Schnittstelle&amp;diff=753</id>
		<title>Plug-in-Schnittstelle</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Plug-in-Schnittstelle&amp;diff=753"/>
		<updated>2012-11-19T07:17:15Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Allgemeines Prinzip =&lt;br /&gt;
&lt;br /&gt;
OMSI verfügt über die Möglichkeit, Plugin-DLLs zu programmieren, welche Lese- und Schreibzugriff auf die [[System-_und_vordefinierte_lokalen_Variablen#Fahrzeuge|Fahrzeugvariablen]] haben und [[Scriptsystem#Trigger|Fahrzeug-Trigger]] auslösen können.&lt;br /&gt;
&lt;br /&gt;
Jedes Plugin besteht aus einer [[Konfigurationsdatei]] mit der Dateiendung *.opl und einer zugehörigen DLL. Beide Dateien müssen im Verzeichnis &amp;quot;OMSI\plugins&amp;quot; liegen.&lt;br /&gt;
&lt;br /&gt;
= Beschreibung des Beispiels =&lt;br /&gt;
&lt;br /&gt;
In OMSI enthalten ist bereits ein Beispiel-Plugin enthalten. Um es zu aktivieren, muss die Datei &amp;quot;test.txt&amp;quot; im &amp;quot;OMSI\plugins&amp;quot;-Verzeichnis in &amp;quot;test.opl&amp;quot; umbenannt werden.&lt;br /&gt;
&lt;br /&gt;
== Funktionsumfang ==&lt;br /&gt;
&lt;br /&gt;
Dieses Plugin hat drei Funktionen: Einen Tacho (analog und digital) ganz oben, einen Sollwertregler für den roten Heizungsregler (obwohl da falscherweise &amp;quot;Rollband-Sollwert&amp;quot; steht) und einen Türtaster &amp;quot;Button1&amp;quot; (der aber trotzdem nur funktioniert, wenn die Haltestellenbremse aktiv und die Elektrik an ist).&lt;br /&gt;
&lt;br /&gt;
[[Datei:Beispiel-Plugin.jpg|600px|thumb|right|Oberfläche des Beispiel-Plugins]]&lt;br /&gt;
&lt;br /&gt;
== Aufbau der *opt-Datei ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
To activate, rename this file to &amp;quot;test.opl&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[dll]&lt;br /&gt;
Test.dll&lt;br /&gt;
&lt;br /&gt;
[varlist]&lt;br /&gt;
2&lt;br /&gt;
Velocity&lt;br /&gt;
cockpit_heizregler_temp&lt;br /&gt;
&lt;br /&gt;
[triggers]&lt;br /&gt;
1&lt;br /&gt;
bus_doorfront0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zeile ist nur eine Kommentarzeile. Der [dll]-Befehl gibt den Dateinamen der zugehörigen DLL an.&lt;br /&gt;
&lt;br /&gt;
Der [varlist]-Befehl beginnt mit der Anzahl der zu erwartenden (lokalen) Fahrzeugvariablen. Hierbei können auch User-Variablen eines bestimmten Busses angegeben werden. Wenn der tatsächlich gefahrene Bus dann diese Variable nicht hat, dann werden die zugehörigen Zugriffe natürlich nicht durchgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Variable mit dem Index 0 ist also bei dieser DLL &amp;quot;Velocity&amp;quot;, die Variable mit dem Index 1 ist &amp;quot;cockpit_heizregler_temp&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Der [triggers]-Befehl beginnt ebenfalls mit der Anzahl der zu erwartenden Fahrzeugtrigger. In diesem Fall ist dies nur ein Trigger: &amp;quot;bus_doorfront0&amp;quot; mit dem Index 0.&lt;br /&gt;
&lt;br /&gt;
== Aufbau der DLL ==&lt;br /&gt;
&lt;br /&gt;
Anhand der Beispiel-DLL wird nun erklärt, wie der zugehörige Delphi-Code aussehen soll. Im Allgemeinen sollte es möglich sein, auch mit anderen Programmiersprachen passende DLLs zu programmieren. Ausprobiert habe ich dies allerdings nicht.&lt;br /&gt;
&lt;br /&gt;
Die DLL besteht aus zwei Units. Erklärt wird aber nur die Hauptunit (Test.dpr) (die zweite Unit enthält nur einige wenige nicht-relevante Implementierungen für die Form):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
library Test;&lt;br /&gt;
&lt;br /&gt;
uses&lt;br /&gt;
  SysUtils,&lt;br /&gt;
  Dialogs,&lt;br /&gt;
  Classes,&lt;br /&gt;
  TestU in 'TestU.pas' {Form1};&lt;br /&gt;
&lt;br /&gt;
{$R *.res}&lt;br /&gt;
&lt;br /&gt;
procedure Start( AOwner: TComponent ); stdcall;&lt;br /&gt;
begin&lt;br /&gt;
        form1 := TForm1.Create( AOwner );&lt;br /&gt;
        form1.Show;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure Finalize; stdcall;&lt;br /&gt;
begin&lt;br /&gt;
        form1.Free;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure AccessVariable( varindex: word; var value: single; var write: boolean ); stdcall;&lt;br /&gt;
begin&lt;br /&gt;
        case varindex of&lt;br /&gt;
                0:&lt;br /&gt;
                begin&lt;br /&gt;
                        form1.Label2.Caption := floattostrF( value, ffFixed, 5, 1 ) + ' km/h';&lt;br /&gt;
                        form1.Gauge1.Progress := round( value );&lt;br /&gt;
                        write := false;                        &lt;br /&gt;
                end;&lt;br /&gt;
                1:&lt;br /&gt;
                begin&lt;br /&gt;
                        value := form1.TrackBar1.Position / 30;&lt;br /&gt;
                        write := true;&lt;br /&gt;
                end;&lt;br /&gt;
        end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure AccessTrigger( triggerindex: word; var active: boolean ); stdcall;&lt;br /&gt;
begin&lt;br /&gt;
        case triggerindex of&lt;br /&gt;
                0:&lt;br /&gt;
                begin&lt;br /&gt;
                        active := form1.button1_pressed;&lt;br /&gt;
                end;&lt;br /&gt;
        end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
exports&lt;br /&gt;
        AccessVariable,&lt;br /&gt;
        AccessTrigger,        &lt;br /&gt;
        Start,&lt;br /&gt;
        Finalize;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zunächst ist der letzte Abschnitt &amp;quot;exports&amp;quot; zu beachten: Die vier gelisteten Prozeduren sollen von der DLL angeboten werden: ''AccessVariable'', ''AccessTrigger'', ''Start'' und ''Finalize''.&lt;br /&gt;
&lt;br /&gt;
Die vier Prozeduren haben folgenden Aufbau:&lt;br /&gt;
&lt;br /&gt;
=== Aufbau der Prozedur ''Start'' ===&lt;br /&gt;
&lt;br /&gt;
''Start( AOwner: TComponent )'' wird am Anfang aufgerufen und ermöglicht es der DLL, sich zu initialisieren. In diesem Fall wird ''Form1'' erzeugt und der gleichnamigen Variable zugeordnet, welche sich jedoch in der Unit ''TestU'' befindet. Als zweiter Schritt wird der ''Show''-Befehl aufgerufen, um die ''Form1'' anzuzeigen. ''Start'' übergibt den Parameter &amp;quot;AOwner&amp;quot;, welcher der Handler des Hauptprogramms von OMSI darstellt.&lt;br /&gt;
&lt;br /&gt;
=== Aufbau der Prozedur ''Finalize'' ===&lt;br /&gt;
&lt;br /&gt;
''Finalize'' dagegen wird beim Schließen aufgerufen. Hier wird schlicht das Objekt ''Form1'' zerstört.&lt;br /&gt;
&lt;br /&gt;
=== Aufbau der Prozedur ''AccessVariable'' ===&lt;br /&gt;
&lt;br /&gt;
Im Betrieb ruft OMSI diese Prozedur für alle in der *.opl-Datei gelisteten lokalen Variablen auf. Sie übergibt dabei stets den Index der Variable (''varindex''). Die Prozedur kann nun ihrerseits die Variablen ''value'' und ''write'' schreiben.&lt;br /&gt;
&lt;br /&gt;
Bei einem Lesezugriff kann die Prozedur wie im Beispiel unter &amp;quot;0:&amp;quot; die Variable über ''value'' einfach auslesen. Es ist aber wie unter &amp;quot;1&amp;quot; auch möglich, dem Wert von ''value'' einen neuen Wert zuzuweisen. Dann aber muss die Variable ''write'' auch auf ''wahr'' gesetzt werden, damit der Wert von OMSI übernommen wird. Im Beispiel wird die ''TrackBar'' ausgelesen und der Wert auf den Wert von ''value'' geschrieben.&lt;br /&gt;
&lt;br /&gt;
=== Aufbau der Prozedur ''AccessTrigger'' ===&lt;br /&gt;
&lt;br /&gt;
Diese Prozedur arbeitet recht ähnlich. Hier allerdings wird die Triggerliste durchgearbeitet. Die DLL kann bei Aufruf dieser Funktion den Wert ''active'' auf ''true'' setzen; dann löst OMSI den gewünschten Trigger aus.&lt;br /&gt;
&lt;br /&gt;
= Ausführliches Tutorial =&lt;br /&gt;
&lt;br /&gt;
Ein ausführliches Tutorial zur Nutzung dieser Schnittstelle - allerdings mit der Programmiersprache C++ - ist hier im Wiki in der Kategorie [[OMSI Plugin Framework|Tutorials]] zu finden.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Nachschlagewerk_für_Addon-Entwickler]]&lt;br /&gt;
&lt;br /&gt;
[[en:Plug-In Interface]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=752</id>
		<title>OMSI Plugin Framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=752"/>
		<updated>2012-11-19T07:09:05Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Inhaltsverzeichnis ==&lt;br /&gt;
&lt;br /&gt;
* [[#Vorwort|Vorwort]]&lt;br /&gt;
* [[OMSI Plugin Framework I|Kapitel 1]] - Allgemeines&lt;br /&gt;
** Voraussetzungen und Installation&lt;br /&gt;
* [[OMSI Plugin Framework II|Kapitel 2]] - Die graue Theorie&lt;br /&gt;
** ein bisschen Theorie muss sein&lt;br /&gt;
* [[OMSI Plugin Framework III|Kapitel 3]] - Die Plugin-Schnittstelle&lt;br /&gt;
** die Arbeitsweise der Plugin-Schnittstelle&lt;br /&gt;
* [[OMSI Plugin Framework IV|Kapitel 4]] - Das OMSI Plugin Framework&lt;br /&gt;
** detaillierte Beschreibung des Frameworks&lt;br /&gt;
* [[OMSI Plugin Framework V|Kapitel 5]] - Der OMSI Plugin Log Viewer&lt;br /&gt;
** Beschreibung der Debug-Hilfe zum Debuggen eines Plugins&lt;br /&gt;
* [[OMSI Plugin Framework VI|Kapitel 6]] - Ein Beispielprojekt&lt;br /&gt;
** Beispielprojekt für eine (fast) vollautomatische Klimaanlage&lt;br /&gt;
&lt;br /&gt;
== Vorwort zum Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Liebe angehende Plugin-Programmierer,&lt;br /&gt;
&lt;br /&gt;
dieses Tutorial zum '''''OMSI Plugin Framework''''' ist - wie man so schön neudeutsch sagt, &amp;quot;Working under progress&amp;quot;. Ich stelle das unfertige Tutorial hauptsächlich aus zwei Gründen bereits zur Verfügung:&amp;lt;br&amp;gt;1.) damit diejenigen unter euch, die schon über ausreichende Programmiererfahrung verfügen und ohne viele weitere Erklärungen auskommen, schon mal loslegen können und&amp;lt;br&amp;gt;2.) damit jeder schon während ich die einzelnen Kapitel schreibe, über das Forum Ideen, Verbesserungsvorschläge, Fragen zu Unklarheiten usw. einbringen kann.&lt;br /&gt;
&lt;br /&gt;
Bitte, werdet nicht ungeduldig, wenn mir nicht jeden Tag ein neues Kapitel aus der Feder tropft. Ich habe so nebenbei noch eine 'richtige' Arbeit bei der Berliner Feuerwehr und ... äh, da war doch noch was ... irgendwas war da noch ... was war denn da bloß noch ... ach ja, 'ne Familie ist da ja auch noch.&lt;br /&gt;
&lt;br /&gt;
In diesem Sinne, viel Spass beim programmieren und diskutieren&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Holmexx|Holmexx]] ([[Benutzer Diskussion:Holmexx|Diskussion]]) 07:07, 19. Nov. 2012 (CET)&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Vielleicht hat der/die Eine oder Andere ja schon mal mit dem Gedanken gespielt, sich an ein Plugin heranzuwagen, das Vorhaben aber dann verworfen, weil er/sie gedacht, programmieren ist was für Profis und viel zu schwer. Die Erstellung eines Plugins für den OMSI ist - auch mit geringer Programmiererfahrung - gar nicht so schwierig wie es auf den ersten Blick aussieht. Das Entscheidende wird ja schon hier im [http://www.omnibussimulator.de/omsiwiki.de/index.php?title=Plug-in-Schnittstelle OMSI-Wiki] erklärt. Allerdings beziehen sich diese Erklärungen auf die Programmiersprache Pascal, die einstmals mit Borlands Delphi weite Verbreitung fand. Borland ist seit langem Geschichte und damit Delphi schon fast in Vergessenheit geraten. Die Firma [http://www.embarcadero.com/de/products/delphi Embarcadero] vertreibt zwar Delphi wieder, die Preise dort werden aber jeden Hobbyprogrammierer abschrecken. Die Alternative kommt von Microsoft. Dort kann man sich [http://www.microsoft.com/germany/express/download/default.aspx Visual Studio Express] kostenlos herunterladen. Für die Plugin-Programmierung benötigst Du '''Visual C++ 2010 EXPRESS'''. Wenn Du nun noch über wenigstens grundlegende Kenntnisse in der Programmiersprache C++ verfügst, kann es ja losgehen. Aber halt, warum C++? Geht nicht auch C# oder Visual Basic? Aus technischer Sicht ist es absolut möglich, ein Plugin in C# oder VB zu entwickeln. Allerdings stehen sich mit C#/VB und OMSI zwei Welten gegenüber. Die erste &lt;br /&gt;
Welt ist die des &amp;quot;Managed Code&amp;quot; und die Andere die des &amp;quot;Unmanaged Code&amp;quot;. Um beide Welten zusammen zu bringen, brauchst Du eine Wrapper-DLL. Und die kannst Du nur mit - Du ahnst es bereits - C/C++ programmieren, auch noch verbunden mit einem dramatisch erhöhten Schwierigkeitsgrad. Außerdem macht COM-Programmierung keinen Spaß, sondern ist einfach nur schmerzhaft. Ein weiteres Hindernis ist die Architektur eines &amp;quot;Managed Code&amp;quot;-Programmes. Managed Code ist auf maximale Sicherheit ausgelegt, nicht auf Performance. Es ist ungefähr so, als ob Du mit einer voll gepanzerten Limousine bei der DTM antrittst. Dein Auto ist zwar unkaputtbar, schade ist nur, dass die anderen Fahrer schon beim ersten Bier sitzen nach dem Rennen, während Du noch 6 Runden zu fahren hast. Bleiben wir also lieber bei C++.&lt;br /&gt;
&lt;br /&gt;
Um die Sache, insbesondere für Programmiernovizen, noch etwas zu vereinfachen, habe ich dieses Framework entwickelt, mit dem sich - hoffentlich ;-) - schnell und einfach Plugins programmieren lassen. Ich habe mich ganz bewusst für die Programmiersprache C++ entschieden, obwohl mit dem OpenSource-Projekt [http://www.lazarus.freepascal.org Lazarus] ein gut gelungener Delphi-Klon existiert und man damit sogar in reinrassigem Pascal im Delphi-Stil programmieren könnte. Aber C++ ist doch noch etwas systemnaher als Pascal und bietet dem Plugin-Programmierer Möglichkeiten, die in Pascal nur recht umständlich oder sogar überhaupt nicht möglich wären (z.B. Klassen-Templates, Verwendung von Makros).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorials für Addon-Entwickler]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=751</id>
		<title>Hauptseite</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=751"/>
		<updated>2012-11-19T07:00:46Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font style=&amp;quot;font-size:1.2em;&amp;quot;&amp;gt;&lt;br /&gt;
'''Herzlich willkommen auf der deutschen Version von OMSIWiki!'''&lt;br /&gt;
&lt;br /&gt;
Hier geht's direkt zu einer der Hauptkategorien:&lt;br /&gt;
&lt;br /&gt;
* [[FAQs - Häufig gestellte Fragen]]&lt;br /&gt;
* [[:Kategorie:Busfahren in OMSI|Busfahren in OMSI]]&lt;br /&gt;
* Entwicklung von Addons:&lt;br /&gt;
** [[:Kategorie:Nachschlagewerk für Addon-Entwickler|Nachschlagewerk]]&lt;br /&gt;
** [[:Kategorie:Tutorials für Addon-Entwickler|Tutorials]]&lt;br /&gt;
** [[:Kategorie:Tipps und Tricks für Addon-Entwickler|Tipps und Tricks]]&lt;br /&gt;
* [[:Kategorie:Anschlussprojekte|Anschlussprojekte (z.B. Addon-Manager, OAT)]]&lt;br /&gt;
* [[:Kategorie:Addon-Präsentationen|Addon-Präsentationen]]&lt;br /&gt;
* [[:Kategorie:Hintergrundinformationen|Hintergrundinformationen]]&lt;br /&gt;
&lt;br /&gt;
'''Achtung: Vor dem Verfassen eigener Beiträge bitte zuerst die Regeln lesen!''' Weiter unten gibt es noch eine Ultra-Kurzanleitung für Neulinge.&lt;br /&gt;
&lt;br /&gt;
''Aktuell in Arbeit:''&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Tutorial zum programmieren eines [[OMSI Plugin Framework|OMSI-Plugins in C++]] --[[Benutzer:Holmexx|Holmexx]] 07:49, 19. Nov. 2012 (MET) &lt;br /&gt;
* Übersetzen der Artikel, zuletzt [[Repainting of OMSI buses (also over panes)]] --[[Benutzer:Dario|Dario]] 12:04, 17. Jul. 2012 (MEST)&lt;br /&gt;
* [[Fahrpläne erstellen]] --[[Benutzer:Felix (Keyway)|Felix (Keyway)]] 16:21, 31. Dez. 2011 (MET) ----- Weitergeführt von [[Benutzer:Dario|Dario]] 11:33, 18. Jul. 2012 (MEST)&lt;br /&gt;
* ''(aktuell pausiert)'' [[Fahrzeug-SDK]] (c) von Rüdiger, Einbau ins OMSIWiki von --[[Benutzer:Marcel Kuhnt|Marcel Kuhnt]] 16:12, 2. Dez. 2011 (MET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Wir Entwickler von OMSI haben OMSIWiki eingerichtet, um eine bessere Plattform für alle Arten von Informationen rund um OMSI zu erhalten. Folgende Themengebiete sind von uns vorläufig vorgesehen:&lt;br /&gt;
&lt;br /&gt;
* Präsentation von Hintergrundinformationen über das Addon-Design von unserer Seite (Objekt- und Fahrzeugbar, Soundengine, Scriptengine usw.)&lt;br /&gt;
* Tipps und Tricks oder auch ganze Tutorials von Usern z.B. zum Erstellen von Repaints oder Mapbau würden unsere Kernthemen abrunden. Entweder als Ergänzung unserer oder als weiterreichende Artikel.&lt;br /&gt;
* Die Bedienung von OMSI und insbesondere der Busse könnte ein weiterer Themenkomplex sein. Zwar gibt es natürlich ein Handbuch für OMSI, dennoch gibt es vieleicht die eine oder andere Sache, die ausführlicher erklärt werden soll. Hier werden wir uns allerdings etwas zurückhalten.&lt;br /&gt;
* Weiterhin könnten hier bewährte Anschlussprojekte zu OMSI präsentiert werden, z.B. OAT oder der Addon-Manager. Höchstwahrscheinlich werden die zugehörigen Artikel dann von den Leitern oder treuesten Fans dieser Projekte geschrieben, wir werden uns hier ebenfalls zurückhalten.&lt;br /&gt;
* Ähnlich hierzu haben wir nichts gegen eine hochqualitative Präsentation von komplexen Addons; denkbar wäre hier z.B. die Bedienungsanleitung eines Addon-Busses oder die Beschreibung und Hinweise für die Fahrt durch eine Addon-Karte mit Fahrplänen und/oder Karten. Wo wir hier allerdings die Grenze setzen, steht noch nicht fest. Insbesondere sollen hier keine &amp;quot;Mini-Artikel&amp;quot; entstehen, wo nur ein Screenshot von einem Repaint und ein Download-Link präsentiert wird!&lt;br /&gt;
* Selbstverständlich dürfen hier auch gerne Hintergrundinformationen zu unserer Strecke oder unseren Bussen oder aber zu Addons gegeben werden (wie sah Spandau in der Realität 1989 aus? Wie wurde damals in Berlin Bus gefahren?). Es sollte sich aber um abgeschlossene und ernsthaft geschriebene Artikel handeln und es sollte definitiv ein Bezug zu OMSI vorhanden sein! Also keine schnell hingeschriebenen Tagesberichte von irgendeinem Busunternehmen, was keiner kennt und was auch nicht in OMSI mindestens als Addon simuliert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Regeln ==&lt;br /&gt;
&lt;br /&gt;
=== Ist das Thema hier erwünscht? ===&lt;br /&gt;
&lt;br /&gt;
Der Idee von OMSIWiki entsprechend sollte jeder Artikel letztlich in eine der oben genannten Kategorien passen!&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Goldene Regel&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
Zunächst die '''&amp;quot;goldene Regel&amp;quot;''': Bevor ein Artikel verfasst oder geändert wird, sollte stets geschaut werden, ob sich an den Regeln etwas geändert hat! Gerade in der Anfangszeit wird es sicher vorkommen, dass sich Regeln ändern oder neue hinzukommen.&lt;br /&gt;
&lt;br /&gt;
=== Erwünscht ===&lt;br /&gt;
&lt;br /&gt;
* Wenn ihr einen kleinen oder großen Fehler entdeckt (auch in einem unserer Artikel!), dann darf ihn jeder korrigieren! Aber nur, wenn ihr euch dabei auch sicher seid.&lt;br /&gt;
* Ihr findet einen Artikel z.B. im Addon-Handbuch zu trocken? Dann dürft ihr gerne ein kleines Beispiel ergänzen! Von mir weiß ich z.B., dass die Anschauung und Klarheit leidet, wenn ich viele und lange Texte schreibe!&lt;br /&gt;
* Ihr findet einen Fachbegriff, der nicht erklärt wird? Wenn es ein bisher nicht erklärter Begriff von OMSI ist, dürft ihr gerne einen Artikel anfertigen und ihn mit dem Fachbegriff verlinken; handelt es sich um einen allgemeinen Fachbegriff, dann reicht meist ein externer Link zu einem entsprechenden Artikel z.B. in der Wikipedia aus.&lt;br /&gt;
* Um zu vermeiden, dass euch bereits jemand anderes &amp;quot;dazwischen funkt&amp;quot;, obwohl euer Artikel noch gar nicht fertig ist, ergänzt bitte hierzu oben den Hinweis: &amp;quot;''Hinweis: Dieser Artikel befindet sich noch im Aufbau!''&amp;quot;. Dadurch wird auch vermieden, dass der unter Umständen erst halbfertige Artikel schon von jemandem übersetzt wird, sodass nach Fertigstellung der deutschen Version die englische noch unvollständig ist.&lt;br /&gt;
* Wenn euer Artikel auch ein englischsprachiges Pendant hat, dann verknüpft ihn bitte! Ein Blick ans Ende des Quelltextes ''dieser'' Seite zeigt euch, wie das geht! Hat er jedoch ''kein'' Pendant und muss demnach in der englischen OMSIWiki noch angelegt werden, so wäre ein Hinweis ganz oben nicht schlecht: &amp;quot;''Hinweis: Dieser Artikel wurde noch nicht ins Englische übersetzt!''&amp;quot; oder &amp;quot;''Hinweis: Die englische Version muss noch aktualisiert werden!''&amp;quot;&lt;br /&gt;
* Wenn ihr Spaß am Übersetzen habt, dann könnt ihr eine sehr wertvolle Hilfe für OMSIWiki sein! Wenn ihr einen dieser Hinweise entdeckt, scheut euch nicht, den Artikel in die englische OMSIWiki einzupflegen! Ihr solltet danach aber den Original-Autor informieren (damit er die Gelegenheit hat, einmal drüber zu schauen) und dann natürlich die beidseitige Verlinkung mit der deutschen Seite vornehmen und den Hinweis entfernen.&lt;br /&gt;
&lt;br /&gt;
=== Unerwünscht ===&lt;br /&gt;
&lt;br /&gt;
* '''Ganz wichtig: Der Name des Artikels muss wohlüberlegt gewählt werden, weil man den nicht mal eben ändern kann! Wer hier grob fahrlässig schlampt, fliegt raus!'''&lt;br /&gt;
* Schlechter Schreibstil! Was im Chat normal ist und im Forum zwangsweise geduldet wird, ist hier tabu: Bitte gebt euch etwas Mühe, wenn ihr hier einen Artikel verfasst!&lt;br /&gt;
* Werbung für unbekannte, kleine Projekte, Foren, virtuelle Gesellschaften etc. Der Sinn von OMSIWiki ist nicht die Werbung für Projekte! Es soll eine Informationsplattform sein!&lt;br /&gt;
&lt;br /&gt;
Hier dazu was Passendes zum schmunzeln: [http://meta.wikimedia.org/wiki/Wikipedia_Anti-Regeln Wikipedia-Anti-Regeln]&lt;br /&gt;
&lt;br /&gt;
=== Absprachen ===&lt;br /&gt;
&lt;br /&gt;
* Vor Beginn der Arbeit bitte oben bei &amp;quot;Aktuell in Arbeit&amp;quot; eine Zeile mit der geplanten Arbeit und eurer Signatur ergänzen. Nach Fertigstellung diesen wieder entfernen. Sollte jedoch dann gar kein Punkt mehr übrigbleiben, dann ein &amp;quot; * ''Nichts'' &amp;quot; stehen lassen.&lt;br /&gt;
* Wenn ihr größere Korrekturen an unseren Artikeln vornehmt, wär es natürlich gut, wenn ihr uns zumindest nachher darüber informiert, damit wir den Überblick behalten.&lt;br /&gt;
* Bevor ein neuer Artikel verfasst wird, kann es nicht schaden, kurz eine E-Mail an uns Administratoren zu schicken mit euren Planungen.&lt;br /&gt;
* Das Einführen neuer Kategorien hat grundstätzlich in Absprache mit den Administratoren zu geschehen.&lt;br /&gt;
&lt;br /&gt;
* Beachtet auch die Möglichkeit, mit den Autoren auf der Diskussionsseite zu diskutieren! Wie der &amp;quot;Quellcode&amp;quot; einer Diskussionsseite aussieht, seht ihr hier: [[Diskussion:OMSI_Addon_Tester_(OAT)]]. Und nicht vergessen: Die Signatur könnt ihr automatisch erzeugen mit &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;!&lt;br /&gt;
&lt;br /&gt;
=== Multilingualität ===&lt;br /&gt;
&lt;br /&gt;
OMSIWiki ist zweisprachig ausgelegt: Englisch und Deutsch. Wie beim großen Vorbild, der Wikipedia, können die Artikel beider Sprachen miteinander verbunden werden. Dies erfolgt auch auf selbem Wege wie bei Wikipedia. Selbstverständlich ist es erstrebenswert, beide Teile der OMSIWiki auf gleichem Stand zu halten - auch wenn das natürlich praktisch nie ganz der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
=== Zugriff ===&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Wikipedia müsst ihr angemeldet sein, um hier Schreibzugriff zu erhalten. Ich denke, dies ist nicht zu viel verlangt und hilft uns eine gewisse Kontrolle über das Verfassen von Artikeln zu behalten.&lt;br /&gt;
&lt;br /&gt;
== Ultra-Kurzhandbuch ==&lt;br /&gt;
&lt;br /&gt;
Ein paar Hinweise für Neulinge, die sich davor scheuen, das ganze Handbuch zu lesen. Wie &amp;quot;baut&amp;quot; man einen OMSIWiki-Artikel?&lt;br /&gt;
&lt;br /&gt;
* Signatur: Gibt's überm Editor-Fenster einen Button, sonst &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
* Anlegen einer neuen Seite: Nachdem ihr im Forum oder uns Bescheid gegeben habt, gebt ihr den ''wohlüberlegten'' Titel der neuen Seite ins ''Suche''-Feld ein. Es erscheint dann der Vorschlag, ob man diese Seite enlegen möchte? Ein &amp;quot;ja&amp;quot; führt dich dann zum leeren Editorfenster.&lt;br /&gt;
* Eine sinnvolle Gliederung kann folgendermaßen erstellt werden:&lt;br /&gt;
 == Hauptüberschrift ==&lt;br /&gt;
 === Subüberschrift ===&lt;br /&gt;
 ==== Sub-Sub-Überschrift ==== usw.&lt;br /&gt;
* Aufzählungen wie diese werden folgendermaßen durchgeführt:&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 ** Sub-Aufzählungspunkt&lt;br /&gt;
* Ein # statt einem * führt zu numerierten Aufzählungen.&lt;br /&gt;
* Fett- und Kursivschreibung wird mittels Apostrophen markiert:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
''Kursiv''&lt;br /&gt;
'''Fett'''&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Die Zuweisung einer Kategorie (im Beispiel der Kategorie &amp;quot;Busfahren in OMSI&amp;quot;) erfolgt ganz am Ende des Artikels mit &amp;lt;nowiki&amp;gt;[[Kategorie:Busfahren in OMSI]]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Weitere Informationen: [http://meta.wikimedia.org/wiki/Hilfe:Handbuch?uselang=de meta.wikimedia.org/wiki/Hilfe:Handbuch]&lt;br /&gt;
&lt;br /&gt;
== Historie ==&lt;br /&gt;
&lt;br /&gt;
* 8. September 2011 - Marcel Kuhnt: Einrichten der deutschen OMSIWiki und Verlinkung mit der englischen.&lt;br /&gt;
* 13. September 2011 - Marcel Kuhnt: OMSIWiki öffentlich angekündigt.&lt;br /&gt;
&lt;br /&gt;
== Links rund ums Thema OMSI ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.omnibussimulator.de www.omnibussimulator.de] - offizielle Seite von OMSI, dem Omnibussimulator&lt;br /&gt;
* [http://www.omnibussimulator.de/forum/ www.omnibussimulator.de/forum/] - offizielles OMSI-Forum&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&lt;br /&gt;
&lt;br /&gt;
[[Technische Informationen zum MediaWiki]]&lt;br /&gt;
&lt;br /&gt;
[[en:Main Page]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Diskussion:Anzeige_E-Gas&amp;diff=750</id>
		<title>Diskussion:Anzeige E-Gas</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Diskussion:Anzeige_E-Gas&amp;diff=750"/>
		<updated>2012-11-19T06:58:28Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Rechtsschreibung ==&lt;br /&gt;
&lt;br /&gt;
An den Autor des Artikels: Bitte in Zukunft die Rechtsschreibung beachten! Siehe [[Hauptseite]] und [[Hilfe:Regeln]].&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Felix (Keyway)|Felix (Keyway)]] 14:17, 20. Nov. 2011 (MET)&lt;br /&gt;
&lt;br /&gt;
== Informationsgehalt dieser Seite ==&lt;br /&gt;
&lt;br /&gt;
Der Informationsgehalt dieser Seite ist sehr fragwürdig. Bitte die Seite komplett überarbeiten und die einzelnen Arbeitsschritte ausführlicher erklären.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Holmexx|Holmexx]] 07:58, 19. Nov. 2012 (MET)&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=749</id>
		<title>OMSI Plugin Framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=749"/>
		<updated>2012-11-19T06:53:22Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Inhaltsverzeichnis ==&lt;br /&gt;
&lt;br /&gt;
* [[#Vorwort|Vorwort]]&lt;br /&gt;
* [[OMSI Plugin Framework I|Kapitel 1]] - Allgemeines&lt;br /&gt;
** Voraussetzungen und Installation&lt;br /&gt;
* [[OMSI Plugin Framework 2|Kapitel 2]] - Die graue Theorie&lt;br /&gt;
** ein bisschen Theorie muss sein&lt;br /&gt;
* [[OMSI Plugin Framework 3|Kapitel 3]] - Die Plugin-Schnittstelle&lt;br /&gt;
** die Arbeitsweise der Plugin-Schnittstelle&lt;br /&gt;
* [[OMSI Plugin Framework 4|Kapitel 4]] - Das OMSI Plugin Framework&lt;br /&gt;
** detaillierte Beschreibung des Frameworks&lt;br /&gt;
* [[OMSI Plugin Framework 5|Kapitel 5]] - Der OMSI Plugin Log Viewer&lt;br /&gt;
** Beschreibung der Debug-Hilfe zum Debuggen eines Plugins&lt;br /&gt;
* [[OMSI Plugin Framework 6|Kapitel 6]] - Ein Beispielprojekt&lt;br /&gt;
** Beispielprojekt für eine (fast) vollautomatische Klimaanlage&lt;br /&gt;
&lt;br /&gt;
== Vorwort zum Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Liebe angehende Plugin-Programmierer,&lt;br /&gt;
&lt;br /&gt;
dieses Tutorial zum '''''OMSI Plugin Framework''''' ist - wie man so schön neudeutsch sagt, &amp;quot;Working under progress&amp;quot;. Ich stelle das unfertige Tutorial hauptsächlich aus zwei Gründen bereits zur Verfügung:&amp;lt;br&amp;gt;1.) damit diejenigen unter euch, die schon über ausreichende Programmiererfahrung verfügen und ohne viele weitere Erklärungen auskommen, schon mal loslegen können und&amp;lt;br&amp;gt;2.) damit jeder schon während ich die einzelnen Kapitel schreibe, über das Forum Ideen, Verbesserungsvorschläge, Fragen zu Unklarheiten usw. einbringen kann.&lt;br /&gt;
&lt;br /&gt;
Bitte, werdet nicht ungeduldig, wenn mir nicht jeden Tag ein neues Kapitel aus der Feder tropft. Ich habe so nebenbei noch eine 'richtige' Arbeit bei der Berliner Feuerwehr und ... äh, da war doch noch was ... irgendwas war da noch ... was war denn da bloß noch ... ach ja, 'ne Familie ist da ja auch noch.&lt;br /&gt;
&lt;br /&gt;
In diesem Sinne, viel Spass beim programmieren und diskutieren&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Holmexx|Holmexx]] ([[Benutzer Diskussion:Holmexx|Diskussion]]) 07:07, 19. Nov. 2012 (CET)&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Vielleicht hat der/die Eine oder Andere ja schon mal mit dem Gedanken gespielt, sich an ein Plugin heranzuwagen, das Vorhaben aber dann verworfen, weil er/sie gedacht, programmieren ist was für Profis und viel zu schwer. Die Erstellung eines Plugins für den OMSI ist - auch mit geringer Programmiererfahrung - gar nicht so schwierig wie es auf den ersten Blick aussieht. Das Entscheidende wird ja schon hier im [http://www.omnibussimulator.de/omsiwiki.de/index.php?title=Plug-in-Schnittstelle OMSI-Wiki] erklärt. Allerdings beziehen sich diese Erklärungen auf die Programmiersprache Pascal, die einstmals mit Borlands Delphi weite Verbreitung fand. Borland ist seit langem Geschichte und damit Delphi schon fast in Vergessenheit geraten. Die Firma [http://www.embarcadero.com/de/products/delphi Embarcadero] vertreibt zwar Delphi wieder, die Preise dort werden aber jeden Hobbyprogrammierer abschrecken. Die Alternative kommt von Microsoft. Dort kann man sich [http://www.microsoft.com/germany/express/download/default.aspx Visual Studio Express] kostenlos herunterladen. Für die Plugin-Programmierung benötigst Du '''Visual C++ 2010 EXPRESS'''. Wenn Du nun noch über wenigstens grundlegende Kenntnisse in der Programmiersprache C++ verfügst, kann es ja losgehen. Aber halt, warum C++? Geht nicht auch C# oder Visual Basic? Aus technischer Sicht ist es absolut möglich, ein Plugin in C# oder VB zu entwickeln. Allerdings stehen sich mit C#/VB und OMSI zwei Welten gegenüber. Die erste &lt;br /&gt;
Welt ist die des &amp;quot;Managed Code&amp;quot; und die Andere die des &amp;quot;Unmanaged Code&amp;quot;. Um beide Welten zusammen zu bringen, brauchst Du eine Wrapper-DLL. Und die kannst Du nur mit - Du ahnst es bereits - C/C++ programmieren, auch noch verbunden mit einem dramatisch erhöhten Schwierigkeitsgrad. Außerdem macht COM-Programmierung keinen Spaß, sondern ist einfach nur schmerzhaft. Ein weiteres Hindernis ist die Architektur eines &amp;quot;Managed Code&amp;quot;-Programmes. Managed Code ist auf maximale Sicherheit ausgelegt, nicht auf Performance. Es ist ungefähr so, als ob Du mit einer voll gepanzerten Limousine bei der DTM antrittst. Dein Auto ist zwar unkaputtbar, schade ist nur, dass die anderen Fahrer schon beim ersten Bier sitzen nach dem Rennen, während Du noch 6 Runden zu fahren hast. Bleiben wir also lieber bei C++.&lt;br /&gt;
&lt;br /&gt;
Um die Sache, insbesondere für Programmiernovizen, noch etwas zu vereinfachen, habe ich dieses Framework entwickelt, mit dem sich - hoffentlich ;-) - schnell und einfach Plugins programmieren lassen. Ich habe mich ganz bewusst für die Programmiersprache C++ entschieden, obwohl mit dem OpenSource-Projekt [http://www.lazarus.freepascal.org Lazarus] ein gut gelungener Delphi-Klon existiert und man damit sogar in reinrassigem Pascal im Delphi-Stil programmieren könnte. Aber C++ ist doch noch etwas systemnaher als Pascal und bietet dem Plugin-Programmierer Möglichkeiten, die in Pascal nur recht umständlich oder sogar überhaupt nicht möglich wären (z.B. Klassen-Templates, Verwendung von Makros).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorials für Addon-Entwickler]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=748</id>
		<title>Hauptseite</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Hauptseite&amp;diff=748"/>
		<updated>2012-11-19T06:49:30Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;font style=&amp;quot;font-size:1.2em;&amp;quot;&amp;gt;&lt;br /&gt;
'''Herzlich willkommen auf der deutschen Version von OMSIWiki!'''&lt;br /&gt;
&lt;br /&gt;
Hier geht's direkt zu einer der Hauptkategorien:&lt;br /&gt;
&lt;br /&gt;
* [[FAQs - Häufig gestellte Fragen]]&lt;br /&gt;
* [[:Kategorie:Busfahren in OMSI|Busfahren in OMSI]]&lt;br /&gt;
* Entwicklung von Addons:&lt;br /&gt;
** [[:Kategorie:Nachschlagewerk für Addon-Entwickler|Nachschlagewerk]]&lt;br /&gt;
** [[:Kategorie:Tutorials für Addon-Entwickler|Tutorials]]&lt;br /&gt;
** [[:Kategorie:Tipps und Tricks für Addon-Entwickler|Tipps und Tricks]]&lt;br /&gt;
* [[:Kategorie:Anschlussprojekte|Anschlussprojekte (z.B. Addon-Manager, OAT)]]&lt;br /&gt;
* [[:Kategorie:Addon-Präsentationen|Addon-Präsentationen]]&lt;br /&gt;
* [[:Kategorie:Hintergrundinformationen|Hintergrundinformationen]]&lt;br /&gt;
&lt;br /&gt;
'''Achtung: Vor dem Verfassen eigener Beiträge bitte zuerst die Regeln lesen!''' Weiter unten gibt es noch eine Ultra-Kurzanleitung für Neulinge.&lt;br /&gt;
&lt;br /&gt;
''Aktuell in Arbeit:''&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Tutorial zum programmieren eines OMSI-Plugins in C++ --[[Benutzer:Holmexx|Holmexx]] 07:49, 19. Nov. 2012 (MET) &lt;br /&gt;
* Übersetzen der Artikel, zuletzt [[Repainting of OMSI buses (also over panes)]] --[[Benutzer:Dario|Dario]] 12:04, 17. Jul. 2012 (MEST)&lt;br /&gt;
* [[Fahrpläne erstellen]] --[[Benutzer:Felix (Keyway)|Felix (Keyway)]] 16:21, 31. Dez. 2011 (MET) ----- Weitergeführt von [[Benutzer:Dario|Dario]] 11:33, 18. Jul. 2012 (MEST)&lt;br /&gt;
* ''(aktuell pausiert)'' [[Fahrzeug-SDK]] (c) von Rüdiger, Einbau ins OMSIWiki von --[[Benutzer:Marcel Kuhnt|Marcel Kuhnt]] 16:12, 2. Dez. 2011 (MET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Wir Entwickler von OMSI haben OMSIWiki eingerichtet, um eine bessere Plattform für alle Arten von Informationen rund um OMSI zu erhalten. Folgende Themengebiete sind von uns vorläufig vorgesehen:&lt;br /&gt;
&lt;br /&gt;
* Präsentation von Hintergrundinformationen über das Addon-Design von unserer Seite (Objekt- und Fahrzeugbar, Soundengine, Scriptengine usw.)&lt;br /&gt;
* Tipps und Tricks oder auch ganze Tutorials von Usern z.B. zum Erstellen von Repaints oder Mapbau würden unsere Kernthemen abrunden. Entweder als Ergänzung unserer oder als weiterreichende Artikel.&lt;br /&gt;
* Die Bedienung von OMSI und insbesondere der Busse könnte ein weiterer Themenkomplex sein. Zwar gibt es natürlich ein Handbuch für OMSI, dennoch gibt es vieleicht die eine oder andere Sache, die ausführlicher erklärt werden soll. Hier werden wir uns allerdings etwas zurückhalten.&lt;br /&gt;
* Weiterhin könnten hier bewährte Anschlussprojekte zu OMSI präsentiert werden, z.B. OAT oder der Addon-Manager. Höchstwahrscheinlich werden die zugehörigen Artikel dann von den Leitern oder treuesten Fans dieser Projekte geschrieben, wir werden uns hier ebenfalls zurückhalten.&lt;br /&gt;
* Ähnlich hierzu haben wir nichts gegen eine hochqualitative Präsentation von komplexen Addons; denkbar wäre hier z.B. die Bedienungsanleitung eines Addon-Busses oder die Beschreibung und Hinweise für die Fahrt durch eine Addon-Karte mit Fahrplänen und/oder Karten. Wo wir hier allerdings die Grenze setzen, steht noch nicht fest. Insbesondere sollen hier keine &amp;quot;Mini-Artikel&amp;quot; entstehen, wo nur ein Screenshot von einem Repaint und ein Download-Link präsentiert wird!&lt;br /&gt;
* Selbstverständlich dürfen hier auch gerne Hintergrundinformationen zu unserer Strecke oder unseren Bussen oder aber zu Addons gegeben werden (wie sah Spandau in der Realität 1989 aus? Wie wurde damals in Berlin Bus gefahren?). Es sollte sich aber um abgeschlossene und ernsthaft geschriebene Artikel handeln und es sollte definitiv ein Bezug zu OMSI vorhanden sein! Also keine schnell hingeschriebenen Tagesberichte von irgendeinem Busunternehmen, was keiner kennt und was auch nicht in OMSI mindestens als Addon simuliert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Regeln ==&lt;br /&gt;
&lt;br /&gt;
=== Ist das Thema hier erwünscht? ===&lt;br /&gt;
&lt;br /&gt;
Der Idee von OMSIWiki entsprechend sollte jeder Artikel letztlich in eine der oben genannten Kategorien passen!&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Goldene Regel&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
Zunächst die '''&amp;quot;goldene Regel&amp;quot;''': Bevor ein Artikel verfasst oder geändert wird, sollte stets geschaut werden, ob sich an den Regeln etwas geändert hat! Gerade in der Anfangszeit wird es sicher vorkommen, dass sich Regeln ändern oder neue hinzukommen.&lt;br /&gt;
&lt;br /&gt;
=== Erwünscht ===&lt;br /&gt;
&lt;br /&gt;
* Wenn ihr einen kleinen oder großen Fehler entdeckt (auch in einem unserer Artikel!), dann darf ihn jeder korrigieren! Aber nur, wenn ihr euch dabei auch sicher seid.&lt;br /&gt;
* Ihr findet einen Artikel z.B. im Addon-Handbuch zu trocken? Dann dürft ihr gerne ein kleines Beispiel ergänzen! Von mir weiß ich z.B., dass die Anschauung und Klarheit leidet, wenn ich viele und lange Texte schreibe!&lt;br /&gt;
* Ihr findet einen Fachbegriff, der nicht erklärt wird? Wenn es ein bisher nicht erklärter Begriff von OMSI ist, dürft ihr gerne einen Artikel anfertigen und ihn mit dem Fachbegriff verlinken; handelt es sich um einen allgemeinen Fachbegriff, dann reicht meist ein externer Link zu einem entsprechenden Artikel z.B. in der Wikipedia aus.&lt;br /&gt;
* Um zu vermeiden, dass euch bereits jemand anderes &amp;quot;dazwischen funkt&amp;quot;, obwohl euer Artikel noch gar nicht fertig ist, ergänzt bitte hierzu oben den Hinweis: &amp;quot;''Hinweis: Dieser Artikel befindet sich noch im Aufbau!''&amp;quot;. Dadurch wird auch vermieden, dass der unter Umständen erst halbfertige Artikel schon von jemandem übersetzt wird, sodass nach Fertigstellung der deutschen Version die englische noch unvollständig ist.&lt;br /&gt;
* Wenn euer Artikel auch ein englischsprachiges Pendant hat, dann verknüpft ihn bitte! Ein Blick ans Ende des Quelltextes ''dieser'' Seite zeigt euch, wie das geht! Hat er jedoch ''kein'' Pendant und muss demnach in der englischen OMSIWiki noch angelegt werden, so wäre ein Hinweis ganz oben nicht schlecht: &amp;quot;''Hinweis: Dieser Artikel wurde noch nicht ins Englische übersetzt!''&amp;quot; oder &amp;quot;''Hinweis: Die englische Version muss noch aktualisiert werden!''&amp;quot;&lt;br /&gt;
* Wenn ihr Spaß am Übersetzen habt, dann könnt ihr eine sehr wertvolle Hilfe für OMSIWiki sein! Wenn ihr einen dieser Hinweise entdeckt, scheut euch nicht, den Artikel in die englische OMSIWiki einzupflegen! Ihr solltet danach aber den Original-Autor informieren (damit er die Gelegenheit hat, einmal drüber zu schauen) und dann natürlich die beidseitige Verlinkung mit der deutschen Seite vornehmen und den Hinweis entfernen.&lt;br /&gt;
&lt;br /&gt;
=== Unerwünscht ===&lt;br /&gt;
&lt;br /&gt;
* '''Ganz wichtig: Der Name des Artikels muss wohlüberlegt gewählt werden, weil man den nicht mal eben ändern kann! Wer hier grob fahrlässig schlampt, fliegt raus!'''&lt;br /&gt;
* Schlechter Schreibstil! Was im Chat normal ist und im Forum zwangsweise geduldet wird, ist hier tabu: Bitte gebt euch etwas Mühe, wenn ihr hier einen Artikel verfasst!&lt;br /&gt;
* Werbung für unbekannte, kleine Projekte, Foren, virtuelle Gesellschaften etc. Der Sinn von OMSIWiki ist nicht die Werbung für Projekte! Es soll eine Informationsplattform sein!&lt;br /&gt;
&lt;br /&gt;
Hier dazu was Passendes zum schmunzeln: [http://meta.wikimedia.org/wiki/Wikipedia_Anti-Regeln Wikipedia-Anti-Regeln]&lt;br /&gt;
&lt;br /&gt;
=== Absprachen ===&lt;br /&gt;
&lt;br /&gt;
* Vor Beginn der Arbeit bitte oben bei &amp;quot;Aktuell in Arbeit&amp;quot; eine Zeile mit der geplanten Arbeit und eurer Signatur ergänzen. Nach Fertigstellung diesen wieder entfernen. Sollte jedoch dann gar kein Punkt mehr übrigbleiben, dann ein &amp;quot; * ''Nichts'' &amp;quot; stehen lassen.&lt;br /&gt;
* Wenn ihr größere Korrekturen an unseren Artikeln vornehmt, wär es natürlich gut, wenn ihr uns zumindest nachher darüber informiert, damit wir den Überblick behalten.&lt;br /&gt;
* Bevor ein neuer Artikel verfasst wird, kann es nicht schaden, kurz eine E-Mail an uns Administratoren zu schicken mit euren Planungen.&lt;br /&gt;
* Das Einführen neuer Kategorien hat grundstätzlich in Absprache mit den Administratoren zu geschehen.&lt;br /&gt;
&lt;br /&gt;
* Beachtet auch die Möglichkeit, mit den Autoren auf der Diskussionsseite zu diskutieren! Wie der &amp;quot;Quellcode&amp;quot; einer Diskussionsseite aussieht, seht ihr hier: [[Diskussion:OMSI_Addon_Tester_(OAT)]]. Und nicht vergessen: Die Signatur könnt ihr automatisch erzeugen mit &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;!&lt;br /&gt;
&lt;br /&gt;
=== Multilingualität ===&lt;br /&gt;
&lt;br /&gt;
OMSIWiki ist zweisprachig ausgelegt: Englisch und Deutsch. Wie beim großen Vorbild, der Wikipedia, können die Artikel beider Sprachen miteinander verbunden werden. Dies erfolgt auch auf selbem Wege wie bei Wikipedia. Selbstverständlich ist es erstrebenswert, beide Teile der OMSIWiki auf gleichem Stand zu halten - auch wenn das natürlich praktisch nie ganz der Fall sein kann.&lt;br /&gt;
&lt;br /&gt;
=== Zugriff ===&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur Wikipedia müsst ihr angemeldet sein, um hier Schreibzugriff zu erhalten. Ich denke, dies ist nicht zu viel verlangt und hilft uns eine gewisse Kontrolle über das Verfassen von Artikeln zu behalten.&lt;br /&gt;
&lt;br /&gt;
== Ultra-Kurzhandbuch ==&lt;br /&gt;
&lt;br /&gt;
Ein paar Hinweise für Neulinge, die sich davor scheuen, das ganze Handbuch zu lesen. Wie &amp;quot;baut&amp;quot; man einen OMSIWiki-Artikel?&lt;br /&gt;
&lt;br /&gt;
* Signatur: Gibt's überm Editor-Fenster einen Button, sonst &amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
* Anlegen einer neuen Seite: Nachdem ihr im Forum oder uns Bescheid gegeben habt, gebt ihr den ''wohlüberlegten'' Titel der neuen Seite ins ''Suche''-Feld ein. Es erscheint dann der Vorschlag, ob man diese Seite enlegen möchte? Ein &amp;quot;ja&amp;quot; führt dich dann zum leeren Editorfenster.&lt;br /&gt;
* Eine sinnvolle Gliederung kann folgendermaßen erstellt werden:&lt;br /&gt;
 == Hauptüberschrift ==&lt;br /&gt;
 === Subüberschrift ===&lt;br /&gt;
 ==== Sub-Sub-Überschrift ==== usw.&lt;br /&gt;
* Aufzählungen wie diese werden folgendermaßen durchgeführt:&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 * Aufzählungspunkt&lt;br /&gt;
 ** Sub-Aufzählungspunkt&lt;br /&gt;
* Ein # statt einem * führt zu numerierten Aufzählungen.&lt;br /&gt;
* Fett- und Kursivschreibung wird mittels Apostrophen markiert:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
''Kursiv''&lt;br /&gt;
'''Fett'''&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Die Zuweisung einer Kategorie (im Beispiel der Kategorie &amp;quot;Busfahren in OMSI&amp;quot;) erfolgt ganz am Ende des Artikels mit &amp;lt;nowiki&amp;gt;[[Kategorie:Busfahren in OMSI]]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Weitere Informationen: [http://meta.wikimedia.org/wiki/Hilfe:Handbuch?uselang=de meta.wikimedia.org/wiki/Hilfe:Handbuch]&lt;br /&gt;
&lt;br /&gt;
== Historie ==&lt;br /&gt;
&lt;br /&gt;
* 8. September 2011 - Marcel Kuhnt: Einrichten der deutschen OMSIWiki und Verlinkung mit der englischen.&lt;br /&gt;
* 13. September 2011 - Marcel Kuhnt: OMSIWiki öffentlich angekündigt.&lt;br /&gt;
&lt;br /&gt;
== Links rund ums Thema OMSI ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.omnibussimulator.de www.omnibussimulator.de] - offizielle Seite von OMSI, dem Omnibussimulator&lt;br /&gt;
* [http://www.omnibussimulator.de/forum/ www.omnibussimulator.de/forum/] - offizielles OMSI-Forum&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&lt;br /&gt;
&lt;br /&gt;
[[Technische Informationen zum MediaWiki]]&lt;br /&gt;
&lt;br /&gt;
[[en:Main Page]]&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_II&amp;diff=747</id>
		<title>OMSI Plugin Framework II</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_II&amp;diff=747"/>
		<updated>2012-11-19T06:41:46Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Die Seite wurde neu angelegt: „== Die graue Theorie ==  Keine Angst, Du musst Dich jetzt nicht durch seitenlange, staubtrockene Texte wühlen, aber um ein bisschen Theorie kommen wir nicht drum…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Die graue Theorie ==&lt;br /&gt;
&lt;br /&gt;
Keine Angst, Du musst Dich jetzt nicht durch seitenlange, staubtrockene Texte wühlen, aber um ein bisschen Theorie kommen wir nicht drumherum. Dieses Kapitel soll auch keine umfassende Einführung in die Programmiersprache C/C++ und in die Spieleprogrammierung sein, sondern eher Anfängern und Unerfahrenen ein paar Tipps geben, damit sie wenigstens die größten Fettnäpfchen auslassen können.&lt;br /&gt;
&lt;br /&gt;
=== Die Regel Nummer 1 ===&lt;br /&gt;
&lt;br /&gt;
Das Plugin, dass Du entwickeln willst, ist ja Bestandteil eines Spieles (nämlich des OMSI) und damit bist Du nun quasi Spieleprogrammierer. Ein Spieleprogrammierer muss sich aber einigen Regeln unterwerfen. Die Regel Nummer 1 heißt: Performance, Performance und noch mal Performance. Ein ungeschickt programmiertes Plugin kann die Framerate des OMSI (die ja schon recht knapp ist) in absolut frostige Tiefen drücken. Das musst Du Dir während der ganzen Programmierung ständig vor Augen halten. Wenn Du z.B. für ein Problem mehrere Lösungswege gefunden hast, solltest Du Dir wirklich die Mühe machen, sie alle nacheinander auszuprobieren. Das kostet viel Zeit, ist aber letztendlich die einzige Möglichkeit, die performanteste Lösung zu finden.&lt;br /&gt;
&lt;br /&gt;
Wie Du in den weiteren Abschnitten noch feststellen wirst, ist es aber abseits der Regel Nummer 1 kaum möglich, eine starre Richtlinie aufzustellen. Du wirst immer einen Kompromiss eingehen müssen. Welches Ergebnis das Beste ist, kannst Du nur durch umfangreiche Tests herausfinden. Und diese Tests solltest Du z.B. von einem Freund durchführen lassen, der von Programmierung gar keine Ahnung hat. Das hat im Wesentlichen zwei Gründe: zum Einen sind Programmierer kurioserweise bei ihren Tests kaum in der Lage, ihre eigenen Fehler zu finden (kein Scherz) und zum Anderen wirst Du verwundert sein auf welche Ideen Benutzer kommen, an die Du bei der Programmierung nicht mal im Traum gedacht hast und die - selbstverständlich - zu Fehlern mit Programmabsturz führen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeitsspeicher ===&lt;br /&gt;
&lt;br /&gt;
Eine andere Regel ist, den zur Verfügung stehenden Arbeitspeicher klug einzusetzen. Heutzutage, wo die meisten Computer in aller Regel über mehrere Gigabyte Speicher verfügen, ist das zwar nicht mehr ganz so eng wie früher, wo wirklich noch um jedes einzelne '''Byte''' gekämpft werden musste. Aus den Augen verlieren darf man das Thema trotzdem nicht. Das Schlimmste was passieren kann, ist, das einem Prozess der Arbeitsspeicher ausgeht. Dann muss Windows nämlich Speicher frei machen, indem es Bereiche des Arbeitsspeichers in die sogenannte Auslagerungsdatei auslagert. Und das ist '''''die''''' Performancebremse überhaupt. Wenn das, vielleicht auch noch mehrfach, passiert, wird das Spiel zu einer reinen Diashow verkommen. Performance und Arbeitsspeicher sind zwei Dinge, die eng miteinander verzahnt sind. Meistens ist es performanter, temporäre (zeitweilige, nur zu diesem Zweck angelegte) Variablen anzulegen und mit diesen eine Aufgabe zu lösen. Wenn aber das Anlegen der temporären Variablen dazu führt, das ersteinmal neuer Arbeitspeicher bei Windows angefordert werden muss, hat sich der ganze Performancevorteil in Nichts aufgelöst. Das gilt insbesondere für das Anlegen von (besonders) großen Datenstrukturen im sogenannten Stack. Der Stack ist in seiner Größe nämlich begrenzt. Er kann zwar vergrößert werden, aber das ist performancetechnisch so teuer, das es ein einem Spiel praktisch nicht vorkommen sollte. Falls so etwas in Deinem Code passiert, ist schlicht und ergreifend das Codedesign falsch und muss unbedingt überarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Datenstrukturen, die Du mehrfach benötigst, legst Du natürlich in der Initialisierungphase an (also bei Aufruf der Funktion '''''Start''''' durch den OMSI) und nicht kurz vor jeder Verwendung. Das würde zwar (vielleicht) den Arbeitsspeicherverbrauch des Programmes reduzieren, kostet aber wertvolle CPU-Zeit (siehe Regel Nummer 1).&lt;br /&gt;
&lt;br /&gt;
=== Fehlerbehandlung ===&lt;br /&gt;
&lt;br /&gt;
Ein weiteres Thema ist die Fehlerbehandlung. Gerade bei der Fehlerbehandlung ist es wichtig, einen gesunden Kompromiss zwischen Absturzsicherheit des Programmes und Performance zu finden. Selbstverständlich möchte jeder, das es nicht zu Programmabstürzen kommt - schon gar nicht in einem Spiel. Überlegungen dazu sind deshalb so wichtig, weil ein gravierender Fehler in Deinem Plugin den gesamten OMSI ins Byte-Nirvana reißen wird. &lt;br /&gt;
&lt;br /&gt;
Eine Technik zur Fehlerbehandlung die C++ bietet, ist die Möglichkeit, Codeabschnitte in try/except-Klammern einzufassen. Ganz allgemein sieht das so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 __try&lt;br /&gt;
 {&lt;br /&gt;
    // hier kommt der Code, der zu einem Fehler führt, z.B.:&lt;br /&gt;
    float x = 5;&lt;br /&gt;
    float y = 0;&lt;br /&gt;
    float z = x / y;  // Super-Idee, diese Division durch 0 ;-)&lt;br /&gt;
    // Code, der jetzt noch hier kommt, wird nie mehr ausgeführt, da die &lt;br /&gt;
    // vorherige Zeile zu einer Division-durch-0-Exception führt&lt;br /&gt;
 }&lt;br /&gt;
 __except ( EXCEPTION_HANDLER )&lt;br /&gt;
 {&lt;br /&gt;
    // mache irgendetwas, um den Fehler wieder gerade zu biegen&lt;br /&gt;
 }&lt;br /&gt;
 // hier gehts ganz normal weiter, als ob nichts passiert wäre&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das hemmungslose Benutzen von try/except und Performance sind allerdings zwei Dinge, die schlecht zusammen passen. Try/except kostet nämlich CPU-Zeit und sollte nur an klug überlegten Stellen eingesetzt werden. Wenn Du in Deinem Code eine Funktion aufrufst die Du nicht selbst geschrieben hast und wo die Dokumentation schon sagt, das im Fehlerfall die oder die Exception auftreten kann, musst Du natürlich try/except verwenden. In selbst geschriebenem Code solltest Du Exceptions vermeiden. Besser ist es, wenn die Funktion im Fehlerfall einen Fehlercode zurückliefert. Dazu zwei Beispiele:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 int NichtSoGuteFunktion(int irgend_ein_wichtiger_wert)&lt;br /&gt;
 {&lt;br /&gt;
    if (irgend_ein_wichtiger_wert != wert_den_ich_hier_erwarte)&lt;br /&gt;
    {&lt;br /&gt;
        throw new exception_xy ( ... );  // sicher, aber teuer&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // weitere Verarbeitung&lt;br /&gt;
    // ...&lt;br /&gt;
 &lt;br /&gt;
    return ergebnis;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein besserer Ansatz könnte so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 enum MeineFehlerwerte&lt;br /&gt;
 {&lt;br /&gt;
    Bescheuerter_Fehler      = -1,&lt;br /&gt;
    Zu_wenig_Kaffee_Fehler   = -2,&lt;br /&gt;
    Zu_viel_Pizza_Fehler     = -3,&lt;br /&gt;
    // usw.&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 int BessereFunktion(int irgend_ein_wichtiger_wert, int* zeiger_auf_variable_die_ergebnis_speichert)&lt;br /&gt;
 {&lt;br /&gt;
    if (irgend_ein_wichtiger_wert != wert_den_ich_hier_erwarte)&lt;br /&gt;
    {&lt;br /&gt;
        return Bescheuerter_Fehler;  // genau so sicher, aber VIEL billiger&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // weitere Verarbeitung&lt;br /&gt;
    // ...&lt;br /&gt;
 &lt;br /&gt;
    *zeiger_auf_variable_die_ergebnis_speichert = ergebnis;&lt;br /&gt;
    return ERROR_SUCCESS; // ERROR_SUCCESS ist vordefiniert und hat den Wert 0&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
Eine Andere, ganz große Kasperfalle ist die Verwendung von nicht initialisierten Variablen, allen voran, die Zeigervariablen. Diese Fehler sind später außerdem relativ schwierig zu entdecken. Im Gegensatz zu z.B. Visual Basic werden bei C/C++ Variablen bei ihrer Deklaration nicht mit einem Wert vorbelegt. Deshalb ist es ganz wichtig, alle Variablen vor ihrer ersten Verwendung mit einem bestimmten Wert zu initialisieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  int variable;           // Variable hat einen zufälligen Inhalt, ist aber meistens weniger gefährlich&lt;br /&gt;
  char* zeiger_variable;  // Variable hat einen zufälligen Inhalt, Verwendung führt totsicher zum Programmabsturz&lt;br /&gt;
 &lt;br /&gt;
  // irgendwo später im Code:&lt;br /&gt;
  if (zeiger_variable != NULL) { ... }  // Absturz ist sicher, da ohne Initialisierung zeiger_variable niemals NULL ist !!!&lt;br /&gt;
 &lt;br /&gt;
  // deshalb immer so:&lt;br /&gt;
  int variable = 0;&lt;br /&gt;
  char* zeiger_variable = NULL;&lt;br /&gt;
 &lt;br /&gt;
  // irgendwo später im Code:&lt;br /&gt;
  if (zeiger_variable != NULL) { ... }  // Alles o.k., da durch Initialisierung zeiger_variable NULL sein kann&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das teuflische an der Sache ist, das die in den Kommentaren als ''totsicher'' und ''niemals'' deklarierten Dinge gar nicht so totsicher sind. Natürlich kann es sein, das der Speicher, der der Variablen durch den Compiler zugewiesen wird, rein zufällig tatsächlich NULL ist. Und laut Murphy's Law ist das bei den ersten drei Programmtests auch so. Beim vierten Test aber plötzlich nicht mehr und das Programm stürzt ab. Und dann geht die verzweifelte Fehlersuche los ...&lt;br /&gt;
&lt;br /&gt;
=== Objektorientierte Programmierung vs. prozedurale Programmierung ===&lt;br /&gt;
&lt;br /&gt;
So manch Hardcore-Spieleprogrammierer wird die Nase rümpfen und denken, objektorientierte Programmierung (wird im OMSI Plugin Framework verwendet), das geht gar nicht, das macht man doch nicht. Ich muss leider zugeben, so ganz unrecht haben sie nicht. Objektorientierte Programmierung erzeugt nämlich einen gewissen Overhead, der CPU-Zeit kostet. Und das ist ja bekanntlich die teuerste Resource, die uns zur Verfügung steht. Aber wie Du eingangs ja schon festgstellt hast, must Du auch hier einen Kompromiss eingehen. Auf der einen Seite steht der Overhead durch die Verwendung von Klassen, auf der anderen Seite steht ein einfacherer, übersichtlicherer Code, der besonders Programmieranfängern den Einstieg erleichtern wird. Wenn Du schon über ausreichend Programmiererfahrung verfügst, kannst Du ja mal versuchen, das Framework in eine rein prozedurale Variante zu überführen. Du wirst feststellen, dass das gar nicht so einfach ist und möglicherweise Anfänger ziemlich überfordert.&lt;br /&gt;
&lt;br /&gt;
Der Overhead bei der Verwendung von Klassen entsteht dadurch, dass jedem Methodenaufruf ein unsichtbarer Parameter (der sogenannte '''this'''-Zeiger) mitgegeben wird. In Pseudo-Assembler sieht das etwa so aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 push  parameter_1&lt;br /&gt;
 push  parameter_2&lt;br /&gt;
 ; usw.&lt;br /&gt;
 mov   ecx, this  ; &amp;lt;-- der zusätzliche Assembler-Befehl&lt;br /&gt;
 call  method_xy&lt;br /&gt;
 ; ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Gleiche gilt für die Verwendung der Felder einer Klasse. Auch der Zugriff erfolgt über den '''this'''-Zeiger. Ein etwas größerer Overhead entsteht noch, wenn die Klasse virtuelle Methoden verwendet. Dann muss nämlich noch eine Tabelle für die virtuellen Methoden angelegt werden und der Aufruf der Methoden erfolgt dann indirekt über diese Tabelle.&lt;br /&gt;
Alles zusammen genommen denke ich aber, das der Overhead für unsere modernen Prozessoren gering ist und die Vorteile der objektorientierten Programmierung überwiegen.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework III|[zum Kapitel 3]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Datei:Project_created.png&amp;diff=746</id>
		<title>Datei:Project created.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Datei:Project_created.png&amp;diff=746"/>
		<updated>2012-11-19T06:40:01Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Datei:Omsi_plugin_project.png&amp;diff=745</id>
		<title>Datei:Omsi plugin project.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Datei:Omsi_plugin_project.png&amp;diff=745"/>
		<updated>2012-11-19T06:39:45Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Datei:New_projekt.png&amp;diff=744</id>
		<title>Datei:New projekt.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=Datei:New_projekt.png&amp;diff=744"/>
		<updated>2012-11-19T06:39:23Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_I&amp;diff=743</id>
		<title>OMSI Plugin Framework I</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework_I&amp;diff=743"/>
		<updated>2012-11-19T06:38:27Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Die Seite wurde neu angelegt: „== Allgemeines ==  === Voraussetzungen ===  Beginnen wir mit einer Definition:  &amp;lt;tt&amp;gt;Ein Programmierer ist eine Maschine, die riesige Mengen Kaffee, Pizza und Scho…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
=== Voraussetzungen ===&lt;br /&gt;
&lt;br /&gt;
Beginnen wir mit einer Definition:&lt;br /&gt;
 &amp;lt;tt&amp;gt;Ein Programmierer ist eine Maschine, die riesige Mengen Kaffee, Pizza und Schokolade zu Programmcode verarbeitet.&amp;lt;/tt&amp;gt;&lt;br /&gt;
Wenn Du also dazu in der Lage bist, hast Du die erste Hürde schon mal genommen. Und die Zweite gleich mit: Du kannst nämlich sogar über uralte Kalauer - naja, wenigstens schmunzeln. So, jetzt wirds aber ernst. Um ein brauchbares Plugin zu produzieren, solltest Du &lt;br /&gt;
&lt;br /&gt;
* über Basiswissen in der Programmiersprache C/C++ verfügen&lt;br /&gt;
* zumindestens ganz grob wissen, was man unter objektorientierter Programmierung versteht (und wenn nicht: am Ende dieses Tutorials weißt Du es)&lt;br /&gt;
* wissen, wozu Klassen in C++ gut sind und wie man mit ihnen umgeht&lt;br /&gt;
&lt;br /&gt;
Das wäre für den Anfang schon mal gar nicht schlecht. Da Du zum Debuggen Deines Plugins den Debugger des Visual Studios nicht verwenden kannst, gehört zum OMSI Plugin Framework auch eine Debug-Hilfe - der '''''OMSI Plugin Log Viewer''''' (mir ist kein längerer Titel eingefallen, deshalb muss es so gehen). Um den Log Viewer sinnvoll einsetzen zu können, musst Du einen zweiten Bildschirm an Deinem Computer haben oder - noch besser - einen weiteren Windows-Computer in Deinem lokalen Netzwerk. Als Programmierwerkzeug eignet sich das bereits im Vorwort erwähnte '''''Visual Studio Express''''' (und natürlich auch alle seine großen Brüder und Schwestern) hervorragend. Der Log Viewer und das Setup-Programm des ''OMSI Plugin Frameworks'' benötigen das Microsoft '''''.Net-Framework 4'''''. Und last but not least benötigst Du natürlich ;-) das '''''OMSI Plugin Framework'''''.&lt;br /&gt;
&lt;br /&gt;
Die Voraussetzungen noch einmal zusammengefasst:&lt;br /&gt;
# &amp;lt;del&amp;gt;Master-Abschluss in IT-Wissenschaften (Promotion wird empfohlen)&amp;lt;/del&amp;gt; :-D&lt;br /&gt;
# zweiter Bildschirm oder Netzwerk-Computer mit mindestens Windows-XP&lt;br /&gt;
# [http://www.microsoft.com/de-de/download/details.aspx?id=17718 Download] des Microsoft .Net Framework 4&lt;br /&gt;
# [http://www.microsoft.com/germany/express/download/default.aspx Download] des Microsoft Visual Studio (Express)&lt;br /&gt;
# [http://omsi.sovoma.de/downloads/opf.zip Download] des OMSI Plugin Framework&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
[[Datei:new_projekt.png|100px|thumb|right|Bild 1]]&lt;br /&gt;
[[Datei:omsi_plugin_project.png|100px|thumb|right|Bild 2]]&lt;br /&gt;
[[Datei:project_created.png|100px|thumb|right|Bild 3]]&lt;br /&gt;
&lt;br /&gt;
Als erstes solltest Du das '''''.Net Framework 4''''' installieren, falls es auf Deinem Computer noch nicht vorhanden ist. Starte also die Installation des '''''.Net Framework 4''''' und erledige in aller Ruhe Deinen Wochenend-Einkauf. Ein herzliches ''Danke schön'' an Microsoft an dieser Stelle für diesen exzellenten Installer. Ach ja, falls Du die automatischen Updates für Windows eingeschaltet hast, wird Dich früher oder später noch das Service Pack 1 für das '''''.Net Framework 4''''' überraschen. Auch dessen Installation dauert so 1-2 Microsoft-Minuten. &lt;br /&gt;
&lt;br /&gt;
Die Installation des '''''Visual Studio Express''''' dagegen ist völlig unkompliziert und in kurzer Zeit erledigt. Nachdem diese Installation abgeschlossen ist, solltest Du als nächstes das '''''OMSI Plugin Framework''''' installieren. Entpacke dazu das heruntergeladene Archiv in einen Ordner Deiner Wahl und starte '''opfsetup.exe'''. Die '''opfsetup.exe''' muss mit Administratorrechten laufen, da zum Einbinden der Projektvorlage ins Visual Studio u.a. Einträge in der Windows-Registry und im ''Programme''-Ordner gemacht werden, welcher für sogenannte ''eingeschränkte Benutzer'' nicht beschreibbar ist. Außerdem wird Windows noch meckern, dass der Herausgeber des Programmes unbekannt ist. Aus Windows-Sicht stimmt das auch, weil die digitale Signatur fehlt. Aber ich will einfach nicht mehrere 100 Dollar pro Jahr ausgeben, nur um ein paar mal meine eigenen Programme digital signieren zu können. Du darfst mir aber vertrauen: '''opfsetup.exe''' ist kein bösartiges Programm, sofern Du es mit dem obigen Link heruntergeladen hast. Das ist nämlich mein eigener Server und der ist ungezieferfrei! Die Installation des Frameworks sollte nach dem Klick auf &amp;quot;Installieren&amp;quot; im Bruchteil einer Sekunde erledigt sein.&lt;br /&gt;
&lt;br /&gt;
Wenn Du den Log Viewer auf einem anderen Computer im Netzwerk laufen lassen willst, musst Du die Leiden mit dem '''''.Net Framework 4''''' auf diesem Computer noch einmal ertragen. Auch auf diesem Computer musst Du das '''''OMSI Plugin Framework''''' herunterladen und entpacken. Natürlich muss '''opfsetup.exe''' auf diesem Computer '''''nicht''''' ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Wenn Du das alles durchgestanden hast, muss nur noch der Log Viewer '''NICHT''' installiert werden. Im Ernst, für den Log Viewer ist keine Installation notwendig. Falls Du den Log Viewer mal in einen anderen Ordner oder auf einen anderen Computer (auf dem das .Net Framework 4 schon existiert) verfrachten willst, musst Du nur darauf achten, das die beiden Dateien ''OMSIPluginLogViewer.exe'' und ''Ionic.Zip.dll'' zusammen bleiben. Das ist alles.&lt;br /&gt;
&lt;br /&gt;
Wenn alles geklappt hat, machen wir doch mal den großen Test. Starte Visual Studio, habe ein bisschen Geduld (nur der allererste Start dauert etwas) und klicke im Start-Bildschirm auf '''Neues Projekt''' (Bild 1). Es öffnet sich der Einstellungsdialog für ein neues Projekt. Klicke im linken Teil unterhalb von '''Visual C++''' auf den Ordner '''OMSI'''. In diesem Ordner gibt es nur eine Projektvorlage, ein OMSI Plugin (Bild 2). Gib dem neuen Projekt noch einen Namen (Eingabefeld '''Name''' am unteren Rand), die anderen Eingabefelder kannst Du so belassen, wie sie sind. Klicke nun auf '''OK''', um das Projekt anzulegen. Es erscheint noch ein Zwischendialog, in dem es aber nichts einzustellen gibt. Klicke nochmals auf '''Erstellen'''. Nach kurzer Zeit sollte Dein Bildschirm wie auf dem Bild 3 aussehen.&lt;br /&gt;
&lt;br /&gt;
Damit belassen wir es ersteinmal. Es sollte nur ein Test sein, ob die Installation insgesamt funktioniert hat.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |[[OMSI Plugin Framework|[zum Inhaltsverzeichnis]]]&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework II|[zum Kapitel 2]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
	<entry>
		<id>http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=742</id>
		<title>OMSI Plugin Framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.omnibussimulator.de/omsiwikineu.de/index.php?title=OMSI_Plugin_Framework&amp;diff=742"/>
		<updated>2012-11-19T06:36:46Z</updated>

		<summary type="html">&lt;p&gt;Holmexx: Die Seite wurde neu angelegt: „== Inhaltsverzeichnis ==  * Vorwort * Kapitel 1 - Allgemeines ** Voraussetzungen und Installation * [[OMSI Plugin Framewo…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Inhaltsverzeichnis ==&lt;br /&gt;
&lt;br /&gt;
* [[#Vorwort|Vorwort]]&lt;br /&gt;
* [[OMSI Plugin Framework I|Kapitel 1]] - Allgemeines&lt;br /&gt;
** Voraussetzungen und Installation&lt;br /&gt;
* [[OMSI Plugin Framework 2|Kapitel 2]] - Die graue Theorie&lt;br /&gt;
** ein bisschen Theorie muss sein&lt;br /&gt;
* [[OMSI Plugin Framework 3|Kapitel 3]] - Die Plugin-Schnittstelle&lt;br /&gt;
** die Arbeitsweise der Plugin-Schnittstelle&lt;br /&gt;
* [[OMSI Plugin Framework 4|Kapitel 4]] - Das OMSI Plugin Framework&lt;br /&gt;
** detaillierte Beschreibung des Frameworks&lt;br /&gt;
* [[OMSI Plugin Framework 5|Kapitel 5]] - Der OMSI Plugin Log Viewer&lt;br /&gt;
** Beschreibung der Debug-Hilfe zum Debuggen eines Plugins&lt;br /&gt;
* [[OMSI Plugin Framework 6|Kapitel 6]] - Ein Beispielprojekt&lt;br /&gt;
** Beispielprojekt für eine (fast) vollautomatische Klimaanlage&lt;br /&gt;
&lt;br /&gt;
== Vorwort zum Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Liebe angehende Plugin-Programmierer,&lt;br /&gt;
&lt;br /&gt;
dieses Tutorial zum '''''OMSI Plugin Framework''''' ist - wie man so schön neudeutsch sagt, &amp;quot;Working under progress&amp;quot;. Ich stelle das unfertige Tutorial hauptsächlich aus zwei Gründen bereits zur Verfügung:&amp;lt;br&amp;gt;1.) damit diejenigen unter euch, die schon über ausreichende Programmiererfahrung verfügen und ohne viele weitere Erklärungen auskommen, schon mal loslegen können und&amp;lt;br&amp;gt;2.) damit jeder schon während ich die einzelnen Kapitel schreibe, über das Forum Ideen, Verbesserungsvorschläge, Fragen zu Unklarheiten usw. einbringen kann.&lt;br /&gt;
&lt;br /&gt;
Bitte, werdet nicht ungeduldig, wenn mir nicht jeden Tag ein neues Kapitel aus der Feder tropft. Ich habe so nebenbei noch eine 'richtige' Arbeit bei der Berliner Feuerwehr und ... äh, da war doch noch was ... irgendwas war da noch ... was war denn da bloß noch ... ach ja, 'ne Familie ist da ja auch noch.&lt;br /&gt;
&lt;br /&gt;
In diesem Sinne, viel Spass beim programmieren und diskutieren&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Holmexx|Holmexx]] ([[Benutzer Diskussion:Holmexx|Diskussion]]) 07:07, 19. Nov. 2012 (CET)&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
Vielleicht hat der/die Eine oder Andere ja schon mal mit dem Gedanken gespielt, sich an ein Plugin heranzuwagen, das Vorhaben aber dann verworfen, weil er/sie gedacht, programmieren ist was für Profis und viel zu schwer. Die Erstellung eines Plugins für den OMSI ist - auch mit geringer Programmiererfahrung - gar nicht so schwierig wie es auf den ersten Blick aussieht. Das Entscheidende wird ja schon hier im [http://www.omnibussimulator.de/omsiwiki.de/index.php?title=Plug-in-Schnittstelle OMSI-Wiki] erklärt. Allerdings beziehen sich diese Erklärungen auf die Programmiersprache Pascal, die einstmals mit Borlands Delphi weite Verbreitung fand. Borland ist seit langem Geschichte und damit Delphi schon fast in Vergessenheit geraten. Die Firma [http://www.embarcadero.com/de/products/delphi Embarcadero] vertreibt zwar Delphi wieder, die Preise dort werden aber jeden Hobbyprogrammierer abschrecken. Die Alternative kommt von Microsoft. Dort kann man sich [http://www.microsoft.com/germany/express/download/default.aspx Visual Studio Express] kostenlos herunterladen. Für die Plugin-Programmierung benötigst Du '''Visual C++ 2010 EXPRESS'''. Wenn Du nun noch über wenigstens grundlegende Kenntnisse in der Programmiersprache C++ verfügst, kann es ja losgehen. Aber halt, warum C++? Geht nicht auch C# oder Visual Basic? Aus technischer Sicht ist es absolut möglich, ein Plugin in C# oder VB zu entwickeln. Allerdings stehen sich mit C#/VB und OMSI zwei Welten gegenüber. Die erste &lt;br /&gt;
Welt ist die des &amp;quot;Managed Code&amp;quot; und die Andere die des &amp;quot;Unmanaged Code&amp;quot;. Um beide Welten zusammen zu bringen, brauchst Du eine Wrapper-DLL. Und die kannst Du nur mit - Du ahnst es bereits - C/C++ programmieren, auch noch verbunden mit einem dramatisch erhöhten Schwierigkeitsgrad. Außerdem macht COM-Programmierung keinen Spaß, sondern ist einfach nur schmerzhaft. Ein weiteres Hindernis ist die Architektur eines &amp;quot;Managed Code&amp;quot;-Programmes. Managed Code ist auf maximale Sicherheit ausgelegt, nicht auf Performance. Es ist ungefähr so, als ob Du mit einer voll gepanzerten Limousine bei der DTM antrittst. Dein Auto ist zwar unkaputtbar, schade ist nur, dass die anderen Fahrer schon beim ersten Bier sitzen nach dem Rennen, während Du noch 6 Runden zu fahren hast. Bleiben wir also lieber bei C++.&lt;br /&gt;
&lt;br /&gt;
Um die Sache, insbesondere für Programmiernovizen, noch etwas zu vereinfachen, habe ich dieses Framework entwickelt, mit dem sich - hoffentlich ;-) - schnell und einfach Plugins programmieren lassen. Ich habe mich ganz bewusst für die Programmiersprache C++ entschieden, obwohl mit dem OpenSource-Projekt [http://www.lazarus.freepascal.org Lazarus] ein gut gelungener Delphi-Klon existiert und man damit sogar in reinrassigem Pascal im Delphi-Stil programmieren könnte. Aber C++ ist doch noch etwas systemnaher als Pascal und bietet dem Plugin-Programmierer Möglichkeiten, die in Pascal nur recht umständlich oder sogar überhaupt nicht möglich wären (z.B. Klassen-Templates, Verwendung von Makros).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
{|style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; |&lt;br /&gt;
|align=&amp;quot;center&amp;quot; |&lt;br /&gt;
|style=&amp;quot;width:33%&amp;quot; align=&amp;quot;right&amp;quot; |[[OMSI Plugin Framework I|[zum Kapitel 1]]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Holmexx</name></author>
		
	</entry>
</feed>