• Keine Ergebnisse gefunden

COM+ in der Prozeßautomatisierung

N/A
N/A
Protected

Academic year: 2022

Aktie "COM+ in der Prozeßautomatisierung"

Copied!
97
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

COM+ in der Prozeßautomatisierung

Diplomarbeit zur Erlangung des akademischen Grades Diplomingenieur

in der Studienrichtung Informatik

Angefertigt am

Institut für Informationsverarbeitung und Mikroprozessortechnik

Betreuung:

o. Univ.-Prof. Dr. Jörg R. Mühlbacher

Von:

Christoph Emsenhuber

Mitbetreuung:

Oberrat Dipl. -Ing. Rudolf Hörmanseder

Linz, Oktober 2002

(2)

Danksagung

Mein Dank gilt zuallererst meinen Eltern, die mich die gesamte Studienzeit hindurch finanziell, ideell und familiär großzügig unterstützt haben. Durch sie war es mir möglich, mich frei von existentiellen Sorgen dem Studium zu widmen.

Meinem Lehrer, Herrn o. Univ.-Prof. Dr. Jörg R. Mühlbacher möchte ich besonders für die Themenstellung für die Diplomarbeit danken, aber auch dafür, daß er mir immer wieder mit ergänzenden Aufträgen zur Seite stand.

Herrn Oberrat Dipl.-Ing. Rudolf Hörmanseder darf ich meinen Dank aussprechen, daß er reges Interesse an meiner Arbeit nahm, mich mit Hinweisen und Ratschlägen unterstützte und damit zu einem vortrefflichen Begleiter für mich und meine Arbeit wurde.

Der VA Technologie AG, vor allem den Herren Dipl.-Ing. Johann Hörl und Dipl.-Ing. Anton Brandstötter verdanke ich hilfreiche Anregungen zur Themenstellung, vor allem aber war mir die Beistellung der betriebseigenen Fachliteratur eine große Hilfe.

Die Fachgespräche mit meinen Studienkollegen lösten in mir öfters wertvolle Impulse aus, weswegen ich mich auch diesen gegenüber zu aufrichtigem Dank verpflichtet weiß.

Nicht zuletzt bedanke ich mich bei allen Professoren, Assistenten und Lehrern für die Mühen und Unterweisungen, die sie mir während meines Studiums widmeten, da diese es mir erst ermöglichten, auf einem guten Fundament die Diplomarbeit zu erstellen und zu beenden.

(3)

Zusammenfassung

Programme und Programmteile miteinander interagieren zu lassen ist in der modernen Softwareentwicklung nicht mehr wegzudenken. Man denke an legendäre Begriffe wie RPC, Zwischenablage oder OLE. Mindestens genauso wichtig ist jedoch COM, das Component Object Model von Microsoft. Computerübergreifende Kommunikation sowie die Wiederver- wendung und Versionierung von Software sind gute Gründe, den Einsatz von COM/DCOM zu überlegen.

Durch die Einführung von Windows 2000 brachte Microsoft eine neue Technologie namens COM+ auf den Markt.

Diese Arbeit befaßt sich damit, inwieweit das Konzept von COM+ für klassische Aufgaben im Bereich der Software-Entwicklung geeignet ist und welche Aspekte grundsätzlich bei der Verwendung überlegt werden sollen. Sie zeigt anhand von Beispielen Ansätze zur

Realisierung von typischen Aufgabenstellungen auf sowie etwaige Probleme, die bei der Realisierung zu erwarten sind.

Abstract

Software development has become nearly impossible without the interaction between programs and pieces of programs. Examples are RPC, clipboard and OLE. But there is also COM, Microsoft's component object model. Distributed communication, code reuse and versioning are good reasons to use COM/DCOM.

With Windows 2000, Microsoft introduced a ne w technology, called COM+.

This thesis focuses on the question, to what extent COM+ can be used for software engineering and it shows that some aspects should be considered carefully.

The examples explain different ways to realize typical tasks and point out possible problems that can occur during the realization.

(4)

Inhaltsverzeichnis

Danksagung...ii

Zusammenfassung...iii

Abstract ...iii

Inhaltsverzeichnis ...iv

1 COM-Grundlagen ...6

1.1 Entwicklung von DCOM ...6

1.2 Wozu Komponentenorientierung? ...8

1.3 Universell Programmieren...9

1.3.1 Unterschiedliche Programmiersprachen...9

1.3.2 Softwarebus ...10

1.4 Aufgabenstellung ...12

2 COM/DCOM Einführung ...13

2.1 Die vier Säulen von COM...13

2.2 Interfaces ...14

2.3 Interface Definition Language (IDL) ...16

2.3.1 Typen ...16

2.3.2 Visual Basic ...18

2.3.3 Visual C++ / ATL ...22

2.4 Versionsverwaltung ...24

2.4.1 Versionierung unter Visual Basic ...26

2.5 In-Process vs. Out-of-Process Server ...27

2.5.1 Instanziierung...28

2.6 Threading ...29

2.7 Anwendungsbeispiel...31

2.7.1 Erstellen einer COM-Komponente ...32

2.7.2 Verwendung von COM...33

2.8 Installation von COM ...34

2.8.1 Registry-Aufbau von COM...36

2.9 DCOM/Marshaling ...42

3 Verbesserungen durch COM+ ...45

3.1 Allgemeine Verbesserungen...45

3.1.1 Threading ...45

3.1.2 Installation von COM+-Anwendungen...46

4 Event-Service ...49

4.1 Einfache Events...49

4.2 Mehrere Subscriber...51

4.3 Einrichten der Event-Klasse...52

4.4 Publisher...53

4.5 Static Subscriber ...54

4.6 Transient Subscriber ...54

4.7 Erweiterte Funktionalität der Events...57

5 Resource-Sharing ...58

(5)

5.1 Shared Properties ...58

5.2 In Memory Data Base ...61

6 COM+ und IIS ...62

6.1 PHP ...64

7 Message Queuing...67

7.1 Microsoft Transaction Server...67

7.2 Queued Components...67

8 .NET ...69

9 Index...70

10 Abbildungsverzeichnis...71

11 Glossar ...72

12 Quellenverzeichnis...73

Eidesstattliche Erklärung ...74

Curriculum Vitae...75

Appendix...76

(6)

1 COM-Grundlagen

Dieser Abschnitt widmet sich den Grundlagen rund um COM. Dieses Wissen ist notwendig, um COM+ zu verstehen und damit arbeiten zu können.

Um große, komplexe Aufgaben zu realisieren, bedarf es ausgeklügelter organisatorischer Strukturen. Probleme ab einer gewis sen Größe bedürfen einer strukturellen Aufteilung. Diese besteht darin, Probleme zu zerlegen und dafür Teillösungen zu suchen, welche dann zu einer Gesamtlösung zusammengefügt werden.

Die Idee, Probleme zu zerlegen ist gleichermaßen für die Softwareentwicklung anzuwenden.

COM ist ein Hilfsmittel, um komplexe Aufgabenstellungen in der Softwareentwicklung in mehrere Ebenen zu zerlegen und anschließend eine Gesamtlösung zu erstellen.

1.1 Entwicklung von DCOM

Wie so oft hat Microsoft mit Distributed COM das Rad nicht innerhalb eines Tages erfunden.

COM/DCOM ist vielmehr das Ergebnis zweier Entwicklungslinien, die früher verfolgt wurden.

Zwischenablage

(1987)

OLE 1

(1992)

OLE 2

(1995)

Verteilte Computer

(1980er)

Open Software Foundation

Distributed Computing Environment Remote Procedure Calls

(1992)

Distributed COM

(1996)

Man muß vorausschicken, daß MS-DOS ursprünglich darauf ausgelegt war, daß nur eine Anwendung auf einem Computer laufen konnte. Erst mit Entwicklung leistungsfähigerer Prozessoren (i80286 und i80386) begann Microsoft an das gleichzeitige Laufen mehrerer Anwendungen auf einem Computer zu denken. Mit der Einführung von Windows gab es erstmals eine Multitasking- Umgebung, die bei den Anwendern den Wunsch nach Datenaus-

(7)

tausch zwischen den unterschiedlichsten Anwendungen aufkommen ließ. Diesem Wunsch wurde mit der Einführung der Zwischenablage und DDE (Dynamic Data Exchange )

Rechnung getragen. DDE war jedoch für Software-Entwickler zu kompliziert, sodaß es nur sehr wenige Anwendungen gibt, die DDE erfolgreich implementieren.

Im Gegensatz zu DDE ist die Zwischenablage wesentlich einfacher für die Software-Ent- wickler aufgebaut. Aufgrund des Copy-Paste-Prinzip sind der Zwischenablage großer Erfolg und Akzeptanz bis heute beschert. Ein Problem konnte die Zwischenablage jedoch nicht lösen: wie verknüpft man beispielsweise ein Winword-Dokument mit einem Excel- Spreadsheet? Die Zwischenablage ist zu unflexibel, um Dokumente und deren Inhalte miteinander verknüpfen zu können. Sobald in einem eingebetteten Dokument eine Änderung notwendig wird, muß dieses bearbeitet, in die Zwischenablage kopiert und letztendlich in das Zieldokument eingefügt werden. Microsofts Antwort auf diese Problemstellung heißt OLE (Object linking and embedding).

OLE kam erstmals mit Windows 3.1 auf den Markt. OLE 1 sollte eine geeignete Schnittstelle bieten, um mit verknüpften Dokumenten besser umgehen zu können. In ein Winword-

Dokument ein Excel-Spreadsheet einzubetten war schon seit DDE kein Kunststück mehr.

