unit uEnumWindowList;

interface

uses
  Winapi.Windows, System.Classes;

type
  TEnumWindow = class(TObject)
  private
    FHandle: HWND;
    FCaption: String;
    FName: String;
    FRect: TRect;
    FVisible: Boolean;
    FStyle: DWORD;
    FExStyle: DWORD;
    FNoWindow: Boolean;
    FTag: Integer;
    procedure SetStyle(const Value: DWORD);
    procedure SetExStyle(const Value: DWORD);
    procedure SetCaption(const Value: String);
    procedure SetRect(const Value: TRect);
  public
    function ToString: String; override;
    property Handle: HWND read FHandle;
    property Name: String read FName;
    property Caption: String read FCaption write SetCaption;
    property Rect: TRect read FRect write SetRect;
    property Visible: Boolean read FVisible;
    property NoWindow: Boolean read FNoWindow;
    property Style: DWORD read FStyle write SetStyle;
    property ExStyle: DWORD read FExStyle write SetExStyle;
    property Tag: Integer read FTag write FTag;
  end;

procedure GetDesktopWindowList(
  const iList: TList;
  const iDesktopHandle: THandle);

procedure FreeWindowList(const iList: TList);

implementation

uses
  System.SysUtils, Vcl.Forms;

procedure TEnumWindow.SetStyle(const Value: DWORD);
begin
  FStyle := Value;

  SetWindowLong(FHandle, GWL_STYLE, FStyle);
end;

function TEnumWindow.ToString: String;
begin
  Result := FCaption + ' (' + FName + ', ' + IntToStr(FHandle) + ')';
end;

procedure TEnumWindow.SetExStyle(const Value: DWORD);
begin
  FExStyle := Value;

  SetWindowLong(FHandle, GWL_EXSTYLE, FExStyle);
end;

procedure TEnumWindow.SetCaption(const Value: String);
begin
  FCaption := Value;

  SetWindowText(FHandle, PChar(FCaption));
end;

procedure TEnumWindow.SetRect(const Value: TRect);
var
  Placement: TWindowPlacement;
  IsVisible: Boolean;
begin
  FRect := Value;

  IsVisible := IsWindowVisible(FHandle);

  with FRect do begin
    Placement.length := SizeOf(Placement);
    GetWindowPlacement(FHandle, @Placement);

    Placement.rcNormalPosition := FRect;
    Placement.ptMaxPosition := FRect.TopLeft;
    SetWindowPlacement(FHandle, @Placement);

    MoveWindow(FHandle, Left, Top, Right - Left, Bottom - Top, True);
  end;

  if (not IsVisible) then
    ShowWindow(FHandle, SW_HIDE);
end;

procedure GetClassNameAndCaption(
  const iWnd: HWND;
  var ioClassName, ioCaption: String;
  const iToUpperClassName: Boolean = True;
  const iToUpperCaption: Boolean = False);
begin
  SetLength(ioClassName, $100);
  SetLength(
    ioClassName,
    GetClassName(iWnd, PChar(ioClassName), Length(ioClassName) - 1));
  ioClassName := Trim(ioClassName);

  if (iToUpperClassName) then
    ioClassName := UpperCase(ioClassName);

  SetLength(ioCaption, $100);
  SetLength(
    ioCaption,
    GetWindowText(iWnd, PChar(ioCaption), Length(ioCaption) - 1));
  ioCaption := Trim(ioCaption);

  if (iToUpperCaption) then
    ioCaption := AnsiUpperCase(ioCaption);
end;

function EnumWindowsProc(vWnd: HWND; vlParam: LPARAM): BOOL; stdcall;
var
  EnumWindow: TEnumWindow;
  ScreenRect: TRect;
  Placement: TWindowPlacement;
begin
  Result := True;

  ScreenRect := Screen.DesktopRect;

  with TList(Pointer(vlParam)) do begin
    EnumWindow := TEnumWindow.Create;

    Add(EnumWindow);

    with EnumWindow do begin
      FHandle := vWnd;

      GetClassNameAndCaption(FHandle, FName, FCaption, False, False);

      Placement.length := SizeOf(Placement);
      GetWindowPlacement(FHandle, @Placement);
      FRect := Placement.rcNormalPosition;
      FNoWindow := (IsRectEmpty(FRect));
      FVisible :=
        (not FNoWindow) and
        (IsWindowVisible(FHandle)) and
        (IntersectRect(ScreenRect, FRect, ScreenRect));

      FStyle := GetWindowLong(FHandle, GWL_STYLE);
      FExStyle := GetWindowLong(FHandle, GWL_EXSTYLE);

      FTag := 0;
    end;
  end;
end;

procedure GetDesktopWindowList(
  const iList: TList;
  const iDesktopHandle: THandle);
begin
  iList.Clear;
  EnumDesktopWindows(iDesktopHandle, @EnumWindowsProc, Integer(Pointer(iList)));
end;

procedure FreeWindowList(const iList: TList);
var
  i: Integer;
begin
  for i := 0 to iList.Count - 1 do
    TEnumWindow(iList[i]).Free;

  iList.Clear;
end;

end.
