Ich mag COM-Technologie. Wir werden jedoch nicht über Technologie, Lob oder Mängel von COM sprechen, sondern über die Erfahrung beim Portieren und Implementieren unter Linux. Fahrrad? Zweckmäßigkeit?
Konzentrieren wir uns nicht darauf.
COM-Objekt (1)Im Allgemeinen ein Objekt einer Klasse, die mindestens eine COM-Schnittstelle implementiert. Die Implementierung des Objekts ist hauptsächlich in einer dynamisch verbundenen Bibliothek versteckt, die als COM-Server (2) bezeichnet wird. Schnittstellen werden veröffentlicht und zur Verwendung verteilt.
COM-Schnittstelle, eine abstrakte Klasse, die nur reine virtuelle Funktionen enthält. Eine spezielle IUnknown-Schnittstelle ist hervorgehoben. Jedes COM-Objekt muss diese Schnittstelle implementieren.
Jede COM-Schnittstelle muss eine eigene Kennung enthalten. In COM wird es durch die Struktur der GUID bestimmt, und hier werden wir den ersten Nachteil von COM sehen. Die GUID ist unverständlich und liest sich nicht gut und alles andere, was im Wiki beschrieben wird. Wir brauchen es genauso, aber besser lesbar und verständlicher (nennen wir es uiid).
Unbekannt und uiid#define define_uiid(name) \ inline static const std::string& guid() { const static std::string idn(dom_guid_pre_name #name); return idn; } namespace Dom { using uiid = std::string; using clsuid= std::string; struct IUnknown { virtual long AddRef() = 0; virtual long Release() = 0; virtual bool QueryInterface(const uiid&, void **ppv) = 0; define_uiid(Unknown) }; }
Neben der Schnittstellenkennung wird auch die Klassenkennung (clsuid) zugeordnet, die zum Erstellen des Objekts erforderlich ist. In unserem Fall, weil Dies ist eine weniger lesbare Kennung, die das Wesentliche bestimmen kann. Sie können ihre Veröffentlichung vorerst vergessen (möglicherweise ist dies nicht gut).
Zusammenfassung
Ein COM-Objekt, das eine einzelne Klassenkennung enthält. Es implementiert mindestens eine COM-Schnittstelle - IUnknown (jede COM-Schnittstelle hat eine eindeutige Schnittstellenkennung). Verschiedene Implementierungen eines COM-Objekts können dieselbe Klassenkennung haben (Beispiel: Release- und Debug-Version).
COM-Server (2)Eine dynamisch verknüpfte Bibliothek (für Linux ist es ein freigegebenes Objekt - also), die mindestens ein COM-Objekt implementiert. Der Server muss bestimmte Funktionen exportieren:
extern "C" bool DllCreateInstance(const uiid& iid, void** ppv)
Erstellt ein Klassenobjekt mit clsuid und erhöht die Anzahl der Verweise auf jedes Objekt, wenn das Objekt erfolgreich erstellt wurde. Der Aufruf von IUnknown :: AddRef sollte auch die Referenzanzahl erhöhen, und IUnknown :: Release sollte abnehmen.
extern "C" bool DllCanUnloadNow()
Wenn die Anzahl der Verweise auf SO 0 ist, können Sie die Bibliothek entladen.
extern "C" bool DllRegisterServer(IUnknown* unknown)
Registriert alle clsuid-Server in der "Registrierung". Wird während der Installation des COM-Servers einmal aufgerufen.
extern "C" bool DllUnRegisterServer(IUnknown* unknown)
Löscht Einträge über den registrierten clsuid-Server aus der Registrierung. Wird bei der Deinstallation des COM-Servers einmal aufgerufen.
Beispiel SimpleHello: Deklarieren Sie die IHello-Schnittstelle: struct IHello : public virtual Dom::IUnknown { virtual void Print() = 0; define_uiid(Hello) };
Schnittstellenimplementierung: class SimpleHello : public Dom::Implement<SimpleHello, IHello> { public: SimpleHello() { printf("%s\n", __PRETTY_FUNCTION__); } ~SimpleHello() { printf("%s\n", __PRETTY_FUNCTION__); } virtual void Print() { printf("Hello from %s\n",__PRETTY_FUNCTION__); } define_clsuid(SimpleHello) }; namespace Dom { DOM_SERVER_EXPORT_BEGIN EXPORT_CLASS(SimpleHello) DOM_SERVER_EXPORT_END DOM_SERVER_INSTALL(IUnknown* unknown) { Interface<IRegistryServer> registry; if (unknown->QueryInterface(IRegistryServer::guid(), registry)) {
Eine Reihe von Makros verbirgt Funktionsimplementierungen, indem sie eine strukturiertere Deklaration und Logik bereitstellen.
Dom :: Implement <SimpleHello, IHello> - verbirgt die Implementierung von IUnknown-Schnittstellenmethoden und fügt "Zucker" hinzu, wenn von einem Objekt implementierte Schnittstellen deklariert werden (C ++ 11 und verschiedene Vorlagen):
template <typename T, typename ... IFACES> struct Implement : virtual public IUnknown, virtual public IFACES… { ... };
IRegistryServer-Schnittstelle - Definiert eine Reihe von Methoden für die Arbeit mit der „Registrierung“ von COM-Servern.
"Register" von COM-Servern (3)Die Bedeutung des Registers kann unterschätzt werden, aber es ist wahrscheinlich die Hauptsäule von COM. Microsoft schreibt in die Registrierung, erstellt eine komplexe Struktur zur Beschreibung von Schnittstellen und deren Attributen (idl), ich bin einen etwas anderen Weg gegangen.
In der Implementierung basiert die Registrierung auf dem Dateisystem.
Was für Brötchen? Verständlichkeit, Einfachheit, die Möglichkeit der Wiederherstellung, ein besonderes Element bei der Registrierung eines Servers. Sie können eine Art Namespace festlegen (ein Verzeichnis relativ zur Basisregistrierung, in der Serverobjekte registriert werden), um die Integrität und Versionierung von Anwendungen mithilfe der Technologie zu implementieren.
Von den Mängeln, möglichen Sicherheitsproblemen, dem Ersetzen von Objektimplementierungen.
Verwendung, Beispielanwendung (4)Damit alles funktioniert, benötigen Sie eine kleine „Bibliothek“ und ein kleines „Programm“.
"Bibliothek" ist nichts anderes als ein Wrapper, der alles in einem Ganzen implementiert und sammelt, mit der Registrierung arbeitet, SO lädt / entlädt und Objekte erstellt.
Dies ist die einzige, die beim Erstellen der Anwendung angegeben werden muss. Alles andere, "Ich möchte glauben", wird sie selbst tun.
" Programka " - regsrv ist eigentlich ein Analogon zum Microsoft RegSrv32-Programm, das dieselben Aktionen ausführt (+ die Möglichkeit, einen Namespace anzugeben, + die Möglichkeit, eine Liste der registrierten clsuid- und COM-Server abzurufen).
Probe #include "../include/dom.h" #include "../../skel/ihello.h" int main() { Dom::Interface<Dom::IUnknown> unkwn; Dom::Interface<IHello> hello; if (Dom::CreateInstance(Dom::clsid("SimpleHello"), unkwn)) { unkwn->QueryInterface(IHello::guid(), hello); hello->Print(); } else { printf("[WARNING] Class `SimpleHello` not register.\nFirst execute command\n\tregsrv <fullpath>/libskel.so\n... and try again."); } return 0; }
Dom (5)Dom (Dynamic Object Model), meine Implementierung für Linux.
Git-Klon
Vielen Dank.