GLS.PlugInManager.pas 11 KB

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