Advertisement
ZardoZAntony

TWindowsInformation

Dec 18th, 2014
320
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 8.02 KB | None | 0 0
  1. /*
  2.    Class show information about windows: list of windows, size, caption, coordinates,
  3.    calculates area of visibilty window, etc.  
  4.  
  5.    Delphi 2009+ (used Generics)
  6.  
  7.    zardoz.antony@gmail.com
  8.    lang = RU
  9. */
  10. unit WindowsTools;
  11.  
  12. interface
  13.  
  14. uses
  15.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Forms, Generics.Collections;
  16.  
  17. type
  18.   TWindowData = record
  19.     Handle: HWND;
  20.     Caption: string;
  21.     Position: TRect;
  22.   end;
  23.  
  24.   pWindowData = ^TWindowData;
  25.  
  26.   TRectArray = array[0..16384] of TRect;
  27.   pRectArray = ^TRectArray;
  28.  
  29.   TWindowsInformation = class
  30.   private
  31.     FWindowsList: TList<pWindowData>;
  32.  
  33.     //проверяет пересекаются ли 2 области
  34.     function OverlapRects(R1, R2: TRect): Boolean;
  35.     //считает площадь области
  36.     function CalcRectSquare(const Rect: TRect): Integer;
  37.     function GetWindowHandleByCaption(Caption: string): HWND;
  38.     //возвращает индекс окна с переданным хэндлом в списке окон
  39.     function GetWindowIndexByHandle(Wnd: HWND): Integer;
  40.   protected
  41.     //получает видимую площадь окна в пикселях
  42.     function GetVisibleWindowSquare(Wnd: HWND): Integer; virtual;
  43.     //получает текущий список видимых окон упорядоченному как в z-order (индекс 0 - самое верхнее окно)
  44.     procedure GetWindowsList; virtual;
  45.   public
  46.     constructor Create;
  47.     destructor Destroy; override;
  48.  
  49.     //возвращает процент видимости по Wnd окна
  50.     function GetWindowVisibleAreaProcent(Wnd: HWND): Extended; overload;
  51.     //возвращает процент видимости по заголовку окна, в том числе по частичному совпадению заголовка
  52.     //(если совпадений больше 1, то выбьет исключение)
  53.     function GetWindowVisibleAreaProcent(WindowCaption: string): Extended; overload;
  54.  
  55.     procedure RefreshWindowList;
  56.  
  57.     property WindowsList: TList<pWindowData> read FWindowsList;
  58.   end;
  59.  
  60. implementation
  61.  
  62. { TWindowsInformation }
  63.  
  64. function TWindowsInformation.CalcRectSquare(const Rect: TRect): Integer;
  65. begin
  66.   with Rect do
  67.     Result := (Right - Left) * (Bottom - Top);
  68.  
  69.   Result := Abs(Result);
  70. end;
  71.  
  72. constructor TWindowsInformation.Create;
  73. begin
  74.   inherited;
  75.   FWindowsList := TList<pWindowData>.Create;
  76.   GetWindowsList;
  77. end;
  78.  
  79. destructor TWindowsInformation.Destroy;
  80. var
  81.   i: Integer;
  82. begin
  83.   for i := 0 to FWindowsList.Count - 1 do
  84.     Dispose(FWindowsList[i]);
  85.  
  86.   FWindowsList.Free;
  87.   inherited;
  88. end;
  89.  
  90. function TWindowsInformation.GetVisibleWindowSquare(Wnd: HWND): Integer;
  91. var
  92.   i,
  93.   CurIdx: Integer;
  94.   CurWinData,
  95.   WinData: pWindowData;
  96.   HgrCurReg,
  97.   HgrNewReg,
  98.   HgrDestReg: HRGN;
  99.   SizeBuff: DWORD;
  100.   DestRegnData: pRgnData;
  101.   Rectangles: pRectArray;
  102. begin
  103.   Result := -1;
  104.   CurIdx := GetWindowIndexByHandle(Wnd);
  105.  
  106.   if CurIdx = -1 then
  107.     raise Exception.Create('Указанный Handle окна не найдет в списке!');
  108.  
  109.   //окон выше нет
  110.   if CurIdx = 0 then
  111.     Exit;
  112.  
  113.   CurWinData := FWindowsList[CurIdx];
  114.  
  115.   HgrNewReg := 0;
  116.   try
  117.     //пустой регион назначения
  118.     HgrDestReg := CreateRectRgn(0,0,0,0);
  119.     //регион целевого окна
  120.     HgrCurReg := CreateRectRgnIndirect(CurWinData.Position);
  121.  
  122.     for i := 0 to CurIdx - 1 do
  123.     begin
  124.       WinData := pWindowData(FWindowsList[i]);
  125.       //окно не перекрывается с нашим
  126.       if not OverlapRects(CurWinData.Position, WinData.Position) then
  127.         Continue;
  128.  
  129.       if HgrNewReg <> 0 then
  130.         DeleteObject(HgrNewReg);
  131.  
  132.       HgrNewReg := CreateRectRgnIndirect(WinData.Position);
  133.       //объединяем все регионы окон сверху
  134.       CombineRgn(HgrDestReg, HgrDestReg, HgrNewReg, RGN_OR);
  135.     end;
  136.  
  137.     //находим область перекрытия
  138.     CombineRgn(HgrDestReg, HgrCurReg, HgrDestReg, RGN_DIFF);
  139.  
  140.     //подготавливает структуру для получения данных о регионе
  141.     SizeBuff := GetRegionData(HgrDestReg, 0, nil);
  142.     GetMem(DestRegnData, SizeBuff);
  143.     FillChar(DestRegnData^, SizeBuff, 0);
  144.  
  145.     //получаем данные о регионе
  146.     if GetRegionData(HgrDestReg, SizeBuff, DestRegnData) = 0 then
  147.       raise Exception.Create('Не удалось получить данные по региону!');
  148.  
  149.     //приводим указатель на буфер к нужному типу
  150.     Rectangles := pRectArray(@DestRegnData.Buffer);
  151.     //считаем площадь всех регионов в буфере
  152.     Result := 0;
  153.     for i := 0 to Pred(DestRegnData.rdh.nCount) do
  154.       Inc(Result, CalcRectSquare(Rectangles^[i]));
  155.   finally
  156.     DeleteObject(HgrNewReg);
  157.     DeleteObject(HgrDestReg);
  158.     DeleteObject(HgrCurReg);
  159.     FreeMem(DestRegnData, SizeBuff);
  160.   end;
  161. end;
  162.  
  163. function TWindowsInformation.GetWindowHandleByCaption(Caption: string): HWND;
  164. var
  165.   CurWinData: pWindowData;
  166.   i: Integer;
  167. begin
  168.   Result := 0;
  169.   for i := 0 to FWindowsList.Count - 1 do
  170.   begin
  171.     CurWinData := FWindowsList[i];
  172.  
  173.     if (Pos(Caption, CurWinData.Caption) <> 0) then
  174.     begin
  175.       if Result = 0 then
  176.         Result := CurWinData.Handle
  177.       else
  178.         raise Exception.Create('Больше одного окна с такими словами в заголовке!');
  179.     end;
  180.   end;
  181. end;
  182.  
  183. function TWindowsInformation.GetWindowIndexByHandle(Wnd: HWND): Integer;
  184. var
  185.   i: Integer;
  186. begin
  187.   Result := -1;
  188.   for i := 0 to FWindowsList.Count - 1 do
  189.   begin
  190.     if FWindowsList[i].Handle <> Wnd then
  191.       Continue;
  192.  
  193.     Result := i;
  194.     Break;
  195.   end;
  196. end;
  197.  
  198. procedure TWindowsInformation.GetWindowsList;
  199. var
  200.   Wnd: HWND;
  201.   Buff: array [0 .. 1024] of Char;  //будет выбивать исключения, если текст заголовка окна будет больше 1024 символов
  202.   Data: pWindowData;
  203.   WinInfo: TWindowInfo;
  204. begin
  205.   FWindowsList.Clear;
  206.   Wnd := GetWindow(Application.MainForm.Handle, GW_HWNDFIRST);
  207.  
  208.   while Wnd <> 0 do
  209.   begin
  210.     if (Wnd <> Application.handle) // Собственное окно
  211.       and IsWindowVisible(Wnd)
  212.       and (GetWindow(wnd, GW_OWNER) = 0) // Дочерние окна
  213.       and (GetWindowText(Wnd, Buff, SizeOf(Buff)) <> 0) then
  214.     begin
  215.       New(Data);
  216.       Data.Handle := Wnd;
  217.  
  218.       GetWindowText(Wnd, Buff, SizeOf(Buff));
  219.       Data.Caption := StrPas(buff);
  220.  
  221.       GetWindowInfo(Wnd, WinInfo);
  222.       Data.Position:= WinInfo.rcWindow;
  223.  
  224.       FWindowsList.Add(Data);
  225.     end;
  226.  
  227.     Wnd := GetWindow(Wnd, GW_HWNDNEXT);
  228.   end;
  229. end;
  230.  
  231. function TWindowsInformation.GetWindowVisibleAreaProcent(Wnd: HWND): Extended;
  232. var
  233.   CurWinData: pWindowData;
  234.   CurIdx,
  235.   Square: Integer;
  236. begin
  237.   CurIdx := GetWindowIndexByHandle(Wnd);
  238.   if CurIdx = -1 then
  239.     raise Exception.Create('Указанный Handle окна не найдет в списке!');
  240.  
  241.   CurWinData := FWindowsList[CurIdx];
  242.  
  243.   Square := GetVisibleWindowSquare(Wnd);
  244.   //если окон выше нет
  245.   if Square = -1 then
  246.     Result := 100
  247.   else
  248.     Result := 100 * Square / (CurWinData.Position.Size.Width * CurWinData.Position.Size.Height);
  249. end;
  250.  
  251. function TWindowsInformation.GetWindowVisibleAreaProcent(WindowCaption: string): Extended;
  252. begin
  253.   Result := GetWindowVisibleAreaProcent(GetWindowHandleByCaption(WindowCaption));
  254. end;
  255.  
  256. function TWindowsInformation.OverlapRects(R1, R2: TRect): Boolean;
  257. var
  258.   Temp: TRect;
  259. begin
  260.   Result := False;
  261.   if not UnionRect(Temp, R1, R2) then
  262.     Exit;
  263.   if (Temp.Right - Temp.Left <= R1.Right - R1.Left + R2.Right - R2.Left) and
  264.     (Temp.Bottom - Temp.Top <= R1.Bottom - R1.Top + R2.Bottom - R2.Top) then
  265.     Result := True;
  266. end;
  267.  
  268. procedure TWindowsInformation.RefreshWindowList;
  269. begin
  270.   GetWindowsList;
  271. end;
  272.  
  273. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement