unit Mod_SysInfo;

interface

uses
  Windows, Classes, ComCtrls, Mod_Common, SysUtils, WinSock, xBase;

type
  PInstAppItem = ^TInstAppItem;
  TInstAppItem = record
    AppName: String;
    AppVersion: String;
  end;

  PDriveItem = ^TDriveItem;
  TDriveItem = record
    Drive: Char;
    DriveType: LongWord;
    TotalSpace: Int64;
    FreeSpace: Int64;
  end;

  TModuleSysInfo = class(TModule)
  private
    procedure FreeInstAppsList;
    procedure FreeDriveList;
    procedure GetCPUName;
    procedure GetOsName;
    function GetIP: LongWord;
  protected
    class function GetModuleName: String; override;
    class function GetModuleVersion: Integer; override;
    class function GetModuleID: Integer; override;
    function GetIsEmpty: Boolean; override;
  public
    InstAppsList: TList;
    IPList: TList;
    DriveList: TList;
    ProcList: TStringList;

    Memory: MEMORYSTATUS;
    OsVersion: OSVERSIONINFO;
    UserName: String;
    ComputerName: String;
    Host: String;
    Country: String;
    Language: String;

    CPUSpeed: LongWord;
    CPUVendor: String;
    CPUInfo: LongWord;
    CPUName: String;

    OsName: String;

    FolderWindows: String;
    FolderSystem: String;
    FolderTemp: String;
    FolderCurrent: String;
    FolderStartup: String;

    DesktopWidth: LongWord;
    DesktopHeight: LongWord;
    DesktopBits: LongWord;

    UID: LongWord;
    RepTime: TDateTime;

    procedure Run; override;
    destructor Destroy; override;

    function GetAsText: String; override;
    procedure GetAsTree; override;
    property IP: LongWord read GetIP;

    procedure ExportModule(DBStream: TMemoryStream); override;
    procedure ImportModule(DBStream: TMemoryStream); override;
  end;


implementation

const
  TYPE_SYSINFO_INST	  = 0;
  TYPE_SYSINFO_INSTVER	  = 1;
  TYPE_SYSINFO_MEM	  = 2;
  TYPE_SYSINFO_NAME	  = 3;
  TYPE_SYSINFO_DRIVE	  = 4;
  TYPE_SYSINFO_OS	  = 5;
  TYPE_SYSINFO_CPU	  = 6;
  TYPE_SYSINFO_HOST	  = 7;
  TYPE_SYSINFO_IP	  = 8;
  TYPE_SYSINFO_CNTRY	  = 9;
  TYPE_SYSINFO_LANG	  = 10;
  TYPE_SYSINFO_PROC	  = 11;
  TYPE_SYSINFO_FOLDER	  = 12;
  TYPE_SYSINFP_D_WIDTH	  = 13;
  TYPE_SYSINFP_D_HEIGHT	  = 14;
  TYPE_SYSINFP_D_RES	  = 15;
  TYPE_SYSINFO_DRIVE_EX   = 16;
  TYPE_SYSINFO_UID        = 17;
  TYPE_SYSINFO_TIME       = 18;

  // UserName & CompName
  SUBTYPE_SYSINFO_USER	  = 0;
  SUBTYPE_SYSINFO_COMP	  = 1;

  // CPU
  SUBTYPE_SYSINFO_CSPEED  = 0;
  SUBTYPE_SYSINFO_CVENDOR = 1;
  SUBTYPE_SYSINFO_CINFO	  = 2;

  // Folders
  SUBTYPE_SYSINFO_WINDOWS = 0;
  SUBTYPE_SYSINFO_SYSTEM  = 1;
  SUBTYPE_SYSINFO_CURRENT = 2;
  SUBTYPE_SYSINFO_TEMP    = 3;
  SUBTYPE_SYSINFO_STARTUP = 4;

{ TModuleSysInfo }

destructor TModuleSysInfo.Destroy;
begin
  FreeInstAppsList;
  if IPList <> nil then IPList.Free;
  FreeDriveList;
  if ProcList <> nil then ProcList.Free;
  inherited;
end;

procedure TModuleSysInfo.FreeInstAppsList;
var
  i: Integer;
