Inhaltsverzeichnis
Commands
Ein Command ist eine benannte Aktion. Jeder Menüpunkt, jeder Toolbar-Button und jedes Tastenkürzel verweist auf einen Command. Der Command selbst definiert keine Sichtbarkeit und keinen Ort — das übernehmen die anderen Contribution-Typen (Menüs, Toolbar, Keybindings). Der Command stellt lediglich einen Namen, einen Titel und einen Handler bereit.
Diese Trennung hat einen konkreten Vorteil: Ein und derselbe Command kann gleichzeitig in einem Menü, in der Toolbar und über ein Tastenkürzel erreichbar sein, ohne dass die Logik dupliziert werden muss. Wenn sich der Handler ändert, ändert er sich an einer einzigen Stelle.
Zurück zur Contributions-Übersicht oder zur Hauptübersicht.
Manifest-Deklaration
"contributes": { "commands": [ { "command": "assets.open", "title": "Anlage öffnen", "category": "Assets", "icon": "media/asset-open.svg" }, { "command": "assets.list", "title": "Anlageliste", "category": "Assets", "icon": "media/asset-list.svg" } ] }
| Feld | Pflicht | Beschreibung |
command | ja | Eindeutiger Bezeichner. Konvention: addin-name.aktion (z.B. assets.open). Dieser Name wird überall referenziert — in Menüs, Toolbar, Keybindings und bei ExecuteCommand. |
title | ja | Anzeigename des Commands. Erscheint in der CommandPalette und als Standard-Label in Menüs. Kann über NLS übersetzt werden. |
category | nein | Gruppierung in der CommandPalette. Wird dem Titel als Prefix vorangestellt (Assets: Anlage öffnen). Erleichtert das Filtern in langen Command-Listen. |
icon | nein | Relativer Pfad zu einer SVG- oder PNG-Datei. Wird in Toolbar-Buttons und Menüpunkten angezeigt. |
Lazy-Stubs und Aktivierung
Wenn der Host die Manifeste verarbeitet, registriert er für jeden deklarierten Command einen sogenannten Lazy-Stub. Das ist ein Platzhalter-Handler, der beim ersten Aufruf die Aktivierung des zugehörigen Add-ins auslöst.
Der Ablauf im Detail:
- Der Host liest das Manifest und findet den Command
assets.openmit dem AktivierungsereignisonCommand:assets.open. - Der Host registriert einen
TLazyCommandHandlerunter dem Namenassets.open. Dieser Handler macht nichts außer: beim erstenExecutedas Add-in aktivieren. - Der Benutzer klickt auf den Menüpunkt „Anlage öffnen“.
- Der Lazy-Stub fängt den Aufruf ab, entfernt sich selbst und aktiviert das Add-in.
- Das Add-in wird geladen (ABI-Handshake, CreatePlugin, Activate).
- In
Activateregistriert das Add-in den echten Handler fürassets.open. - Der Host führt den Command erneut aus, diesmal mit dem echten Handler.
Für den Benutzer ist dieser Vorgang transparent — er sieht nur eine kurze Verzögerung beim ersten Aufruf.
Dieses Vorgehen hat einen messbaren Vorteil: Wenn zehn Add-ins installiert sind, aber der Benutzer nur zwei davon tatsächlich verwendet, werden nur zwei DLLs geladen. Die Oberfläche zeigt trotzdem alle Commands aller zehn Add-ins, weil die Metadaten aus den Manifesten stammen.
Handler-Registrierung
Der echte Command-Handler wird in der Activate-Methode des Add-ins registriert:
type TOpenAssetHandler = class(TInterfacedObject, ICommandHandler) private FHost: IHost; public constructor Create(const AHost: IHost); procedure Execute; end; procedure TOpenAssetHandler.Execute; begin FHost.Documents.OpenDocument('assets.editor'); end; procedure TAssetPlugin.Activate(const AContext: IExtensionContext); begin AContext.Subscribe( FHost.Commands.RegisterCommand('assets.open', 'Anlage öffnen', TOpenAssetHandler.Create(FHost)) ); end;
Der ICommandHandler hat eine einzige Methode Execute, die vom Host aufgerufen wird. Der Rückgabewert von RegisterCommand ist ein IDisposable, das an den IExtensionContext übergeben wird. Beim Deaktivieren des Add-ins wird der Handler automatisch abgemeldet.
CommandPalette
Die CommandPalette ist eine schnelle Suchleiste, über die der Benutzer jeden registrierten Command finden und ausführen kann. Sie funktioniert ähnlich wie in VSCode: Der Benutzer drückt ein Tastenkürzel, tippt einen Suchbegriff, und die Palette filtert die Liste der verfügbaren Commands.
Jeder Command, der im Manifest deklariert ist, erscheint automatisch in der CommandPalette. Die category wird als Prefix angezeigt, was das Filtern erleichtert:
Assets: Anlage öffnen Assets: Anlageliste Berichte: Monatsbericht erstellen Einstellungen: Sprache ändern
Commands können über den commandPalette-Ort im Menü-Merge gezielt aus der Palette ausgeschlossen werden, wenn sie nur über andere Wege erreichbar sein sollen:
"menus": { "commandPalette": [ { "command": "assets.internal.refresh", "when": "false" } ] }
Script-Commands
Neben nativen Commands, deren Handler in einer DLL implementiert ist, unterstützt der Host auch Script-Commands. Ein Script-Command verweist auf ein PowerShell-Script (.ps1), das der Host als pwsh-Kindprozess ausführt. Script-Commands erscheinen in der CommandPalette und können über Menüs, Toolbar und Keybindings ausgelöst werden — identisch zu nativen Commands.
Ziel dieser Erweiterung ist es, leichtgewichtige Automatisierungen ohne DLL-Kompilierung zu ermöglichen. Im Unterschied zu nativen Commands benötigt ein Script-Command keinen ABI-Handshake und keine Aktivierungsphase — der Host startet das Script direkt. Der Vorteil besteht darin, dass Entwickler PowerShell-Scripts als vollwertige Commands registrieren können, ohne den DLL-Entwicklungszyklus durchlaufen zu müssen.
Manifest-Deklaration
"contributes": { "commands": [ { "command": "export.run-csv", "title": "CSV-Export ausführen", "category": "Export", "icon": "media/export-csv.svg", "kind": "script", "script": "scripts/export-csv.ps1" } ] }
| Feld | Pflicht | Beschreibung |
kind | nein | „native“ (Standard) oder „script“. Bestimmt, ob der Command einen DLL-Handler oder ein PowerShell-Script ausführt. |
script | bei kind: „script“ | Relativer Pfad zur .ps1-Datei innerhalb des Add-in-Pakets. Der Host löst den Pfad beim Laden auf und validiert, dass die Datei existiert. |
Die Felder command, title, category und icon funktionieren identisch zu nativen Commands.
Sicherheit
Bei der ersten Ausführung eines Script-Commands zeigt der Host einen Bestätigungsdialog. Der Benutzer sieht den vollständigen Pfad zum Script und muss die Ausführung explizit genehmigen. Einmal genehmigte Scripts werden in einer internen Liste gespeichert und bei künftigen Aufrufen ohne Dialog gestartet.
Host-Kommunikation
Scripts können über das WvdSHostContract-PowerShell-Modul mit dem Host kommunizieren. Das Modul stellt Cmdlets bereit, die strukturierte Nachrichten über stdout senden. Normaler Text landet direkt im PowerShell-Panel des BottomPanels. Ausführliche Dokumentation: ScriptHost & Host-Contract.
Programmatischer Aufruf
Ein Add-in kann Commands anderer Add-ins programmatisch auslösen:
FHost.Commands.ExecuteCommand('anderes-addin.command-name');
Dieser Aufruf funktioniert wie ein Benutzerklick — er löst die Aktivierung des Ziel-Add-ins aus, falls es noch nicht geladen ist, und führt dann den Handler aus.
Weiter zu Menü-Merge oder zurück zur Contributions-Übersicht.