GLS.PlugInManager.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.PlugInManager;
  5. (* An old PlugIn Manager unit. Yet not ever was used... *)
  6. interface
  7. {$I GLScene.inc}
  8. uses
  9. Winapi.Windows,
  10. System.Classes,
  11. System.SysUtils;
  12. type
  13. TPIServiceType = (stRaw, stObject, stBitmap, stTexture, stImport, stExport);
  14. TPIServices = set of TPIServiceType;
  15. TEnumCallBack = procedure(Name: PAnsiChar); stdcall;
  16. TEnumResourceNames = procedure(Service: TPIServiceType;
  17. Callback: TEnumCallBack); stdcall;
  18. TGetServices = function: TPIServices; stdcall;
  19. TGetVendor = function: PAnsiChar; stdcall;
  20. TGetDescription = function: PAnsiChar; stdcall;
  21. TGetVersion = function: PAnsiChar; stdcall;
  22. type
  23. PPlugInEntry = ^TGLPlugInEntry;
  24. TGLPlugInEntry = record
  25. Path: TFileName;
  26. Handle: HINST;
  27. FileSize: Integer;
  28. FileDate: TDateTime;
  29. EnumResourcenames: TEnumResourceNames;
  30. GetServices: TGetServices;
  31. GetVendor: TGetVendor;
  32. GetDescription: TGetDescription;
  33. GetVersion: TGetVersion;
  34. end;
  35. TGLPlugInManager = class;
  36. TGLResourceManager = class(TComponent)
  37. public
  38. procedure Notify(Sender: TGLPlugInManager; Operation: TOperation;
  39. Service: TPIServiceType; PlugIn: Integer); virtual; abstract;
  40. end;
  41. TGLPlugInList = class(TStringList)
  42. private
  43. FOwner: TGLPlugInManager;
  44. function GetPlugInEntry(Index: Integer): PPlugInEntry;
  45. procedure SetPlugInEntry(Index: Integer; AEntry: PPlugInEntry);
  46. protected
  47. procedure DefineProperties(Filer: TFiler); override;
  48. procedure ReadPlugIns(Reader: TReader);
  49. procedure WritePlugIns(Writer: TWriter);
  50. public
  51. constructor Create(AOwner: TGLPlugInManager); virtual;
  52. procedure ClearList;
  53. property Objects[Index: Integer]: PPlugInEntry read GetPlugInEntry
  54. write SetPlugInEntry; default;
  55. property Owner: TGLPlugInManager read FOwner;
  56. end;
  57. PResManagerEntry = ^TResManagerEntry;
  58. TResManagerEntry = record
  59. Manager: TGLResourceManager;
  60. Services: TPIServices;
  61. end;
  62. TGLPlugInManager = class(TComponent)
  63. private
  64. FLibraryList: TGLPlugInList;
  65. FResManagerList: TList;
  66. protected
  67. procedure DoNotify(Operation: TOperation; Service: TPIServiceType;
  68. PlugIn: Integer);
  69. function FindResManager(AManager: TGLResourceManager): PResManagerEntry;
  70. function GetIndexFromFilename(FileName: String): Integer;
  71. function GetPlugInFromFilename(FileName: String): PPlugInEntry;
  72. public
  73. constructor Create(AOwner: TComponent); override;
  74. destructor Destroy; override;
  75. function AddPlugIn(Path: TFileName): Integer;
  76. procedure EditPlugInList;
  77. procedure RegisterResourceManager(AManager: TGLResourceManager;
  78. Services: TPIServices);
  79. procedure RemovePlugIn(Index: Integer);
  80. procedure UnRegisterRessourceManager(AManager: TGLResourceManager;
  81. Services: TPIServices);
  82. published
  83. property PlugIns: TGLPlugInList read FLibraryList write FLibraryList;
  84. end;
  85. // ------------------------------------------------------------------------------
  86. implementation
  87. // ------------------------------------------------------------------------------
  88. // ----------------- TGLPlugInList ------------------------------------------------
  89. constructor TGLPlugInList.Create(AOwner: TGLPlugInManager);
  90. begin
  91. inherited Create;
  92. FOwner := AOwner;
  93. Sorted := False;
  94. Duplicates := DupAccept;
  95. end;
  96. // ------------------------------------------------------------------------------
  97. procedure TGLPlugInList.ClearList;
  98. begin
  99. while Count > 0 do
  100. FOwner.RemovePlugIn(0);
  101. end;
  102. // ------------------------------------------------------------------------------
  103. function TGLPlugInList.GetPlugInEntry(Index: Integer): PPlugInEntry;
  104. begin
  105. Result := PPlugInEntry( inherited Objects[Index]);
  106. end;
  107. // ------------------------------------------------------------------------------
  108. procedure TGLPlugInList.SetPlugInEntry(Index: Integer; AEntry: PPlugInEntry);
  109. begin
  110. inherited Objects[Index] := Pointer(AEntry);
  111. end;
  112. // ------------------------------------------------------------------------------
  113. procedure TGLPlugInList.WritePlugIns(Writer: TWriter);
  114. var
  115. I: Integer;
  116. begin
  117. Writer.WriteListBegin;
  118. for I := 0 to Count - 1 do
  119. Writer.WriteString(Objects[I].Path);
  120. Writer.WriteListEnd;
  121. end;
  122. // ------------------------------------------------------------------------------
  123. procedure TGLPlugInList.ReadPlugIns(Reader: TReader);
  124. begin
  125. ClearList;
  126. Reader.ReadListBegin;
  127. while not Reader.EndOfList do
  128. FOwner.AddPlugIn(Reader.ReadString);
  129. Reader.ReadListEnd;
  130. end;
  131. // ------------------------------------------------------------------------------
  132. procedure TGLPlugInList.DefineProperties(Filer: TFiler);
  133. begin
  134. Filer.DefineProperty('Paths', ReadPlugIns, WritePlugIns, Count > 0);
  135. end;
  136. // ----------------- TGLPlugInManager ---------------------------------------------
  137. constructor TGLPlugInManager.Create(AOwner: TComponent);
  138. begin
  139. inherited Create(AOwner);
  140. FLibraryList := TGLPlugInList.Create(Self);
  141. FResManagerList := TList.Create;
  142. end;
  143. // ------------------------------------------------------------------------------
  144. destructor TGLPlugInManager.Destroy;
  145. var
  146. I: Integer;
  147. begin
  148. FLibraryList.ClearList;
  149. FLibraryList.Free;
  150. for I := 0 to FResManagerList.Count - 1 do
  151. FreeMem(PResManagerEntry(FResManagerList[I]), SizeOf(TResManagerEntry));
  152. FResManagerList.Free;
  153. inherited Destroy;
  154. end;
  155. // ------------------------------------------------------------------------------
  156. function TGLPlugInManager.AddPlugIn(Path: TFileName): Integer;
  157. // open the given DLL and read its properties, to identify
  158. // whether it's a valid plug-in or not
  159. var
  160. NewPlugIn: PPlugInEntry;
  161. OldError: Integer;
  162. NewHandle: HINST;
  163. ServiceFunc: TGetServices;
  164. SearchRec: TSearchRec;
  165. Service: TPIServiceType;
  166. Services: TPIServices;
  167. begin
  168. Result := -1;
  169. OldError := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  170. if Length(Path) > 0 then
  171. try
  172. Result := GetIndexFromFilename(Path);
  173. // plug-in already registered?
  174. if Result > -1 then
  175. Exit;
  176. // first step is loading the file into client memory
  177. NewHandle := LoadLibrary(PChar(Path));
  178. // loading failed -> exit
  179. if NewHandle = 0 then
  180. Abort;
  181. // get the service function address to identify the plug-in
  182. ServiceFunc := GetProcAddress(NewHandle, 'GetServices');
  183. if not assigned(ServiceFunc) then
  184. begin
  185. // if address not found then the given library is not valid
  186. // release it from client memory
  187. FreeLibrary(NewHandle);
  188. Abort;
  189. end;
  190. // all went fine so far, we just loaded a valid plug-in
  191. // allocate a new entry for the plug-in list and fill it
  192. New(NewPlugIn);
  193. NewPlugIn.Path := Path;
  194. with NewPlugIn^ do
  195. begin
  196. Handle := NewHandle;
  197. FindFirst(Path, faAnyFile, SearchRec);
  198. FileSize := SearchRec.Size;
  199. FileDate := SearchRec.TimeStamp;
  200. FindClose(SearchRec);
  201. GetServices := ServiceFunc;
  202. EnumResourcenames := GetProcAddress(Handle, 'EnumResourceNames');
  203. GetVendor := GetProcAddress(Handle, 'GetVendor');
  204. GetVersion := GetProcAddress(Handle, 'GetVersion');
  205. GetDescription := GetProcAddress(Handle, 'GetDescription');
  206. end;
  207. Result := FLibraryList.Add(string(NewPlugIn.GetVendor));
  208. FLibraryList.Objects[Result] := NewPlugIn;
  209. // now notify (for all provided services) all registered resource managers
  210. // for which these services are relevant
  211. Services := NewPlugIn.GetServices;
  212. for Service := Low(TPIServiceType) to High(TPIServiceType) do
  213. if Service in Services then
  214. DoNotify(opInsert, Service, Result);
  215. finally
  216. SetErrorMode(OldError);
  217. end;
  218. end;
  219. // ------------------------------------------------------------------------------
  220. procedure TGLPlugInManager.DoNotify(Operation: TOperation;
  221. Service: TPIServiceType; PlugIn: Integer);
  222. var
  223. I: Integer;
  224. begin
  225. for I := 0 TO FResManagerList.Count - 1 do
  226. if Service in PResManagerEntry(FResManagerList[I]).Services then
  227. PResManagerEntry(FResManagerList[I]).Manager.Notify(Self, Operation,
  228. Service, PlugIn);
  229. end;
  230. // ------------------------------------------------------------------------------
  231. function TGLPlugInManager.FindResManager(AManager: TGLResourceManager)
  232. : PResManagerEntry;
  233. var
  234. I: Integer;
  235. begin
  236. Result := nil;
  237. for I := 0 to FResManagerList.Count - 1 do
  238. if PResManagerEntry(FResManagerList[I]).Manager = AManager then
  239. begin
  240. Result := PResManagerEntry(FResManagerList[I]);
  241. Exit;
  242. end;
  243. end;
  244. // ------------------------------------------------------------------------------
  245. function TGLPlugInManager.GetIndexFromFilename(FileName: String): Integer;
  246. var
  247. I: Integer;
  248. begin
  249. Result := -1;
  250. for I := 0 to FLibraryList.Count - 1 do
  251. if CompareText(FLibraryList[I].Path, FileName) = 0 then
  252. begin
  253. Result := I;
  254. Exit;
  255. end;
  256. end;
  257. // ------------------------------------------------------------------------------
  258. function TGLPlugInManager.GetPlugInFromFilename(FileName: String): PPlugInEntry;
  259. var
  260. I: Integer;
  261. begin
  262. I := GetIndexFromFilename(FileName);
  263. if I > -1 then
  264. Result := FLibraryList[I]
  265. else
  266. Result := nil;
  267. end;
  268. // ------------------------------------------------------------------------------
  269. procedure TGLPlugInManager.RegisterResourceManager(AManager: TGLResourceManager;
  270. Services: TPIServices);
  271. var
  272. ManagerEntry: PResManagerEntry;
  273. begin
  274. ManagerEntry := FindResManager(AManager);
  275. if assigned(ManagerEntry) then
  276. ManagerEntry.Services := ManagerEntry.Services + Services
  277. else
  278. begin
  279. New(ManagerEntry);
  280. ManagerEntry.Manager := AManager;
  281. ManagerEntry.Services := Services;
  282. FResManagerList.Add(ManagerEntry);
  283. end;
  284. end;
  285. // ------------------------------------------------------------------------------
  286. procedure TGLPlugInManager.RemovePlugIn(Index: Integer);
  287. var
  288. Entry: PPlugInEntry;
  289. Service: TPIServiceType;
  290. Services: TPIServices;
  291. begin
  292. Entry := FLibraryList.Objects[Index];
  293. Services := Entry.GetServices;
  294. // notify for all services to be deleted all registered resource managers
  295. // for which these services are relevant
  296. for Service := Low(TPIServiceType) to High(TPIServiceType) do
  297. if Service in Services then
  298. DoNotify(opRemove, Service, Index);
  299. FreeLibrary(Entry.Handle);
  300. Dispose(Entry);
  301. FLibraryList.Delete(Index);
  302. end;
  303. // ------------------------------------------------------------------------------
  304. procedure TGLPlugInManager.EditPlugInList;
  305. begin
  306. ///TGLPlugInManagerEditor.EditPlugIns(Self); //Circular call to edit Listbox items?
  307. end;
  308. // ------------------------------------------------------------------------------
  309. procedure TGLPlugInManager.UnRegisterRessourceManager(AManager: TGLResourceManager;
  310. Services: TPIServices);
  311. var
  312. ManagerEntry: PResManagerEntry;
  313. Index: Integer;
  314. begin
  315. ManagerEntry := FindResManager(AManager);
  316. if assigned(ManagerEntry) then
  317. begin
  318. ManagerEntry.Services := ManagerEntry.Services - Services;
  319. if ManagerEntry.Services = [] then
  320. begin
  321. Index := FResManagerList.IndexOf(ManagerEntry);
  322. Dispose(ManagerEntry);
  323. FResManagerList.Delete(Index);
  324. end;
  325. end;
  326. end;
  327. // ------------------------------------------------------------------------------
  328. end.