begin
  if InstAppsList = nil then Exit;
  for i := 0 to InstAppsList.Count-1 do begin
    PInstAppItem(InstAppsList.Items[i]).AppName := '';
    PInstAppItem(InstAppsList.Items[i]).AppVersion := '';
    Dispose(InstAppsList.Items[i]);
  end;
  InstAppsList.Free;
end;

procedure TModuleSysInfo.FreeDriveList;
var
  i: Integer;
begin
  if DriveList = nil then Exit;
  for i := 0 to DriveList.Count-1 do
    Dispose(DriveList.Items[i]);
  DriveList.Free;
end;

procedure TModuleSysInfo.Run;
var
  DataItem: TDataItem;
  P: Pointer;
  i: Integer;

begin
  inherited;

  InstAppsList := TList.Create;
  IPList := TList.Create;
  DriveList := TList.Create;
  ProcList := TStringList.Create;

  while HasMoreData do begin
    DataItem := ReadData;
    case DataItem.cType of
      // Installed apps
      TYPE_SYSINFO_INST: begin
        P := New(PInstAppItem);
          i := Pos(' (remove only)', DataItem.Data);
          if i > 0 then
            Delete(DataItem.Data, i, 14);
        PInstAppItem(P).AppName := DataItem.Data;
        if HasMoreData and (ReadNextDataType.cType = TYPE_SYSINFO_INSTVER) then begin
          DataItem := ReadData;
          PInstAppItem(P).AppVersion := DataItem.Data;
        end;
        InstAppsList.Add(P);
      end;
      // System memory
      TYPE_SYSINFO_MEM:
        Move(DataItem.Data[1], Memory.dwMemoryLoad, 7*4);
      // OS
      TYPE_SYSINFO_OS:
        Move(DataItem.Data[1], OsVersion.dwMajorVersion, 4*4+128);
      // UserName/ComputerName
      TYPE_SYSINFO_NAME:
        case DataItem.cSubtype of
          SUBTYPE_SYSINFO_USER:
            UserName := DataItem.Data;
          SUBTYPE_SYSINFO_COMP:
            ComputerName := DataItem.Data;
        else begin
            FError := ERR_UNK_ITEM;
            Exit;
          end;
        end;
      // Drives
      TYPE_SYSINFO_DRIVE: begin
        P := New(PDriveItem);

        PDriveItem(P).Drive := Chr(DataItem.cSubtype);
        PDriveItem(P).DriveType := PLongWord(@DataItem.Data[1])^;
        PDriveItem(P).FreeSpace := Int64(PLongWord(@DataItem.Data[1+4])^) * PLongWord(@DataItem.Data[1+8])^ * PLongWord(@DataItem.Data[1+12])^;
        PDriveItem(P).TotalSpace := Int64(PLongWord(@DataItem.Data[1+4])^) * PLongWord(@DataItem.Data[1+8])^ * PLongWord(@DataItem.Data[1+16])^;

        DriveList.Add(P);
      end;
      TYPE_SYSINFO_DRIVE_EX: begin
        P := New(PDriveItem);

        PDriveItem(P).Drive := Chr(DataItem.cSubtype);
        PDriveItem(P).DriveType := PLongWord(@DataItem.Data[1])^;
        PDriveItem(P).FreeSpace := PInt64(@DataItem.Data[1+4])^;
        PDriveItem(P).TotalSpace := PInt64(@DataItem.Data[1+12])^;

        DriveList.Add(P);
      end;
      // CPU
      TYPE_SYSINFO_CPU:
        case DataItem.cSubtype of
          SUBTYPE_SYSINFO_CSPEED:
            CPUSpeed := PLongWord(@DataItem.Data[1])^;
          SUBTYPE_SYSINFO_CVENDOR:
            CPUVendor := DataItem.Data;
          SUBTYPE_SYSINFO_CINFO:
            CPUInfo := PLongWord(@DataItem.Data[1])^;
        else begin
            FError := ERR_UNK_ITEM;
            Exit;
          end;
        end;
      // Hostname
      TYPE_SYSINFO_HOST:
        Host := DataItem.Data;
      // IPs
      TYPE_SYSINFO_IP:
        if PInteger(@DataItem.Data[1])^ <> inet_addr('127.0.0.1') then
          IPList.Add(Pointer(PLongWord(@DataItem.Data[1])^));
      // Country
      TYPE_SYSINFO_CNTRY:
        Country := DataItem.Data;
      // Language
      TYPE_SYSINFO_LANG:
        Language := DataItem.Data;
      // Process list
      TYPE_SYSINFO_PROC:
        ProcList.Add(DataItem.Data);
      // Folders
      TYPE_SYSINFO_FOLDER:
        case DataItem.cSubtype of
          SUBTYPE_SYSINFO_WINDOWS: FolderWindows := DataItem.Data;
          SUBTYPE_SYSINFO_SYSTEM: FolderSystem := DataItem.Data;
          SUBTYPE_SYSINFO_CURRENT: FolderCurrent := DataItem.Data;
          SUBTYPE_SYSINFO_TEMP: FolderTemp := DataItem.Data;
          SUBTYPE_SYSINFO_STARTUP: FolderStartup := DataItem.Data;
        else begin
            FError := ERR_UNK_ITEM;
            Exit;
          end;
        end;
      // Desktop size & resolution
      TYPE_SYSINFP_D_WIDTH: DesktopWidth := PLongWord(@DataItem.Data[1])^;
      TYPE_SYSINFP_D_HEIGHT: DesktopHeight := PLongWord(@DataItem.Data[1])^;
      TYPE_SYSINFP_D_RES: DesktopBits := PLongWord(@DataItem.Data[1])^;
      // UID
      TYPE_SYSINFO_UID: UID := PLongWord(@DataItem.Data[1])^;
      // Report time
      TYPE_SYSINFO_TIME: RepTime := SystemTimeToDateTime(PSystemTime(@DataItem.Data[1])^);
    else begin
        FError := ERR_UNK_ITEM;
        Exit;
      end;
    end;
  end;
  GetCPUName;
  GetOSName;

  if ProcList.Count > 1 then
    ProcList.Delete(0);
