DecaTec

Programmieren, Fotografie, Home-Server und einiges mehr

Erweitertes Plugin für Windows Server Advanced Power Management entwickeln

Nachdem in einem der letzten Artikel bereits die Entwicklung eines einfachen Plugins für Windows Server Advanced Power Management beschrieben wurde, soll hier nun die Vorgehensweise zur Entwicklung eines erweiterten Plugins für WSAPM beschrieben werden.

Zur Entwicklung kommt Visual Studio 2013 zum Einsatz, die Vorgehensweise sollte aber auch auf andere Entwicklungsumgebungen übertragbar sein. Die Programmiersprache ist C#, man kann aber auch jede andere .NET-Programmiersprache verwenden.

Einfaches oder erweitertes Plugin?

Zunächst sollen noch einmal kurz die Unterschiede zwischen einem einfachen und einem erweitertem Plugin für WSAPM erläutert werden:
Beide Plugin-Typen dienen in erster Linie dazu, WSAPM mit benutzerdefinierten Richtlinien zum regelbasierten Unterdrücken des Standby-Modus zu erweitern. Einfache Plugins für WSAPM können dabei nur recht einfache Richtlinien implementieren, wie beispielsweise die Überprüfung, ob momentan Wechsellaufwerke mit dem Rechner verbunden sind.

Erweiterte Plugins für WSAPM bieten darüber hinaus auch benutzerdefinierte Einstellungen mit der dazugehörigen Oberfläche zur Konfiguration.

Genau aus diesem Grund macht die Entwicklung eines erweiterten Plugins nur dann Sinn, wenn dieses auch Einstellungen benötigt, die vom Benutzer veränderbar sein sollen. Falls dies nicht der Fall ist, sollte ein einfaches Plugin entwickelt werden, da sich die Entwicklung eines einfachen Plugins um einiges einfacher gestaltet.

Anforderungen

Das hier zu implementierende erweiterte Plugin soll folgenden Anforderungen entsprechen:

  • Das Plugin soll überprüfen, ob ein (lokal) installierter Drucker eingeschaltet ist und den Standby-Modus ggf. unterdrücken. Die Beschränkung auf lokal installierte Drucker erfolgt hier deshalb, da es nicht ohne weiteres möglich ist, den Status von Netzwerkdruckern oder auf einer anderen Maschine freigegebenen Druckern zu überprüfen.
  • Da bei einem Rechner durchaus mehrere Drucker installiert sein können, soll das Plugin dem Benutzer die Möglichlkeit bieten, die zu überprüfenden Drucker auszuwählen. Dazu soll eine eigene Oberfläche mittels WPF implementiert werden.

Voraussetzungen

  • Windows Server Advanced Power Management muss bereits installiert sein, da die Installation die DLL enthält, die später im Projekt referenziert werden muss.

 Erstellung des Grundgerüsts für das erweiterte Plugin

Zunächst wird in Visual Studio ein neues Projekt vom Typ Class Library angelegt. Wir nennen das Projekt LocalPrintersOnlinePlugin.

Neuanlage eines Projekts vom Typ Class Library

Neuanlage eines Projekts vom Typ Class Library

Die automatisch erzeugte Klasse Class1 wird in LocalPrintersOnlinePlugin umbenannt.

Anschließend wird eine Referenz auf die Datei Wsapm.Extensions.dll hinzugefügt.

Hinzufügen einer Referenz in Visual Studio

Hinzufügen einer Referenz in Visual Studio

Diese befindet sich im Installationsordner von Windows Server Advanced Power Management (standardmäßig unter C:\Program Files (x86)\Windows Server Advanced Power Management). Im Reference Manager muss dafür mittels Browse nach der Datei gesucht werden.

Angabe der Datei Wsaom.Extensions.dll im Reference Manager

Angabe der Datei Wsaom.Extensions.dll im Reference Manager

Ebenso muss eine Referenz auf System.ComponentModel.Composition hinzugefügt werden. Dies ist eine .NET Framework DLL und kann im Reference Manager unter Assemblies gefunden werden.

Implementierung der Überprüfungs-Logik