OLE 1 ermöglichte es jedoch, in einem Excel-Spreadsheet Daten zu ändern und sorgte dafür, daß diese Änderungen auch in jene Dokumente übernommen wurden, in die das betreffende Excel-Spreadsheet eingebettet war. Das eingefügte Dokument konnte sogar durch

Doppelklick geöffnet werden. OLE 1 basierte trotz neuem Namen in Wirklichkeit wieder auf DDE, welches das Protokoll für die Kommunikation zwischen den einzelnen Prozessen war.

Die für dama lige Zeit revolutionären Ansätze von OLE 1 wurden mit der Zeit weiter verfeinert, bis man erkannte, daß eingebettete Dokumente (Objekte) kleine Software- Komponenten sind, die in jede beliebige Anwendung eingebaut werden können und die Funktionalität der betreffenden Anwendung erweitern.

OLE 2 hat die Verknüpfungs- und Einbettungs-Funktionen von OLE 1 im Jahr 1993 durch Vorort-Aktivierung erweitert. Es war von nun an möglich durch Doppelklick auf ein Objekt dieses im gleichen Fenster zu bearbeiten, in dem sich das Objekt befindet. Was auf den ersten Blick hierbei nicht so auffiel war die Tatsache, daß sich OLE mehr und mehr zurückzog und statt dessen COM in den Vordergrund trat. 1996 war der Punkt erreicht, an dem COM mit der Einführung von Microsoft Windows NT 4.0 auch lernte, in Netzwerken sich mit mehreren Computern zu unterhalten; DCOM war geboren.

(8)

Wie wurde aber eine einfache Kommunikation im Netzwerk ermöglicht? In den frühen 80ern war es noch eine große Herausforderung, mehrere Computer über ein LAN zu vernetzen.

Oftmals mußten Räder neu erfunden werden, sie ermöglichten jedoch kein ordentliches Zusammenspiel der Rechner im Netz. Das änderte sich einige Jahre später wie die Open Software Foundation (OSF) mit dem Ziel ins Leben gerufen wurde, Standards für die Vernetzung von Computern zu definieren. Remote Procedure Calls (RPCs) sind wohl das bekannteste Werkzeug in der Windows-Welt, um verteilte Anwendungen miteinander kommunizieren zu lassen.

Infolge dessen wurde der Grundstein für Distributed Computing Environment (DCE) gelegt.

DCE beinhaltet eine Sammlung von Werkzeugen und Diensten, die die Erstellung von

verteilten Anwendungen erleichtern. Nachdem sich RPCs bewährt haben, war es naheliegend, COM um den Kommunikationsmechanismus RPC zu erweitern und DCOM entstehen zu lassen.

1.2 Wozu Komponentenorientierung?

Programmierer haben die Eigenschaft, eine Sammlung von Routinen bei der Programmierung in vielen Programmen wiederzuverwenden. In einigen Routinen werden komplizierte Rechen- operationen ausgeführt, andere greifen auf Windows-Funktionen zurück. Da diese Biblio- theken im Allgemeinen in mehreren Programmen Verwendung finden, ist das Copy-Paste- Prinzip der verwendeten Bibliotheken in das jeweilige Programm der Weg des geringsten Widerstands. So schön und einfach diese Vorgehensweise nun klingen mag, so unschön wird sie mit steigender Anzahl der Verwendung.

Änderungen in Bibliotheken sind auf Dauer unvermeidbar, seien es Fehlerkorrekturen, Laufzeitoptimierung oder Erweiterung der Funktionalität. Die Folge einer derartigen

Änderung ist das Suchen aller Anwendungen, die unter Verwendung der betroffenen Biblio- thek erstellt wurden. Ein erneutes Kompilieren der Anwendungen ist unvermeidlich, um die Änderungen auch an die Applikationen weiterzugeben. Auch die Verwendung einer ge- meinsamen Bibliothek erlöst den Programmierer nicht von unserem Problem.

Die Lösung dazu liegt im Erstellen sogenannter Komponenten, die den gesamten Funktions- umfang im Sinne obiger Bibliothek implementieren. Sie unterscheiden sich nur insofern von den besprochenen Bibliotheken, als daß sie eine Möglichkeit bieten, in kompilierter Form ver-

(9)

wendet zu werden und auch nach einer Modifikation mit bestimmten Auflagen ohne neuer- lichem Erstellen der davon abhängigen Applikationen weiter verwendet werden können.

1.3 Universell Programmieren

Es ist keine einfache Aufgabe, Software zu entwickeln, die ein problemloses Zusammenspiel von Komponenten zuläßt, die in unterschiedlichen Entwicklungsumgebungen, aber auch in unterschiedlichen Programmiersprachen geschrieben wurde. Wer sich schon länger mit Programmiersprachen beschäftigt, wird wissen, daß jede Sprache seine eigene Syntax hat.

Unterschiedliche Befehle für Funktionsaufrufe, Exception-Handling sowie die Adressierung von Variablen erschweren es Softwareentwicklern, mehrere Sprachen zusammenarbeiten zu lassen.

Sicherlich gibt es Mittel und Wege, diese Aufgabenstellung ohne COM oder mit COM vergleichbaren Programmierkonzepten (z.B. CORBA) zu lösen. Eigene Methoden zu entwickeln, die universelles Programmieren ermöglichen, sind jedoch sehr aufwendig und daher als ineffizient zu betrachten.

1.3.1 Unterschiedliche Programmiersprachen

Wie schaut jedoch ein Lösungsansatz für die Programmiersprachen-Problematik unter COM aus? Unter Berücksichtigung unterschiedlicher Methodenaufrufe in den einzelnen Sprachen ist erkennbar, daß die Syntaxen im wesentlichen einander sehr ähnlich sind. Gemeinsam ist ihnen die Übergabe von Parametern und gleichen, aber zumindest ähnlichen Typen zur Deklaration derselben. Unter COM werden die unterschiedlichen Syntaxen auf eine eigene Sprache zusammengefaßt. Ziel dieser gemeinsamen Sprache ist die Schnittstellendefinition einer COM-Komponente, die ein genormtes Aussehen nach außen hat und die Methoden einer Komponente gemeinsam mit ihren Parametern für alle COM-Sprachen in Binärform exakt festlegt. COM-Komponenten kommunizieren mittels Interfaces, die als arrays of function pointers definiert sind.

Dank ihrer Interfaces können COM-Komponenten mit jeder beliebigen COM-Entwicklungs- umgebung erstellt werden. Vertreter von COM-Entwicklungsumgebungen sind beispielweise Microsoft Visual Basic, Microsoft Visual J++ und Microsoft Visual C++ (Active Template Library, kurz ATL). Es wären hier auch noch andere Sprachen als Vertreter für COM-Spra- chen zu nennen, wenngleich man pauschal folgendes sagen kann: Jede Sprache, die die

(10)

Schnittstellendefinitionssprache von COM zur Erstellung eines binär kompatiblen Interfaces versteht, ist eine COM-konforme Sprache. Das trifft auf Visual FoxPro genauso zu wie auf Active Server Pages, die beim Aufruf einer Seite interpretiert werden. Wesentlich ist, daß die binäre Schnittstelle einer Komponente unveränderlich ist.

Letztendlich haben COM-kompatible Sprachen eine unterschiedliche Terminologie, können aber jede beliebige Komponente einer anderen Programmiersprache mit einer etwaigen Einschränkung der Mächtigkeit der Sprache in ihrer Funktionalität und Schnittstellenge- staltung auf Binärebene in ihrer Funktionalität gleich nachbilden. Weiters können Komponenten auch unabhängig von der Programmiersprache wiederverwendet werden.

Reduziert man Komponenten auf ihre Schnittstellendefinition und auf ihr Verhalten, unterscheiden sie sich nur durch ihre Be zeichnung in Abhängigkeit von der Programmier- sprache, unter der sie erstellt wurden; Visual Basic bezeichnet seine Komponenten als ActiveX-DLLs, Visual J++ als COM-DLLs und Visual C++ ATL erzeugt sogenannte DLL- Server. Abgesehen von unterschiedlich lautendenden Namen ist aber stets vom gleichen Produkt – von COM-Komponenten – die Rede. [Pla99]

Wie gut das Zusammenspiel von Komponenten unterschiedlicher Programmiersprachen funk- tioniert, zeigt das Beispiel eines Softwareentwicklers: Dieser hatte ein auf COM basierendes Produkt namens Data Access Add-In (DAA) im Einsatz, das Klassen unter Visual Basic Zugriff auf eine relationale Datenbank gab. Während der Softwareentwicklung mit DAA war er noch sehr zufrieden. Nach Auslieferung der fertigen Anwendung an den Kunden mußte er jedoch feststellen, daß die Anwendung wesentlich langsamer arbeitete als vermutet und beabsichtigt gewesen war. Auf Nachfrage stellte sich heraus, daß DAA in Java geschrieben wurde. Er hätte DAA wohl nie verwendet, wenn er vor Beginn seiner Arbeit gewußt hätte, daß DAA in Java implementiert wurde. Dieses Beispiel zeigt nur zu gut, daß COM einem auch ausgezeichnete Dienste leistet, wenn es die Implementierung und deren Sprache einer Komponente verstecken soll. [Gor00]

1.3.2 Softwarebus

Softwareentwicklung und Softwareverwendung könnten wesentlich erleichtert werden, wenn Komponenten immer gleich wiederverwendet werden könnten – unabhängig davon, ob es sich dabei um eine Dynamic Link Library (DLL) oder ein Executable handelt. Es wäre für anspruchsvolle Software auch wünschenswert, wenn es bei der Entwicklung nicht mehr relevant ist, ob auf dem selben oder einem entfernten Rechner eine Komponente installiert

