====== 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 [[start|SDK-Übersicht]] oder zur [[..:start|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|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 [[..:contributions:menus|Menüs]], [[..:contributions:toolbar|Toolbar-Buttons]] und [[..:contributions:keybindings|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|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: [[..:contributions:menus|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: [[..:contributions:toolbar|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: [[..:contributions:statusbar|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|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: [[..:contributions:sidebarviews|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 [[..:sicherheit|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|Manifest]] registriert. Der Service ermöglicht die Registrierung zur Laufzeit für dynamische Szenarien. Ausführliche Beschreibung: [[..:contributions:keybindings|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-addin|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-contract|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|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|Connection Manager]].
Weiter zum [[document-frame|Document-Frame]] oder zurück zur [[start|SDK-Übersicht]].