Bevor das die bestehende Klasse nun als Plugin deklariert wird, implementieren wir zunächst die Überprüfungs-Logik. Hierbei ist es empfehlenswert, die Überprüfungs-Logik in eine separate Klasse auszulagern, damit dieser Code vom technischen Plugin-Code getrennt werden kann.

Zunächst wird dem Projekt eine neue Klasse PrintHelper hinzugefügt. Diese Klasse bietet Methoden, um die lokal installierten Drucker zu finden und zu überprüfen, ob ein angegebener Drucker eingeschaltet ist. Die erforderlichen Daten werden hierbei über WMI ermittelt. Daher muss dem Projekt noch eine Referenz auf System.Management hinzugefügt werden.

Die komplette Klasse PrintHelper sieht somit folgendermaßen aus:

 Implementieren der Settings-Klasse

Da ein erweitertes Plugin Einstellungen bietet, muss ebenfalls eine Settings-Klasse implementiert werden, in der sämtliche Plugin-Einstellungen gespeichert werden. Dazu fügen wir eine neue Klasse LocalPrintersOnlinePluginSettings hinzu.
Diese Klasse besitzt nur eine Eigenschaft OnlinePrinters, die eine Liste der Drucker zurück liefert, deren Status überprüft werden soll:

Die Klasse (und alle Eigenschaften) müssen dabei als public deklariert werden. Ebenfalls sollte die Klasse serialisierbar sein, also das Attribut Serializable aufweisen. Diese Schritte sind notwendig, da beim Speichern der Einstellungen eine Instanz dieser Klasse mittels XML serialisiert wird.

 Implementieren der Oberfläche

Als nächstes wird die Oberfläche implementiert. Die Oberfläche kann sowohl ein Windows Forms Control, als auch mittels WPF implementiert werden. Ich entscheide mich hier für ein WPF-Control. Dieses wird dem Projekt als LocalPrintersOnlinePluginSettingsControl hinzugefügt.

Hinzufügen eines WPF-Controls

Hinzufügen eines WPF-Controls

Damit das Projekt nun fehlerfrei gebaut werden kann, muss noch manuell eine Referenz auf System.Xaml hinzugefügt werden.

Die Oberfläche soll später eine Liste mit den lokal installierten Druckern anzeigen. Diese Liste wird dynamisch bei Laden der Oberfläche erzeugt. Daher fügen wir an dieser Stelle nur eine GroupBox und ein DockPanel hinzu, welches wiederum ein StackPanel beinhaltet. Die Oberflächen-Klasse sieht somit folgendermaßen aus:

In der Code-Behind-Datei der Oberfläche muss nun der Code hinzugefügt werden, damit das Control als WSAMP-SettingsControl verwendet werden kann. Dazu muss die Klasse das Interface IWsapmPluginSettingsControl implementieren. Dazu müssen zwei Methoden ausprogrammiert werden:

  1. GetSettingsBeforeSave: Diese Methode wird von WSAPM aufgerufen, wenn die Einstellungen des Plugins gespeichert werden sollen. An dieser Stelle muss aus dem Einstellungen an der Oberfläche eine Instanz der Settings-Klasse erstellt werden.
  2. SetSettings: Diese Methode wird von WSAPM aufgerufen, wenn die Oberfläche des Plugins in WSAPM angezeigt werden soll. Der Parameter liefert eine Instanz der Settings-Klasse, in der die aktuell gespeicherten Einstellungen enthalten sind. Da die Einstellungen als object geliefert werden, muss hier ein Cast auf die konkrete Einstellungs-Klasse (in diesem Fall LocalPrintersOnlinePluginSettings) erfolgen.

Neben den Methoden aus dem Interface muss an dieser Stelle auch der Code zum dynamischen Aufbereiten der Oberfläche implementiert werden (Methode BuildUI), so dass die komplette Code-Behind-Datei folgendermaßen aussieht:

 Implementieren der Plugin-Klasse

