123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- ****************************************************************}
- { }
- { Project JEDI }
- { OS independent Dynamic Loading Helpers }
- { }
- { The initial developer of the this code is }
- { Robert Marquardt <robert_marquardt att gmx dott de) }
- { }
- { Copyright (C) 2000, 2001 Robert Marquardt. }
- { }
- { Obtained through: }
- { Joint Endeavour of Delphi Innovators (Project JEDI) }
- { }
- { You may retrieve the latest version of this file at the Project }
- { JEDI home page, located at http://delphi-jedi.org }
- { }
- { The contents of this file are used with permission, subject to }
- { the Mozilla Public License Version 1.1 (the "License"); you may }
- { not use this file except in compliance with the License. You may }
- { obtain a copy of the License at }
- { http://www.mozilla.org/NPL/NPL-1_1Final.html }
- { }
- { Software distributed under the License is distributed on an }
- { "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or }
- { implied. See the License for the specific language governing }
- { rights and limitations under the License. }
- { }
- {******************************************************************}
- {$IFNDEF JWA_OMIT_SECTIONS}
- unit ModuleLoader;
- {$ENDIF JWA_OMIT_SECTIONS}
- {.$I jvcl.inc}
- {$IFNDEF JWA_OMIT_SECTIONS}
- {$WEAKPACKAGEUNIT ON}
- interface
- {$IFDEF MSWINDOWS}
- uses
- Windows;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- uses
- Types, Libc;
- {$ENDIF UNIX}
- {$ENDIF JWA_OMIT_SECTIONS}
- {$IFNDEF JWA_IMPLEMENTATIONSECTION}
- {$IFDEF MSWINDOWS}
- type
- // Handle to a loaded DLL
- TModuleHandle = HINST;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- type
- // Handle to a loaded .so
- TModuleHandle = Pointer;
- {$ENDIF UNIX}
- const
- // Value designating an unassigned TModuleHandle or a failed loading
- INVALID_MODULEHANDLE_VALUE = TModuleHandle(0);
- {$IFNDEF JWA_INCLUDEMODE}
- function LoadModule(var Module: TModuleHandle; FileName: Ansistring): Boolean;
- {$ELSE}
- function ModuleLoader_LoadModule(var Module: TModuleHandle; FileName: Ansistring): Boolean;
- {$ENDIF JWA_INCLUDEMODE}
- function LoadModuleEx(var Module: TModuleHandle; FileName: Ansistring; Flags: Cardinal): Boolean;
- procedure UnloadModule(var Module: TModuleHandle);
- function GetModuleSymbol(Module: TModuleHandle; SymbolName: Ansistring): Pointer;
- function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: Ansistring; var Accu: Boolean): Pointer;
- function ReadModuleData(Module: TModuleHandle; SymbolName: Ansistring; var Buffer; Size: Cardinal): Boolean;
- function WriteModuleData(Module: TModuleHandle; SymbolName: Ansistring; var Buffer; Size: Cardinal): Boolean;
- // (p3)
- // Simple DLL loading class. The idea is to use it to dynamically load
- // a DLL at run-time using the GetProcedure method. Another (better) use is to derive a
- // new class for each DLL you are interested in and explicitly call GetProcedure for
- // each function in an overridden Load method. You would then add procedure/function
- // aliases to the new class that maps down to the internally managed function pointers.
- // This class is built from an idea I read about in Delphi Magazine a while ago but
- // I forget who was the originator. If you know, let me know and I'll put it in the credits
- // NB!!!
- // * Prepared for Kylix but not tested
- // * Is GetLastError implemented on Kylix? RaiseLastOSError implies it is...
- type
- TModuleLoadMethod = (ltDontResolveDllReferences, ltLoadAsDataFile, ltAlteredSearchPath);
- TModuleLoadMethods = set of TModuleLoadMethod;
- TModuleLoader = class(TObject)
- private
- FHandle: TModuleHandle;
- FDLLName: ansistring;
- function GetLoaded: Boolean;
- protected
- procedure Load(LoadMethods: TModuleLoadMethods); virtual;
- procedure Unload; virtual;
- procedure Error(ErrorCode: Cardinal); virtual;
- public
- // Check whether a DLL (and optionally a function) is available on the system
- // To only check the DLL, leave ProcName empty
- class function IsAvaliable(const ADLLName: ansistring; const AProcName: AnsiString = ''): Boolean;
- constructor Create(const ADLLName: ansistring; LoadMethods: TModuleLoadMethods = []);
- destructor Destroy; override;
- // Get a pointer to a function in the DLL. Should be called as GetProcedure('Name',@FuncPointer);
- // Returns True if the function was found. Note that a call to GetProcAddress is only executed if AProc = nil
- function GetProcedure(const AName: ansistring; var AProc: Pointer): Boolean;
- // Returns a symbol exported from the DLL and puts it in Buffer.
- // Make sure AName is actually a symbol and not a function or this will crash horribly!
- function GetExportedSymbol(const AName: ansistring; var Buffer; Size: Integer): Boolean;
- // Changes a symbol exported from the DLL into the value in Buffer.
- // The change is not persistent (it will get lost when the DLL is unloaded)
- // Make sure AName is actually a symbol and not a function or this will crash horribly!
- function SetExportedSymbol(const AName: ansistring; var Buffer; Size: Integer): Boolean;
- property Loaded: Boolean read GetLoaded;
- property DLLName: ansistring read FDLLName;
- property Handle: TModuleHandle read FHandle;
- end;
- {$ENDIF JWA_IMPLEMENTATIONSECTION}
- {$IFNDEF JWA_OMIT_SECTIONS}
- implementation
- //uses ...
- {$ENDIF JWA_OMIT_SECTIONS}
- {$IFNDEF JWA_INTERFACESECTION}
- {$IFDEF MSWINDOWS}
- // load the DLL file FileName
- // the rules for FileName are those of LoadLibrary
- // Returns: True = success, False = failure to load
- // Assigns: the handle of the loaded DLL to Module
- // Warning: if Module has any other value than INVALID_MODULEHANDLE_VALUE
- // on entry the function will do nothing but returning success.
- {$IFNDEF JWA_INCLUDEMODE}
- function LoadModule(var Module: TModuleHandle; FileName: AnsiString): Boolean;
- {$ELSE}
- function ModuleLoader_LoadModule(var Module: TModuleHandle; FileName: AnsiString): Boolean;
- {$ENDIF JWA_INCLUDEMODE}
- begin
- if Module = INVALID_MODULEHANDLE_VALUE then
- Module := LoadLibraryA(PAnsiChar(FileName));
- Result := Module <> INVALID_MODULEHANDLE_VALUE;
- end;
- // load the DLL file FileName
- // LoadLibraryEx is used to get better control of the loading
- // for the allowed values for flags see LoadLibraryEx documentation.
- function LoadModuleEx(var Module: TModuleHandle; FileName: AnsiString; Flags: Cardinal): Boolean;
- begin
- if Module = INVALID_MODULEHANDLE_VALUE then
- Module := LoadLibraryExA(PAnsiChar(FileName), 0, Flags);
- Result := Module <> INVALID_MODULEHANDLE_VALUE;
- end;
- // unload a DLL loaded with LoadModule or LoadModuleEx
- // The procedure will not try to unload a handle with
- // value INVALID_MODULEHANDLE_VALUE and assigns this value
- // to Module after unload.
- procedure UnloadModule(var Module: TModuleHandle);
- begin
- if Module <> INVALID_MODULEHANDLE_VALUE then
- FreeLibrary(Module);
- Module := INVALID_MODULEHANDLE_VALUE;
- end;
- // returns the pointer to the symbol named SymbolName
- // if it is exported from the DLL Module
- // nil is returned if the symbol is not available
- function GetModuleSymbol(Module: TModuleHandle; SymbolName: AnsiString): Pointer;
- begin
- Result := nil;
- if Module <> INVALID_MODULEHANDLE_VALUE then
- Result := GetProcAddress(Module, PAnsiChar(SymbolName));
- end;
- // returns the pointer to the symbol named SymbolName
- // if it is exported from the DLL Module
- // nil is returned if the symbol is not available.
- // as an extra the Boolean variable Accu is updated
- // by anding in the success of the function.
- // This is very handy for rendering a global result
- // when accessing a long list of symbols.
- function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: AnsiString; var Accu: Boolean): Pointer;
- begin
- Result := nil;
- if Module <> INVALID_MODULEHANDLE_VALUE then
- Result := GetProcAddress(Module, PAnsiChar(SymbolName));
- Accu := Accu and (Result <> nil);
- end;
- // get the value of variables exported from a DLL Module
- // Delphi cannot access variables in a DLL directly, so
- // this function allows to copy the data from the DLL.
- // Beware! You are accessing the DLL memory image directly.
- // Be sure to access a variable not a function and be sure
- // to read the correct amount of data.
- function ReadModuleData(Module: TModuleHandle; SymbolName: AnsiString; var Buffer; Size: Cardinal): Boolean;
- var
- Sym: Pointer;
- begin
- Result := True;
- Sym := GetModuleSymbolEx(Module, SymbolName, Result);
- if Result then
- Move(Sym^, Buffer, Size);
- end;
- // set the value of variables exported from a DLL Module
- // Delphi cannot access variables in a DLL directly, so
- // this function allows to copy the data to the DLL!
- // BEWARE! You are accessing the DLL memory image directly.
- // Be sure to access a variable not a function and be sure
- // to write the correct amount of data.
- // The changes are not persistent. They get lost when the
- // DLL is unloaded.
- function WriteModuleData(Module: TModuleHandle; SymbolName: AnsiString; var Buffer; Size: Cardinal): Boolean;
- var
- Sym: Pointer;
- begin
- Result := True;
- Sym := GetModuleSymbolEx(Module, SymbolName, Result);
- if Result then
- Move(Buffer, Sym^, Size);
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- const
- TYPE_E_ELEMENTNOTFOUND = $8002802B;
- // load the .so file FileName
- // the rules for FileName are those of dlopen()
- // Returns: True = success, False = failure to load
- // Assigns: the handle of the loaded .so to Module
- // Warning: if Module has any other value than INVALID_MODULEHANDLE_VALUE
- // on entry the function will do nothing but returning success.
- {$IFNDEF JWA_INCLUDEMODE}
- function LoadModule(var Module: TModuleHandle; FileName: AnsiString): Boolean;
- {$ELSE}
- function ModuleLoader_LoadModule(var Module: TModuleHandle; FileName: AnsiString): Boolean;
- {$ENDIF JWA_INCLUDEMODE}
- begin
- if Module = INVALID_MODULEHANDLE_VALUE then
- Module := dlopen(PAnsiChar(FileName), RTLD_NOW);
- Result := Module <> INVALID_MODULEHANDLE_VALUE;
- end;
- // load the .so file FileName
- // dlopen() with flags is used to get better control of the loading
- // for the allowed values for flags see "man dlopen".
- function LoadModuleEx(var Module: TModuleHandle; FileName: AnsiString; Flags: Cardinal): Boolean;
- begin
- if Module = INVALID_MODULEHANDLE_VALUE then
- Module := dlopen(PAnsiChar(FileName), Flags);
- Result := Module <> INVALID_MODULEHANDLE_VALUE;
- end;
- // unload a .so loaded with LoadModule or LoadModuleEx
- // The procedure will not try to unload a handle with
- // value INVALID_MODULEHANDLE_VALUE and assigns this value
- // to Module after unload.
- procedure UnloadModule(var Module: TModuleHandle);
- begin
- if Module <> INVALID_MODULEHANDLE_VALUE then
- dlclose(Module);
- Module := INVALID_MODULEHANDLE_VALUE;
- end;
- // returns the pointer to the symbol named SymbolName
- // if it is exported from the .so Module
- // nil is returned if the symbol is not available
- function GetModuleSymbol(Module: TModuleHandle; SymbolName: AnsiString): Pointer;
- begin
- Result := nil;
- if Module <> INVALID_MODULEHANDLE_VALUE then
- Result := dlsym(Module, PAnsiChar(SymbolName));
- end;
- // returns the pointer to the symbol named SymbolName
- // if it is exported from the .so Module
- // nil is returned if the symbol is not available.
- // as an extra the Boolean variable Accu is updated
- // by anding in the success of the function.
- // This is very handy for rendering a global result
- // when accessing a long list of symbols.
- function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: AnsiString; var Accu: Boolean): Pointer;
- begin
- Result := nil;
- if Module <> INVALID_MODULEHANDLE_VALUE then
- Result := dlsym(Module, PAnsiChar(SymbolName));
- Accu := Accu and (Result <> nil);
- end;
- // get the value of variables exported from a .so Module
- // Delphi cannot access variables in a .so directly, so
- // this function allows to copy the data from the .so.
- // Beware! You are accessing the .so memory image directly.
- // Be sure to access a variable not a function and be sure
- // to read the correct amount of data.
- function ReadModuleData(Module: TModuleHandle; SymbolName: AnsiString; var Buffer; Size: Cardinal): Boolean;
- var
- Sym: Pointer;
- begin
- Result := True;
- Sym := GetModuleSymbolEx(Module, SymbolName, Result);
- if Result then
- Move(Sym^, Buffer, Size);
- end;
- // set the value of variables exported from a .so Module
- // Delphi cannot access variables in a .so directly, so
- // this function allows to copy the data to the .so!
- // BEWARE! You are accessing the .so memory image directly.
- // Be sure to access a variable not a function and be sure
- // to write the correct amount of data.
- // The changes are not persistent. They get lost when the
- // .so is unloaded.
- function WriteModuleData(Module: TModuleHandle; SymbolName: AnsiString; var Buffer; Size: Cardinal): Boolean;
- var
- Sym: Pointer;
- begin
- Result := True;
- Sym := GetModuleSymbolEx(Module, SymbolName, Result);
- if Result then
- Move(Buffer, Sym^, Size);
- end;
- {$ENDIF UNIX}
- //=== { TModuleLoader } ======================================================
- constructor TModuleLoader.Create(const ADLLName: AnsiString; LoadMethods: TModuleLoadMethods = []);
- begin
- inherited Create;
- FHandle := INVALID_MODULEHANDLE_VALUE;
- FDLLName := ADLLName;
- Load(LoadMethods);
- end;
- destructor TModuleLoader.Destroy;
- begin
- Unload;
- inherited Destroy;
- end;
- procedure TModuleLoader.Error(ErrorCode: Cardinal);
- begin
- // overridden classes should handle this
- end;
- function TModuleLoader.GetExportedSymbol(const AName: AnsiString; var Buffer;
- Size: Integer): Boolean;
- var
- ASymbol: Pointer;
- begin
- Result := GetProcedure(AName, ASymbol);
- if Result then
- Move(ASymbol^, Buffer, Size);
- end;
- function TModuleLoader.GetLoaded: Boolean;
- begin
- Result := Handle <> INVALID_MODULEHANDLE_VALUE;
- end;
- function TModuleLoader.GetProcedure(const AName: AnsiString; var AProc: Pointer): Boolean;
- begin
- Result := Loaded;
- if Result and not Assigned(AProc) then
- begin
- AProc := GetModuleSymbol(Handle, AName);
- Result := Assigned(AProc);
- end;
- if not Result then
- begin
- AProc := nil;
- Error(DWORD(TYPE_E_ELEMENTNOTFOUND));
- end;
- end;
- class function TModuleLoader.IsAvaliable(const ADLLName: AnsiString; const AProcName: AnsiString = ''): Boolean;
- var
- Module: TModuleHandle;
- P: Pointer;
- begin
- {$IFNDEF JWA_INCLUDEMODE}
- Result := LoadModule(Module, ADLLName);
- {$ELSE}
- Result := ModuleLoader_LoadModule(Module, ADLLName);
- {$ENDIF JWA_INCLUDEMODE}
- if Result then
- begin
- if AProcName <> '' then
- begin
- P := GetModuleSymbol(Module, AProcName);
- Result := Assigned(P);
- end;
- UnloadModule(Module);
- end;
- end;
- procedure TModuleLoader.Load(LoadMethods: TModuleLoadMethods);
- const
- cLoadMethods: array [TModuleLoadMethod] of DWORD =
- {$IFDEF MSWINDOWS}
- (DONT_RESOLVE_DLL_REFERENCES, LOAD_LIBRARY_AS_DATAFILE, LOAD_WITH_ALTERED_SEARCH_PATH);
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- (RTLD_LAZY, RTLD_LAZY, RTLD_LAZY); // there is not really a equivalent under Linux
- {$ENDIF UNIX}
- var
- Flags: DWORD;
- I: TModuleLoadMethod;
- begin
- Flags := 0;
- for I := Low(TModuleLoadMethod) to High(TModuleLoadMethod) do
- if I in LoadMethods then
- Flags := Flags or cLoadMethods[I];
- if FHandle = INVALID_MODULEHANDLE_VALUE then
- LoadModuleEx(FHandle, DLLName, Flags);
- if FHandle = INVALID_MODULEHANDLE_VALUE then
- Error(GetLastError);
- end;
- function TModuleLoader.SetExportedSymbol(const AName: AnsiString; var Buffer;
- Size: Integer): Boolean;
- var
- ASymbol: Pointer;
- begin
- Result := GetProcedure(AName, ASymbol);
- if Result then
- Move(Buffer, ASymbol^, Size);
- end;
- procedure TModuleLoader.Unload;
- begin
- if FHandle <> INVALID_MODULEHANDLE_VALUE then
- UnloadModule(FHandle);
- FHandle := INVALID_MODULEHANDLE_VALUE;
- end;
- {$ENDIF JWA_INTERFACESECTION}
- {$IFNDEF JWA_OMIT_SECTIONS}
- end.
- {$ENDIF JWA_OMIT_SECTIONS}
|