dynlibs.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. Implements OS-independent loading of dynamic libraries.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFDEF FPC}
  12. {$MODE OBJFPC}
  13. {$ENDIF}
  14. unit dynlibs;
  15. interface
  16. uses
  17. SysUtils, RtlConsts, SysConst;
  18. { ---------------------------------------------------------------------
  19. Read OS-dependent interface declarations.
  20. ---------------------------------------------------------------------}
  21. {$define readinterface}
  22. {$i dynlibs.inc}
  23. {$undef readinterface}
  24. { ---------------------------------------------------------------------
  25. OS - Independent declarations.
  26. ---------------------------------------------------------------------}
  27. Function SafeLoadLibrary(Name : AnsiString) : TLibHandle;
  28. Function LoadLibrary(Name : AnsiString) : TLibHandle;
  29. Function GetProcedureAddress(Lib : TlibHandle; ProcName : AnsiString) : Pointer;
  30. Function UnloadLibrary(Lib : TLibHandle) : Boolean;
  31. // Kylix/Delphi compability
  32. Type
  33. HModule = TLibHandle;
  34. Function FreeLibrary(Lib : TLibHandle) : Boolean;
  35. Function GetProcAddress(Lib : TlibHandle; ProcName : AnsiString) : Pointer;
  36. // Dynamic Library Manager
  37. { Note: If you look for some code that uses this library handler, take a look at
  38. sqlite3.inc of sqlite package (simple) or
  39. mysql.inc of mysql package (advanced)
  40. }
  41. type
  42. PLibHandler = ^TLibHandler;
  43. TLibEventLoading = function(User: Pointer; Handler: PLibHandler): Boolean;
  44. TLibEventUnloading = procedure(Handler: PLibHandler);
  45. PPLibSymbol = ^PLibSymbol;
  46. PLibSymbol = ^TLibSymbol;
  47. TLibSymbol = record
  48. pvar: PPointer; { pointer to Symbol variable }
  49. name: String; { name of the Symbol }
  50. weak: Boolean; { weak }
  51. end;
  52. TLibHandler = record
  53. InterfaceName: String; { abstract name of the library }
  54. Defaults : array of String; { list of default library filenames }
  55. Filename : String; { handle of the current loaded library }
  56. Handle : TLibHandle; { filename of the current loaded library }
  57. Loading : TLibEventLoading; { loading event, called after the unit is loaded }
  58. Unloading : TLibEventUnloading; { unloading event, called before the unit is unloaded }
  59. SymCount : Integer; { number of symbols }
  60. Symbols : PLibSymbol; { symbol address- and namelist }
  61. ErrorMsg : String; { last error message }
  62. RefCount : Integer; { reference counter }
  63. end;
  64. { handler definition }
  65. function LibraryHandler(const InterfaceName: String; const DefaultLibraries: array of String;
  66. const Symbols: PLibSymbol; const SymCount: Integer; const AfterLoading: TLibEventLoading = nil;
  67. const BeforeUnloading: TLibEventUnloading = nil): TLibHandler;
  68. { initialization/finalization }
  69. function TryInitializeLibrary(var Handler: TLibHandler; const LibraryNames: array of String;
  70. const User: Pointer = nil; const NoSymbolErrors: Boolean = False): Integer;
  71. function TryInitializeLibrary(var Handler: TLibHandler; const LibraryName: String = '';
  72. const User: Pointer = nil; const NoSymbolErrors: Boolean = False): Integer;
  73. function InitializeLibrary(var Handler: TLibHandler; const LibraryNames: array of String;
  74. const User: Pointer = nil; const NoSymbolErrors: Boolean = False): Integer;
  75. function InitializeLibrary(var Handler: TLibHandler; const LibraryName: String = '';
  76. const User: Pointer = nil; const NoSymbolErrors: Boolean = False): Integer;
  77. function ReleaseLibrary(var Handler: TLibHandler): Integer;
  78. { errors }
  79. procedure AppendLibraryError(var Handler: TLibHandler; const Msg: String);
  80. function GetLastLibraryError(var Handler: TLibHandler): String;
  81. procedure RaiseLibraryException(var Handler: TLibHandler);
  82. { symbol load/clear }
  83. function LoadLibrarySymbols(const Lib: TLibHandle; const Symbols: PLibSymbol; const Count: Integer;
  84. const ErrorSym: PPLibSymbol = nil): Boolean;
  85. procedure ClearLibrarySymbols(const Symbols: PLibSymbol; const Count: Integer);
  86. Implementation
  87. { ---------------------------------------------------------------------
  88. OS - Independent declarations.
  89. ---------------------------------------------------------------------}
  90. {$i dynlibs.inc}
  91. Function FreeLibrary(Lib : TLibHandle) : Boolean;
  92. begin
  93. Result:=UnloadLibrary(lib);
  94. end;
  95. Function GetProcAddress(Lib : TlibHandle; ProcName : AnsiString) : Pointer;
  96. begin
  97. Result:=GetProcedureAddress(Lib,Procname);
  98. end;
  99. Function SafeLoadLibrary(Name : AnsiString) : TLibHandle;
  100. {$ifdef i386}
  101. var w : word;
  102. {$endif}
  103. Begin
  104. {$ifdef i386}
  105. w:=get8087cw;
  106. {$endif}
  107. result:=loadlibrary(name);
  108. {$ifdef i386}
  109. set8087cw(w);
  110. {$endif}
  111. End;
  112. function LibraryHandler(const InterfaceName: String; const DefaultLibraries: array of String;
  113. const Symbols: PLibSymbol; const SymCount: Integer; const AfterLoading: TLibEventLoading;
  114. const BeforeUnloading: TLibEventUnloading): TLibHandler;
  115. var
  116. I: Integer;
  117. begin
  118. Result.InterfaceName := InterfaceName;
  119. Result.Filename := '';
  120. Result.Handle := NilHandle;
  121. Result.Loading := AfterLoading;
  122. Result.Unloading := BeforeUnloading;
  123. Result.SymCount := SymCount;
  124. Result.Symbols := Symbols;
  125. Result.ErrorMsg := '';
  126. Result.RefCount := 0;
  127. SetLength(Result.Defaults, Length(DefaultLibraries));
  128. for I := 0 to High(DefaultLibraries) do
  129. Result.Defaults[I] := DefaultLibraries[I];
  130. end;
  131. function TryInitializeLibraryInternal(var Handler: TLibHandler; const LibraryName: String;
  132. const User: Pointer; const NoSymbolErrors: Boolean): Integer;
  133. var
  134. ErrSym: PLibSymbol;
  135. begin
  136. if (Handler.Filename <> '') and (Handler.Filename <> LibraryName) then
  137. begin
  138. AppendLibraryError(Handler, Format(SLibraryAlreadyLoaded, [Handler.InterfaceName, Handler.Filename]));
  139. Result := -1;
  140. Exit;
  141. end;
  142. Result := InterlockedIncrement(Handler.RefCount);
  143. if Result = 1 then
  144. begin
  145. Handler.Handle := LoadLibrary(LibraryName);
  146. if Handler.Handle = NilHandle then
  147. begin
  148. AppendLibraryError(Handler, Format(SLibraryNotLoaded, [Handler.InterfaceName, LibraryName]));
  149. Handler.RefCount := 0;
  150. Result := -1;
  151. Exit;
  152. end;
  153. Handler.Filename := LibraryName;
  154. if not LoadLibrarySymbols(Handler.Handle, Handler.Symbols, Handler.SymCount, @ErrSym) and not NoSymbolErrors then
  155. begin
  156. AppendLibraryError(Handler, Format(SLibraryUnknownSym, [ErrSym^.name, Handler.InterfaceName, LibraryName]));
  157. UnloadLibrary(Handler.Handle);
  158. Handler.Handle := NilHandle;
  159. Handler.Filename := '';
  160. Handler.RefCount := 0;
  161. Result := -1;
  162. Exit;
  163. end;
  164. if Assigned(Handler.Loading) and not Handler.Loading(User, @Handler) then
  165. begin
  166. UnloadLibrary(Handler.Handle);
  167. Handler.Handle := NilHandle;
  168. Handler.Filename := '';
  169. Handler.RefCount := 0;
  170. Result := -1;
  171. Exit;
  172. end;
  173. end;
  174. end;
  175. function TryInitializeLibrary(var Handler: TLibHandler; const LibraryName: String;
  176. const User: Pointer; const NoSymbolErrors: Boolean): Integer;
  177. begin
  178. if LibraryName <> '' then
  179. begin
  180. Handler.ErrorMsg := '';
  181. Result := TryInitializeLibraryInternal(Handler, LibraryName, User, NoSymbolErrors);
  182. end else
  183. Result := TryInitializeLibrary(Handler, Handler.Defaults, User, NoSymbolErrors);
  184. end;
  185. function TryInitializeLibrary(var Handler: TLibHandler; const LibraryNames: array of String;
  186. const User: Pointer; const NoSymbolErrors: Boolean): Integer;
  187. var
  188. I: Integer;
  189. begin
  190. Handler.ErrorMsg := '';
  191. if Length(LibraryNames) <= 0 then
  192. begin
  193. if Length(Handler.Defaults) > 0 then
  194. begin
  195. Result := TryInitializeLibrary(Handler, Handler.Defaults, User, NoSymbolErrors);
  196. Exit;
  197. end;
  198. AppendLibraryError(Handler, SVarInvalid);
  199. Result := -1;
  200. Exit;
  201. end;
  202. for I := 0 to High(LibraryNames) do
  203. begin
  204. Result := TryInitializeLibraryInternal(Handler, LibraryNames[I], User, NoSymbolErrors);
  205. if Result > 0 then
  206. begin
  207. Handler.ErrorMsg := '';
  208. Exit;
  209. end;
  210. end;
  211. end;
  212. function InitializeLibrary(var Handler: TLibHandler; const LibraryNames: array of String;
  213. const User: Pointer; const NoSymbolErrors: Boolean): Integer;
  214. begin
  215. Result := TryInitializeLibrary(Handler, LibraryNames, User, NoSymbolErrors);
  216. if Result < 0 then
  217. RaiseLibraryException(Handler);
  218. end;
  219. function InitializeLibrary(var Handler: TLibHandler; const LibraryName: String;
  220. const User: Pointer; const NoSymbolErrors: Boolean): Integer;
  221. begin
  222. Result := TryInitializeLibrary(Handler, LibraryName, User, NoSymbolErrors);
  223. if Result < 0 then
  224. RaiseLibraryException(Handler);
  225. end;
  226. function ReleaseLibrary(var Handler: TLibHandler): Integer;
  227. begin
  228. Handler.ErrorMsg := '';
  229. Result := InterlockedDecrement(Handler.RefCount);
  230. if Result = 0 then
  231. begin
  232. if Assigned(Handler.Unloading) then
  233. Handler.Unloading(@Handler);
  234. ClearLibrarySymbols(Handler.Symbols, Handler.SymCount);
  235. UnloadLibrary(Handler.Handle);
  236. Handler.Handle := NilHandle;
  237. Handler.Filename := '';
  238. end else
  239. if Result < 0 then
  240. Handler.RefCount := 0;
  241. end;
  242. procedure AppendLibraryError(var Handler: TLibHandler; const Msg: String);
  243. begin
  244. if Handler.ErrorMsg <> '' then
  245. Handler.ErrorMsg := Handler.ErrorMsg + LineEnding + Msg
  246. else
  247. Handler.ErrorMsg := Msg;
  248. end;
  249. function GetLastLibraryError(var Handler: TLibHandler): String;
  250. begin
  251. Result := Handler.ErrorMsg;
  252. Handler.ErrorMsg := '';
  253. end;
  254. procedure RaiseLibraryException(var Handler: TLibHandler);
  255. var
  256. Msg: String;
  257. begin
  258. Msg := GetLastLibraryError(Handler);
  259. if Msg <> '' then
  260. raise EInOutError.Create(Msg)
  261. else
  262. raise EInOutError.Create(SUnknown);
  263. end;
  264. function LoadLibrarySymbols(const Lib: TLibHandle; const Symbols: PLibSymbol; const Count: Integer;
  265. const ErrorSym: PPLibSymbol): Boolean;
  266. var
  267. P,L: PLibSymbol;
  268. begin
  269. P := Symbols;
  270. L := @Symbols[Count];
  271. while P < L do
  272. begin
  273. P^.pvar^ := GetProcedureAddress(Lib, P^.name);
  274. if not Assigned(P^.pvar^) and not P^.weak then
  275. begin
  276. if Assigned(ErrorSym) then
  277. ErrorSym^ := P;
  278. Result := False;
  279. Exit;
  280. end;
  281. Inc(P);
  282. end;
  283. Result := True;
  284. end;
  285. procedure ClearLibrarySymbols(const Symbols: PLibSymbol; const Count: Integer);
  286. var
  287. P,L: PLibSymbol;
  288. begin
  289. P := Symbols;
  290. L := @Symbols[Count];
  291. while P < L do
  292. begin
  293. P^.pvar^ := nil;
  294. Inc(P);
  295. end;
  296. end;
  297. end.