Nun folgen die Schritte, um die Klasse in ein WSAPM Plugin zu wandeln und alle bis hierhin hinzugefügten Komponenten und Klassen zusammen spielen zu lassen: Zunächst wird die Klasse LocalPrintersOnlinePlugin mit dem Attribut WsapmPlugin versehen. Durch dieses Attribut wird Windows Server Advanced Power Management das Plugin als solches erkennen und einbinden. Dazu müssen drei Parameter angegeben werden, die das Plugin beschreiben:

  1. Der erste Parameter gibt den (internen) Namen des Plugins an. Dieser Name ist nur der interne Name des Plugins und gibt prinzipiell nur den Namen des Orders an, in dem das Plugin installiert wird.
  2. Der zweite Parameter gibt die Versionsnummer des Plugins an..
  3. Der letzte Parameter muss eine GUID sein. Diese kann einfach in Visual Studio unter Tools > Create GUID (am besten das Registry Format wählen) erzeugt werden. Es ist sehr wichtig, dass jedes Plugin eine eigene GUID besitzt, da WSAPM die Plugins anhand ihrer GUID unterscheidet. Diese GUID darf sich bei einem Plugin niemals ändern, auch wenn eine neue Version des Plugins erscheint.
    Im Rahmen dieser Anleitung werde ich keine konkrete GUID angeben (sondern nur den Platzhalter {YOUR-GUID-HERE}) dass diese nicht kopiert werden kann.

Danach muss noch das Attribut System.ComponentModel.Composition.Export über die Klasse LocalPrintersOnlinePlugin geschrieben werden. Dies sorgt im Grunde genommen dafür, dass die Plugin-DLL dynamisch zur Laufzeit von WSAPM geladen werden kann. Der Parameter  definiert das Plugin als WSAPM-Plugin und muss immer typeof(WsapmPluginBase) heißen, auch wenn es sich hierbei um ein erweitertes Plugin handelt.

Somit haben wir folgende Klassendefinition für die Plugin-Klasse:

Als nächstes muss die Klasse von WsapmPluginAdvancedBase abgeleitet werden. Dies sorgt dafür, dass sechs Methoden überschrieben werden müssen:

  1. Initialize: Diese Methode dient zur Initialisierung des Plugins und wird genau ein mal nach dem Laden des Plugins aufgerufen und kann dazu verwendet werden, einmalige Initialisierungs-Maßnahmen vorzunehmen.
    Der Rückgabewert gibt Auskunft darüber, ob die Initialisierung des Plugins erfolgreich abgeschlossen wurde. Wird hier false zurückgeliefert, wurde das Plugin nicht erfolgreich initialisiert (z.B. im Fehlerfall) und wird von WSAPM nicht in die Überprüfungs-Routinen mit einbezogen. Da keine Initialisierung für das Plugin nötig ist, wird hier einfach true zurückgeliefert.
  2. Prepare: Diese Methode wird immer kurz vor der eigentlichen Überprüfungs-Routine aufgerufen und kann dazu verwendet werden, Initialisierungen vorzunehmen, die vor jeder Überprüfung stattfinden müssen.
    Der Rückgabewert gibt wiederum Auskunft darüber, ob die Vorbereitung erfolgreich abgeschlossen wurde. Wird hier false zurückgeliefert (z.B. im Fehlerfall), wird WSAPM die Überprüfungs-Routine des Plugins im Folgenden nicht ausführen. Da das Plugin keinerlei Vorbereitungen zur Ausführung der Überprüfungs-Routine benötigt, wird hier einfach true zurückgeliefert.
  3. CheckPluginPolicy: Dies ist die eigentliche Überprüfungs-Routine des Plugins.
    Das Ergebnis der Überprüfung wird als PluginCheckSuspendResult zurückgeliefert. Der Konstruktor dieser Klasse erwartet zwei Parameter: Der erste Parameter gibt Auskunft darüber, ob der Standby-Modus von WSAPM unterdrückt werden soll (true: Standby-Modus soll unterdrückt werden; false: Standby-Modus soll nicht unterdrückt werden). Der zweite Parameter ist ein String, welcher den Grund für eine mögliche Unterdrückung des Standby-Modus angibt. Dieser Parameter wird von WSAPM nur ausgewertet, wenn der Standby-Modus tatsächlich unterdrückt werden soll.
    In diesem Fall muss an dieser Stelle die Überprüfung der einzelnen Drucker erfolgen. Für alle Drucker, die in den Einstellungen ausgewählt wurden, wird hier überprüft, ob das entsprechende Gerät eingeschaltet ist. Dazu kommt wieder die Klasse PrintHelper zum Einsatz.
  4. TearDown: Diese Methode wird jedes Mal direkt nach der Überprüfung aufgerufen und kann dazu verwendet werden, um notwendige Aufräumarbeiten durchzuführen.
    Der Rückgabewert gibt wieder an, ob das Aufräumen erfolgreich beendet wurde. Da das Plugin keine solcher Aufräumarbeiten ausführen muss, wird hier wieder einfach nur true zurückgeliefert.
  5. LoadDefaultSettings: Mit dieser Methode werden die Standard-Einstellungen des Plugins geladen und zurück geliefert. In diesem Fall handelt es sich dabei nur um eine leere Instanz der Settings-Klasse, da ohne bereits vorliegende Einstellungen kein Drucker zur Überprüfung ausgewählt sein soll.
  6. SettingsControl: Im Getter dieser Eigenschaft wird die Referenz auf die Oberflächen-Klasse des Plugins zurück geliefert. Wichtig dabei ist, dass immer die gleiche Instanz der Oberflächen-Klasse geliefert wird. Daher wird eine private Variable des Typs der SettingsControl-Klasse angelegt und immer nur diese eine Instanz im Getter der Eigenschaft zurückgeliefert. Diese Vorgehensweise ähnelt dem Singleton-Entwurfsmuster.

