aboutsummaryrefslogtreecommitdiffstats
path: root/ServiceBasedPlugins
diff options
context:
space:
mode:
Diffstat (limited to 'ServiceBasedPlugins')
-rw-r--r--ServiceBasedPlugins/src/pluginsupport/UPlugin.pas47
-rw-r--r--ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas92
-rw-r--r--ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas153
3 files changed, 260 insertions, 32 deletions
diff --git a/ServiceBasedPlugins/src/pluginsupport/UPlugin.pas b/ServiceBasedPlugins/src/pluginsupport/UPlugin.pas
index 19c23999..447627ca 100644
--- a/ServiceBasedPlugins/src/pluginsupport/UPlugin.pas
+++ b/ServiceBasedPlugins/src/pluginsupport/UPlugin.pas
@@ -45,19 +45,26 @@ type
Filename: WideString;
ErrorReason: WideString;
+ Info: TUS_PluginInfo;
+
procedure OnChangeStatus(Status: TUS_PluginStatus); virtual;
public
constructor Create(Handle: TUS_Handle; Filename: WideString); virtual;
-
+
+ function GetLoader: LongInt; virtual;
+
function GetStatus: TUS_PluginStatus; virtual;
procedure SetStatus(Status: TUS_PluginStatus); virtual;
+ function GetInfo: TUS_PluginInfo; virtual;
+ function Identify(Info: TUS_PluginInfo): boolean; virtual;
+
function GetHandle: TUS_Handle; virtual;
function GetUniqueID: TUS_Handle; virtual;
function GetFilename: WideString; virtual;
- procedure Init; virtual;
- procedure DeInit; virtual;
+ procedure Init; virtual; {$IFDEF HasInline}inline;{$ENDIF}
+ procedure DeInit; virtual; {$IFDEF HasInline}inline;{$ENDIF}
procedure SetError(Reason: WideString); virtual;
function GetErrorReason: WideString; virtual;
@@ -75,6 +82,13 @@ begin
Self.Status := psNone;
Self.UniqueID := CalculateUSHash(Filename); //< this should be done another way ;) just for testing purposes
+
+ Self.Info.Version := US_VERSION_UNDEFINED;
+end;
+
+function TPlugin.GetLoader: LongInt;
+begin
+ Result := US_LOADER_UNDEFINED;
end;
function TPlugin.GetStatus: TUS_PluginStatus;
@@ -88,6 +102,29 @@ begin
OnChangeStatus(Status);
end;
+function TPlugin.GetInfo: TUS_PluginInfo;
+begin
+ Result := Info;
+end;
+
+function TPlugin.Identify(Info: TUS_PluginInfo): boolean;
+begin
+ Result := false;
+ If (Self.Info.Version = US_VERSION_UNDEFINED) then
+ begin //first identify
+
+ If (Length(Info.Name) > 0) AND (Length(Info.Author) > 0) AND (Length(Info.PluginDesc) > 0) AND (Info.Version <> US_VERSION_UNDEFINED) then
+ begin
+ Self.Info := Info;
+ Result := true;
+ end
+ else
+ SetError('Identify called with incomplete info struct');
+ end
+ else
+ Log.LogWarn('Identify is called twice', Self.Info.Name);
+end;
+
function TPlugin.GetHandle: TUS_Handle;
begin
Result := Handle;
@@ -103,13 +140,13 @@ begin
Result := Filename;
end;
-procedure TPlugin.Init;
+procedure TPlugin.Init; {$IFDEF HasInline}inline;{$ENDIF}
begin
if (Status = psWaitingInit) then
SetStatus(psInited);
end;
-procedure TPlugin.DeInit;
+procedure TPlugin.DeInit; {$IFDEF HasInline}inline;{$ENDIF}
begin
if (Status = psInited) then
SetStatus(psDeInited);
diff --git a/ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas b/ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas
index 5a042f1a..4d053ad0 100644
--- a/ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas
+++ b/ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas
@@ -36,18 +36,31 @@ interface
{$I switches.inc}
const
- SDK_Version = 0001000000000000; //< identifies the used SDK version (1.0.0.0)
+ US_VERSION_SHMAJOR = 20;
+ US_VERSION_SHMINOR = 10;
+ US_VERSION_SHFIX = 0;
+
+ SDK_Version = 1 shl US_VERSION_SHMAJOR; //< identifies the used SDK version (1.0.0.0)
type
- { this type is used for all version ints in this SDK }
+ { this type is used for all version ints in this SDK
+ the versions are structured as follows
+ 0 ... 11| 12 ... 21| 22 ... 31
+ major | minor | bugfix, etc.
+ e.g. 1 . 0 . 0 = 1 shl 20 }
+
TUS_Version = LongInt;
{ this type is used for all plugin handles in this SDK }
TUS_Handle = LongInt;
+ PInterface = ^IInterface;
+
const
- US_HANDLE_CORE = 137; //handle of core, also first defined handle
- US_HANDLE_UNDEFINED = 0; //undefined handle, used to indicate errors
+ US_HANDLE_CORE = 137; //< handle of core, also first defined handle
+ US_HANDLE_UNDEFINED = 0; //< undefined handle, used to indicate errors
+ US_VERSION_UNDEFINED = 0; //< defines an unset version, used by core,
+ // should not be used by Plugins
{ this type is used for all id strings in this SDK }
const
@@ -66,16 +79,18 @@ type
PUS_PluginInfo = ^TUS_PluginInfo;
{ this function reads the plugins information from a TUS_PluginInfo record,
- and saves it. Can be called onced per plugin.
+ and saves it. Can be called once per plugin.
Version is the SDK_Version used by the plugin
BufferLength is the size of buffer in bytes }
- TUS_Func_Identify = function (Handle: TUS_Handle; Version: TUS_Version; Buffer: PUS_PluginInfo; BufferLength: LongInt): LongInt; stdcall;
+ TUS_Func_Identify = function (Handle: TUS_Handle; Version: TUS_Version; Buffer: PUS_PluginInfo; BufferLength: LongInt): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
{ this plugin is used for selfshutdown by the plugin on an error
case.
Reason should be used to describe the reason for the shutdown
OnChangeStatus(psDeInited) is called when old status was psInited }
- TUS_Func_Error = function (Handle: TUS_Handle; Reason: PWideChar): LongInt; stdcall;
+ TUS_Func_Error = function (Handle: TUS_Handle; Reason: PWideChar): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
{ this function writes the plugins filename including its path ,
to buffer. A call with Buffer=nil or Len<=0 returns the actual
@@ -83,32 +98,37 @@ type
BufferLength is the size of buffer in bytes
Filename is used to identify duplicate load of one plugin
so it should even set when plugin is not loaded from file}
- TUS_Func_GetFilename = function (Handle: TUS_Handle; Version: TUS_Version; Buffer: PWideChar; BufferLength: LongInt): LongInt; stdcall;
+ TUS_Func_GetFilename = function (Handle: TUS_Handle; Buffer: PWideChar; BufferLength: LongInt): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
{ this function writes an interface, identified by 'ID', to the
buffer.
Version is the version of the interface that is used
BufferLength is the size of buffer in bytes}
- TUS_Func_GetInterface = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt; stdcall;
+ TUS_Func_GetInterface = function (IID: TGUID; Buffer: PInterface): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
{ this function reads an interface, identified by 'ID', from the
buffer, to offer it to calls of GetInterface.
version is the version of the interface
BufferLength is the size of buffer in bytes }
- TUS_Func_SetInterface = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt; stdcall;
+ TUS_Func_SetInterface = function (IID: TGUID; Buffer: PInterface): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
{ this function writes a record or some other data,
identified by 'ID', to the buffer.
Version is the version of the data that is used
BufferLength is the size of buffer in bytes}
- TUS_Func_GetData = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt; stdcall;
+ TUS_Func_GetData = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
{ this function reads a record or some other data,
identified by 'ID', from the buffer, to offer it
to calls of GetData.
version is the version of the record
BufferLength is the size of buffer in bytes }
- TUS_Func_SetData = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt; stdcall;
+ TUS_Func_SetData = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
{ a record w/ some useful methods for plugins }
TUS_PluginInterface = packed record
@@ -140,7 +160,7 @@ type
{$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
- TUS_PluginStatus = (psNone, psWaitingInit, psWaitingIdentify, psInited, psDeInited, psError);
+ TUS_PluginStatus = (psNone, psWaitingInit, psInited, psDeInited, psError);
{ this function is called everytime tbe plugins status changes
status is the new status.
@@ -154,12 +174,18 @@ type
plugin itself in the case of integrated plugins }
IUS_Plugin = Interface
['{23F7B722-D979-4402-9953-C6B229A6E888}']
- function GetStatus: TUS_PluginStatus;
- procedure SetStatus(status: TUS_PluginStatus);
+ function GetLoader: LongInt; //< Returns id of this plugins loader
+
+ function GetStatus: TUS_PluginStatus; //< Returns current pluginstatus
+ procedure SetStatus(status: TUS_PluginStatus); //< set current pluginstatus, calls OnChangeStatus,
+ // status may not be updated in case of an error
+
+ function GetInfo: TUS_PluginInfo; //< Returns TUS_Plugininfo record for this plugin
+ function Identify(Info: TUS_PluginInfo): boolean; //< Sets TUS_Plugininfo record for this plugin, can only be called once
- function GetHandle: TUS_Handle;
+ function GetHandle: TUS_Handle; //< Returns plugins handle
function GetUniqueID: TUS_Handle; //< This ID is unique for the given plugin it may be a hash of the plugins code or s/t like that. used to identify plugins laoded twice
- function GetFilename: WideString;
+ function GetFilename: WideString; //< Returns plugins filename
Procedure Init;
Procedure DeInit;
@@ -175,9 +201,11 @@ type
breakable is true if the hook chain can be interupted by
returning US_HOOK_BREAK or US_HOOK_UNHOOKME_BREAK
by returning US_HOOK_UNHOOKME the callback will immediately
- be removed from the chain }
- TUS_Func_OnEvent = function(data: pointer; breakable: boolean): integer;
- TUS_cFunc_OnEvent = function(data: pointer; breakable: boolean): integer of object;
+ be removed from the chain
+ UserID is the value that the UserID had when hook was called.
+ can be used to store user defined data, e.g. to use one hook procedure for different hooks }
+ TUS_Func_OnEvent = function(data: pointer; breakable: boolean; UserID: LongInt): integer;
+ TUS_cFunc_OnEvent = function(data: pointer; breakable: boolean; UserID: LongInt): integer of object;
{ this interface represents an event that can be hooked by
e.g. the core or other}
@@ -191,8 +219,8 @@ type
//proc is the callback function
//parent is the plugins handle, or US_HANDLE_CORE if called by core
//returns hook-handle on succes or US_HANDLE_UNDEFINED on failure
- function Hook(proc: TUS_Func_OnEvent; Parent: TUS_Handle): TUS_Handle;
- function cHook(proc: TUS_cFunc_OnEvent; Parent: TUS_Handle): TUS_Handle;
+ function Hook(proc: TUS_Func_OnEvent; Parent: TUS_Handle; UserID: LongInt): TUS_Handle;
+ function cHook(proc: TUS_cFunc_OnEvent; Parent: TUS_Handle; UserID: LongInt): TUS_Handle;
//removes a callback from the chain using the handle returned
//by the hook function
@@ -220,9 +248,16 @@ const
US_HOOK_UNHOOKME = High(integer) - 2; //this will remove the callback from the hooks chain
US_HOOK_UNHOOKME_BREAK = High(integer) - 1; //this will do both explained above
+ US_LOADER_UNDEFINED = 0;
+ US_LOADER_LIBRARY = 100;
+ US_LOADER_INCLUDED = 200;
+
{ this function converts an errorcode to its textual expression }
function USErrortoString(Code: LongInt): String;
+{ this function converts a TUS_PluginStatus to its textual expression }
+function USPluginStatustoString(Status: TUS_PluginStatus): String;
+
{ this funtion creates a hash for an TUS_Identifier
the hash is not guaranteed to be unique, it is just
for a fast search of an identifier }
@@ -245,6 +280,19 @@ begin
end;
end;
+function USPluginStatustoString(Status: TUS_PluginStatus): String;
+begin
+ Case Status of
+ psNone: Result := 'none';
+ psWaitingInit: Result := 'waiting init';
+ psInited: Result := 'inited';
+ psDeinited: Result := 'deinited';
+ psError: Result := 'error';
+
+ Else Result := 'unknown';
+ end;
+end;
+
{ this funtion creates a hash for an TUS_Identifier
the hash is not guaranteed to be unique, it is just
for a fast search of an identifier }
diff --git a/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas b/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas
index 388ae334..c11fe708 100644
--- a/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas
+++ b/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas
@@ -40,6 +40,8 @@ type
protected
PluginDir: WideString;
public
+ PluginInterface: TUS_PluginInterface;
+
constructor Create(PluginDir: WideString);
procedure Browse(Dir: WideString);
end;
@@ -53,6 +55,7 @@ type
procedure OnChangeStatus(Status: TUS_PluginStatus); override;
public
constructor Create(Handle: TUS_Handle; Filename: WideString); override;
+ function GetLoader: LongInt; override;
destructor Destroy; override;
end;
@@ -65,6 +68,15 @@ const
DLLExt = '.so';
{$IFEND}
+// procedures used in the PluginInterface record
+// see UPluginDefines for descriptions
+function DLL_Identify (Handle: TUS_Handle; Version: TUS_Version; Buffer: PUS_PluginInfo; BufferLength: LongInt): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
+function DLL_Error (Handle: TUS_Handle; Reason: PWideChar): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
+function DLL_GetFilename (Handle: TUS_Handle; Buffer: PWideChar; BufferLength: LongInt): LongInt;
+ {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
+
implementation
uses
{$IFDEF MSWINDOWS}
@@ -74,11 +86,23 @@ uses
{$ENDIF}
SysUtils,
UPluginManager,
- UPlatform;
+ UPlatform,
+ ULog;
{ implementation of TPluginLoader_DLL }
constructor TPluginLoader_DLL.Create(PluginDir: WideString);
begin
+ //start to fill the plugininterface w/ default values
+ PluginInterface.Handle := US_HANDLE_UNDEFINED;
+ PluginInterface.Version := SDK_Version;
+ PluginInterface.Identify := DLL_Identify;
+ PluginInterface.Error := DLL_Error;
+ PluginInterface.GetFilename := DLL_GetFilename;
+ PluginInterface.GetInterface := nil;
+ PluginInterface.SetInterface := nil;
+ PluginInterface.GetData := nil;
+ PluginInterface.SetData := nil;
+
Self.PluginDir := PluginDir;
Browse(PluginDir);
end;
@@ -112,6 +136,11 @@ begin
SetStatus(psWaitingInit);
end;
+function TPlugin_DLL.GetLoader: LongInt;
+begin
+ Result := US_LOADER_LIBRARY;
+end;
+
destructor TPlugin_DLL.Destroy;
begin
@@ -128,7 +157,7 @@ begin
begin
@Lib_Proc_Init := GetProcAddress(hLib, PChar('Proc_Init'));
- If (not Assigned(Lib_Proc_Init)) then
+ if (not Assigned(Lib_Proc_Init)) then
begin
FreeLibrary(hLib);
@@ -142,7 +171,7 @@ begin
@Lib_OnChangeStatus := GetProcAddress(hLib, PChar('OnChangeStatus'));
- If (not Assigned(Lib_OnChangeStatus)) then
+ if (not Assigned(Lib_OnChangeStatus)) then
begin
FreeLibrary(hLib);
@@ -165,15 +194,129 @@ begin
Exit;
end;
+ //library + procedure pointers are loaded
+ //now try to do the handshake
+ //call Proc_Init
+ Lib_Proc_Init(Self.Handle, SDK_Version, nil);
+
+ //check if plugin has identified itself
+ if (Self.Info.Version = US_VERSION_UNDEFINED) then
+ begin
+ SetError('library did not identify');
+ exit;
+ end;
end;
end;
//call plugins OnChangeStatus procedure
- If assigned(Lib_OnChangeStatus) then
- Lib_OnChangeStatus(Self.Handle, Status);
+ if assigned(Lib_OnChangeStatus) then
+ try
+ Lib_OnChangeStatus(Self.Handle, Status);
+ except
+ if (Status <> psError) then
+ SetError('exception in librarys OnChangeStatus (from: ' + USPluginStatustoString(Self.Status) + ' to: ' + USPluginStatustoString(Status) + ')');
+ end;
Self.Status := Status;
end;
+// procedures used in the PluginInterface record
+// see UPluginDefines for descriptions
+// --------
+function DLL_Identify (Handle: TUS_Handle; Version: TUS_Version; Buffer: PUS_PluginInfo; BufferLength: LongInt): LongInt;
+var
+ Plugin: IUS_Plugin;
+ Info: TUS_PluginInfo;
+begin
+ Result := US_ERROR_Unknown;
+ Plugin := PluginManager.GetPluginbyHandle(Handle);
+
+ if (Plugin <> nil) then
+ begin
+ if (Plugin.GetLoader = US_LOADER_LIBRARY) then
+ begin
+ If (Version = SDK_Version) then
+ begin
+ If (BufferLength = SizeOf(TUS_PluginInfo)) then
+ begin
+ try
+ move(Buffer^, Info, BufferLength);
+ except
+ Plugin.SetError('error copying plugininfo from buffer in DLL_Identify');
+ end;
+
+ If Plugin.Identify(Info) then
+ begin
+ Result := US_ERROR_None;
+ end;
+ end
+ else
+ begin
+ Result := US_ERROR_SizeMismatch;
+ Plugin.SetError('reported buffersize is wrong in DLL_Identify');
+ end;
+ end
+ else
+ begin
+ Result := US_ERROR_VersionMismatch;
+ Plugin.SetError('SDK version is not supported in DLL_Identify');
+ end;
+
+ end
+ else
+ begin
+ Result := US_ERROR_WrongHandle;
+ Log.LogError('called w/ handle of plugin from another loader', 'DLL_Identify');
+ end;
+ end
+ else
+ begin
+ Result := US_ERROR_WrongHandle;
+ Log.LogError('called w/ invalid handle', 'DLL_Identify');
+ end;
+end;
+
+function DLL_Error (Handle: TUS_Handle; Reason: PWideChar): LongInt;
+var
+ Plugin: IUS_Plugin;
+ S: WideString;
+begin
+ Result := US_ERROR_Unknown;
+ Plugin := PluginManager.GetPluginbyHandle(Handle);
+
+ if (Plugin <> nil) then
+ begin
+ if (Plugin.GetLoader = US_LOADER_LIBRARY) then
+ begin
+ Result := US_ERROR_None;
+
+ //try to copy the error reason
+ try
+ SetLength(S, Length(Reason^));
+ S := copy(Reason^, 1, Length(S)); //or has this to be len*2 ?
+ except
+ Reason := 'couldn''t copy error reason in DLL_Error';
+ end;
+
+ Plugin.SetError(Reason);
+ end
+ else
+ begin
+ Result := US_ERROR_WrongHandle;
+ Log.LogError('called w/ handle of plugin from another loader', 'DLL_Identify');
+ end;
+ end
+ else
+ begin
+ Result := US_ERROR_WrongHandle;
+ Log.LogError('called w/ invalid handle', 'DLL_Identify');
+ end;
+end;
+
+function DLL_GetFilename (Handle: TUS_Handle; Buffer: PWideChar; BufferLength: LongInt): LongInt;
+begin
+
+end;
+
end. \ No newline at end of file