(11)

wird. Warum soll man für Softwareentwicklung nicht ein Äquivalent zu den Vorteilen eines Hardwarebus suchen, nur nicht für Hard- sondern für Software?

Der Hardwarebus eines Computers hat viele Vorzüge. Es ist dabei hervorzuheben, daß sich selbst Komponenten mit Computern und deren Busse verstehen, die erst nach den Computern entwickelt wurden. Sofern sich die zu installierenden Komponenten an einen gewissen Stan- dard halten (PCI, ISA, SCSI...), lassen sich beliebige Komponenten in einen Hardwarebus einbauen.

Warum soll es Busse jedoch nur für Hard- und nicht auch für Software geben? Die Vorteile eines Hard- bzw. eines Softwarebus werden aus ihrer einzigen konzeptionellen Gemeinsam- keit erzielt, nämlich einem wohldefinierten Standard, an den sich alle Komponenten halten.

Abbildung 1 zeigt eine mögliche Architektur eines Softwarebus. Es ist hierbei hervorzuheben, daß dieser Softwarebus nicht auf einen einzigen Rechner limitiert ist. Sowohl die Architektur des Softwarebus COM als auch die von CORBA haben den Vorteil, daß Applikationen in einem Netzwerk verteilt laufen können. Hinter dieser Architektur steht die Überlegung, an einem beliebigen Rechner im Netzwerk eine neue Komponente zu installieren und alle übrigen Rechner können auf diese unter Einhaltung vorgegebener Sicherheitsrichtlinien zugreifen.

System Service

Anwendung - Frontend

System Service Software

Komponente

Software Komponente

COM/CORBA Software-Bus

Abbildung 1: Architektur eines Softwarebus

Grundlage dafür ist, daß Frameworks eine besondere Architektur haben, um das Zusam- menspiel unterschiedlicher Programmiersprachen zu ermöglichen. COM ist ähnlich wie CORBA als Softwarebus modelliert.

(12)

1.4 Aufgabenstellung

Um auch einen praktischen Nutzen aus dieser Arbeit ziehen zu können, werden die theo- retischen Erläuterungen von COM durch praktische Bespiele ergänzt. Daraus soll ein Anwendungsbeispiel entwickelt werden, das Problemlösung für folgende Aufgabenstellung sein soll:

Durch die Einführung von COM+ mit seiner gegenüber MTS 2.0 und COM/DCOM erweiterten Funktionalität sind neue Möglichkeiten zu evaluieren, Kommunikation in verteilten System zu unterstützen. Im wesentliche n wird sich die Arbeit auf drei Säulen (COM/DCOM, IIS/ASP und MSMQ) stützen, die durch die Clients 1 bis 3 in Abbildung 2 dargestellt werden.

http COM/DCOM erzeugt Datenstrom

COM/DCOM

MSMQ

Client 2

Client 3 Client 1Client 1

IIS / ASP COM+-

Appl-Server

Daten- Client

Abbildung 2: Skizzierung der Aufgabenstellung

Daten-Clients schicken einen beliebigen Datenstrom an einen COM+-Server, der die Daten wiederum an die Clients links verteilen soll. Für die Verteilung stehen unterschiedliche Wege zu Verfügung, die im folgenden an kurzen anschaulichen Beispielen demonstriert werden sollen. In weiterer Folge wird das Lösungsmodell sukzessiv verfeinert, um ein breites Spektrum von COM+ zu betrachten. Performance in großen Systemen – eventuell auch Server-Farmen – werden hier einen nicht unwesentlichen Einfluß auf die Qualität der zu entwickelnden Anwendungen haben.

(13)

2 COM/DCOM Einführung

2.1 Die vier Säulen von COM

Nun ist es keineswegs einfach, in wenigen Sätzen eine komplette Definition von COM geben zu können. Am ehesten lassen sich die Funktionalität und Mächtigkeit von COM anhand seiner vier Ent wicklungsideen erklären:

+ Wiederverwendbarkeit

Erstens sollten die einzelnen Komponenten wiederverwendbar sein, da Wartung sowie die Erweiterung von Komponenten in großen Anwendungen große Probleme mit sich bringen. Ein Aufteilen in wiederverwendbare Komponenten ist naheliegend, die die Erstellung neuer Applikationen, Erweiterung sowie Wartung erleichtern. Der Vorteil von COM liegt darin, daß es Klassen-Code in binären Komponenten verteilt. Das heißt, COM-Komponenten können ohne Abhä ngigkeiten vom Source-Code

wiederverwendet werden. Im gleichen Zug müssen Software-Entwickler nicht mehr Algorithmen oder Teile ihres Quell-Codes preisgeben, wenn sie Komponenten an eine Entwicklergemeinde verteilen wollen. Daß durch die Wiederverwendung binärer COM-Komponenten Probleme vermieden werden können, die zur Compile-Zeit auftreten, ist ein positiver Seiteneffekt, der nicht zu vernachlässigen ist.

+ Interface-orientierte Programmierung

Um Mißverständnissen vorzubeugen, sei an dieser Stelle darauf verwiesen, daß Microsoft und ein Großteil der Fachliteratur die Unterstützung objekt-orientierter Programmierung als eine weitere Säule verstehen. Tatsächlich handelt es sich dabei jedoch um interface-orientierte Programmierung, da das Konzept der Objektvererbung nicht unterstützt wird. Unabhängig davon, mit welchen Anwendungen man sich unter Windows beschäftigt, Programmierer haben mitunter auch unwissentlich mit COM- Komponenten zu tun. Komponenten sind fertige Module oder Einzelteile, die von beliebigen Programmen wiederverwendet werden können. Man denke nur an Daten- bankanbindung von Applikationen, Automatisierung von Office-Applikationen oder die Wiederverwendung von Teilen des Internet-Explorers. Diese Einzelteile als Objekte in Applikationen einzubauen, vereinfacht die Erstellung großer Programme

(14)

nicht unwesentlich. Letztendlich ist OOP, in diesem Fall jedoch zumindest interface- orientierte Programmierung doch eine Grundlage für einfachere Wartung der Quell- codes.

+ Unabhängigkeit von der verwendeten Programmiersprache

Nicht minder wichtig ist bei COM die Unabhängigkeit von der Programmiersprache, in der eine fertige Komponente erstellt wurde. Da jede Programmiersprache in Abhängigkeit von der Aufgabestellung teiloptimale Lösungen anbietet, ist es naheliegend, die Vorteile der jeweiligen Sprachen auszuschöpfen und Teillösungen über gekapselte, wiederverwendbare, binäre Komponenten zu verknüp fen.

+ Client/Server-Architektur

Schließlich soll COM aber auch Client/Server-Architekturen mit Ortsunabhängigkeit unterstützen. Ab einer gewissen Komplexität ist es nicht mehr möglich, alle

geforderten Funktionen einer großen Applikation auf einem Rechner ablaufen zu lassen. Ein Aufteilen von einer Aufgabe in mehrere kleine Teilaufgaben auf mehreren Rechnern ist naheliegend und bei größeren Projekten auch schon zum Zeitpunkt der Programmentwicklung durchaus praktikabel.

Ergebnis dieser Forderungen ist Microsofts Component Object Model, kurz COM, um das man als zeitgemäßer Programmierer in der Windows-Welt nicht mehr herumkommt.

2.2 Interfaces

COM unterscheidet sich von anderen Komponententechnologien dadurch, daß es mit

unbekannten Elementen umgehen kann. Wird eine COM-Komponente von einem Programm instanziiert, muß das Programm Information darüber bekommen können, welche

Schnittstellen in der COM-Komponente implementiert sind. Die Methode QueryInterface von IUnknown ist die Antwort auf diese Problemstellung, nur was ist IUnknown und wie kommt eine Komponente dazu?

Es gilt, daß jede COM-Klasse IUnknown implementieren und jede COM-Schnittstelle davon erben muß. Die Schnittstelle von IUnknown definiert sich wie folgt1:

1 Folgende Definition entspricht der Sprache IDL, mehr dazu in Abschnitt 2.3

(15)

interface IUnknown {

HRESULT QueryInterface([in] REFIID riid, [out, iid_is(riid)] void **ppv);

ULONG AddRef(void);

ULONG Release(void);

};

QueryInterface wird automatisch aufgerufen, wenn eine COM-Klasse instanziiert wird. riid übergibt den GUID der angeforderten Schnittstelle. Existiert für den betreffenden GUID eine Implementierung, gibt diese über den Zeiger ppv einen vTable-Pointer zurück.

Ein vTable (engl. virtual method table ) ist ein Array von Pointern. Jeder Pointer zeigt auf eine bestimmte Methode oder Property im betreffenden Objekt.

Die Methoden in einem vTable enthalten neben der Adresse noch andere Zusatzinformationen wie den Namen der Methode, den Return- Type sowie die Datentypen für die einzelnen

Parameter.

COM vertraut darauf, daß vTable und die IDL-Schnittstelle übereinstimmen. Programmierer können davon ausgehen, daß bei Visual Basic, Visua l C++ und Visual J++ das auch der Fall ist. Andernfalls würde es zu einem Kompilierungsfehler kommen.

AddRef und Release sind die zwei noch verbleibenden Methoden in IUnknown. Diese übernehmen die Verwaltung der Verweiszählung.

Erstellt ein Prozeß eine Instanz von einer COM-Klasse, wird ein Verweiszähler mit AddRef erhöht. Analog dazu wird der Verweiszähler einer COM-Klasse mit Release erniedrigt, wenn eine Instanz nicht mehr benötigt wird. Hat die Verweiszählung eines COM-Objekts den Wert Null erreicht, wird das COM-Objekt automatisch zerstört.