Darüber hinaus braucht die Plugin-Klasse einen parameterlosen Konstruktor, der als public deklariert wird und den Konstruktor der Basis-Klasse (LocalPrintersOnlinePluginSettings) mit dem Typ der Settings-Klasse aufruft.

Die komplette Implementierung der Plugin-Klasse:

Das Plugin-Manifest

Ein weiterer wichtiger Punkt ist das sog. Plugin-Manifest. Dies ist eine XML-Datei mit weiteren Angaben zum Plugin. Diese Informationen dienen zwei Zwecken: Zum einen werden die Informationen aus dem Manifest an der Oberfläche von WSAPM (Tabe Plugins in den Einstellungen) angezeigt. Zum anderen wird durch das Manifest eine Unterstützung von mehreren Sprachen möglich.

Das Manifest hat einen definierten Aufbau:

In stellt eine sog. DescriptionSet die Beschreibung eines Plugins für eine bestimmte Sprache dar. Die Sprache wird dabei mit dem Attribut lang angegeben und ist ein zweistelliger Sprachcode nach ISO 639-1 (z.B. „en“ für Englisch, „de“ für Deutsch). Der hier angegebene Name des Plugins, die Beschreibung und der Name des Autors werden in der entsprechenden Sprache des Benutzers auf der Oberfläche von WSAPM angezeigt.

Weitere Informationen zum Plugin

Darüber hinaus ist es auch möglich, weitere Informationen zu einem Plugin anzugeben. Wenn das Plugin beispielsweise einige Einstellungen hat, bietet es sich an, diese Einstellungen weiter zu beschreiben. Dazu wird eine Datei ReadMe.txt dem Plugin hinzugefügt. Die Inhalte dieser Datei werden angezeigt, wenn auf der Oberfläche auf die Schaltfläche Plugin Info geklickt wird (Tabe Plugins in den Einstellungen). Es können auch weitere Dateien für andere Sprachen hinzugefügt werden: hier sollte dann wieder ein zweistelliger Sprachcode an den Dateinamen angehängt werden (z.B. ReadMe_de.txt für eine Beschreibung des Plugins in Deutsch).

Diese Dateien sind dabei optional. Wenn ein Plugin keine ReadMe-Datei beinhaltet, werden beim Klick auf die Schaltfläche Plugin Info einfach nur allgemeine Informationen zu einem Plugin angezeigt.

Das Plugin für die Verteilung vorbereiten

