From 44d215e69d768b32c26f62b711baaf41b36fe1ea Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Tue, 24 Mar 2009 18:53:27 +0000 Subject: some changes to TPlugin handshake finished git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/experimental@1657 b956fd51-792f-4845-bead-9b4dfca2ff2c --- ServiceBasedPlugins/src/pluginsupport/UPlugin.pas | 47 ++++++- .../src/pluginsupport/UPluginDefines.pas | 92 ++++++++++--- .../src/pluginsupport/UPluginLoader_DLL.pas | 153 ++++++++++++++++++++- 3 files changed, 260 insertions(+), 32 deletions(-) (limited to 'ServiceBasedPlugins') 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 -- cgit v1.2.3