Wenn ein Interface von IUnknown erbt, wird dieses als benutzerdefiniertes Interface

bezeichnet. Diese haben die Eigenschaft der frühen Bindung gemeinsam. Das heißt, daß der vTable eines Interface schon zur Compile-Zeit bekannt ist. Frühe Bindung basiert auf einem Vertrag, der durch die Typbibliothek vorgegeben ist.

Es ist zu beachten, daß Komponenten bei Verwendung von früher Bindung schneller sind, da schon zur Compile-Zeit bekannt ist, wo die Implementierung der verwendeten Methoden ist.

Der Vorteil schnellerer Anwendungen bei früher Bindung bringt den Nachteil mit sich, daß die Implementierung den Vertrag nicht ändern darf ohne die davon abhängigen Anwendungen davon in Kenntnis zu setze n. Eine Änderung des Vertrages würde automatisch das erneute

(16)

Erstellen aller auf dem Vertrag aufbauenden Programme und/oder Komponenten erforderlich machen. Andernfalls führen derartige Änderungen im vTable zu Anwendungsfehlern.

Kommt anstatt früher Bindung späte Bindung (auch OLE-Automatisierung genannt) zum Einsatz, muß zur Compile-Zeit keine Typbibliothek angelegt werden; diese darf zur Laufzeit variieren. Späte Bindung kennt die IDispatch-Schnittstelle, der eine ganz besondere

Bedeutung zukommt: Wird mit Hilfe von IDispatch eine Methode oder Property aufgerufen, ermittelt IDispatch, welche Methode gemeint ist. IDispatch ist ASP als Bindeglied zwischen COM-Komponenten und ASP beispielsweise für Aufrufe unerläßlich.

2.3 Interface Definition Language (IDL)

Wie schon erwähnt, kommunizieren COM-Applikationen miteinander und mit dem System durch eine als Interface spezifizierte Menge von Methoden. Ein Interface ist bei COM ein streng definierter Vertrag zwischen Software und Client, der eine Menge an Operationen zur Verfügung stellt.

Es wurde eingangs in Abschnitt 1.3 erwähnt, daß COM und CORBA konzeptionell gewisse Ähnlichkeiten haben. CORBA kennt ebenfalls die Interface Definition Language IDL. Das einzige, was COM IDL und CORBA IDL gemeinsam haben sind ihr Name und ihre Aufgabe.

In der Syntax sind sie jedoch vollkommen unterschiedlich! [Gor00]

2.3.1 Typen

Um in IDL den Vertrag in Form einer Schnittstellendefinition zu schreiben sind zur

Spezifizierung der Methoden Basistypen für Variablen unverzichtbar. Alle COM-Interfaces müssen in IDL definiert werden. IDL gestattet, verhältnismäßig komplexe Datentypen zur Beschreibung einer Schnittstelle zu verwenden.

Tabelle 1 listet die am häufigsten verwendeten IDL-Basistypen für die COM-Sprachen C++, Visual Basic und Java auf:

Sprache IDL Microsoft C++ Visual Basic Microsoft Java boolean unsigned char nicht vorhanden char

byte unsigned char nicht vorhanden char Basistypen

small char nicht vorhanden char

(17)

short short Integer short

long long Long int

hyper __int64 nicht vorhanden long

float float Single float

double double Double double

char unsigned char nicht vorhanden char

wchar_t wchar_t Integer short

enum enum Enum int

Interface Pointer Interface Pointer

Interface Ref. Interface Ref.

VARIANT VARIANT Variant ms.com.Variant

BSTR BSTR String java.lang.String

Erweiterte Typen

VARIANT_BOOL short [-1/10] Boolean [True/False]

boolean [true/false]

Tabelle 1: IDL-Basistypen in C++, Visual Basic und Java

Dem Typ BSTR (Bytestring) kommt eine ganz besondere Bedeutung zu, zumal es sich um einen durchaus häufig verwendeten Typ handelt. C/C++ verwendet ein null- terminiertes Array of Char und Visual Basic verwaltet seine Strings als Array of Char mit Längenangabe des Strings. Eine BSTR-Variable ist ein Pointer, der auf ein wide character array zeugt. Die Anzahl der Buchstaben im Array ist unmittelbar vor dem Array im Speicher abgelegt. Dieses Konzept hat zwei Vorteile: Erstens kann die Länge des Arrays schnell bestimmt werden, was mehrere NULL als Zeichen im Array zuläßt. Zweitens kann ein BSTR wesentlich einfacher zwischen unterschiedlichen Prozessen ausgetauscht / übertragen werden als ein null-

terminierter String.

(18)

Anzahl Buchstaben 'A' 'N' 'Y' '\0' 'B' 'S' 'T' 'R' '\0'

BSTR Mehrfache Null

Abbildung 3: Aufbau eines Byte Strings

Zwecks besserem Verständnis der folgenden Abschnitte soll an dieser Stelle der Begriff des GUID erklärt werden. Ein GUID (engl. Globally Unique Identifier) ist ein 128-Bit langer Integer, der Datentypen wie Interfaces und Co-Klassen2 eindeutig identifizieren soll. Ein GUID eignet sich zur Identifikation wesentlich besser als ein Klassenname, da Klassennamen durch Menschen und nicht durch Zufallszahlen vergeben werden und die Wahrscheinlichkeit geringer ist, daß für unterschiedliche Komponenten gleiche Namen existieren. Im übrigen ist die Anzahl von ca. 3.4 * 1083 Zahlenmöglichkeiten nicht zu vernachlässigen. Da gängige Compiler mit 128 Bit langen Zahlen jedoch nichts anfangen können, werden diese meist in einem anderen Datenformat gespeichert. Bei C++ und Visual Basic werden die 128 Bit in kleinere Integer zerlegt. Im hexadezimalen Zahlenformat reduziert sich der GUID auf 32 Zeichen. Dieses Zahlenformat ist auch als Registry-Format bekannt, da GUIDs in der Windows Registry auch genauso abgespeichert werden.

{F3CF9127-79BE-4506-8AA8-5C0213C5C489}

ist ein klassisches Beispiel für einen GUID.

Um etwaigen Problemen infolge der nächsten Abschnitte vorzubeugen, empfiehlt [Pat00]

die aktuellste Version von MIDL zu verwenden. Im Allgemeinen hat man als Programmierer keine Probleme mit älteren MIDL-Releases zu arbeiten, jedoch unterstützen ältere Versionen eventuell nicht alle der aktuellen Features der Interface Definition Language.

2.3.2 Visual Basic

Ohne eingangs viel Erfahrung mit der Syntax der Interface Definition Language zu haben, soll in folgendem Beispiel veranschaulicht werden, wie trivial es ist ein IDL-File zu erzeugen bzw. dessen Syntax zu lesen. IDLs lassen sich bei der Programmierung unter Visual Basic sehr einfach erstellen (d.h. sie werden automatisch generiert). Abschnitt 2.7 wird noch eine

2 COM-Klasse

(19)

genauere Beschreibung zur Erstellung von COM-Komponenten bringen, folgendes Beispiel soll jedoch das Konzept von IDL demonstrieren:

Nachdem ein Projekt vom Projekttyp ActiveX-DLL angelegt wurde, müssen die einzelnen Methoden spezifiziert werden. Eine Implementierung ist hierbei nicht zwingend erforderlich.

Folgendes Beispiel der Klasse HelloWorld implementiert zwei Methoden:

Sub SayHello()

MsgBox ("Hello world!") End Sub

Sub SayAnything(message As String) MsgBox (message)

End Sub

SayHello ist ein einfacher Aufruf einer Methode ohne Parameter, SayAnything will bewußt jedoch einen String als Argument übergeben bekommen.

Nach erstmaligem Erstellen der DLL-Datei des betreffenden Projektes existiert für die Entwicklungsumgebung eine definierte Schnittstelle, die zwar nicht separat als IDL-Datei gespeichert wird, jedoch in der DLL vorhanden ist.

Um die Schnittstellendefinition sichtbar zu machen muß das zu Visual Studio 6.0 gehörende Dienstprogramm OLE-Ansicht (oleview.exe) gestartet werden. Der Befehl View TypeLib öffnet ein Dialogfenster, in dem die neu erstellte COM-Komponente HelloWorld.dll ausgewählt werden kann. Ergebnis dieses Beispiels ist folgende Interface-Definition, die einiger Erklärung bedarf.

// Generated .IDL file (by the OLE/COM Object Viewer) //

// typelib filename: HelloWorld.dll

[

uuid(F3CF9127-79BE-4506-8AA8-5C0213C5C489), version(1.0)

]

library Projekt1 {

// TLib : // TLib : OLE Automation : {00020430-0000-0000-C000- 000000000046}

importlib("STDOLE2.TLB");

// Forward declare all types defined in this typelib

(20)

interface _Class1;

[ odl,

uuid(5ADF5EEA-ABAC-48DC-BF1B-23405388FA76), version(1.0),

hidden, dual,

nonextensible, oleautomation ]

interface _Class1 : IDispatch {

[id(0x60030000)] HRESULT SayHello();

[id(0x60030001)] HRESULT SayAnything([in, out] BSTR* message);

};

[

uuid(241EC540-0FBC-4FB4-8629-A2A8108C83B8), version(1.0)

]

coclass Class1 {

[default] interface _Class1;

};

};

IDL zeichnet sich durch eine bestimmte Strukturierung aus. Eine COM-Komponente ist ein Paket, das über das library gekennzeichnet wird und in obigem Fall den Namen Projekt1 hat. Dieses Paket kann wiederum mehrere COM-Klassen beinhalten. Obiges Beispiel beschränkt sich ausschließlich auf die Co-Klasse Class1.

