Inhaltsverzeichnis
Service-Referenz
Der Host stellt über IHost neunzehn Services bereit. Jeder Service ist über eine gleichnamige Property erreichbar und steht dem Add-in ab dem Zeitpunkt der Aktivierung zur Verfügung. Diese Seite beschreibt jeden Service mit seiner Aufgabe, seinen Methoden und einem Beispiel.
Zurück zur SDK-Übersicht oder zur Hauptübersicht.
ICommandService
Der Command-Service verwaltet alle registrierten Commands. Ein Command ist eine benannte Aktion, die von Menüpunkten, Toolbar-Buttons, Tastenkürzeln oder anderen Add-ins ausgelöst werden kann.
ICommandService = interface function RegisterCommand(const AName, ATitle: string; AHandler: ICommandHandler): IDisposable; procedure ExecuteCommand(const AName: string); procedure GetCommandList(ANames, ATitles: TStringList); end;
RegisterCommand registriert einen Handler für einen Command-Namen. Der Name muss dem im Manifest deklarierten Command entsprechen. Der Rückgabewert ist ein IDisposable, das an den IExtensionContext übergeben werden muss.
ExecuteCommand löst einen Command programmatisch aus. Das ist nützlich, wenn ein Add-in die Funktionalität eines anderen Add-ins aufrufen möchte, ohne den Benutzer über die Oberfläche gehen zu lassen.
GetCommandList füllt zwei parallele Listen mit allen registrierten Command-Namen und ihren Titeln. Das wird intern von der CommandPalette verwendet.
// Beispiel: Command registrieren procedure TMyPlugin.Activate(const AContext: IExtensionContext); begin AContext.Subscribe( FHost.Commands.RegisterCommand('assets.open', 'Anlage öffnen', TOpenAssetHandler.Create) ); end;
Der ICommandHandler hat eine einzige Methode Execute, die vom Host aufgerufen wird, wenn der Benutzer den Command auslöst.
IEventBus
Der Event-Bus ermöglicht die lose gekoppelte Kommunikation zwischen Host und Add-ins sowie zwischen Add-ins untereinander.
IEventBus = interface function Subscribe(const AEventName: string; AHandler: IEventHandler): IDisposable; procedure Fire(const AEventName: string; const APayload: string); end;
Events werden über Namen identifiziert. Jeder Subscriber erhält den Event-Namen und ein JSON-Payload als String. Fehler in einem Subscriber unterbrechen die Zustellung an andere Subscriber nicht — der Host fängt Exceptions pro Subscriber ab.
Standard-Events des Hosts:
debug.sessionStarted— Eine Debug-Sitzung wurde gestartet.debug.sessionStopped— Eine Debug-Sitzung wurde beendet.
Add-ins können eigene Events definieren. Es empfiehlt sich, den Add-in-Namen als Prefix zu verwenden (assets.dataChanged), um Namenskollisionen zu vermeiden.
IConfigurationService
Der Konfigurations-Service bietet Zugriff auf die mehrstufige Konfigurationshierarchie des Hosts.
IConfigurationService = interface function GetValue(const AKey, ADefault: string): string; procedure SetValue(const AKey, AValue: string; AScope: TConfigurationScope); function OnDidChangeConfiguration( AHandler: IConfigChangeHandler): IDisposable; end;
Konfigurationswerte werden in vier Ebenen aufgelöst, wobei spezifischere Ebenen allgemeinere überschreiben:
- csDefault — Standardwerte aus dem Manifest (
contributes.configuration.properties[].default) - csUser — Benutzer-Einstellungen (
~/.wvdsx/settings.json) - csWorkspace — Workspace-Einstellungen (
.wvdsx/settings.json) - csMemory — Laufzeit-Überschreibungen (nicht persistiert)
OnDidChangeConfiguration meldet Änderungen. Das ist wichtig für Add-ins, die ihr Verhalten anpassen müssen, wenn der Benutzer eine Einstellung ändert.
IContextService
Der Kontext-Service verwaltet Schlüssel-Wert-Paare, die den aktuellen Zustand der Anwendung beschreiben.
IContextService = interface procedure SetContext(const AKey, AValue: string); function GetContext(const AKey: string): string; end;
Context Keys werden für when-Ausdrücke in Menüs, Toolbar-Buttons und Keybindings verwendet. Wenn ein Add-in einen Kontextwert setzt (z.B. hasAssets = true), wertet der Host automatisch alle betroffenen when-Ausdrücke neu aus und blendet Menüpunkte ein oder aus.
// Beispiel: Kontextwert setzen FHost.Context.SetContext('hasAssets', 'true'); // Menüpunkt mit when="hasAssets" wird jetzt sichtbar
IMenuService
Der Menü-Service ermöglicht die Registrierung von Menüpunkten zur Laufzeit.
IMenuService = interface function AddMenuItem(const AMenuPath, ACommandName: string; const AWhen: string): IDisposable; end;
AMenuPath bestimmt den Ort: menuBar/tools fügt einen Eintrag ins Tools-Menü ein, view/title erzeugt eine Aktion in der Titelleiste einer View. Der Host erzeugt Zwischenknoten automatisch.
In den meisten Fällen genügt die deklarative Registrierung über das Manifest. Die Laufzeit-Registrierung über diesen Service ist für dynamische Szenarien gedacht, etwa wenn Menüpunkte von Laufzeitdaten abhängen.
Ausführliches Merge-Verfahren: Menü-Merge.
IToolbarService
IToolbarService = interface function AddToolbarItem(const AToolbarId, ACommandName: string; const AIcon, ATooltip: string; const AWhen: string): IDisposable; end;
Der Toolbar-Service funktioniert analog zum Menü-Service. AToolbarId gruppiert Buttons logisch — der Host ordnet sie in der entsprechenden Toolbar-Leiste an. Ausführliche Beschreibung: Toolbar.
IStatusBarService
IStatusBarService = interface function CreateItem(const AId, AText: string; AAlignment: TStatusBarAlignment; APriority: Integer): IStatusBarItem; end; IStatusBarItem = interface procedure SetText(const AText: string); procedure SetTooltip(const ATooltip: string); procedure SetCommand(const ACommandName: string); procedure Show; procedure Hide; procedure Dispose; end;
StatusBar-Items werden programmatisch erzeugt und können danach aktualisiert werden. APriority bestimmt die Reihenfolge — niedrigere Werte stehen weiter links (bei sbaLeft) bzw. weiter rechts (bei sbaRight). Das IStatusBarItem bleibt veränderbar: Text, Tooltip und zugeordneter Command können jederzeit aktualisiert werden.
Ausführliche Beschreibung: StatusBar.
INotificationService
INotificationService = interface procedure ShowInfo(const AMessage: string); procedure ShowWarning(const AMessage: string); procedure ShowError(const AMessage: string); end;
Benachrichtigungen erscheinen als kurze Meldungen in der Anwendung. Sie sind für Benutzer-Feedback gedacht, nicht für Logging. Für strukturierte Ausgaben steht ILogService zur Verfügung.
IDocumentService
IDocumentService = interface function RegisterFactory(const ADocumentType: string; AFactory: IWvdSDocumentFactory): IDisposable; procedure OpenDocument(const ADocumentType: string); procedure CloseDocument(const ADocumentType: string); end;
Der Document-Service verbindet Dokumenttypen mit Fabriken. Wenn der Benutzer ein Dokument öffnet, fragt der Host die passende Factory nach einem neuen TWvdSDocumentFrame und bettet ihn in einen Tab ein. Dokumenttypen können als Single-Instance oder Multi-Instance deklariert werden. Bei Single-Instance-Dokumenten aktiviert der Host den bestehenden Tab, statt einen neuen zu erzeugen.
Ausführliche Beschreibung: Document-Frame.
ISidebarService
ISidebarService = interface function RegisterPanel(const AId, ATitle, AIcon: string; AFrameClass: TWvdSDocumentFrameClass): IDisposable; procedure ShowPanel(const AId: string); procedure HidePanel(const AId: string); end;
Der Sidebar-Service registriert Panels in der Seitenleiste. Jedes Panel ist ein TWvdSDocumentFrame, das der Host in die Seitenleiste einbettet. ShowPanel und HidePanel steuern die Sichtbarkeit programmatisch.
Ausführliche Beschreibung: Sidebar-Views.
ITreeViewService
ITreeViewService = interface function RegisterTreeView(const AViewId, ATitle: string; AProvider: ITreeDataProvider): IDisposable; end;
Der TreeView-Service verbindet eine deklarierte View-Id mit einem Datenanbieter. Der ITreeDataProvider liefert die Baumstruktur (Kinder, Labels, Icons, Kontextwerte), die der Host in einem TreeView rendert.
ITreeViewHandle — Refresh & Selection Events
Das von RegisterTreeView zurückgegebene IDisposable implementiert zusätzlich ITreeViewHandle. Dieses erweiterte Interface ermöglicht es, den TreeView programmatisch zu aktualisieren und auf Selektionsänderungen zu reagieren.
ITreeViewHandle = interface(IDisposable) procedure Refresh(const ANodeId: string); procedure SetOnSelectionChanged(AValue: TWvdSTreeSelectionEvent); end; TWvdSTreeSelectionEvent = procedure(const AViewId, ANodeId: string) of object;
Add-ins, die nur Cleanup benötigen, verwenden weiterhin IDisposable.Dispose — das Verhalten ist abwärtskompatibel. Add-ins, die Refresh oder Selection-Events benötigen, nutzen Supports (QueryInterface):
var LDisp: IDisposable; LHandle: ITreeViewHandle; begin LDisp := FHost.TreeViews.RegisterTreeView( 'assets.nav', 'Asset-Navigator', FProvider); AContext.Subscribe(LDisp); if Supports(LDisp, ITreeViewHandle, LHandle) then begin LHandle.SetOnSelectionChanged(@HandleSelection); // Spaeter: LHandle.Refresh('') laedt den gesamten Baum neu end; end; procedure TMyPlugin.HandleSelection( const AViewId, ANodeId: string); begin FHost.Context.SetContext('selectedAsset', ANodeId); end;
Refresh löst ein Neuladen der Baumdaten aus. Wenn ANodeId leer ist, wird der gesamte Baum neu aufgebaut. Wenn ANodeId eine gültige Knoten-Id enthält, wird nur der Teilbaum ab diesem Knoten neu geladen.
SetOnSelectionChanged registriert einen Callback, der bei jedem Selektionswechsel im TreeView aufgerufen wird. Der Callback erhält die View-Id und die Id des selektierten Knotens. Ein leerer ANodeId bedeutet, dass die Selektion aufgehoben wurde.
IStorageService
IStorageService = interface function ReadFile(const APath: string): string; procedure WriteFile(const APath, AContent: string); function FileExists(const APath: string): Boolean; end;
Der Storage-Service bietet kontrollierten Dateizugriff. Er respektiert das Berechtigungsmodell — ein Add-in ohne fs.read oder fs.write Berechtigung erhält eine Exception. Pfade werden relativ zum Storage-Verzeichnis des Add-ins aufgelöst.
IDialogService
IDialogService = interface function ShowOpenDialog(const ATitle: string; const AFilters: string): string; function ShowSaveDialog(const ATitle: string; const AFilters: string): string; function ShowMessageBox(const AMessage, ATitle: string; AButtons: TMessageButtons): TModalResult; end;
Der Dialog-Service zeigt native Datei- und Nachrichtendialoge an. Er stellt sicher, dass Dialoge immer über dem Hauptfenster erscheinen und das modale Verhalten korrekt funktioniert, auch wenn mehrere Add-ins gleichzeitig aktiv sind.
IKeybindingService
IKeybindingService = interface function RegisterKeybinding(const AKey, ACommandName: string; const AWhen: string): IDisposable; end;
Tastenkürzel werden typischerweise deklarativ im Manifest registriert. Der Service ermöglicht die Registrierung zur Laufzeit für dynamische Szenarien. Ausführliche Beschreibung: Keybindings.
IServiceRegistry
IServiceRegistry = interface function RegisterService(const AContractName: string; const AService: IUnknown): IDisposable; function GetService(const AContractName: string): IUnknown; function HasService(const AContractName: string): Boolean; function OnServiceChanged(const AContractName: string; AHandler: IEventHandler): IDisposable; end;
Die Service-Registry ermöglicht die Kommunikation zwischen Add-ins über benannte Verträge. Ausführliche Beschreibung: Inter-Add-in-Kommunikation.
IProgressService
IProgressService = interface function CreateProgress(const ATitle: string): IProgressItem; end; IProgressItem = interface procedure Report(APercentage: Integer; const AMessage: string); procedure Done; end;
Der Progress-Service zeigt Fortschrittsanzeigen für lang laufende Operationen. Report aktualisiert den Prozentsatz und die Nachricht. Done entfernt die Anzeige.
ILogService
ILogService = interface procedure Info(const AMessage: string); procedure Warn(const AMessage: string); procedure Error(const AMessage: string); procedure Debug(const AMessage: string); end;
Der Log-Service schreibt in das Ausgabefenster des Hosts. Er ist für strukturierte Diagnose gedacht, nicht für Benutzer-Feedback (dafür steht INotificationService bereit).
Log-Einträge werden an zwei Ziele gleichzeitig geroutet: in die Datei-basierte Log-Infrastruktur (TWvdSLog) und in das Output-Panel im BottomPanel der Shell. Das Output-Panel zeigt Zeitstempel, Level-Badge, Kanal (Add-in-Id) und Nachricht in einer Monospace-Ansicht mit farbcodiertem Level (Debug=gedimmt, Info=normal, Warn=gelb, Error=rot).
Der Benutzer kann im Output-Panel nach Kanal, Level und Freitext filtern, sodass sich Log-Einträge einzelner Add-ins isoliert betrachten lassen. Das BottomPanel ist über Ctrl+J erreichbar.
IThemeService
IThemeService = interface function GetCurrentThemeId: string; function OnDidChangeTheme(AHandler: IEventHandler): IDisposable; end;
Der Theme-Service informiert über das aktuelle Skin und meldet Theme-Wechsel. Add-ins, die eigene Zeichenlogik verwenden, können hier auf Farbänderungen reagieren. Für Standardcontrols ist das nicht nötig, weil der Skin-Vertrag die Farben automatisch anwendet.
IPermissionService
IPermissionService = interface function HasCapability(const ACapability: string): Boolean; function RequestCapability(const ACapability: string): Boolean; end;
Der Permission-Service prüft und fordert Berechtigungen an. HasCapability prüft, ob eine Berechtigung bereits gewährt wurde. RequestCapability zeigt dem Benutzer einen Dialog und gibt True zurück, wenn er zustimmt. Details zum Berechtigungsmodell stehen unter Sicherheit.
IWvdSConnectionManager
Der Connection Manager verwaltet benannte Datenverbindungen zentral für alle Add-ins. Er ist ein provider-agnostischer Connection Broker: Add-ins fordern eine Verbindung per Name an und erhalten eine Borrowed Reference auf den konkreten Provider. Die Shell liest die Verbindungsdefinitionen aus der user.config.json, erzeugt Provider-Instanzen lazy beim ersten Zugriff und hält sie als Singletons über die gesamte Laufzeit.
IWvdSConnectionManager = interface function RegisterFactory( AFactory: IWvdSProviderFactory): IDisposable; function GetConnection(const AName: string): TObject; procedure GetConnectionNames(AList: TStringList); function CheckInfrastructure( const AProviderType: string): TWvdSInfraCheckResult; function TestConnection( const AName: string): TWvdSConnectionTestResult; end;
RegisterFactory registriert eine Provider-Factory für einen bestimmten Typ (z. B. mssql, rest, sqlite). Der Host registriert die eingebaute mssql-Factory (ODBC Driver 17/18) beim Start. Add-ins können eigene Factories für benutzerdefinierte Provider-Typen nachregistrieren. Der Rückgabewert ist ein IDisposable, das an den IExtensionContext übergeben werden muss.
GetConnection gibt die Provider-Instanz für die benannte Verbindung zurück. Beim ersten Aufruf wird der Provider über die zuständige Factory erzeugt und gecacht. Die zurückgegebene Referenz ist eine Borrowed Reference — das Add-in darf sie nicht freigeben.
GetConnectionNames füllt die übergebene TStringList mit den Namen aller konfigurierten Verbindungen.
CheckInfrastructure prüft, ob die Laufzeitumgebung für einen Provider-Typ vorhanden ist (z. B. ob ein ODBC-Treiber installiert ist).
TestConnection baut eine Verbindung tatsächlich auf und misst die Latenz.
// Beispiel: Provider abrufen und verwenden var LProvider: TObject; begin LProvider := FHost.Connections.GetConnection('wis'); if LProvider <> nil then TWvdSSQLDBProvider(LProvider).FillWithParams( FDataSet, SSqlExecTree, []); end;
Ausführliche Beschreibung: Connection Manager.
Weiter zum Document-Frame oder zurück zur SDK-Übersicht.