Ein bisschen Praxis für Erweiterungen
Erinnern Sie sich noch an meinen Beitrag “Ein bisschen Theorie für Erweiterungen“? Darin ging es um die theoretischen Grundlagen, die hinter den Erweiterungsmöglichkeiten von in-STEP BLUE stecken. Erläutert habe ich Ihnen das am Beispiel Hallo Thomas. Auf die Theorie folgt heute das erste Anwendungsbeispiel.
Mit Hallo Thomas sind Sie schon vertraut. Da bietet es sich doch an, genau dieses Beispiel auch für den ersten Praxistest zu verwenden. Das Ziel ist diesmal die Erstellung eines eigenen Befehls, der im Kontextmenü von Produkten angeboten wird und mit dem ich das Produkt begrüße.
In meinem ersten Beitrag hatte ich bereits geschildert, dass für einen eigenen Befehl zwei Schnittstellen aus der isExtension.dll benötigt werden:
- Die ICommandServer-Schnittstelle, über die Befehle in in-Step-Sichten bereitgestellt werden.
- Die ICommand-Schnittstelle, die den eigentlichen Befehl darstellt.
Beispiele für Command-Server finden Sie reichlich in Ihrem in-STEP BLUE-Projekt: Öffnen Sie einfach mal die Eigenschaften einer beliebigen Sicht und wechseln Sie dann auf die Registerkarte Menüpunkte. Sie sehen hier die im Projekt verfügbaren Command-Server und auch welche davon in der gewählten Sicht verwendet werden.
Wie Sie einen Command-Server in Ihr Projekt einbinden und wie dieser dann bei Sichten zugewiesen werden kann, werden Sie im Laufe des Beitrags erfahren.
.NET-Projekt anlegen
Als erstes lege ich im Visual Studio .NET ein neues Projekt inStepHelloExtension des TypsKlassenbibliothek an. Im nächsten Schritt muss ich nun die nötigen Interop-Assemblies referenzieren, um die Erweiterung realisieren zu können. Sie finden die Dlls im in-STEP BLUE-Installationsverzeichnis im Order Interops.
Für meine Komponente mit dem Hallo-Befehl sind dies genau vier:
- Die microTOOL.inStep.Extension.Interop.dll stellt die nötigen Schnittstellen zur Verfügung.
- Die Microsoft.MSXML3.Interop.dll, die microTOOL.Util.Interop.dll und diemicroTOOL.inStep.ModelInterface.Interop.dll muss ich referenzieren, weil diese Komponenten bei den notwendigen Schnittstellen ICommand und ICommandServer verwendet werden.
Außerdem füge ich noch System.Windows.Forms aus dem .NET-Framework hinzu, um in meinem Befehl überhaupt eine Meldung anzeigen zu können. Damit meine Komponente später mit in-STEP BLUE kommunizieren kann, muss sie für COM-Interop registriert werden. Dies ist eine entsprechende Build-Einstellung des Projekts. Dadurch wird beim Kompilieren des Projekts zusätzlich zu der Assembly-Datei eine Typbibliothek erzeugt, über die in-STEP BLUE dann via COM kommunizieren kann.
Befehl implementieren
Nun kann ich mit der Implementierung beginnen. Ich lege zwei neue Klassen an: HelloCommand für den Befehl und HelloCommandServer für dessen Bereitstellung. Wenden wir uns zuerst der HelloCommandServer-Klasse zu. Als erstes werden die entsprechenden Interop-Namespaces per using angegeben, damit deren Typen in meiner Klasse importiert und ohne Vollqualifizierung verwendet werden können. Anschließend kann ich meine Klasse von der Schnittstelle ICommandServer erben lassen.
Zum besseren Verständnis hier eine kleine Liste mit Methoden:
Init: Diese Methode wird von in-Step beim Öffnen einer Sicht bei jedem zugeordneten Command-Server aufgerufen.
Name: Der Name des Command-Servers, der beispielsweise auf der Registerkarte Menüpunkte zu sehen ist.
Supports: Wenn Sie die Eigenschaften einer Sicht öffnen, ruft in-Step von dem registrierten Command-Server diese Methode auf und übergibt per XML-Schema die Art der gewählten Sicht. Der Command-Server kann darüber entscheiden, ob er für diesen Kontext zur Verfügung steht.
Get_Commands: Wenn das Kontextmenü auf einem Element geöffnet wird, übergibt in-Step dem jeweiligen Command-Server die Liste der bereits zugewiesenen Befehle (pi_colCommands). Der Command-Server kann diese Liste nun manipulieren, indem bereits enthaltene Befehle entfernt und eigene Befehle für das Kontextmenü hinzugefügt werden. Die geänderte Collection wird abschließend zurückgeliefert. Das XML-Dokument pi_xdContext enthält die Informationen der in der Sicht selektierten Elemente. Ein Befehl wird i.d.R. mit diesem Kontext und dem im Init übergebenen Model initialisiert.
Bevor ich nun den Command-Server implementiere, richte ich erst mal meinen Befehl ein. Wie beim Command-Server werden die notwendigen using-Statements gesetzt und die Schnittstelle ICommand vererbt. Dabei ist beabsichtigt, dass der Befehl gar nicht über eine Initialisierungsmethode verfügt, über die dem Befehl das Model und der Kontext übergeben werden. Die Initialisierung kann von Ihnen frei definiert werden. Da wir uns in einem C#-Projekt befinden, nehme ich hierzu einen Konstruktor.
Nun kann ich meinen Befehl initialisieren, also rufe ich ihn in meinem Command-Server auf.
Wenn in-STEP BLUE jetzt die Befehle des Command-Servers abfragt, instanziiert dieser ein Objekt meiner Klasse HelloCommand und fügt es der Liste der Commands hinzu. Der zweite Parameter ist ein eindeutiger Schlüssel zur Identifizierung des Befehls. Der dritte Parameter ist immer ein Leerstring (Die MTUTIL.Collection beherrscht zwar grundsätzlich auch die Sortierung, diese Funktionalität wird aber bei Befehlen nicht unterstützt).
Aktuell würde der Befehl immer angezeigt werden. Wenn Sie sich die Schnittstelle von ICommand anschauen, sehen Sie, dass hier zwei Properties angeboten werden, die für die Anzeige bedeutsam sind: Visible und Enabled. Das erste Property regelt, ob der Befehl überhaupt sichtbar ist, das zweite, ob der Befehl ausführbar ist.
Wenn mein Befehl in einem bestimmten Kontext gar nicht sichtbar sein soll, empfiehlt es sich, ihn gar nicht erst in die Liste der Commands aufzunehmen.
Der Befehl wird nun nur dann angeboten, wenn der Benutzer genau ein Produkt ausgewählt hat.
Als nächstes lege ich den Namen des Befehls fest. Da ich das Produkt mit der gebührenden Höflichkeit begrüßen möchte, hole ich mir erst einmal den Namen des Produkts.
Natürlich muss der Befehl auch etwas tun, wenn er ausgeführt wird. Das ist der letzte Schritt meiner Implementierung:
Über die SystemModel-Schnittstelle ermittle ich einfach den Namen des aktuell angemeldeten Benutzers und gebe diesen in einem Nachrichtenfenster aus.
COM-Aufruf vorbereiten
Meine Komponente ist damit fertig. Allerdings lässt sie sich noch nicht in in-STEP BLUE zuweisen. Der Grund ist, dass die beiden Klassen über COM noch nicht sichtbar sind.
Um dies einzustellen, erstelle ich einen using-Statement auf die InteropServices in beiden Klassen. Über ComVisible(true) wird festgelegt, dass diese Klasse über COM aufgerufen werden kann. Dazu muss sie über eine ProgID verfügen und über eine eindeutige ID (Guid). Die Guid können Sie im Visual Studio über Extras/GUID erzeugen.
Die neue Komponente in in-STEP BLUE registrieren
Nachdem nun beide Klassen sichtbar sind, kann ich das Projekt im Visual Studio kompilieren. Anschließend öffne ich mein in-STEP BLUE-Projekt – als System- oder Projektadministrator – und wähle im Hauptmenü den Befehl Projekt/Komponenten und anschließend auf Registrieren.
Hier wähle ich die inStepHelloExtension.tlb aus. Einige Anwender, die in dem Dialog bereits unterwegs gewesen sind, werden sich eventuell fragen, warum ich nicht die Dll auswähle (wie man es hier normalerweise tut).
Der Grund ist, dass es sich bei den Dlls von in-STEP BLUE in den meisten Fällen um ActiveX-Dlls handelt. Diese sind direkt über COM verfügbar. In meinem Beispiel handelt es sich jedoch um ein .NET-Assembly, das erst über die Typbibliothek via COM sichtbar gemacht wird. Deshalb muss in diesem Fall die Typbibliothek zugewiesen werden.
Hinweis:
Sollten Sie die Meldung bekommen, dass die Datei keine gültige Typbibliothek ist, kann dies unterschiedliche Ursachen haben:
- Die tlb-Datei wurde nicht zugewiesen.
- Die Komponente (in diesem Fall die Dll) wurde bisher nicht unter Windows registriert (siehe unten).
- Es tritt ein Fehler innerhalb der Komponente auf, der nicht von der Komponente selbst behandelt wird.
Beispielsweise ist noch der Standardaufruf “throw new NotImplementedException” im Property-Name des Command-Servers enthalten. In diesem Fall kann in-Step den Namen der Klasse zur Anzeige in der Liste nicht ermitteln. - Die ProgID der jeweiligen Klasse muss sich immer wie folgt zusammensetzen: %DllName%.%Klassenname%
Anderenfalls findet in-STEP BLUE diese Klassen nicht. Dies ist deshalb besonders anzumerken, weil Sie im Visual Studio die ProgID generell frei bestimmen können.
Nach der erfolgreichen Zuweisung finde ich meinen Command-Server in der Liste der Menüpunkte wieder und ordne ihn einer meiner Produktsichten zu:
Hallo!
Jetzt kann ich mein Projekt erfolgreich begrüßen! Freude.
Anmerkung zum Registrieren:
Wenn Sie die Komponente übersetzen, dann wird sie standardmäßig auf Ihrem Rechner registriert. Damit auch andere Anwender in Ihrem System den Befehl aufrufen können – und keine Fehlermeldung erhalten, dass die Komponente nicht gefunden wurde –, müssen Sie diese auf allen Clients verteilen.
Dazu werden die Dateien, die im Debug-Ordner des Projekts zu finden sind, in den Interop-Ordner des Clients kopiert. Die Dateien, die in-STEP BLUE standardmäßig mitliefert, brauchen Sie natürlich nicht extra zu kopieren. In meinem Beispiel müsste ich also die inStepHelloExtension.dll und die inStepHelloExtension.tlb kopieren.
Jetzt muss die Komponente nur noch auf den Clients registriert werden: Öffnen Sie dazu als Administrator die Kommandozeile von Windows und geben Sie abhängig von Ihrer Verzeichnisstruktur folgenden Befehl ein:
“C:WindowsMicrosoft.NETFrameworkv2.0.50727RegAsm.exe”
“C:ProgrammemicroTOOLin-StepInteropsinStepHelloExtension.dll” /codebase
Die Komponente kann nun auch auf dem entsprechenden Client verwendet werden. Da der Command-Server nur auf der Client-Seite aktiv ist, weil er auf den Server nur mittels Model-Funktionen zurückgreift, muss eine Registrierung auf dem in-STEP BLUE-Server-Rechner nicht erfolgen.
Ich bin gespannt auf Ihre Erfahrung.
Diskutieren Sie mit.