Sowohl Pakete als auch Co-Klassen werden durch einen GUID identifiziert; bei Co-Klassen spricht man hier von einem Class ID (CLSID). Das geschieht durch das uuid(universally unique identifier)-Attribut.

Ein Library-Block kann im Gegensatz zu dem Beispiel auch andere Attribute enthalten. Der Vollständigkeit halber sollen hiermit alle Attribute aufgezählt werden:

+ uuid: ID zur Identifikation der Bibliothek. Dieser Parameter ist zwingend erforderlich.

+ version: Gibt die Versionsnummer der Bibliothek an.

+ helpstring: Gibt in Textform zusätzliche Information zur Bibliothek und kann auch in Objektbrowsern abgelesen werden.

(21)

+ lcid: Gibt die Sprache der Bibliothek an.

+ hidden: Versteckt das Objekt vor einem COM-Objektbrowser.

coclass Class1 definiert die Implementierung einer COM-Komponente. Die Definition einer Co-Klasse hat folgende Syntax:

[attributes]

coclass classname {

[interface attributes] [interface | dispinterface] interfacename;

};

Folgende Attribute können für eine Co-Klasse definiert werden:

+ uuid: Gibt die Class ID (CLSID) zur Identifizierung eines Objekts an.

+ version: Gibt die Versionsnummer der Bibliothek an.

+ helpstring: Gibt in Textform zusätzliche Information zur Klasse und kann auch in Objektbrowsern abgelesen werden.

+ licensed: Veranlaßt die Klasse, das betreffende Objekt zu prüfen.

+ hidden: Versteckt das Objekt vor einem COM-Objektbrowser.

Weiters gibt es noch folgende Attribute innerhalb der coclass-Definition:

+ source: Gibt an, daß das Interface Events (Ereignisse) unterstützt.

+ default : Legt fest (bei VBScript), welches Interface standardmäßig aufgerufen wird, wenn keines angegeben ist.

+ restricted: Verhindert die Verwendung eines Interfaces durch Makroprogrammierer.

Interessant erscheint hier noch, daß in jeder IDL das Statement importlib("STDOLE2.TLB")

vorkommt. STDOLE2.TLB muß immer importiert werden, da dieses die Schnittstellen von IUnknown und IDispatch definiert.

Der Block interface _Class1 : IDispatch besteht aus der Definition der Methoden

SayHello und SayAnything. Methoden in COM-Komponenten haben grundsätzlich immer den return type HRESULT. HRESULT gibt an, ob ein Methodenaufruf unter COM erfolgreich aufgerufen wurde oder nicht. Wie läßt sich aber HRESULT mit einem beliebigen return type einer Funktion vereinbaren? Die Funktion

Function GetRandomNumber() As Double

wird in IDL folgendermaßen umschrieben:

HRESULT GetRandomNumber([out, retval] double*);

(22)

Die Richtungsattribute [in], [out], [in, out] geben die Richtung der Parameter an.

Standardwert ist [in], d.h. daß Daten vom Konsumenten nur zur Implementierung geschickt werden. [out] steht dementsprechend für einen Datenfluß in die entgegengesetzte Richtung.

Die Kombination [in, out] gibt an, daß Daten von einem Konsumenten zur Komponente fließen, in der Implementierung gelöscht und neu geschrieben werden, um letztendlich wieder an den Konsumenten zurückgeschickt zu werden.

Man sieht, daß Visual Basic auf Umwegen IDL-Dateien erzeugen kann. Wenn es aber darum geht, fremde Komponenten zu verwenden, die nicht unter Visual Basic erzeugt wurden, kann das für den Software-Entwickler unangenehm werden. Um dennoch auf externe

Komponenten zugreifen zu können, bietet Visual Basic einen Visual Basic-to-COM mapping layer. Wenn man bedenkt, daß in den vTables (vgl. frühe Bindung) die Methoden mit ihren Einsprungpunkten gespeichert sind, ist es kein Problem auf eine Komponente auch ohne IDL zugreifen zu können. [Gor00 , Gro00]

2.3.3 Visual C++ / ATL

Komponentenorientierte Programmierung unter Visual Basic bringt einige Einschränkungen mit sich. So hat der Benutzer keine Möglichkeit, die im Interface verwendeten GUIDs selbst zu bestimmen. Visual Basic hat automatisch GUIDs für die neue Komponente vergeben.

COM stellt eine Funktion namens CoCreateGUID zur Verfügung, die neue GUIDs erzeugt.

Diese Funktion baut auf dem Wissen auf, daß die MAC-Adresse einer Netzwerkkarte3 in Verbindung mit der Systemuhrzeit eine Zufallszahl garantieren muß, die weltweit eindeutig ist. Wer einen GUID manuell außerhalb von Visual Basic erzeugen möchte, verwendet dazu das Programm guidgen.exe, das Bestandteil von Visual Studio ist.

Zwar etwas gewöhnungsbedürftig, aber wesentlich eleganter gestaltet sich die Schnittstellen- definition unter Visual C++. Es gibt viele Wege, die nach Rom und zu einer IDL führen.

Unter Zuhilfenahme der ATL (Active Template Library) wandelt sich ein auf den ersten Blick kompliziertes Unterfangen zu einer einfachen Sache.

Zunächst wird ein neues Projekt (ATL-COM-Anwendungs-Assistent) angelegt:

3 Sollte keine Netzwerkkarte vorhanden sein, werden andere Informationen über den Computer und seine Hardware zur Berechnung des GUIDs verwendet.

(23)

Als Server-Typ wird Dynamic Link Library (DLL) gewählt und anschließend erzeugt der Assistent eine neue Projektumgebung, die schon die wichtigsten Elemente für COM- Komponenten enthält.

Anschließend wird dem Projekt ein neues ATL-Objekt hinzugefügt, das dann die Basis für die IDL werden soll. Im folgenden Dialog wird festgelegt, wie die neue Klasse (und daher auch das Interface) heißen sollen.

(24)

Es genügt hierbei, nur die Kurzbezeichnung (Komponentenname) auszufüllen, da der ATL- Objekt-Assistent die übrigen Namen (für Dateien, Klasse etc.) automatisch ergänzt. Der Assistent erstellt COM-Interface und Co-Klasse in einem Arbeitsschritt, weshalb eben noch mehr Namen notwendig sind. Der Schnittstelle wird ein "I" vorangestellt, welches eine COM- Schnittstelle kennzeichnen soll. Die Programm- ID setzt sich aus dem Komponentennamen und der Co-Klasse zusammen. Das Threading-Modell aus dem Dialog Einstellungen unter Attribute bleibt Apartment und auch die übrigen Einstellungen können vorerst akzeptiert werden.

Im Fenster Arbeitsbereich ist jetzt die neue Klasse in der Klassenansicht sichtbar.

Über das Kontextmenü lassen sich nun Methoden und Properties hinzufügen. Hierbei wird nicht nur automatisch das IDL-File von Visual C++ bearbeitet, sondern zugleich die Header- Datei und das betreffende Klassenmodul. Fazit: Wer auf IDL nicht verzichten will, der soll sich zwecks Einfachheit der ATL bedienen.

2.4 Versionsverwaltung

Komponenten-Versionierung zählt zu einer der Hauptstärken von COM. Um größtmögliche Flexibilität bei der Softwareentwicklung und -wartung zu erreichen, bedient man sich der Versionierung.

Komponentenorientierte Programmierung basiert auf der Überlegung, Komponenten mit gleicher Schnittstelle aber unterschiedlicher Versionsnummer und meist auch

unterschiedlicher Implementierung zu unterstützen. Immerhin hat das Konzept der binären Komponenten den Vorteil, daß einzelne Komponenten einer großen Anwendung ausgetauscht oder erweitert werden können, ohne daß davon abhängige Teile beeinflußt werden. Meistens zumindest! Was aber, wenn bei der Installation eines Programms eine bestehende

(25)

Komponente von einer Komponente älteren Datums überschrieben wird? Das Problem dabei ist meist in Komponenten zu suchen, die von mehreren unterschiedlichen Programmen verwendet werden. Die MFC Runtime DLL mfc42.dll ist ein Klassiker für weit verbreitete DLLs; diese wird nämlich von jedem Programm verwendet, das mit Visual C++ geschrieben wurde.

COM wurde mit dem Hintergedanken entwickelt, daß einmal definierte Schnittstellen (Inter- faces) von Komponenten nicht mehr verändert werden. Das heißt, daß Methoden in einem bestehenden Interface nicht mehr hinzugefügt, verändert oder entfernt werden dürfen. Will man dennoch eine bestehende Schnittstelle erweitern oder deren Implementierung verändern, muß ein neues Interface definiert werden.

Alte Schnittstellendefinitionen in neuen Versionen nicht zu verändern, erlaubt es alten wie neuen Clients, die neue Komponente zu verwenden. Weiters können neuere Clients alte Komponenten fragen, ob diese einen bestimmten Interface identifier (IID) und mit ihm bestimmte Operationen unterstützen. Zu diesem Zweck sei die Methode QueryInterface in

IUnknown wärmstens empfohlen. Mittels QueryInterface kann ein neuer Client sein Verhalten an das Vorhandensein einer älteren Komponente anpassen, um gegebenenfalls nur einen eingeschränkten Funktionsumfang zu unterstützen. Letztendlich sollen dadurch

ungültige Funktionsaufrufe als Auslöser für Laufzeit fehler rechtzeitig abgefangen werden können.

