unit Modules;

interface

{$WARN SYMBOL_PLATFORM OFF}

uses
  Windows, Classes, SysUtils, Forms, pTBXVersionInfo;

Const
  MaxCount = 32;

type


  TArrayValues = array [0..MaxCount - 1] of double;
  TArrayStates = array [0..MaxCount - 1] of boolean;
  TArrayGains  = array [0..MaxCount - 1] of integer;

  TModule = class
    Handle       : HMODULE;
    VersionInfo  : TVersionInfo;
    Name         : string;
    Size         : integer;
    Init         : procedure(Handle: HWND; Path : PChar); stdcall;
    Final        : procedure; stdcall;
    About        : procedure; stdcall;
    ShowSettings : procedure; stdcall;
    DiveceList   : procedure (var Text: PChar); stdcall;
    ConnectTo    : function (const Inf: PChar):BOOL; stdcall;
    Disconnect   : procedure export; stdcall;
    Connected    : function (const Inf: PChar):BOOL; stdcall;
//    GetValues    : procedure(var Arr:array of integer); stdcall;
    GetCount     : function:UCHAR; stdcall;
    GetValues    : procedure(var ArrayValues: TArrayValues;var ArrayStates: TArrayStates; var ArrayGains: TArrayGains); stdcall;
    Start        : procedure export; stdcall;
    Stop         : procedure export; stdcall;
  end;


  TModuleList = class
  private
    FList: TList;
    function GetCount: Integer;
    function GetItems(Index: Integer): TModule;
    procedure Search(APath : string; SubFolders : boolean);

  public
    ActiveModule : TModule;
    constructor Create(APath : string); virtual;
    destructor Destroy; override;
    procedure Clear;
    function Add: TModule;
    procedure Delete(AModule: TModule);overload;
    procedure Delete(Index: integer);overload;
    procedure MoveRow(FromPos, ToPos: Integer);
    property Count: Integer read GetCount;
    property Items[Index: Integer]: TModule read GetItems; default;
  end;


var
  ModuleList: TModuleList;

implementation

{
function GetFileVersion(FileName: string): String;
var
  hHandle, Size : LongWord;
  Buffer : PChar;
  P : pointer;
begin
  Size := GetFileVersionInfoSize(PChar(FileName), hHandle);
  GetMem(Buffer, Size);
  try
    if GetFileVersionInfo(PChar(FileName), hHandle, Size, Buffer) then
    begin
      VerQueryValue(Buffer, '\VarFileInfo\Translation', P, Size);
      if (p <> nil) and
          (VerQueryValue(Buffer,
           PChar('\StringFileInfo\' + IntToHex(MakeLong(HiWord(Longint(P^)), LoWord(Longint(P^))), 8) + '\FileVersion'),
           P,
           Size)) then
                      Result := StrPas(PChar(P));

    end;
  finally
    FreeMem(Buffer);
  end;
end;
}
constructor TModuleList.Create(APath : string);
begin
  inherited Create;
  FList := TList.Create;
  ActiveModule := nil;
  Search(APath, true);
end;

destructor TModuleList.Destroy;
begin
  Clear;
  FList.Free;
  inherited Destroy;
end;


procedure TModuleList.Search(APath : string; SubFolders : boolean);
var
  SearchRec  : TSearchRec;
  Module     : TModule;
begin
  APath := IncludeTrailingBackslash(APath);

  if FindFirst(APath + '*.*', faAnyFile, SearchRec) = 0 then
  begin
    repeat
      Application.ProcessMessages;
      if Application.Terminated then exit;

      if (SearchRec.Attr and faDirectory) = faDirectory then
      begin
        if SubFolders and (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
            Search(APath + SearchRec.Name, SubFolders);
      end
      else
      begin
        if AnsiSameText(ExtractFileExt(SearchRec.Name), '.dlp') then
          begin
//          hn:= LoadLibrary(PChar(APath + SearchRec.Name));
//          hn:= LoadLibrary(PChar('E:\Programming\Delphi\!Spetspribor\ADCS14-8D\DataLogger\Plugins\lib2\Lib2.dll'));
//          FreeLibrary(hn);
          Module := Add();
          Module.Handle:= LoadLibrary(PChar(APath + SearchRec.Name));

          if Module.Handle > HINSTANCE_ERROR then
          begin
            @Module.Init :=  GetProcAddress(Module.Handle, 'Init');
//            @Module.GetVersion :=  GetProcAddress(Module.Handle, 'GetVersion');
            if Assigned(@Module.Init) then
            begin
              Module.Name        := SearchRec.Name;
              Module.Size        := SearchRec.Size;
              Module.VersionInfo := TVersionInfo.Create(APath + SearchRec.Name);

              @Module.ShowSettings := GetProcAddress(Module.Handle, 'ShowSettings');
              @Module.Final        := GetProcAddress(Module.Handle, 'Final');
              @Module.About        := GetProcAddress(Module.Handle, 'About');
              @Module.DiveceList   := GetProcAddress(Module.Handle, 'DiveceList');
              @Module.ConnectTo    := GetProcAddress(Module.Handle, 'ConnectTo');
              @Module.Connected    := GetProcAddress(Module.Handle, 'Connected');
              @Module.GetCount     := GetProcAddress(Module.Handle, 'GetCount');
              @Module.GetValues    := GetProcAddress(Module.Handle, 'GetValues');
              @Module.Disconnect   := GetProcAddress(Module.Handle, 'Disconnect');
              @Module.Start        := GetProcAddress(Module.Handle, 'Start');
              @Module.Stop         := GetProcAddress(Module.Handle, 'Stop');
              Module.Init(Application.Handle, PChar(APath));
              Continue;
            end

          end;
          Delete(Module);

        end;
      end;

    until FindNext(SearchRec) <> 0;
    FindClose(SearchRec);
  end;

end;

function TModuleList.GetItems(Index: Integer): TModule;
begin
  Result := TModule(FList[Index]);
end;

function TModuleList.GetCount: Integer;
begin
  Result := FList.Count;
end;

function TModuleList.Add(): TModule;
begin
  Result := TModule.Create;
  Result.Handle := 0;

  FList.Add(Result);
end;


procedure TModuleList.Clear;
begin
  while FList.Count > 0 do
      Delete(FList.Count - 1);
end;

procedure TModuleList.Delete(AModule: TModule);
begin
  Delete(FList.IndexOf(AModule));
end;

procedure TModuleList.Delete(Index: integer);
var
  Module : TModule;
begin
  Module := TModule(FList[Index]);

  if Assigned(Module.VersionInfo) then
      FreeAndNil(Module.VersionInfo);

  if Module.Handle > HINSTANCE_ERROR then
  begin
    if Assigned(@Module.Final) then
        Module.Final;
    FreeLibrary(Module.Handle);
    Module.Handle := 0;
  end;

  FreeAndNil(Module);

  FList.Delete(Index);
end;

procedure TModuleList.MoveRow(FromPos, ToPos: Integer);
begin
  FList.Move(FromPos, ToPos);
end;

initialization
  ModuleList := TModuleList.Create(ExtractFilePath(Application.ExeName) + 'Plugins\');

finalization
  if Assigned(ModuleList) then
      ModuleList.Free;

end.