end;

procedure TModuleSysInfo.GetCPUName;
var
  Info: LongWord;
  Model: Byte;
  Family: Byte;
  ExtFamily: Byte;
begin
  Info := CPUInfo;
  {Stepping := Info and $f; }Info := Info shr 4;
  Model := Info and $f; Info := Info shr 4;
  Family := Info and $f; Info := Info shr 4;
  {ProcType := Info and $3; }Info := Info shr 2;
  {ExtModel := Info and $f; }Info := Info shr 4;
  ExtFamily := Info and $ff;

  if CPUVendor = 'AuthenticAMD' then
    case Family of
      4: case Model of
           3:                   CPUName := '486 DX/2';
           7:                   CPUName := '486 DX/2-WB';
           8:                   CPUName := '486 DX/4';
           9:                   CPUName := '486 DX/4-WB';
  	   14:                  CPUName := 'Am5x86-WT';
 	   15:                  CPUName := 'Am5x86-WB';
         end;
      5: case Model of
           0:                   CPUName := 'K5/SSA5';
  	   1, 2, 3:             CPUName := 'K5';
  	   6,7:                 CPUName := 'K6';
 	   8:                   CPUName := 'K6-2';
 	   9:                   CPUName := 'K6-3';
 	   13:                  CPUName := 'K6-2+ or K6-III+';
         end;
      6: case Model of
           0, 1:	        CPUName := 'Athlon (25 µm)';
 	   2:	                CPUName := 'Athlon (18 µm)';
 	   3:	                CPUName := 'Duron';
 	   4:	                CPUName := 'Athlon (Thunderbird)';
 	   6:	                CPUName := 'Athlon (Palamino)';
 	   7:	                CPUName := 'Duron (Morgan)';
 	   8:	                CPUName := 'Athlon (Thoroughbred)';
 	   10:	                CPUName := 'Athlon (Barton)';
         end;
      15: if ExtFamily = 0 then
         case Model of
           4:                   CPUName := 'Athlon 64';
           5:                   CPUName := 'Athlon 64 FX, Opteron';
         end;
    end
  else if CPUVendor = 'GenuineIntel' then
    case Family of
      4: case Model of
           0:                   CPUName := '486 DX-25/33';
 	   1:                   CPUName := '486 DX-50';
 	   2:                   CPUName := '486 SX';
           3:                   CPUName := '486 DX/2';
 	   4:                   CPUName := '486 SL';
 	   5:                   CPUName := '486 SX/2';
 	   7:                   CPUName := '486 DX/2-WB';
 	   8:                   CPUName := '486 DX/4';
 	   9:                   CPUName := '486 DX/4-WB';
        end;
      5: case Model of
      	   0:                   CPUName := 'Pentium 60/66 A-step';
 	   1:                   CPUName := 'Pentium 60/66';
 	   2:                   CPUName := 'Pentium 75 - 200';
 	   3:                   CPUName := 'OverDrive PODP5V83';
 	   4:                   CPUName := 'Pentium MMX';
 	   7:                   CPUName := 'Mobile Pentium 75 - 200';
 	   8:                   CPUName := 'Mobile Pentium MMX';
        end;
      6: case Model of
      	   0:                   CPUName := 'Pentium Pro A-step';
 	   1:                   CPUName := 'Pentium Pro';
 	   3:                   CPUName := 'Pentium II (Klamath)';
 	   5:                   CPUName := 'Pentium II (Deschutes), Celeron (Covington), Mobile Pentium II (Dixon)';
 	   6:                   CPUName := 'Mobile Pentium II, Celeron (Mendocino)';
 	   7:                   CPUName := 'Pentium III (Katmai)';
 	   8:                   CPUName := 'Pentium III (Coppermine)';
 	   9:                   CPUName := 'Mobile Pentium III';
 	   10:                  CPUName := 'Pentium III (0.18 µm)';
 	   11:                  CPUName := 'Pentium III (0.13 µm)';
        end;
      7:                        CPUName := 'Itanium (IA-64)';
      15: case ExtFamily of
            0: case Model of
                 0, 1:          CPUName := 'Pentium IV (0.18 µm)';
                 2:             CPUName := 'Pentium IV (0.13 µm)';
                 3:             CPUName := 'Pentium IV (0.09 µm)';
               end;
            1:                  CPUName := 'Itanium 2 (IA-64)';
          end;
    end
  else if CPUVendor = 'CyrixInstead' then
    case Family of
      4: case Model of
      	   4:                   CPUName := 'MediaGX';
         end;
      5: case Model of
           2:                   CPUName := '6x86 / 6x86L (Identifying the difference)';
           4:                   CPUName := 'MediaGX MMX Enhanced';
         end;
      6: case Model of
           0:                   CPUName := 'm II (6x86MX)';
 	   5:                   CPUName := 'VIA Cyrix M2 core';
 	   6:                   CPUName := 'WinChip C5A';
 	   7:                   CPUName := 'WinChip C5B ,WinChip C5C';
 	   8:                   CPUName := 'WinChip C5N';
 	   9:                   CPUName := 'WinChip C5XL, WinChip C5P';
         end;
    end
  else if CPUVendor = 'GenuineTMx86' then begin
    if (Family = 5) and (Model = 4) then
      CPUName := 'Transmeta Crusoe TM3x00/TM5x00'
    else
      CPUName := 'Transmeta Unknown';
  end else if CPUVendor = 'CentaurHauls' then begin
    if Family = 5 then
      case Model of
        4: CPUName := 'C6';
        8: CPUName := 'C2';
        9: CPUName := 'C3';
      else
        CPUName := 'Centaur Unknown';
      end
    else
      CPUName := 'Centaur Unknown';    
  end else if CPUVendor = 'RiseRiseRise' then begin
    if (Family = 5) and (Model in [0, 1]) then
      CPUName := 'Rise mP6'
    else
      CPUName := 'Rise Unknown';
  end;

  if CPUName = '' then CPUName := 'Unknown';
