Skip to content

Latest commit

 

History

History

README.md

CustomServiceDemo

Plugin-to-plugin communication via custom interfaces. Shows how plugins define, register, and consume services -- without the host needing to know about them.

Architecture

CustomServiceDemo.exe
|   DCC_UsePackage = rtl;fmx;FMXPluginFramework
|
+-- TBPLLoader.LoadAll(plugins.json)
|
+-- PluginProvider.bpl (required)
|   +-- CustomService.Intf.pas -> defines IDataStore
|   +-- PluginProvider.Main.pas -> implements + registers TDataStore
|
+-- PluginConsumer.bpl (required, requires PluginProvider)
|   +-- PluginConsumer.Main.pas -> IPlugin + IFrameProvider
|   +-- PluginConsumer.View.pas -> Frame with Key/Value UI
|
+-- MainForm
    +-- TMemoLogger -> displays plugin logs
    +-- Consumer frame embedded -> interacts with IDataStore

What This Demo Shows

  • Custom Interfaces: Plugins define their own interfaces with GUIDs
  • TServiceRegistry as mediator: Provider registers, consumer retrieves -- without knowing each other directly
  • BPL dependency chain: Consumer package has requires PluginProvider in its .dpk
  • Interface unit rule: CustomService.Intf.pas lives in exactly one package (Provider). The consumer uses requires instead of contains to avoid duplicates
  • Frame embedding: Consumer provides a UI frame (IFrameProvider) that the host embeds

Files

File Purpose
CustomServiceDemo.dpr Host app (does not know about IDataStore!)
Source/uMain.pas + .fmx MainForm with TMemoLogger + frame embedding
CustomServiceDemo.groupproj Build: Framework -> Provider -> Consumer -> App
plugins.json Both plugins as required
../DemoPlugins/PluginProvider/ Defines + implements IDataStore
../DemoPlugins/PluginConsumer/ Uses IDataStore, provides UI frame

IDataStore Interface

IDataStore = interface
  ['{F1A2B3C4-D5E6-4F7A-8B9C-0D1E2F3A4B5C}']
  procedure SetValue(const AKey, AValue: string);
  function GetValue(const AKey: string): string;
  function GetAllKeys: TArray<string>;
  procedure Clear;
end;

How It Works

  1. Host loads PluginProvider.bpl first (required: true)
  2. Provider registers TDataStore as IDataStore service in Initialize
  3. Host loads PluginConsumer.bpl (BPL dependency: requires PluginProvider)
  4. Consumer retrieves IDataStore via GetService and provides a frame with Key/Value UI
  5. Host embeds the consumer frame -- communication runs entirely between the plugins
  6. Host code knows neither IDataStore nor CustomService.Intf -- purely a plugin concern