{ $Id: PDOPlainLoader.pas 23 2007-01-19 22:06:28Z jmarino $

############################################################################################

	Pascal Data Objects Library
	Copyright © 2006 John Marino, http://www.synsport.com
	Project site: http://pdo.sourceforge.net

	Note: This file contains code fragments from Zeoslib
	Copyright © 1999-2004 Sergey Seroukhov

############################################################################################

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library 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.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

############################################################################################}


unit PDOPlainLoader;

interface

{$I directives.inc}

uses Types
{$IFDEF UNIX}
,PDOCompatibility
{$ENDIF UNIX}
;

type
  {** Implements a loader for native library. }
  TZNativeLibraryLoader = class (TObject)
  private
    FLocations: TStringDynArray;
    FHandle: LongWord;
    FLoaded: Boolean;
  protected
    function LoadNativeLibrary: Boolean; virtual;
    procedure FreeNativeLibrary; virtual;
    function GetAddress(ProcName: PChar): Pointer;
  public
    constructor Create(Locations: array of string);
    destructor Destroy; override;

    function Load: Boolean; virtual;
    procedure LoadIfNeeded; virtual;

//    property Locations: TStringDynArray read FLocations write FLocations;
    property Handle: LongWord read FHandle write FHandle;
    property Loaded: Boolean read FLoaded write FLoaded;
  end;

implementation

uses
{$IFNDEF UNIX}
  Windows,
{$ELSE}
 { libc,}
{$ENDIF}
  PDOMessages, SysUtils;

{ TZNativeLibraryLoader }

{**
  Creates this loader class and assignes main properties.
  @param Locations locations of native library on windows platform.
}
constructor TZNativeLibraryLoader.Create(Locations: array of string);
var
  I: Integer;
begin
  SetLength(FLocations, Length(Locations));
  for I := 0 to High(Locations) do
    FLocations[I] := Locations[I]; 
  FHandle := 0;
  FLoaded := False;
end;

{**
  Destroys the library and cleanups the memory.
}
destructor TZNativeLibraryLoader.Destroy;
begin
  if Loaded then
    FreeNativeLibrary;
  inherited Destroy;
end;

{**
  Loads a library module.
  @return <code>True</code> if library was successfully loaded.
}
function TZNativeLibraryLoader.Load: Boolean;
begin
  Result := LoadNativeLibrary;
end;

{**
  Loads a library if it was not previously loaded.
}
procedure TZNativeLibraryLoader.LoadIfNeeded;
begin
  if not Loaded then
    Load;
end;

{**
  Loads a library module and initializes the handle.
  @return <code>True</code> is library was successfully loaded.
}
function TZNativeLibraryLoader.LoadNativeLibrary: Boolean;
var
  I: Integer;
  Location: Ansistring;
  TriedLocations: Ansistring;
begin
  Loaded := False;
  Location := '';
  TriedLocations := '';
  if Handle = 0 then
  begin
    for I := 0 to High(FLocations) do
    begin
      Location := FLocations[I];
      Handle := GetModuleHandle(PChar(Location));
      if Handle = 0 then
      begin
{$IFDEF UNIX}
  {$IFDEF FPC}
        Handle := LoadLibrary(PChar(Location));
  {$ELSE}
        Handle := HMODULE(dlopen(PChar(Location), RTLD_GLOBAL));
  {$ENDIF}
{$ELSE}
        Handle := LoadLibrary(PChar(Location));
{$ENDIF}
      end;
      if Handle <> 0 then
      begin
        Loaded := True;
        Break;
      end;
      if TriedLocations <> '' then
        TriedLocations := TriedLocations + ', ';
      TriedLocations := TriedLocations + Location;
    end;
  end;

  if not Loaded then
    raise Exception.Create(Format(SLibraryNotFound, [TriedLocations]));
  Result := True;
end;

{**
  Frees a previously loaded library.
}
procedure TZNativeLibraryLoader.FreeNativeLibrary;
begin
  if (Handle <> 0) and Loaded then
    FreeLibrary(Handle);
  Handle := 0;
  Loaded := False;
end;

{**
  Gets a procedure address from the loaded library by its name.
  @param ProcName a name of the procedure.
  @return a procedure address.
}
function TZNativeLibraryLoader.GetAddress(ProcName: PChar): Pointer;
begin
  Result := GetProcAddress(Handle, ProcName);
end;

end.


