Inhaltsverzeichnis
Tutorial: Hello World Add-in
Dieses Tutorial zeigt, wie ein minimales Add-in von Grund auf erstellt wird. Am Ende steht ein funktionierendes Add-in, das einen Command registriert, einen Menüpunkt hinzufügt und eine Benachrichtigung anzeigt.
Zurück zur Übersicht.
Voraussetzungen
- Free Pascal Compiler (FPC) in der Version, die der Host verwendet
- Lazarus IDE (optional, aber empfohlen für die Formular-Entwicklung)
- WvdS Add-in SDK (die Unit
WvdS.Document.Host.Api)
Projektstruktur
hello-world/
├── plugin.json ← Manifest
├── package.nls.json ← Standard-Übersetzung
├── bin/
│ └── HelloWorld.dll ← Wird vom Compiler erzeugt
├── media/
│ └── hello.svg ← Command-Icon
└── src/
├── HelloWorld.lpr ← Library-Hauptdatei
└── HelloWorldPlugin.pas ← Plugin-Implementierung
Schritt 1: Manifest erstellen
Die Datei plugin.json beschreibt das Add-in vollständig. Der Host liest sie, bevor die DLL geladen wird.
{ "id": "demo.hello-world", "name": "hello-world", "displayName": "Hello World", "description": "Ein minimales Beispiel-Add-in", "version": "1.0.0", "publisher": "demo", "kind": "native", "main": "bin/HelloWorld.dll", "engineVersion": "^1.0.0", "activationEvents": [ "onCommand:hello.sayHello" ], "permissions": [], "contributes": { "commands": [ { "command": "hello.sayHello", "title": "Hallo sagen", "category": "Hello" } ], "menus": { "menuBar/help": [ { "command": "hello.sayHello", "group": "demo", "order": 1 } ], "commandPalette": [ { "command": "hello.sayHello" } ] } } }
Die Datei deklariert einen einzigen Command (hello.sayHello), der im Hilfe-Menü erscheint und über die CommandPalette erreichbar ist. Das activationEvents-Array sagt dem Host, dass die DLL erst geladen werden soll, wenn dieser Command zum ersten Mal aufgerufen wird.
Schritt 2: Library-Hauptdatei
Die Datei HelloWorld.lpr ist der Einstiegspunkt der DLL. Sie exportiert die beiden Funktionen, die der Host erwartet.
library HelloWorld; {$mode objfpc}{$H+} uses WvdS.Document.Host.Api, HelloWorldPlugin; const WVDS_MAGIC = $57564453; ABI_VERSION = 1; FPC_VERSION = {$I %FPCVERSION%}; function GetAbiInfo: TPluginAbiInfo; stdcall; begin Result.Magic := WVDS_MAGIC; Result.AbiVersion := ABI_VERSION; Result.FpcVersion := FPC_VERSION; end; function CreatePlugin(const AHost: IHost): IPlugin; stdcall; begin Result := THelloWorldPlugin.Create(AHost); end; exports GetAbiInfo, CreatePlugin; end.
GetAbiInfo liefert die Kompatibilitätsinformationen. Der Host prüft Magic-Number, ABI-Version und FPC-Version, bevor er CreatePlugin aufruft. CreatePlugin erzeugt das Plugin-Objekt und gibt es als IPlugin zurück.
Schritt 3: Plugin-Implementierung
Die Datei HelloWorldPlugin.pas enthält das Plugin und seinen Command-Handler.
unit HelloWorldPlugin; {$mode objfpc}{$H+} interface uses WvdS.Document.Host.Api; type THelloWorldPlugin = class(TInterfacedObject, IPlugin) private FHost: IHost; public constructor Create(const AHost: IHost); procedure Activate(const AContext: IExtensionContext); procedure Deactivate; end; implementation type TSayHelloHandler = class(TInterfacedObject, ICommandHandler) private FHost: IHost; public constructor Create(const AHost: IHost); procedure Execute; end; { THelloWorldPlugin } constructor THelloWorldPlugin.Create(const AHost: IHost); begin inherited Create; FHost := AHost; end; procedure THelloWorldPlugin.Activate(const AContext: IExtensionContext); begin AContext.Subscribe( FHost.Commands.RegisterCommand('hello.sayHello', 'Hallo sagen', TSayHelloHandler.Create(FHost)) ); end; procedure THelloWorldPlugin.Deactivate; begin // Nichts zu tun — der Host räumt alle Registrierungen automatisch auf. end; { TSayHelloHandler } constructor TSayHelloHandler.Create(const AHost: IHost); begin inherited Create; FHost := AHost; end; procedure TSayHelloHandler.Execute; begin FHost.Notifications.ShowInfo('Hallo von Hello World!'); end; end.
Der TSayHelloHandler ist der eigentliche Code hinter dem Command. Wenn der Benutzer „Hallo sagen“ auswählt, ruft der Host Execute auf, und das Add-in zeigt eine Benachrichtigung an.
Wichtig: Die Deactivate-Methode ist leer. Das ist der Normalfall, weil der Host alle über AContext.Subscribe registrierten Disposables automatisch aufräumt. Nur wenn das Add-in eigene Ressourcen verwaltet (Threads, Datenbankverbindungen), muss es in Deactivate selbst aufräumen.
Schritt 4: Kompilieren
fpc -FUbin -obin/HelloWorld.dll src/HelloWorld.lpr
Die DLL wird im bin/-Verzeichnis erzeugt, wo das Manifest sie erwartet („main“: „bin/HelloWorld.dll“).
Schritt 5: Paketieren
Das fertige Add-in wird als .wvdsx-Paket ausgeliefert:
cd hello-world zip -r ../demo.hello-world-1.0.0.wvdsx plugin.json package.nls.json bin/ media/
Schritt 6: Installieren und Testen
wdochost --install-extension demo.hello-world-1.0.0.wvdsx
Nach dem Neustart der Anwendung erscheint „Hallo sagen“ im Hilfe-Menü und in der CommandPalette. Beim ersten Aufruf wird die DLL geladen und der Handler aktiviert.
Was passiert unter der Haube
- Start — Der Host scannt das Erweiterungsverzeichnis, findet
plugin.jsonund liest es. - Contributions — Der Host registriert den Command
hello.sayHelloals Lazy-Stub und fügt den Menüpunkt ins Hilfe-Menü ein. - Benutzerklick — Der Benutzer wählt „Hallo sagen“ im Menü.
- Lazy-Aktivierung — Der Stub fängt den Aufruf ab, lädt
HelloWorld.dll, ruftGetAbiInfoundCreatePluginauf. - Activate —
THelloWorldPlugin.Activateregistriert den echten Handler. - Execute — Der Host führt
TSayHelloHandler.Executeaus. Die Benachrichtigung erscheint.
Ab diesem Punkt ist das Add-in aktiv. Jeder weitere Aufruf des Commands geht direkt an den Handler, ohne erneute Aktivierung.
Weiter zum Document-View Tutorial oder zurück zur Übersicht.