end;

function TModuleSysInfo.GetAsText: String;
var
  i: Integer;
  inaddr: in_addr;
begin
  Result := 'UserName: ' + Self.UserName + #13#10;
  Result := Result + 'ComputerName: ' + Self.ComputerName + #13#10;
  Result := Result + 'Host: ' + Self.Host + #13#10;
  Result := Result + 'UID: ' + IntToHex(Self.UID, 8) + #13#10;  
  Result := Result + 'Country: ' + Self.Country + #13#10;
  Result := Result + 'Language: ' + Self.Language + #13#10;
  Result := Result + 'Desktop resolution: ' + IntToStr(DesktopWidth) + 'x' + IntToStr(DesktopHeight) + 'x' + IntToStr(DesktopBits) + #13#10;
  Result := Result + 'Time: ' + DateTimeToStr(RepTime) + #13#10#13#10;

  Result := Result + 'OS: ' + Self.OsName + #13#10;
  Result := Result + 'Memory: ' + IntToStr(Self.Memory.dwTotalPhys div (1024*1024) + 1) + ' MB'#13#10;
  Result := Result + 'CPU: ' + Self.CPUName + ' ' + IntToStr(Self.CPUSpeed) + ' Mhz'#13#10;
  Result := Result + 'CPU Vendor: ' + Self.CPUVendor + #13#10#13#10;

  for i := 0 to IPList.Count-1 do begin
    inaddr.S_addr := LongWord(IPList.Items[i]);
    Result := Result + 'IP' + IntToStr(i) + ': ' + inet_ntoa(inaddr) + #13#10;
  end;
  Result := Result + #13#10;

  Result := Result + 'Windows folder: ' + FolderWindows + #13#10 +
    'System folder: ' + FolderSystem + #13#10 +
    'Temp folder: ' + FolderTemp + #13#10 +
    'Current folder: ' + FolderCurrent + #13#10 +
    'Autorun folder: ' + FolderStartup + #13#10#13#10;

  for i := 0 to DriveList.Count-1 do begin
    Result := Result + 'Drive ' + PDriveItem(DriveList.Items[i]).Drive + ' (';
    case PDriveItem(DriveList.Items[i]).DriveType of
      DRIVE_REMOVABLE: Result := Result + 'Removable)';
      DRIVE_FIXED: Result := Result + 'Fixed): Total ' + IntToStr(PDriveItem(DriveList.Items[i]).TotalSpace div (1024*1024)) + ' MB, Free ' +
        IntToStr(PDriveItem(DriveList.Items[i]).FreeSpace div (1024*1024)) + ' MB';
      DRIVE_REMOTE: Result := Result + 'Remote)';
      DRIVE_CDROM: Result := Result + 'CDROM)';
      DRIVE_RAMDISK: Result := Result + 'Ramdisk)';
    else
      Result := Result + 'Unknown)';
    end;
    Result := Result + #13#10;
  end;
  Result := Result + #13#10;

  Result := Result + 'Process list:'#13#10;
  for i := 0 to ProcList.Count-1 do
    Result := Result + ProcList.Strings[i] + #13#10;

  Result := Result + #13#10;

  Result := Result + 'Installed apps:'#13#10;
  for i := 0 to InstAppsList.Count-1 do begin
    Result := Result + PInstAppItem(InstAppsList.Items[i]).AppName;

    if PInstAppItem(InstAppsList.Items[i]).AppVersion <> '' then
      Result := Result + ' (Version: ' + PInstAppItem(InstAppsList.Items[i]).AppVersion + ')';

    Result := Result + #13#10;
  end;
