123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2000 by the Free Pascal development team
- Implements OS-independent loading of dynamic libraries.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$IFDEF FPC}
- {$MODE OBJFPC}
- {$ENDIF}
- unit dynlibs;
- interface
- uses
- SysUtils, RtlConsts, SysConst;
- { ---------------------------------------------------------------------
- Read OS-dependent interface declarations.
- ---------------------------------------------------------------------}
- {$define readinterface}
- {$i dynlibs.inc}
- {$undef readinterface}
- { ---------------------------------------------------------------------
- OS - Independent declarations.
- ---------------------------------------------------------------------}
- Function SafeLoadLibrary(const Name : AnsiString) : TLibHandle;
- Function LoadLibrary(const Name : AnsiString) : TLibHandle;
- Function GetProcedureAddress(Lib : TlibHandle; const ProcName : AnsiString) : Pointer;
- Function UnloadLibrary(Lib : TLibHandle) : Boolean;
- // Kylix/Delphi compability
- Type
- HModule = TLibHandle;
- Function FreeLibrary(Lib : TLibHandle) : Boolean;
- Function GetProcAddress(Lib : TlibHandle; const ProcName : AnsiString) : Pointer;
- // Dynamic Library Manager
- { Note: If you look for some code that uses this library handler, take a look at
- sqlite3.inc of sqlite package (simple) or
- mysql.inc of mysql package (advanced)
- }
- type
- PLibHandler = ^TLibHandler;
- TLibEventLoading = function(User: Pointer; Handler: PLibHandler): Boolean;
- TLibEventUnloading = procedure(Handler: PLibHandler);
- TLibIdent = QWord;
- TLibIdentGetter = function(const Filename: String): TLibIdent;
- PPLibSymbol = ^PLibSymbol;
- PLibSymbol = ^TLibSymbol;
- TLibSymbol = record
- pvar: PPointer; { pointer to Symbol variable }
- name: String; { name of the Symbol }
- weak: Boolean; { weak }
- end;
- PLibSymbolPtrArray = ^TLibSymbolPtrArray;
- TLibSymbolPtrArray = array of PLibSymbol;
- TLibHandler = record
- InterfaceName: String; { abstract name of the library }
- Defaults : array of String; { list of default library filenames }
- Filename : String; { filename of the current loaded library }
- Handle : TLibHandle; { handle of the current loaded library }
- Loading : TLibEventLoading; { loading event, called after the unit is loaded }
- Unloading : TLibEventUnloading; { unloading event, called before the unit is unloaded }
- IdentGetter : TLibIdentGetter; { identifier getter event }
- Ident : TLibIdent; { identifier of the current loaded library }
- SymCount : Integer; { number of symbols }
- Symbols : PLibSymbol; { symbol address- and namelist }
- ErrorMsg : String; { last error message }
- RefCount : Integer; { reference counter }
- end;
- { handler definition }
- function LibraryHandler(const InterfaceName: String; const DefaultLibraries: array of String;
- const Symbols: PLibSymbol; const SymCount: Integer; const AfterLoading: TLibEventLoading = nil;
- const BeforeUnloading: TLibEventUnloading = nil; const IdentGetter: TLibIdentGetter = nil): TLibHandler;
- { initialization/finalization }
- function TryInitializeLibrary(var Handler: TLibHandler; const LibraryNames: array of String;
- const User: Pointer = nil; const NoSymbolErrors: Boolean = True): Integer;
- function TryInitializeLibrary(var Handler: TLibHandler; const LibraryName: String = '';
- const User: Pointer = nil; const NoSymbolErrors: Boolean = True): Integer;
- function InitializeLibrary(var Handler: TLibHandler; const LibraryNames: array of String;
- const User: Pointer = nil; const NoSymbolErrors: Boolean = True): Integer;
- function InitializeLibrary(var Handler: TLibHandler; const LibraryName: String = '';
- const User: Pointer = nil; const NoSymbolErrors: Boolean = True): Integer;
- function ReleaseLibrary(var Handler: TLibHandler): Integer;
- { errors }
- procedure AppendLibraryError(var Handler: TLibHandler; const Msg: String);
- function GetLastLibraryError(var Handler: TLibHandler): String;
- procedure RaiseLibraryException(var Handler: TLibHandler);
- { symbol load/clear }
- function LoadLibrarySymbols(const Lib: TLibHandle; const Symbols: PLibSymbol; const Count: Integer;
- const ErrorSymbols: PLibSymbolPtrArray = nil): Boolean;
- procedure ClearLibrarySymbols(const Symbols: PLibSymbol; const Count: Integer);
- Implementation
- { ---------------------------------------------------------------------
- OS - Independent declarations.
- ---------------------------------------------------------------------}
- {$i dynlibs.inc}
- Function FreeLibrary(Lib : TLibHandle) : Boolean;
- begin
- Result:=UnloadLibrary(lib);
- end;
- Function GetProcAddress(Lib : TlibHandle; const ProcName : AnsiString) : Pointer;
- begin
- Result:=GetProcedureAddress(Lib,Procname);
- end;
- Function SafeLoadLibrary(const Name : AnsiString) : TLibHandle;
- {$ifdef i386}
- var w : word;
- {$endif}
- Begin
- {$ifdef i386}
- w:=get8087cw;
- {$endif}
- result:=loadlibrary(name);
- {$ifdef i386}
- set8087cw(w);
- {$endif}
- End;
- function LibraryHandler(const InterfaceName: String; const DefaultLibraries: array of String;
- const Symbols: PLibSymbol; const SymCount: Integer; const AfterLoading: TLibEventLoading;
- const BeforeUnloading: TLibEventUnloading; const IdentGetter: TLibIdentGetter): TLibHandler;
- var
- I: Integer;
- begin
- Result.InterfaceName := InterfaceName;
- Result.Filename := '';
- Result.Handle := NilHandle;
- Result.Loading := AfterLoading;
- Result.Unloading := BeforeUnloading;
- Result.IdentGetter := IdentGetter;
- Result.Ident := 0;
- Result.SymCount := SymCount;
- Result.Symbols := Symbols;
- Result.ErrorMsg := '';
- Result.RefCount := 0;
- SetLength(Result.Defaults, Length(DefaultLibraries));
- for I := 0 to High(DefaultLibraries) do
- Result.Defaults[I] := DefaultLibraries[I];
- end;
- function TryInitializeLibraryInternal(var Handler: TLibHandler; const LibraryName: String;
- const User: Pointer; const NoSymbolErrors: Boolean): Integer;
- var
- ErrSyms: TLibSymbolPtrArray;
- NewIdent: TLibIdent;
- I: Integer;
- begin
- if Handler.Filename <> '' then
- begin
- if Assigned(Handler.IdentGetter) then
- begin
- NewIdent := Handler.IdentGetter(LibraryName);
- if NewIdent <> Handler.Ident then
- begin
- AppendLibraryError(Handler, Format(SLibraryAlreadyLoaded, [Handler.InterfaceName, Handler.Filename]));
- Result := -1;
- Exit;
- end;
- end;
- end;
- Result := InterlockedIncrement(Handler.RefCount);
- if Result = 1 then
- begin
- Handler.Handle := LoadLibrary(LibraryName);
- if Handler.Handle = NilHandle then
- begin
- AppendLibraryError(Handler, Format(SLibraryNotLoaded, [Handler.InterfaceName, LibraryName]));
- Handler.RefCount := 0;
- Result := -1;
- Exit;
- end;
- Handler.Filename := LibraryName;
- if not LoadLibrarySymbols(Handler.Handle, Handler.Symbols, Handler.SymCount, @ErrSyms) and not NoSymbolErrors then
- begin
- for I := 0 to Length(ErrSyms) - 1 do
- AppendLibraryError(Handler, Format(SLibraryUnknownSym, [ErrSyms[I]^.name, Handler.InterfaceName, LibraryName]));
- UnloadLibrary(Handler.Handle);
- Handler.Handle := NilHandle;
- Handler.Filename := '';
- Handler.RefCount := 0;
- Result := -1;
- Exit;
- end;
- if Assigned(Handler.Loading) and not Handler.Loading(User, @Handler) then
- begin
- UnloadLibrary(Handler.Handle);
- Handler.Handle := NilHandle;
- Handler.Filename := '';
- Handler.RefCount := 0;
- Result := -1;
- Exit;
- end;
- if Assigned(Handler.IdentGetter) then
- Handler.Ident := Handler.IdentGetter(Handler.Filename)
- else
- Handler.Ident := 0;
- end;
- end;
- function TryInitializeLibrary(var Handler: TLibHandler; const LibraryName: String;
- const User: Pointer; const NoSymbolErrors: Boolean): Integer;
- begin
- if LibraryName <> '' then
- begin
- Handler.ErrorMsg := '';
- Result := TryInitializeLibraryInternal(Handler, LibraryName, User, NoSymbolErrors);
- end else
- Result := TryInitializeLibrary(Handler, Handler.Defaults, User, NoSymbolErrors);
- end;
- function TryInitializeLibrary(var Handler: TLibHandler; const LibraryNames: array of String;
- const User: Pointer; const NoSymbolErrors: Boolean): Integer;
- var
- I: Integer;
- begin
- Handler.ErrorMsg := '';
- if Length(LibraryNames) <= 0 then
- begin
- if Length(Handler.Defaults) > 0 then
- begin
- Result := TryInitializeLibrary(Handler, Handler.Defaults, User, NoSymbolErrors);
- Exit;
- end;
- AppendLibraryError(Handler, SVarInvalid);
- Result := -1;
- Exit;
- end;
- for I := 0 to High(LibraryNames) do
- begin
- Result := TryInitializeLibraryInternal(Handler, LibraryNames[I], User, NoSymbolErrors);
- if Result > 0 then
- begin
- Handler.ErrorMsg := '';
- Exit;
- end;
- end;
- end;
- function InitializeLibrary(var Handler: TLibHandler; const LibraryNames: array of String;
- const User: Pointer; const NoSymbolErrors: Boolean): Integer;
- begin
- Result := TryInitializeLibrary(Handler, LibraryNames, User, NoSymbolErrors);
- if Result < 0 then
- RaiseLibraryException(Handler);
- end;
- function InitializeLibrary(var Handler: TLibHandler; const LibraryName: String;
- const User: Pointer; const NoSymbolErrors: Boolean): Integer;
- begin
- Result := TryInitializeLibrary(Handler, LibraryName, User, NoSymbolErrors);
- if Result < 0 then
- RaiseLibraryException(Handler);
- end;
- function ReleaseLibrary(var Handler: TLibHandler): Integer;
- begin
- Handler.ErrorMsg := '';
- Result := InterlockedDecrement(Handler.RefCount);
- if Result = 0 then
- begin
- if Assigned(Handler.Unloading) then
- Handler.Unloading(@Handler);
- ClearLibrarySymbols(Handler.Symbols, Handler.SymCount);
- UnloadLibrary(Handler.Handle);
- Handler.Handle := NilHandle;
- Handler.Filename := '';
- Handler.Ident := 0;
- end else
- if Result < 0 then
- Handler.RefCount := 0;
- end;
- procedure AppendLibraryError(var Handler: TLibHandler; const Msg: String);
- begin
- if Handler.ErrorMsg <> '' then
- Handler.ErrorMsg := Handler.ErrorMsg + LineEnding + Msg
- else
- Handler.ErrorMsg := Msg;
- end;
- function GetLastLibraryError(var Handler: TLibHandler): String;
- begin
- Result := Handler.ErrorMsg;
- Handler.ErrorMsg := '';
- end;
- procedure RaiseLibraryException(var Handler: TLibHandler);
- var
- Msg: String;
- begin
- Msg := GetLastLibraryError(Handler);
- if Msg <> '' then
- raise EInOutError.Create(Msg)
- else
- raise EInOutError.Create(SUnknown);
- end;
- function LoadLibrarySymbols(const Lib: TLibHandle; const Symbols: PLibSymbol; const Count: Integer;
- const ErrorSymbols: PLibSymbolPtrArray): Boolean;
- var
- P,L: PLibSymbol;
- Len: Integer;
- begin
- P := Symbols;
- L := @Symbols[Count];
- while P < L do
- begin
- P^.pvar^ := GetProcedureAddress(Lib, P^.name);
- if not Assigned(P^.pvar^) and not P^.weak then
- begin
- if Assigned(ErrorSymbols) then
- begin
- Len := Length(ErrorSymbols^);
- SetLength(ErrorSymbols^, Len+1);
- ErrorSymbols^[Len] := P;
- end;
- Result := False;
- end;
- Inc(P);
- end;
- Result := True;
- end;
- procedure ClearLibrarySymbols(const Symbols: PLibSymbol; const Count: Integer);
- var
- P,L: PLibSymbol;
- begin
- P := Symbols;
- L := @Symbols[Count];
- while P < L do
- begin
- P^.pvar^ := nil;
- Inc(P);
- end;
- end;
- end.
|