Nachdem die Implementierung des Plugins abgeschlossen wurde, kann das Plugin für die Verteilung vorbereitet werden. Dazu sollte die Solution zunächst einmal gebaut werden (im Release-Modus). Anschließend suchen wir den bin\Release Ordner im Projektverzeichnis. Dieser enthält die gebauten Dateien unseres Plugins. Wichtig ist in diesem Fall zunächst die Datei LocalPrintersOnlinePlugin.dll. Die anderen Dateien (v.a. die Wsapm.Extensions.dll) sollte nicht weitergegeben werden.

Falls eine Lokalisierung des Plugins vorgenommen wurde, befindet sich im Order bin\Release\<Sprache> eine Satelliten-Assembly namens LocalPrintersOnlinePlugin.resources.dll mit den lokalisierten Ressourcen (z.B. im Ordner bin\Release\de für eine Ressourcen-DLL mit deutschen Ressourcen). Ressourcen-DLLs, die Teil von WSAPM sind (z.B. Wsapm.Extensions.resources.dll) sollten auch nicht weitergegeben werden.

Alle zum Plugin gehörenden Dateien werden nun durch ein ZIP-Programm (z.B. 7zip) gepackt. Wichtig dabei ist, dass es sich um eine ZIP-Datei (Dateiendung *.zip) handelt. Nur so kann das Plugin in WSAPM installiert werden. Diese ZIP-Datei kann nun weitergeben werden.

Installation des Plugins

Das Plugin lässt sich nun in den Einstellungen von WSAPM installieren. Dazu einfach in die Tabe Plugins wechseln und auf Plugin installieren klicken. WSAPM wird im Rahmen der Installation beendet und neu gestartet. Danach muss das Plugin nur noch in den Einstellungen aktiviert werden.

Plugin nach der Installation

Plugin nach der Installation

Mit einem Klick auf den Button Plugin-Einstellungen gelangt man zu den Einstellungen des soeben installierten Plugins.

Die Einstellungen des Plugins

Die Einstellungen des Plugins

Weitere Möglichkeiten

Dieses erweiterte Plugin wurde von Grund auf entwickelt. Wer sich nicht mit der Erstellung des Plugin-Grundgerüsts beschäftigen will, für den gibt es ein Vorlage als Visual Studio Solution zum Download. Zu finden ist diese auf der Seite von Windows Server Advanced Power Management. Mit Hilfe dieser Vorlage ist im Grunde genommen nur noch die reine Plugin-Logik und das Zusammenspiel mit der Oberflächen-Klasse zu implementieren.

Darüber hinaus bietet es sich an, ein Plugin zu lokalisieren, wenn dieses nicht nur für den privaten Gebrauch programmiert wurde und weitergegeben werden soll. Windows Server Advanced Power Management unterstützt aktuell Deutsch und Englisch, daher wäre es wünschenswert, wenn Plugins ebenso beide Sprachen unterstützen würden.
Da die Lokalisierung von .NET Anwendungen den Rahmen dieses Artikels sprengen würde, wird an dieser Stelle nicht weiter auf dieses Thema eingegangen.

Im Sourcecode des Plugins, welcher weiter unten herunter geladen werden kann, ist eine solche Lokalisierung bereits implementiert.

Sourcecode

Der gesamte Sourcecode des entwickelten Plugins kann hier herunter geladen werden. Es wurde lediglich die Lokalisierung (Deutsch/Englisch) für das entwickelte Plugin hinzugefügt.
Damit der Code als Plugin lauffähig ist, muss nur noch eine echte GUID in das WsapmPlugin Attribut eingefügt werden, wie bereits weiter oben beschrieben.

LocalPrintersOnlinePlugin_Source.zip

Ihr habt ein eigenes Plugin entwickelt?

Falls ihr ein eigenes Plugin für WSAPM entwickelt habt und der Meinung seid, dass dieses Plugin auch für andere interessant sein könnte, dann schreibt mir doch einfach eine E-Mail. Beschreibt kurz, was euer Plugin macht und wie es funktioniert. Ich werde dann das Plugin (mir eurer Genehmigung) auf der Website veröffentlichen, so dass es auch andere herunterladen und nutzen können.

Falls ihr eine gute Idee für ein Plugin habt, es aber nicht selbst programmieren wollt, könnt ihr mir natürlich auch eine E-Mail schreiben.

, , , , ,

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.