end;

procedure TModuleSysInfo.GetOSName;
begin
  OsName := 'Windows';
  case OsVersion.dwMajorVersion of
    3: if OsVersion.dwMinorVersion = 51 then OsName := OsName + ' NT 3.51';
    4: case OsVersion.dwMinorVersion of
         0: if OsVersion.dwPlatformId = VER_PLATFORM_WIN32_NT then
              OsName := OsName + ' NT 4.0'
            else begin
              OsName := OsName + ' 95';
              if (OsVersion.szCSDVersion[1] = 'C') or (OsVersion.szCSDVersion[1] = 'B') then
                OsName := OsName + ' OSR2';
            end;
         10: begin
           OsName := OsName + ' 98';
           if OsVersion.szCSDVersion[1] = 'A' then
             OsName := OsName + ' SE';
         end;
         90: OsName := OsName + ' Me';
       end;
    5: case OsVersion.dwMinorVersion of
         0: OsName := OsName + ' 2000';
         1: OsName := OsName + ' XP';
         2: OsName := OsName + ' .NET Server 2003 family';
       end;
  end;

  if OsVersion.dwPlatformId = VER_PLATFORM_WIN32_NT then
    OsName := OsName + ' ' + PChar(@OsVersion.szCSDVersion[0]) + ' (Build ' + IntToStr(OsVersion.dwBuildNumber and $FFFF) + ')';
end;

procedure TModuleSysInfo.GetAsTree;
var
  i, icon: Integer;
  inaddr: in_addr;
  S: String;