Wie auch immer man als Programmierer zu Interfaces von Komponenten stehen mag, zwei wesentliche Punkte soll man nie aus dem Auge verlieren: Sobald ein COM-Interface veröffentlicht wurde, soll es nicht mehr geändert werden und wenn wirklich einmal der Bedarf einer Änderung gegeben ist, so soll das Interface so definiert sein, daß die

Kompatibilität zu älteren Clients gesichert bleibt; es dürfen also bestehende Schnittstellen nicht modifiziert oder enterbt werden.

Nehmen wir also an, es gibt von einer Komponente zwei Versionen, v1 und v2, wobei v2 mehr Methoden als v1 unterstützt. Wird eine Anwendung mit der Komponente v2 erstellt, ist dieser nicht bekannt, daß es auch eine v1 mit einem einge schränkten Interface gibt. Laufzeit- fehler sind vorprogrammiert, sobald die Anwendung v1 anstatt der aktuellen v2 verwendet und eine Methode der neueren Komponente v2 aufgerufen wird. Es gibt zwei Möglichkeiten dieses Problem zu vermeiden: Entweder werden stets die neuesten Versionen von Clients und COM-Komponenten verwendet, oder man verwendet User-Definierte Interfaces. Hierbei werden abstrakte Klassen definiert und separat von der Klassendefinition implementiert.

(26)

Versuchen wir doch die Klasse HelloWorld (v1) aus Abschnitt 2.3.2 um die Methode

SayNothing zu erweitern (v2). Zuerst wird für v1 ein Interface namens IHelloWorld definiert, analog dazu für v2 ein Interface namens IHelloWorld2, wobei IHelloWorld2 das gesamte Interface von IHelloWorld unterstützen muß. Folgendermaßen könnte die Implementierung des Clients aussehen:

Option Explicit

Dim HW As IHelloWorld Set HW = New HelloWorld2

' Prüfen, ob HW IHelloWorld2 unterstützt If TypeOf HW Is IHelloWorld2 Then

Dim HW2 As IHelloWorld2 Set HW2 = HW

' Zugriff auf HW über typsicheres Objekt HW2 Else

' Zugriff auf HW mit eingeschränktem Interface End If

Zusammenfassend kann gesagt werden, daß diese Art der Versions- und Interfaceabfrage eine sehr einfache ist. Gerade in großen Projekten mit sich häufig ändernden Schnittstellen ist diese Methode sehr effizient und praktikabel.

2.4.1 Versionierung unter Visual Basic

Da Visual Basic IDL nicht kennt, muß ein anderer Mechanismus angeboten werden, um Versionskompatibilität zu ermöglichen. Abbildung 4 zeigt im Dialog Projekteigenschaften folgende Auswahlmöglichkeiten für Versionierung unter Visual Basic an:

+ Keine Kompatibilität: Bei jedem Kompilierungs-Aufruf werden ein neuer CLSID und neue IIDs erstellt. Dadurch können Anwendungen eine früher referenzierte COM- Komponente beim Rekompilieren nicht mehr gefunden werden.

+ Projekt-Kompatibilität: Komponenten können geändert werden, ohne daß neue CLSIDs und IIDs erstellt werden. Nur jene Klassen, die zur vorherge henden Version nicht binär kompatibel sind, bekommen neue IIDs.

+ Binär-Kompatibilität: Visual Basic überprüft die COM-Komponente auf Änderungen im binären Interface. Es gibt hier drei Unterteilungen

o Idente Version: es gibt keine Änderungen im Interface.

(27)

o Kompatible Version: Das bestehende Interface wurde nicht verändert, jedoch wurden neue Methoden, Objekte oder Eigenschaften hinzugefügt.

o Unkompatible Version: Mindestens eine Schnittstelle der alten COM- Komponente wurde verändert. Die Wiederverwendbarkeit als eine der 4 Säulen von COM ist nicht mehr gegeben.

Abbildung 4: Projekteigenschaften - Versionskompatibilität

2.5 In-Process vs. Out-of-Process Server

COM-Komponenten sind Sammlungen von Methoden, die beliebig vielen Prozessen zur Verfügung gestellt werden; das trifft sowohl für weitere COM-Komponenten als auch auf Anwendungen zu. Funktionen und Methoden in DLLs werden auch In-Process-Routinen genannt, weil sie nur innerhalb des eigenen Speicherbereichs adressiert und daher aufgerufen werden können. Out-of-Process Server (Executables) hingegen haben den Vorteil auch außerhalb des eigenen Speicherbereichs Funktionen und Methoden für andere Prozesse zugänglich zu machen; davon leitet sich auc h ihr Name ab.

Out-of-Process Server gehen mit Prozeßabstürzen fehlertoleranter um, sofern der Source- Code Error-Handling unterstützt. Dadurch wird die Stabilität der von einem Out-of-Process Server abhängigen Anwendungen sichergestellt und der Server-Prozeß kann neu gestartet werden. Ein anderer Grund Out-of-Process Server den In-Process Servern vorzuziehen ist die Tatsache, daß sich mehrere Anwendungen einen Out-of-Process Server miteinander teilen können.

(28)

Es ist naheliegend, daß Methodenaufrufe innerha lb des selben Prozesses (und

Speicherbereich) schneller ablaufen werden als Methodenaufrufe eines Out-of-Process Server; das ist wohl auch der größte Nachteil eines Out-of-Process Server. Um

prozeßübergreifende Methodenaufrufe zu ermöglichen, ist ein Vorga ng namens Marshaling (mehr dazu in Abschnitt 2.9) notwendig, welcher verhältnismäßig viel Zeit in Anspruch nimmt. [Fre00]

2.5.1 Instanziierung

Ein In-Process Server läuft grundsätzlich immer im Prozeß seines Client. Out-of-Process Server haben stets ihren eigenen Prozeß. Es stellt sich nun die Frage wie viele Server-

Prozesse erzeugt werden sollen. Immerhin kann im worst case jedes Objekt seinen separaten Server-Prozeß haben. Diese Frage läßt sich nicht allgemein beant worten, letztendlich muß sie vom Software-Entwickler entschieden werden unter dem Hinblick, was ihm zweckmäßig erscheint. Sowohl Visual C++ als Visual Basic bieten dem Programmierer die Möglichkeit für jede Klasse zu bestimmen, ob sie in einem separaten Server-Prozeß zu laufen hat oder nicht.

Dies geschieht durch die Instancing-Eigenschaft einer COM-Klasse. Folgende Werte stehen dafür zur Auswahl::

+ Private: Funktionen und Methoden der Klasse werden nicht veröffentlicht und können nur innerhalb des lokalen Projektes verwendet werden. Daraus ergibt sich, daß die Klasse weder einen CLSID noch einen IID hat.

+ PublicNotCreatable : Die Klasse erzeugt eine nicht erzeugbare Co-Klasse sowie ein Interface. Diese Einstellung wird mitunter auch unter Visual Basic verwend et, um eine abstrakte Klasse zwecks Schnittstellendefinition ohne Implementierung zu erzeugen (vgl. Type Libraries unter Visual Basic). Die erzeugte Klasse ist wie bei Private keine richtige COM-Komponente, da keine Objekte instanziiert werden können und daher die Klasse nicht wiederverwendbar ist.

+ MultiUse: Alle Instanzen einer Klasse laufen im gleichen Prozeß.

+ GlobalMultiUse: Ist wie MultiUse und gibt zugleich Zugriff auf die Methoden als wären sie globale Funktionen.

+ SingleUse: Dieser Wert kann nur bei Out-of-Process Servern der Instancing-Property zugewiesen werden. Es wird sichergestellt, daß jede Instanz der betroffenen Klasse in einem separaten Prozeß abläuft.

(29)

+ GlobalSingleUse: Ist wie SingleUse und gibt zugleich Zugriff auf die Methoden als wären sie globale Funktionen.

Obwohl man für jede COM-Klasse obige Eigenschaft separat vergeben kann ist es empfehlenswert, für alle Klassen in einem Server die gleiche Einstellung zu verwenden.

[MSD00, Pat00]

2.6 Threading

In den vergangenen Abschnitten wurde schon einige Male der Begriff des Threading geprägt.

In den Programmbeispielen wurden bestimmte Threading- Einstellungen vorgegeben ohne deren Bedeutung näher zu erklären. Das Verständnis für Threadingmodelle und deren Bedeu- tung auf eigene Programme ist jedoch für COM-Programmierung unerläßlich.

Freundschaft mit Threads schließen zu können geht über die Leiche des Verständnisses für das Apartment-Konzept. Ein Apartment läßt sich am Einfachsten mit einem logischen Container innerhalb eines Prozesses beschreiben. Dieser Container ist für Objekte mit den gleichen Thread-Zugriffsanforderungen vorgesehen.

Schon der Umstieg von Windows 3.1 auf Windows 95/NT 3.5 oder höher brachte Software- entwicklern immense Vorteile, was die Threading-Unterstützung anbelangt. Mit der Ein- führung der Multithreaded Apartments (MTAs) unter Windows NT 4.0 war es erstmals möglich, mehrere Objekte in einem Apartment zu haben.

Um ein COM-Objekt einem Thread zuzuordnen, muß über die Funktion CoInitializeEx

COM initialisiert werden, wobei als Parameter die Konstanten COINIT_APARTMENTTHREADED

oder COINIT_MULTITHREADED zur Festlegung des Threading-Modells übergeben werden. Erst das Terminieren des Threads oder der Aufruf der Funktion CoUninitialize entfernen den Thread wieder aus seinem zugeordneten Apartment.

