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:

  1. csDefault — Standardwerte aus dem Manifest (contributes.configuration.properties[].default)
  2. csUser — Benutzer-Einstellungen (~/.wvdsx/settings.json)
  3. csWorkspace — Workspace-Einstellungen (.wvdsx/settings.json)
  4. 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.

Zuletzt geändert: den 18.03.2026 um 20:47