begin
  inherited;

  Append(ModuleName, 'Этот модуль содержит информацию о системе', ICON_FOLDER);
  MoveIn;
  Expand;
  Append('Пользователь', GenHTMLList(['Имя пользователя: ' + UserName, 'Имя компьютера: ' + ComputerName, 'Хост: ' + Host, 'UID: ' + IntToHex(UID, 8), 'Страна: ' + Country, 'Язык: ' + Language, 'Разрешение экрана: ' + IntToStr(DesktopWidth) + 'x' + IntToStr(DesktopHeight) + 'x' + IntToStr(DesktopBits), 'Время: ' + DateTimeToStr(RepTime)]), ICON_USER);
  Append('Процессор', GenHTMLList(['Процессор: ' + CPUName + ' ' + IntToStr(Self.CPUSpeed) + ' Mhz', 'Произоводитель: ' + CPUVendor]), ICON_CPU);
  Append('OS', GenHTMLList(['OS: ' + OSName]), ICON_OS);
  Append('Память', GenHTMLList(['Всего: ' + IntToStr(Memory.dwTotalPhys div (1024*1024) + 1) + ' MB', 'Свободно: ' + IntToStr(Memory.dwAvailPhys div (1024*1024)) + ' MB', 'Загружено: ' + IntToStr(Memory.dwMemoryLoad) + '%', 'Размер файла подкачки: ' + IntToStr(Memory.dwTotalPageFile div (1024*1024)) + ' MB', 'Количество виртуальной памяти: ' + IntToStr(Memory.dwTotalVirtual div (1024*1024)) + ' MB']), ICON_MEMORY);

  S := '<ul>';
  for i := 0 to IPList.Count-1 do begin
    inaddr.S_addr := LongWord(IPList.Items[i]);
    S := S + '<li>IP<sub>' + IntToStr(i) + '</sub>: ' + inet_ntoa(inaddr) + #13#10;
  end;
  S := S + '</ul>';
  Append('IP адреса', S, ICON_IP);

  Append('Диски', '', ICON_FOLDER);
  MoveIn;
  for i := 0 to DriveList.Count-1 do begin
    S := '<ul><li>Тип: ';
    icon := ICON_DISK;
    case PDriveItem(DriveList.Items[i]).DriveType of
      DRIVE_REMOVABLE: begin S := S + 'съемный'; icon := ICON_REMDISK; end;
      DRIVE_FIXED: S := S + 'физический' + '<li>Всего: ' + IntToStr(PDriveItem(DriveList.Items[i]).TotalSpace div (1024*1024)) + ' MB<li>Свободно: ' +
        IntToStr(PDriveItem(DriveList.Items[i]).FreeSpace div (1024*1024)) + ' MB';
      DRIVE_REMOTE: begin S := S + 'удаленный'; icon := ICON_NETDISK; end;
      DRIVE_CDROM: begin S := S + 'CDROM'; icon := ICON_CDROM; end;
      DRIVE_RAMDISK: S := S + 'ramdisk';
    else
      S := 'Невозможно определить';
    end;
    S := S + '</ul>';
    Append('Диск ' + PDriveItem(DriveList.Items[i]).Drive, S, icon);
  end;
  MoveOut;

  Append('Папки', GenHTMLList(['Windows: ' + FolderWindows, 'Системная: ' + FolderSystem, 'Временная: ' + FolderTemp, 'Текущая: ' + FolderCurrent, 'Автозапуска: ' + FolderStartup]), ICON_FOLDERS);

  S := '<ul>';
  for i := 0 to ProcList.Count-1 do
    S := S + '<li>' + HTMLSafe(ProcList.Strings[i]);
  S := S + '</ul>';
  Append('Список процессов', S, ICON_TASKS);

  S := '<ul>';
  for i := 0 to InstAppsList.Count-1 do begin
    S := S + '<li>' + HTMLSafe(PInstAppItem(InstAppsList.Items[i]).AppName);
    if PInstAppItem(InstAppsList.Items[i]).AppVersion <> '' then
      S := S + ' (Версия: ' + HTMLSafe(PInstAppItem(InstAppsList.Items[i]).AppVersion) + ')';
  end;
  S := S + '</ul>';
  Append('Установленные программы', S, ICON_PROGS_INSTALL);

  MoveOut;
end;

