DasComponent Object Model [kəmˈpoʊnənt ˈɒbdʒɪkt ˈmɒdl] (abgekürztCOM) ist eine vonMicrosoft entwickelte Technik zurInterprozesskommunikation unterWindows. COM-Komponenten können sowohl in Form vonLaufzeitmodulen (DLLs) als auch als ausführbare Programme umgesetzt sein. COM soll eine leichte Wiederverwendung von bereits geschriebenem Programmcode ermöglichen, zum Teil auch über Betriebssystemgrenzen hinweg. COM-Komponenten können unabhängig von der Programmiersprache eingesetzt werden.
Das Component Object Model wurde von Microsoft 1992 mit der grafischen BenutzeroberflächeWindows 3.1 eingeführt.
COM basiert auf demClient-Server-Modell. Ein COM-Client erzeugt eine COM-Komponente in einem sogenannten COM-Server und nutzt die Funktionalität des Objektes über COM-Schnittstellen. Der Zugriff auf Objekte wird innerhalb eines Prozesses durch sogenannte COM-Apartments synchronisiert.
Unter einem COM-Server versteht man ein Laufzeitmodul (Dynamic Link Library) oder ein ausführbares Programm, das in einer COM-unterstützenden Programmiersprache erstellt wurde und COM-Komponenten anbietet und erstellen kann. Es gibt drei Typen von COM-Servern:
Im Falle desIn-process-Servers ist die COM-Komponente in einerDLL implementiert (sie tragen unter Windows oft die DateiendungOCX). Diese DLLs müssen die FunktionenDllGetClassObject(),DllCanUnloadNow(),DllRegisterServer() undDllUnregisterServer() exportieren.Wird eine COM-Komponente eines In-process-Servers erzeugt, so wird der zugehörige Server (ein Server kann mehrere COM-Komponenten anbieten) in denProzess des Clients geladen. In-process-Server sind besonders schnell, da der Zugriff auf die Funktionen der COM-Komponenten ohne Umwege erfolgt. Nachteilig ist, dass auf diese Weise jeder Prozess eigenen Speicherplatz mit den benutzten COM-Komponenten belegt und keine gemeinsame Speichernutzung möglich ist.ActiveX verwendet dieses Modell.
Local Server sind unter Windows ausführbare Programme, die COM-Komponenten implementieren. Bei der Erzeugung einer COM-Komponente wird dieses Programm gestartet (sofern es nicht schon läuft) – dies bedeutet, dass ein ausführbares Programm vorliegen muss, eine DLL kann hier nicht aufgerufen werden. Zur Kommunikation zwischen Client und Server wird ein vereinfachtes RPC-Protokoll (Remote Procedure Call) benutzt. Local Server haben den Vorteil, dass sie nur einmal gestartet werden müssen und dann viele Clients bedienen können, was weniger Speicherplatz belegt. Zudem lassen sich so recht leicht Datenzugriffe auf einen gemeinsamen Datenbestand synchronisiert von mehreren laufenden Clients durchführen (wie zum Beispiel inMicrosoft Outlook). Die Zugriffe über RPC sind allerdings langsamer.
Befinden sich Server und Client in einemRechnernetz, so kommtDCOM (Distributed COM) zum Einsatz. Der Einsatz von DCOM ermöglicht grundsätzlich den Betrieb von Server und Client auf unterschiedlichen Betriebssystemen.
DCOM benutzt im Gegensatz zum Local Server ein vollständig implementiertes RPC, was die Aufrufe jedoch (auch bei sehr geringer Netzwerkauslastung) deutlich verlangsamt. Die Implementierung vom DCOM unterscheidet sich von der von COM mit Local Server zusätzlich noch durch den vorgeschaltetenProtokollstack.
Die COM-Schnittstelle dient der Kommunikation zwischen Client und Server. Eine COM-Komponente kann dazu über allgemein definierte und vorgegebene Schnittstellen (zum Beispiel IUnknown, IDispatch) sowie über spezielle Schnittstellen angesprochen werden.
Jede Schnittstelle hat eine weltweit eindeutige Identifikationsnummer, dieGUID (Globally Unique Identifier). Dadurch können auch mehrere Schnittstellen mit demselben Namen existieren (aber nicht mit derselben GUID).
Um eine programmiersprachenübergreifende Client/Server-Kommunikation zu ermöglichen, findet an der Schnittstelle das sogenannteMarshalling statt, das die auszutauschenden Daten in eine vordefinierte Binärrepräsentation wandelt.
EineSchnittstelle erfüllt die Funktion einerabstrakten Klasse, die lediglich virtuelle Elementfunktionen enthält, die (wegen der Trennung von Deklaration und Implementierung) in derVTable alle auf 0 gesetzt werden. Die C-Version einer Schnittstelle ist entsprechend eineStruktur, dieFunktionszeiger enthält. Die erzeugten COM-Objekte nutzt man dabei überZeiger auf deren Schnittstellen.
Wenn ein COM-Objekt eine Schnittstelle implementiert, muss es alle Methoden der Schnittstelle überschreiben, also die VTable füllen. Dabei sind mindestens die drei Methoden vonIUnknown zu implementieren, die für das Lebenszyklusmanagement zuständig sind und eventuell vorhandene, weitere implementierte Schnittstellen offenlegen.
Eine Schnittstelle sieht in der für COM-Komponenten nutzbarenIDL (Interface Definition Language) wie folgt aus (als Beispiel dient das InterfaceIUnknown):
//StandardschnittstelleallerCOM-Komponenten[object,uuid(00000000-0000-0000-C000-000000000046)]interfaceIUnknown{[restricted]HRESULT_stdcallQueryInterface([in]GUID*rrid,[out]void**ppvObj);[restricted]unsignedlong_stdcallAddRef();[restricted]unsignedlong_stdcallRelease();}
Jede Schnittstelle muss über eine Schnittstellen-Vererbung die Funktionen der hier gezeigten SchnittstelleIUnknown definieren, da dieses die grundlegenden Funktionen für COM implementiert. Eine weitereVererbung der Schnittstellendefinitionen ist möglich.
Da Programmiersprachen wieVisual Basic Script keine Typen kennen, hat Microsoft eine weitere Möglichkeit entwickelt, Funktionen aus COM-Schnittstellen aufzurufen. Für diese Möglichkeit muss die Schnittstelle die Funktionen der SchnittstelleIDispatch definieren. Dies ermöglicht es, eine COM-Komponente überIDispatch.Invoke() anzusprechen, ohne dass der COM-Client dieTypbibliothek des Servers kennen muss. Da der Zugriff über das Dispatch-Interface sehr viel langsamer als der Zugriff über ein typisiertes Interface ist, wird oft beides implementiert (Dual Interface), so dass bei Programmiersprachen, dieZeiger beherrschen, beide Zugriffsmöglichkeiten zur Verfügung stehen.
Eine COM-Komponente bietet die aufrufbaren Funktionen über eine oder mehrere COM-Schnittstellen an. Die Erzeugung des Objektes erfolgt durch die Implementierung vonIClassFactory.CreateInstance() im COM-Server.
Die Lebensdauer eines Objektes wird mittelsReferenzzählung gesteuert. Eine COM-Komponente lebt nur so lange, wie die Differenz der Aufrufe vonAddRef() (am Beginn der Verwendung einer Instanz) undRelease() (Freigabe nach Verwendung der Instanz) nicht 0 ergibt.
Eine COM-Komponente kann mehrere Schnittstellen anbieten. Dies ist in bestimmten Situationen auch notwendig, um ein Programm erweitern zu können, ohne andere Programme neu kompilieren zu müssen, denn der Compiler kodiert die aus der VTable gelesenen Einsprungadressen der vom Client aufgerufenen Funktionen unter bestimmten Umständen fest. Wird die Schnittstelle einer Komponente später geändert, kann sich die Einsprungadresse ändern, was die Funktionstüchtigkeit des Clients beeinträchtigen würde. Zur Erweiterung der Serverfunktionalität wird also stattdessen eine weitere Schnittstelle implementiert.
Eine Vererbung von COM-Komponenten (Aggregation) ist durch die Anforderungen der Binärkompatibilität nur in wenigen Programmiersprachen möglich. Dazu wird die zu vererbende Komponente über explizite Durchleitung der Schnittstellen über die erbende Komponente veröffentlicht.[1]
Der Client ist das Programm, das
Der Client kennt die Funktionen, die von der COM-Komponente angeboten werden, da diese in den entsprechenden COM-Schnittstellen deklariert sind. Die Veröffentlichung von Schnittstellen erfolgt entweder über Typbibliotheken oder Beschreibungen in derIDL (Interface Definition Language).
COM-Objekte werden bei der Erzeugung immer einem sogenannten Apartment zugeordnet. Dabei handelt es sich um transparente Rahmen, die zur Synchronisierung von Methodenaufrufen mehrerer Objekte dienen, die mit unterschiedlichen Anforderungen an dieThreadsicherheit arbeiten. Wird COM nicht mitgeteilt, dass eine entsprechende Komponente threadsicher ist, wird COM nur einen Aufruf gleichzeitig an ein Objekt erlauben. Threadsichere Komponenten können auf jedem Objekt beliebig viele Aufrufe gleichzeitig ausführen.
Geschieht ein Aufruf im gleichen Apartment zwischen verschiedenen Objekten, ist kein Marshalling erforderlich. Wird jedoch eine Schnittstelle über Apartmentgrenzen hinweg benutzt, muss ein Marshalling erfolgen.
Jeder Thread, der COM verwenden möchte, muss sich vor der ersten Verwendung einer COM-Funktionalität einem Apartment zuordnen (MTA) oder ein neues Apartment erstellen (STA). Dies geschieht über die FunktionCoInitialize(). Programmiersprachen mit integrierter COM-Unterstützung (zum Beispiel VB6 und die meisten.Net-Framework-Sprachen) führen diese Zuordnung oft automatisch durch.
Jede COM-Komponente wird bei Erzeugung einem Apartment zugeordnet. Falls die Apartment-Anforderungen der erzeugten Komponente zum Apartment des erzeugenden Threads passen, wird das Objekt dem gleichen Apartment zugeordnet. Bei Aufrufen über Prozessgrenzen hinweg liegen die beiden Objekte immer in verschiedenen Apartments. Die Zuordnung zu einem Apartment kann während der Lebensdauer des Objektes nicht geändert werden.
Es gibt drei Arten von Apartments:[2]
Durch den Einsatz von COM gibt es die Möglichkeiten
zu programmieren.Viele der Funktionen des „Windows PlatformSDKs“ sind über COM zugänglich. COM ist die Basis, auf derOLE-Automation undActiveX aufbauen. Mit der Einführung des.NET-Frameworks verfolgte Microsoft allerdings die Strategie, COM unter Windows durch dieses Framework abzulösen. Im Folgenden werden die einzelnen Punkte der Aufzählung genauer erläutert.
COM-Komponenten sind unabhängig von der Programmiersprache. COM unterstützt den sogenanntenBinärstandard. Die erzeugte Binärdatei stellt einerseits die implementierten Funktionen zur Verfügung und andererseits eineSchnittstelle, die diese Funktionen aufzeigt. Mit Hilfe der Schnittstelle ist es möglich, von anderen Programmen aus die Funktionen zu verwenden. Dabei wird mit Konzepten aus dem BereichVerteilte Systeme gearbeitet.
Ein weiterer Vorteil beim Einsatz von COM ist es, dass man die Verwaltung von neuen Softwarefeatures einfach in eine bestehende Anwendung integrieren kann. Oftmals kann es Probleme geben, wenn man herstellerneutrale oder herstellerübergreifende Softwarekomponenten mit weiteren Funktionen ausstattet. Dadurch kann zwar die eigene Software erweitert werden, jedoch besteht die Gefahr, dass andere Software, die ebenfalls die herstellerübergreifenden Komponenten verwendet, nicht mehr funktionsfähig bleibt.
COM bietet eine robuste Möglichkeit an, um eine Softwarekomponente mit neuen Funktionen zu erweitern. Dies wird dadurch ermöglicht, dass mehrere Schnittstellen in einerHeader-Datei zusammengefasst werden können. Der folgendeC++-Programmcode verdeutlicht dies:
//// Interface mathematik.h//classIStandardMathFunctions:publicIUnknown{public:STDMETHOD(Addieren)(long,long,long*)STDMETHOD(Subtrahieren)(long,long,long*)};classIAdvancedMathFunctions:publicIUnknown{public:STDMETHOD(Fibonacci)(short,long*)}
DieseHeader-Datei namensmathematik.h enthält zwei Schnittstellen. Die erste Schnittstelle könnte beispielsweise die herstellerübergreifenden Funktionen anbieten, die von verschiedenen Programmen verwendet werden. Durch die zweite SchnittstelleIAdvancedMathFunctions wird diese Softwarekomponente erweitert. Weitere Schnittstellen können jederzeit hinzugefügt werden. Die alten Schnittstellen und darin enthaltenen Funktionen gehen dabei nicht verloren. Das Hinzufügen neuer Schnittstellen statt des Veränderns derselben ist so die von Microsoft gedachte Form, Softwarekomponenten zu erweitern, da so keine Inkonsistenzen entstehen.
x64-Applikationen können dank Marshalling auf 32-bittige COM-Server zugreifen (und umgekehrt). Der COM-Server muss dann in einem eigenen Prozess laufen und seine Objekte können demnach nicht als In-process-Server instanziiert werden. COM-Applikationen sind jedoch fast ausschließlich auf die Windows-Betriebssystemfamilie und von dieser unterstützte Hardware angewiesen, eine Plattformunabhängigkeit war konzipiert[3][4], wurde aber wohl nur in wenigen Ausnahmefällen realisiert.
Beim Einsatz von COM wirdobjektorientiert gearbeitet. Trotzdem können COM-Komponenten auch zum Beispiel in C erstellt und genutzt werden, da dieSchnittstellen tatsächlich eine Sammlung vonFunktionszeigern sind (abstrakte Klasse inC++,struct inC).
COM istortsunabhängig, d. h., dass die einzelnen COM-Komponenten an einer zentralen Stelle(Registrierungsdatenbank) angemeldet werden und so der Zugriff auf die Komponenten unabhängig von ihrem eigentlichen Ort erfolgen kann.
Das Steuern von Anwendungen über COM-Schnittstellen wird als Automatisierung bezeichnet. Von dieser Anwendungsmöglichkeit wird häufig im Rahmen von OLE (Object Linking and Embedding) Gebrauch gemacht.
Durch eine Sicherheitslücke in der RPC-Implementierung von DCOM wurde die Angriffsweise des bekannten WurmsW32.Blaster möglich.