{*******************************************************}
{                                                       }
{       Tocsg.WinInfo                                   }
{                                                       }
{       Copyright (C) 2022 kkuzil                       }
{                                                       }
{*******************************************************}

unit Tocsg.WinInfo;

interface

uses
  SysUtils, WinApi.Windows, System.Classes;

type
  TIsWow64Process = function(hProcess: THandle;var bWow64Proc: Boolean): Boolean; stdcall;

function IsWow64: Boolean;
function IsAdminAccount: Boolean;

function GetCPUInfo: String;
function GetComName: String;
function GetAccount: String;
function GetGUID: String;
function GetTotalPhysMem: ULONGLONG;
function GetAvailPhysMem: ULONGLONG;

function GetWinVer: String;

function GetWinUpdateAbleList(aList: TStringList = nil): Integer;
function GetWinUpdateInstList(aList: TStringList = nil): Integer;

implementation

uses
  Winapi.WinSvc, Tocsg.Registry, EM.WinOSVersion, Winapi.ActiveX, System.Win.ComObj,
  Tocsg.Exception, System.Variants, Tocsg.Trace;

function IsWow64: Boolean;
var
  h: THandle;
  b: Boolean;
  fnIsWow64Process: TIsWow64Process;
begin
  Result := false;

  h := GetModuleHandle('kernel32');
  if h = 0 then
    exit;

  try
    fnIsWow64Process := GetProcAddress(h, 'IsWow64Process');
    if @fnIsWow64Process = nil then
      exit;

    if fnIsWow64Process(GetCurrentProcess, b) = true then
      Result := b;
  finally
    FreeLibrary(h);
  end;
end;

function IsAdminAccount: Boolean;
var
  h: THandle;
begin
  Result := false;
  try
    h := OpenSCManager(nil, nil, GENERIC_READ or GENERIC_WRITE or GENERIC_EXECUTE);
    if h = 0 then
      exit;
    CloseServiceHandle(h);
    Result := true;
  except

  end;
end;

function GetCPUInfo: String;
begin
  Result := GetRegValueAsString(HKEY_LOCAL_MACHINE,
      'HARDWARE\DESCRIPTION\System\CentralProcessor\0', 'ProcessorNameString');
  if Result = '' then
    Result := GetRegValueAsString(HKEY_LOCAL_MACHINE,
      'HARDWARE\DESCRIPTION\System\CentralProcessor\0', 'Identifier');
  Result := Trim(Result);
end;

function GetComName: String;
var
  sName: array[0..127] of Char;
  dwLen: DWORD;
begin
  try
    Result := GetEnvironmentVariable('COMPUTERNAME');
    if Result = '' then
    begin
      dwLen := 128;
      GetComputerName(@sName[0], dwLen);
      Result := sName;
    end;
  except
    Result := '';
  end;
end;

function GetAccount: String;
var
  sName: array[0..127] of Char;
  dwLen: DWORD;
begin
  try
    Result := GetEnvironmentVariable('USERNAME');
    if Result = '' then
    begin
      dwLen := 128;
      GetUserName(@sName[0], dwLen);
      Result := sName;
    end;
  except
    Result := '';
  end;
end;

function GetGUID: String;
var
  guid: TGuid;
begin
  if CreateGUID(guid) = S_OK then
    Result := GUIDToString(guid)
  else
    Result := '';
end;

function GetTotalPhysMem: ULONGLONG;
VAR
  mse : MemoryStatusEx;
begin
  ZeroMemory(@mse, SizeOf(MemoryStatusEx));
  mse.dwLength := SizeOf(mse);
  GlobalMemoryStatusEx(mse);
  Result:= mse.ullTotalPhys;
end;

function GetAvailPhysMem: ULONGLONG;
VAR
  mse : MemoryStatusEx;
begin
  ZeroMemory(@mse, SizeOf(MemoryStatusEx));
  mse.dwLength := SizeOf(mse);
  GlobalMemoryStatusEx(mse);
  Result:= mse.ullAvailPhys;
end;

function GetWinVer: String;
begin
  Result := GetWinVersion.WinID;
end;

function GetWinUpdateAbleList(aList: TStringList = nil): Integer;
var
  oUpdateSession,
  oUpdateSearcher,
  oUpdateEntry,
  oUpdateSearchResult,
  oUpdateCollection: OleVariant;
  oEnum: IEnumvariant;
  iValue: LongWord;
//  n: Integer;
begin
  Result := 0;
  try
    try
      oUpdateSession := CreateOleObject('Microsoft.Update.Session');
      oUpdateSearcher := oUpdateSession.CreateUpdateSearcher;
      oUpdateSearchResult := oUpdateSearcher.Search('IsInstalled = 0 and Type != ''Driver'' and IsHidden = 0 and BrowseOnly = 0');
  //    n := oUpdateSearchResult.ResultCode;
  //    TTgTrace.T('GetWinUpdateAbleList() .. ResultCode=%d', [n]);
      oUpdateCollection  := oUpdateSearchResult.Updates;
//      if aList = nil then
//      begin
//        Result := oUpdateCollection.Count;
//        exit;
//      end;

      oEnum := IUnknown(oUpdateCollection._NewEnum) as IEnumVariant;
      oEnum.Reset;
      while oEnum.Next(1, oUpdateEntry, iValue) = 0 do
      begin
        Inc(Result);
        if aList <> nil then
          aList.Add(oUpdateEntry.Title);
        VarClear(oUpdateEntry);
      end;
    finally
//      oEnum._Release;
      oUpdateCollection := Unassigned;
      oUpdateSearchResult := Unassigned;
      oUpdateSearcher := Unassigned;
      oUpdateSession := Unassigned;
    end;
  except
    on E: Exception do
      ETgException.TraceException(E, 'Fail .. GetWinUpdateAbleList()');
  end;
end;

function GetWinUpdateInstList(aList: TStringList = nil): Integer;
var
  oUpdateSession,
  oUpdateSearcher,
  oUpdateEntry,
  oUpdateSearchResult,
  oUpdateCollection: OleVariant;
  oEnum: IEnumvariant;
  iValue: LongWord;
//  n: Integer;
begin
  Result := 0;
  try
    try
      oUpdateSession := CreateOleObject('Microsoft.Update.Session');
      oUpdateSearcher := oUpdateSession.CreateUpdateSearcher;
    // 온라인 속성은 업데이트를 검색하기 위해 온라인 상태가 되었는지 확인한다.
    // 이미 설치된 업데이트를 찾는 방법은 이 값은 false로 하면 됨 22_1124 08:51:02 kku
      oUpdateSearcher.online := false;
      oUpdateSearchResult := oUpdateSearcher.Search('IsInstalled = 1');
      oUpdateCollection := oUpdateSearchResult.Updates;
  //    n := oUpdateSearchResult.ResultCode;
//      if aList = nil then
//      begin
//        Result := oUpdateCollection.Count;
//        exit;
//      end;

      oEnum := IUnknown(oUpdateCollection._NewEnum) as IEnumVariant;
      oEnum.Reset;
      while oEnum.Next(1, oUpdateEntry, iValue) = 0 do
      begin
        Inc(Result);
        if aList <> nil then
          aList.Add(oUpdateEntry.Title);
        VarClear(oUpdateEntry);
      end;
    finally
//      oEnum._Release;
      oUpdateCollection := Unassigned;
      oUpdateSearchResult := Unassigned;
      oUpdateSearcher := Unassigned;
      oUpdateSession := Unassigned;
    end;
  except
    on E: Exception do
      ETgException.TraceException(E, 'Fail .. GetWinUpdateInstList()');
  end;
end;

end.