function TModuleSysInfo.GetIP: LongWord;
begin
  Result := 0;
  if IPList = nil then Exit;
  if IPList.Count > 0 then Result := LongWord(IPList.Items[0]);
end;

class function TModuleSysInfo.GetModuleName: String;
begin
  Result := 'System Info';
end;

class function TModuleSysInfo.GetModuleID: Integer;
begin
  Result := MODULE_SYSINFO;
end;

class function TModuleSysInfo.GetModuleVersion: Integer;
begin
  Result := 0;
end;

function TModuleSysInfo.GetIsEmpty: Boolean;
begin
  Result := False;
end;

procedure TModuleSysInfo.ExportModule(DBStream: TMemoryStream);
var
  i: Integer;
begin
  inherited;

  ExportData([InstAppsList.Count]);
  for i := 0 to InstAppsList.Count-1 do
    with PInstAppItem(InstAppsList.Items[i])^ do
      ExportData([AppName, AppVersion]);

  ExportData([IPList.Count]);
  for i := 0 to IPList.Count-1 do
    ExportData([Integer(IPList.Items[i])]);

  ExportData([DriveList.Count]);
  for i := 0 to DriveList.Count-1 do
    with PDriveItem(DriveList.Items[i])^ do
      ExportData([Drive, DriveType, TotalSpace, FreeSpace]);

  ExportData([ProcList.Text]);

  with Memory do
    ExportData([dwMemoryLoad, dwTotalPhys, dwAvailPhys, dwTotalPageFile, dwAvailPageFile, dwTotalVirtual, dwAvailVirtual]);

  with OsVersion do
    ExportData([dwMajorVersion, dwMinorVersion, dwBuildNumber, dwPlatformId, szCSDVersion]);

  ExportData([UserName, ComputerName, Host, Country, Language]);
  ExportData([CPUSpeed, CPUVendor, CPUInfo]);
  ExportData([FolderWindows, FolderSystem, FolderTemp, FolderCurrent, FolderStartup]);
  ExportData([DesktopWidth, DesktopHeight, DesktopBits, UID, RepTime]);
end;

procedure TModuleSysInfo.ImportModule;
var
  i: Integer;
  P1: PInstAppItem;
  P3: PDriveItem;
begin
  inherited;

  InstAppsList := TList.Create;
  IPList := TList.Create;
  DriveList := TList.Create;
  ProcList := TStringList.Create;

  for i := 0 to ImportData-1 do begin
    New(P1);
    with P1^ do begin
      AppName := ImportData;
      AppVersion := ImportData;
    end;
    InstAppsList.Add(P1);
  end;

  for i := 0 to ImportData-1 do
    IPList.Add(Pointer(Integer(ImportData)));

  for i := 0 to ImportData-1 do begin
    New(P3);
    with P3^ do begin
      Drive := Chr(Byte(ImportData));
      DriveType := ImportData;
      TotalSpace := ImportData;
      FreeSpace := ImportData;
    end;
    DriveList.Add(P3);
  end;

  ProcList.Text := ImportData;

  with Memory do begin
    dwMemoryLoad := ImportData;
    dwTotalPhys := ImportData;
    dwAvailPhys := ImportData;
    dwTotalPageFile := ImportData;
    dwAvailPageFile := ImportData;
    dwTotalVirtual := ImportData;
    dwAvailVirtual := ImportData;
  end;

  with OsVersion do begin
    dwMajorVersion := ImportData;
    dwMinorVersion := ImportData;
    dwBuildNumber := ImportData;
    dwPlatformId := ImportData;
    StrPLCopy(szCSDVersion, String(ImportData), SizeOf(szCSDVersion));
  end;
  GetOSName;

  UserName := ImportData;
  ComputerName := ImportData;
  Host := ImportData;
  Country := ImportData;
  Language := ImportData;

  CPUSpeed := ImportData;
  CPUVendor := ImportData;
  CPUInfo := ImportData;
  GetCPUName;

  FolderWindows := ImportData;
  FolderSystem := ImportData;
  FolderTemp := ImportData;
  FolderCurrent := ImportData;
  FolderStartup := ImportData;

  DesktopWidth := ImportData;
  DesktopHeight := ImportData;
  DesktopBits := ImportData;
  UID := ImportData;
  RepTime := ImportData;
end;

end.