Es sei hier darauf hingewiesen, daß sich in den vergangenen Jahren bei der Bezeichnung von Threading-Modellen zwei unterschiedliche Lager gebildet haben. Während die Win32 SDK- Dokumentation von Singlethreaded und Multithreaded Apartments spricht, verwenden andere Entwicklungsumgebungen die Bezeichnungen free threaded bzw. apartment threaded. Wäh- rend free threaded Komponenten in einem MTA laufen, laufen apartment threaded

Komponenten in einem STA.

(30)

Folgende Beschreibung der schon unter COM bekannten Theading-Modelle soll verans- chaulichen, was bei der Wahl des idealen Threading-Modells beachtet werden muß.

Die Hauptfrage zum Finden des optimalen Threading-Modells sollte am Besten lauten: "Wie verhält sich nun aber ein singlethreaded Apartment bei gleichzeitigen Operationen?" Objekte haben es im Allgemeinen nicht sehr gern, wenn ein Thread dieses benutzt, während dieses Objekt schon für einen anderen Thread eine Operation ausführt. Datenkorruption kann die Folge sein. Hier sind entweder gute vorgefertigte Mechanismen gefragt, die Schaden durch gleichzeitige Operationen vermeiden helfen, oder Konzepte, die es ga r nicht erst zu

gleichzeitigen Aufrufen kommen lassen.

Objekte in einem STA werden in jenem Thread ausgeführt, in dem sie erzeugt wurden. STAs gestatten es nur einer Methode gleichzeitig ausgeführt zu werden. So einfach das Vermeiden von Parallelitäten nun sein mag, stellt sich jedoch die Frage, wie ein STA jedoch

Methodenaufrufe aus anderen Apartments zulassen will; immerhin will man ja auch die Wiederverwendbarkeit einer Komponente unterstützen.

Beim Anlegen eines neuen Single Threaded Apartments, wird ein für den Programmierer nicht sichtbarer Bereich angelegt. In diesem wird eine Queue angelegt, an die andere Apart- ments Methodenaufrufe schicken. Diese Queue wird nach dem Prinzip first in first out abgearbeitet, wodurch sichergestellt ist, daß immer nur eine Methode gleichzeitig aufgerufen werden kann. Man kann also sagen, das STA wurde mit der Absicht entwickelt, eine

Umgebung für Komponenten zu schaffen, in der sich der Programmierer nicht explizit um Code für Synchronisierung oder Sperren kümmern muß.

In MTAs wiederum können beliebig viele Methoden gleichzeitig in einem Apartment

ausgeführt werden. Es ist jedoch Vorsicht geboten, da diese sich unter Umständen gegenseitig behindern oder ungewollte Seiteneffekte auftreten. Bei MTAs muß im Gegensatz zum STA eventuell explizit Quellcode zur Vermeidung dieser Seiteneffekte geschrieben werden.

(31)

Client 1 MTA

Prozeß 2

STA A A

A

Client 2 STA

B aufrufen C aufrufen A aufrufen

Queue

Prozeß 1 Client 2

Abbildung 5: Gleichzeitige Aufrufe mehrerer Methoden aus unterschiedlichen Apartments Neben den bis dato erwähnten Singlethreading und Multithreading kennt COM auch noch das Free Threading. Free Threading gestattet mehreren Threads ein beliebiges COM-Objekt innerhalb eines Prozesses gleichzeitig anzusprechen. Mit der aktuellen Version von Visual Basic ist es nicht möglich free threaded Komponenten zu erstellen. Die Verwendung von Visual C++ zur Erstellung von free threaded Komponenten ist daher unumgänglich. Das Free Threading-Modell kennt jedoch keinerlei Synchronisierungsmechanismen, so daß der

Programmierer explizit wieder den erforderlichen Synchronisationscode selbst schreiben muß.

Auch wenn das Schreiben von eigenen Synchronisierungsmechanismen durchaus mühsam sein mag, sollte der vernünftige Software-Entwickler zumindest einmal die Verwendung von C++ sorgfältig andenken. Da aber bei zeitkritischen Anwendungen die Geschwindigkeit eine immer größere Rolle spielt, sollte dieser Mehraufwand jedoch in Kauf ge nommen werden, um in den Genuß vom Free Threading zu kommen.

2.7 Anwendungsbeispiel

Um das Wissen der vergangenen Abschnitte zu festigen, scheint ein Anwendungsbeispiel anhand der behandelten COM-Grundlagen gerade das Richtige zu sein. Um aber auch die Wiederverwendbarkeit herausstreichen zu können, soll sich das Beispiel in die Teile Erstellen einer COM-Komponente und Verwendung von COM (Client – Frontend) gliedern. Nach Belieben darf auch die Programmiersprache der einzelnen Teile ausgetauscht werden – warum denn auch nicht? Folgende Beispiele werden anhand von Visual Basic erklärt, es ist

(32)

jedoch nicht wesentlich komplizierter eine gleiche Implementierung der COM-Komponente mit Visual C++ Active Template Library zu erzeugen.

2.7.1 Erstellen einer COM-Komponente

Die Komponente HelloWorld (vgl. Abschnitt 2.3.2) besteht aus den Methoden SayHello und

SayAnything. Um den Umweg über die Erstellung von Type Libraries zu gehen, wird an dieser Stelle bewußt eine Klasse IHelloWorld mit Interface, jedoch ohne Implementierung erstellt, welche als Schnittstellendefinition für die eigentliche Komponente dienen soll. Um diese zu definieren, muß zuerst ein neues Projekt angelegt werden. Da es beabsichtigt ist einen In-Process Server zu erzeugen, wird ActiveX-DLL anstatt ActiveX-EXE (für Out-of- Process Server) ausgewählt.

Als Projektname kann ein beliebiger vergeben werden, der Klassenname sollte aber durchwegs aussagekräftig sein, da die Komponente ja fortan auch durch seinen Namen identifiziert wird. Um eine abstrakte Klasse zu erzeugen, wird die Eigenschaft Instancing auf PublicNotCreatable geändert. Im Dialog Projekteigenschaften werden alle Einstellungen übernommen, d.h. keine Modifikationen vorgenommen. Wird trotzdem der Schalter Remote- Server-Dateien aktiviert, so werden automatisch Type Libraries beim Kompilieren erstellt.

Folgender Code definiert die Schnittstelle der COM-Komponente:

Option Explicit

Sub SayHello() End Sub

Sub SayAnything(message As String) End Sub

Während SayHello keine Parameter hat, wird an SayAnything ein String übergeben.

Zusätzlich zu IHelloWorld wird noch eine weitere Klasse HelloWorld dem Projekt hinzugefügt. Drei Unterschiede gibt es aber schon im Vergleich zu IHelloWorld:

+ Um auf die abstrakte Klasse IHelloWorld zu verweisen wird der Klasse das Statement

Implements IHelloWorld am Anfang hinzugefügt.

+ Den Methodennamen wird der Name der abstrakten Klasse durch "_" getrennt vorangestellt.

+ Der Source-Code besteht diesmal aus Methodendefinition mit Implementierung.

(33)

+ Die Eigenschaft Instancing hat den Wert MultiUse

Option Explicit

Implements IHelloWorld

Private Sub IHelloWorld_SayHello() MsgBox ("Hello world!")

End Sub

Private Sub IHelloWorld_SayAnything(message As String) MsgBox (message)

End Sub

Nach dem Registrieren der COM-Komponente mittels RegSvr32 (siehe Abschnitt 2.8) wird sich ein entsprechender Eintrag mit dcomcnfg.exe, dem COM Explorer oder dem

Objektbrowser von Visual Basic finden. Der uneingeschränkten Verwendung der soeben erstellten Komponente steht nichts mehr im Weg.

2.7.2 Verwendung von COM

Die COM-Komponente HelloWorld eignet sich fortan zur Wiederverwendung in anderen Komponenten oder Executables. Um zu einem sichtbaren Ergebnis zu kommen soll hier eine Anwendung erstellt werden. Zu diesem Zweck wird ein neues Projekt vom Typ Standard- EXE erstellt. Im Menüpunkt Projekt – Verweise wird auf die zu verwendende Komponente referenziert. In diesem Fall wird auf Projekt1 verwiesen, da dies der Projektname der vorigen Komponente ist. Sollen COM-Komponenten verwendet werden, die noch nicht registriert sind, wird unter Durchsuchen ein Dialog geöffnet, in dem man dann die betreffende Komponente auswählen kann.

Option Explicit

Dim HW As IHelloWorld

Private Sub SayHelloBtn_Click() MsgBox HW.SayHello

End Sub

Private Sub SayAnythingBtn_Click() MsgBox HW.SayAnything(Text1.Text) End Sub

Private Sub Form_Load()

(34)

Set HW = New HelloWorld End Sub

Private Sub Form_Terminate() Set HW = Nothing

End Sub

HW ist jenes Objekt, das den Objekttyp der vorher definierten Klasse IHelloWorld

instanziiert. Beim Start der Anwendung instanziiert HW die COM-Komponente HelloWorld. Von nun an kann auf sämtliche Methoden (Funktionen und Properties) der betreffenden Klasse zugegriffen werden. Wird nun beispielsweise durch Klick auf die Schaltfläche

SayHelloBtn HW.SayHello aufgerufen, gibt diese Methode einen String zurück, der wiederum als Text an eine Messagebox übergeben wird. Welche Operationen tatsächlich beim Methodenaufruf in der COM-Komponente durchgeführt werden, entzieht sich dank Objektkapselung der Kenntnis des Programmierers. Eine saubere Trennung zwischen Client- und Server-Anwendung ist die Folge.

2.8 Installation von COM

