====== 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 [[..:start|Ü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 [[..:paketformat|.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.json'' und liest es.
- **Contributions** — Der Host registriert den Command ''hello.sayHello'' als 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'', ruft ''GetAbiInfo'' und ''CreatePlugin'' auf.
- **Activate** — ''THelloWorldPlugin.Activate'' registriert den echten Handler.
- **Execute** — Der Host führt ''TSayHelloHandler.Execute'' aus. 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|Document-View Tutorial]] oder zurück zur [[..:start|Übersicht]].