====== 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]].