Hallo zusammen,
nachdem man meiner Meinung nach viel zu wenige Informationen zum Thema Pluginentwicklung für DMXControl 2.xx in anderen Sprachen als VB6.0 hier im Forum und im Wiki findet, trag ich hier mal zusammen, was ich die letzten Tage so recherchiert und rausgefunden habe (teilweise durch Trial&Error).
Meine Ausgangslage war, dass ich ein DMX Interface auf der Arduino Plattform entwickelt und erfolgreich zum Laufen gebrachte hatte, und nun dafür ein Ausgabeplugin für DMXControl schreiben wollte. Schnell war klar, dass hier sämtliche Samples und Informationen auf Visual Basic 6.0 hinauslaufen, nachdem auch DMXControl selbst in VB6 geschrieben ist. Das kam für mich allerdings nicht infrage, da ich erstens aus Prinzip (aufgrund persönlicher Vorlieben) vermeide, irgendetwas in BASIC Syntax zu schreiben, und auch nicht irgendwo ein altes VB6 ausgraben wollte, nachdem man als Student schon legalen Zugriff auf die neuesten Versionen von MS Visual Studio hat. Hier und da findet man zwar auch ein paar Anregungen und Anfragen für Plugins in C++ oder .NET, aber wirklich was konkretes war nicht dabei. Auch die Wrapper Lösung (DMXC -> VB6 -> .NET) gefiel mir nicht so besonders.
Zuerst muss man einmal wissen, dass VB6 die letzte Version von VB war, die nicht auf .NET basierte, sondern dessen komplette Objektorientierung über COM/ActiveX Objekte geregelt wurde. Will man also ein Ausgabeplugin für DMXControl schreiben, muss dies konkret dann eine COM/ActiveX-DLL sein, die bestimmte Schnittstellen implementiert (unabhängig von VB6). Deswegen ist die Aussage, dass man Plugins in jeder Sprache schreiben kann, in der man DLL's erzeugen kann, schon einmal grenzwertig. Dies ist zwar prinzipiell immer möglich, stellt aber einen nicht zu realisierenden Aufwand dar, falls die entsprechende Entwicklungsumgebung keine Vorlagen und Konstrukte zur Erzeugung von COM/ActiveX Objekten bereitstellt. In meinem Fall kamen jetzt nur C# (oder jede andere .NET Sprache) und C++ (hier allerdings konkret auch mit MS Visual Studio, sonst kann mans wohl auch so ziemlich vergessen) infrage. Nach etwas Überlegung habe ich mich dann für C++ entschieden.
Nachfolgend noch ein paar Ausführungen, wie DMXControl konkret ein Ausgabeplugin instantiiert (bzw. allgemein COM-Objekte instantiiert werden). Bitte beachten, dass ich keinen Source Code kenne, sondern nur durch die Verhaltensweise, wie ich sie beobachten konnte, beschreiben kann:
- - Grundsätzlich läuft der Aufruf eines COM-Objektes etwas komplizierter als der einer normalen DLL Funktion. Es reicht also nicht der Pfad zur DLL und der Name der Funktion dazu, sondern es gehört weit aus mehr dazu.
- - Konkret wird ein COM/ActiveX Objekt normalerweise immer durch den Aufruf der WindowsAPI-Funktion CoCreateInstance(Ex) instantiiert. Um ein ActiveX-Objekt zu instantiieren, braucht man entweder die ClassID (CLSID, eine eindeutige GUID zur Identifikation der COM/ActiveX Klasse) oder die ProgID (ein freundlicher Name wie z.B. "SampleDMXPlugin.clsOutputDriver"), welcher dann wiederum auf die ClassID verweist). Beide finden sich in der Registry (HKEY_CLASSES_ROOT(/CLSID)), und im Schlüssel "InprocServer32" unter der CLSID verweist dann tatsächlich wieder ein Pfad auf die DLL.
- - Wie kommen die Informationen in die Registry? Klassische ActiveX/COM-Objekte besitzen eine (native) DLL-Funktion DllRegisterServer() die man entweder auf der Kommandozeile mit regsvr32 oder direkt aufrufen kann. Diese Funktion sorgt dafür, dass sämtliche Registry-Einträge erstellt werden, das ActiveX/COM-Objekt wird "registriert". Dies geschieht entweder einmal bei einer Installation durch einen Installer oder wie im Falle von DMXControl bei jedem Programmstart erneut. Dies kann Vorteile haben (die Existenz und Korrektheit der Registry-Einträge ist immer sichergestellt), andererseits auch Nachteile (siehe dann unter C#/.NET). Dies wird v.a. dann gemacht, wenn das konkrete Objekt nur durch ein einziges Programm (hier nur DMXControl) verwendet wird, sodass es dieses am Progammende durch DllUnregisterServer() die Regsistrierung auch wieder entfernen kann.
- - Woher weiß DMXControl aber dann, welche CLSID bzw. ProgID es instantiieren soll, die Anzahl und v.a. welche Plugins sind ja zur Entwicklungszeit nicht bekannt? Zu jedem ActiveX/COM-Objekt gibt es eine sogenannte Type Library. Dies ist eine binäre Datei, in der die Schnittstelle, die konkreten Objekte/Klassen, Methoden und Eigenschaften des ActiveX/COM-Objektes definiert sind. Diese gibt es oft separat als .tlb-Datei und wird auch benötigt, um sich z.B. für ein fremdes ActiveX/COM-Objekt automatisch von Visual Studio in C++ Wrapper-Funktionen generieren lassen kann, um ActiveX/COM-Objekte wie nativen Code aufrufen zu können. In fertigen ActiveX/COM-DLL's wird diese meistens auch als Ressource namens "TYPELIB" in der DLL selbst mit ausgeliefert. Diese verwendet DMXControl, um den Librarynamen und den CoClass-Namen herauszufinden, welche dann als ProgID verwendet werden, welche zur CLSID führt, um die ActiveX/COM-Klasse zu instantiieren.
- - Wenn man also den "Weg" beschreibt, der beschritten wird, beginnt dieser bei der DLL selbst (wo auch sonst?), nimmt dann einige Umwege über die Registry, und landet dann letztendlich doch wieder bei ihr selbst. Ob das ganze im Allgemeinen so sinnvoll ist, sei mal dahingestellt, aber so funktioniert nun mal COM/ActiveX.