Um in den Genuß von COM/DCOM-Funktionalität kommen zu können, ist es vorab einmal wichtig sicherzustellen, daß auch wirklich auf dem eigenen Rechner (D)COM-Unterstützung installiert ist. Bis auf alte Rechner mit Windows 95 wird auf allen neuen Microsoft-

Betriebssystemen die (D)COM-Unterstützung automatisch mitgeliefert. Wenn nicht, so ist ein Besuch im Microsoft Downloadcenter ratsam, das auf den Suchbegriff DCOM95 das

entsprechende Utility zum Aufrüsten bereitstellt. Wer Microsoft Office 2000 oder Internet Explorer 5.0 oder höher sein Eigen nennt, der hat (D)COM automatisch auf seinem Rechner installiert. Gelegentlich ist es auch schon unter Windows 98 Second Edition vorgekommen, daß zwar die (D)COM-Funktionalität verfügbar war, jedoch ein ganz wesentliches Programm zur Konfiguration eigener Komponenten gefehlt hat: dcomcnfg.exe. dcomcnfg.exe sollte im Pfad %SystemRoot%\System32 zu finden sein; wenn nicht, dann findet sich diese Datei in der win98_39.cab der Installations-CD von Windows 98SE.

dcomcnfg.exe ist auch ein gutes Werkzeug, um festzustellen, welche Out-of-Process Server auf einem System registriert sind. Im Allgemeinen soll das den Programmierer nicht in Sicherheit wiegen, daß er keine Leichen in der Registry beherbergt, man kann bestenfalls

(35)

feststellen, welche registrierte Out-of-Process Server-Komponenten auf dem System installiert sind. Im übrigen trifft obiges für In-Process DLLs nicht zu.

ActiveX DLLs haben unter anderem auch Routinen eingebaut, die sich um das Registrieren (Routine DllRegisterServer) und das Unregistrieren kümmern. Die Syntax dazu lautet:

+ RegSvr32 NameDerKomponente zum Registrieren bzw.

+ RegSvr32 /u DLLName, wobei /u für Uninstall steht.

Nach Abschluß des (Un-)Registrierens öffnet sich eine Messagebox, die das Ergebnis des Vorgangs zusammenfaßt. Was versteckt sich aber hinter RegSvr32? RegSvr32 ist eine Anwendung, die folgende Aufgaben beim Registrieren bzw. Unregistrieren einer In-Process Server-Komponente durchführt, wobei der Anwender von diesen Vorgängen nichts

mitbekommt und diese auch nicht manuell anstoßen muß:

+ Aufruf von LoadLibrary um Modul zu laden

+ Aufruf von GetProcAddress um Pointer auf die Funktion DllRegister bzw.

DllUnregister zu bekommen

+ Aufruf von der Funktion DllRegister bzw. DllUnregister

+ Aufruf von FreeLibrary

In-Process Server verwenden die Funktionen DllRegisterServer und

DllUnregisterServer um sich selbst zu registrieren. Während beim Registrieren in der Windows Registry Einträge hinzugefügt werden, werden genau diese beim Unregistrieren wieder aus der Registry entfernt. Die Funktionen DllRegisterServer und

DllUnregisterServer müssen von der betreffenden COM-Komponente exportiert werden.

Ist dies nicht der Fall werden Programme wie RegSvr32 erfolglos beim Aufruf dieser Funktionen abbrechen. Folgendes Listing unter Visual C++ zeigt die Implementierungs- struktur von DllRegisterServer und DllUnregisterServer.

// ...

// DllRegisterServer - Fügt der Systemregistrierung Einträge hinzu // ...

STDAPI DllRegisterServer(void) {

// RegCreateKey() bzw. RegSetValue() zum Hinzufügen von Registry-Keys ...

return NOERROR;

}

(36)

// ...

// DllUnregisterServer - Entfernt Einträge aus der Systemregistrierung // ...

STDAPI DllUnregisterServer(void) {

// RegDeleteKey() zum Entfernen von Registry-Keys ...

return NOERROR;

}

Es ist zu beachten, daß dieses Beispiel in der Implementierung der Funktionen

DllRegisterServer bzw. DllUnregisterServer abweicht, wenn ATL zum Einsatz kommt, da diese einem die Arbeitsschritte für die Registrierung abnimmt. Wird anstatt einer In-

Process Server COM-Komponente ein Out-of-Process Server erstellt, gibt es keine Funktionen DllRegisterServer und DllUnregisterServer, die unter Verwend ung von

RegSvr32 für das korrekte (Un-)Registrieren sorgen. Statt dessen übernimmt die Aufgabe der Registrierung die Funktion WinMain(). Es müssen anschließend nur mehr über die

Eingabeaufforderung die Parameter /RegServer bzw. /UnRegServer zwecks Registrierung übergeben werden.

Im übrigen darf sich jeder Softwareentwickler glücklich schätzen, daß einem die

Implementierung obiger Funktionen unter Visual Basic und Visual C++ (ATL) durch das Softwarewerkzeug abgenommen wird.

2.8.1 Registry-Aufbau von COM

Nachdem unter Abschnitt 2.7.2 schon erwähnt wurde, daß COM-Komponenten in der Windows Registry eingetragen werden, soll der Registry hier nun besonderes Augenmerk geschenkt werden.

COM verwendet den Registry-Abschnitt HKEY_CLASSES_ROOT (HKCR), der sich in sechs Informations-Abschnitte aufteilt:

+ Datei- Erweiterungen + ProgIDs

+ AppIDs + CLSIDs

(37)

+ Interfaces + TypeLibs

Ergänzend zu diesen verwendet COM für Sicherheitseinstellungen noch den Schlüssel

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Ole. 2.8.1.1 Datei-Erweiterungen

Datei- Erweiterungen sind Subschlüssel vom HKEY_CLASSES_ROOT-Schlüssel. Dieser Schlüssel legt fest wo COM nach der ProgID einer COM-Komponente nachschauen muß. Der Schlüssel einer Datei- Erweiterung hat folgende Struktur:

HKEY_CLASSES_ROOT

{ .Erweiterung } = { prog-id }

2.8.1.2 ProgIDs

ProgID-Schlüssel sind genauso wie Datei- Erweiterungen Sub-Schlüssel von

HKEY_CLASSES_ROOT . ProgID-Schlüssel haben folgende Struktur in der Windows Registry:

HKEY_CLASSES_ROOT

{ ModulName.ObjektName } = Beschreibung CLSID = { CLSID als GUID }

CurVer = { versionsunabhängige ProgID4 }

{ ModulName.ObjektName.VersionsNummer } = Beschreibung CLSID = { CLSID als GUID }

Wozu benötigt man als Programmierer eigentlich einen ProgID? Aus obiger Struktur ist ersichtlich, daß jedem ProgID ein CLSID in Form eines GUID zugeordnet ist. GUIDs sind im Allgemeinen jedoch in der Praxis zu kompliziert, um über sie Komponenten zu identifizieren.

ProgIDs sollen dieses Problem umgehen, indem der Programmierer selbst eine Bezeichnung für seine Komponente aussuchen kann. Der CLSID ist also eine Übersetzung eines einfachen ProgID in einen GUID. Da man also annehmen darf, daß ProgIDs und CLSIDs bijektiv sind, können folgende zwei APIs zwischen ProgID und CLSID übersetzen.

WINOLEAPI ProgIDFromCLSID (REFCLSID clsid, LPOLESTR FAR* lpszProgID);

WINOLEAPI CLSIDFromProgID (LPOLESTR lpszProgID, REFCLSID clsid);

4 Es ist zweckmäßig einen ProgID zu haben, der unabhängig von der installierten Version ist, damit Programmierer nicht die installierte Version einer COM -Komponente abfragen müssen. Die Syntax ist ModulName.ObjektName

Abbildung

Abbildung 1 zeigt eine mögliche Architektur eines Softwarebus. Es ist hierbei hervorzuheben,  daß dieser Softwarebus nicht auf einen einzigen Rechner limitiert ist
Abbildung 2: Skizzierung der Aufgabenstellung
Tabelle 1 listet die am häufigsten verwendeten IDL-Basistypen für die COM-Sprachen C++,  Visual Basic und Java auf:
Tabelle 1: IDL-Basistypen in C++, Visual Basic und Java
+7

Referenzen

ÄHNLICHE DOKUMENTE

[r]

Juni 2018 konnten die Schulen Zuschüsse für Fahrten im ersten Schulhalbjahr 2018/19 bean- tragen. Von den insgesamt 114 Fahrten bleiben 71 innerhalb Deutsch- lands, zwölf mit Zielen

[r]

Sparkfun BME280 V1.0.0 https://github.com/sparkfun/Spark- Fun_BME280_Arduino_Library https://github.com/adafruit/Ada- fruit_BME680.

4–8: καί μοι δοκεῖ τὸ τὴν νόησιν ἔχον εἶναι ὁ ἀὴρ καλούμενος ὑπὸ τῶν ἀνθρώπων, καὶ ὑπὸ τούτου πάντας καὶ κυβερνᾶσθαι καὶ πάντων κρα τεῖν· αὐτὸ γάρ μοι τοῦτο

Die nationale rüstungswirtschaft- liche Begründung: Exporte von Waffen, Waffenkomponenten oder sonstigen Rüstungsgütern sind ein wichtiges Ins- trument, um aus sicherheits- und

Die Planungsunterlagen zum B12-Ausbau beschäftigen sich bisher überhaupt nicht mit dem globalen Klimaschutz, obwohl das nochmal verschärfte Klimaschutzgesetz der

Universit¨ at Karlsruhe Institut f¨ ur Theorie der Kondensierten Materie.. Ubungen zur Theoretischen Physik F ¨