unit winlist; //{$DEFINE _DEBUG} interface uses Windows, Classes; type T_MyBounds = record Left, Top, Width, Height: Integer; end; type {T_WinItem} //Pauseの時のすべてのウィンドウの表示情報を保持するためのクラス T_WinItem = class(TObject) private // F_bAllowAdd: Boolean; //追加するか F_bToplevel: Boolean; //トップレベルウィンドウか F_bVisible: Boolean; F_rcClientToScreenRect: TRect; //スクリーン座標のClientRect F_rgRegion: HRGN; //ウィンドウリージョン F_iRegionCode: Integer; //GetWindowRgnの戻り値 F_Parent: T_WinItem; F_Childs: TList; F_hHandle: HWND; F_sClassName: String; F_sText: WideString; F_szWindowSize, F_szClientSize: T_MyBounds; F_ptClientPos: TPoint; F_rcBoundsRect: TRect; F_iControlID, F_iStyle, F_iStyleEx: LongInt; F_iProcessID: DWORD; F_sExeName: WideString; F_sFileVersion: WideString; function F_GetParent: T_WinItem; { F_hParentHandle: HWND; F_sParentClassName: String; F_sParentText: WideString; } function F_GetCount: Integer; function F_GetChild(iIndex: Integer): T_WinItem; public constructor Create(ANode: T_WinItem; hHandle: HWND; rcBoundsRect: TRect; bTopLevel: Boolean); overload; destructor Destroy; override; procedure Clear; procedure Add(AItem: T_WinItem); procedure Delete(iIndex: Integer); function FindWindowItem(hWindow: HWND): T_WinItem; property Count: Integer read F_GetCount; property Items [iIndex: Integer]: T_WinItem read F_GetChild; default; property IsToplevel: Boolean read F_bToplevel; property Visible: Boolean read F_bVisible; property ClientToScreenRect: TRect read F_rcClientToScreenRect; // property AllowAdd: Boolean read F_bAllowAdd; property Parent: T_WinItem read F_GetParent; property Region: HRGN read F_rgRegion; property RegionCode: Integer read F_iRegionCode; property Handle: HWND read F_hHandle; property WinClassName: String read F_sClassName; property Text: WideString read F_sText; property WindowSize: T_MyBounds read F_szWindowSize; property ClientSize: T_MyBounds read F_szClientSize; property ClientPos: TPoint read F_ptClientPos; property BoundsRect: TRect read F_rcBoundsRect; property ControlID: Longint read F_iControlID; property Style: Longint read F_iStyle; property StyleEx: Longint read F_iStyleEx; property ProcessID: DWORD read F_iProcessID; property ExeName: WideString read F_sExeName; property FileVersion: WideString read F_sFileVersion; { property hParentHandle: HWND read F_hParentHandle; property sParentClassName: String read F_sParentClassName; property sParentText: WideString read F_sParentText; } end; T_WinList = class(TObject) private FbAeroThemeEnabled : Boolean; F_Root: T_WinItem; public constructor Create; destructor Destroy; override; procedure Add(AWinItem: T_WinItem); function FindWindowItem(hWindow: HWND): T_WinItem; overload; function FindWindowItem(ptPos: TPoint; bIgnoreLayered: Boolean): T_WinItem; overload; property Items: T_WinItem read F_Root; property AeorThemeEnabled : Boolean read FbAeroThemeEnabled; end; implementation uses {$IFDEF _DEBUG} myDebug, {$ENDIF} SysUtils, Forms, my_monitor, general; constructor T_WinItem.Create(ANode: T_WinItem; hHandle: HWND; rcBoundsRect: TRect; bTopLevel: Boolean); var i : Integer; lpt_Pos : TPoint; l_Item : T_WinItem; begin inherited Create; F_Childs := TList.Create; if (ANode = nil) then begin //ルート。 F_Parent := Self; //Exit; end else begin F_Parent := ANode; end; F_bVisible := False; F_hHandle := hHandle; F_bTopLevel := bTopLevel; F_rcBoundsRect := rcBoundsRect; F_rgRegion := 0; if (bToplevel) then begin if (ANode <> nil) then begin //トップレベルウィンドウ for i := 0 to ANode.Count-1 do begin l_Item := ANode.Items[i]; //レイヤードウィンドウの場合自身をキャプチャしないにすると見えなくなるので除外判定からはずす。 if ((l_Item.StyleEx and WS_EX_LAYERED) = 0) then begin //レイヤードウィンドウではない。 //Zオーダーが手前のトップレベルウィンドウと比較する。 if gfnbCompleteRectInRect(F_rcBoundsRect, l_Item.BoundsRect) then begin //他のトップレベルウィンドウの下に隠れて見えないので登録しない。 Exit; end; end; end; end; end else begin //子ウィンドウ。 //子ウィンドウは見えなくてもリストに登録はする。 if not(IsWindowVisible(F_hHandle)) //自身が見えない or not(ANode.Visible) //親が見えない or not(gfnbRectInRect(F_rcBoundsRect, ANode.ClientToScreenRect)) //親ウィンドウの長方形外 then begin Exit; end; for i := ANode.Count-1 downto 0 do begin l_Item := ANode.Items[i]; //兄弟ウィンドウとの比較 if gfnbCompleteRectInRect(F_rcBoundsRect, l_Item.BoundsRect) then begin //他の兄弟ウィンドウの下に隠れて見えないのでこれ以上情報を取得しない。 Exit; end; end; end; F_szWindowSize.Width := gfniRectWidth (F_rcBoundsRect); F_szWindowSize.Height := gfniRectHeight(F_rcBoundsRect); if (F_szWindowSize.Width <= 0) or (F_szWindowSize.Height <= 0) then begin //サイズが0であるなら見えないのでこれ以上情報を取得しない。 Exit; end; //ClientSize if (Windows.GetClientRect(F_hHandle, F_rcClientToScreenRect)) then begin F_szClientSize.Width := F_rcClientToScreenRect.Right; F_szClientSize.Height := F_rcClientToScreenRect.Bottom; end else begin F_szClientSize.Width := 0; F_szClientSize.Height := 0; end; //クライアントの原点のスクリーン座標 F_ptClientPos := Point(0, 0); Windows.ClientToScreen(F_hHandle, F_ptClientPos); //スクリーン座標のClientRectを算出。 F_rcClientToScreenRect.TopLeft := F_ptClientPos; Windows.ClientToScreen(F_hHandle, F_rcClientToScreenRect.BottomRight); //ウィンドウのサイズ if (bToplevel) then begin //トップレベルウィンドウ F_szWindowSize.Left := F_rcBoundsRect.Left; F_szWindowSize.Top := F_rcBoundsRect.Top; end else begin //子ウィンドウ lpt_Pos := F_rcBoundsRect.TopLeft; if (ScreenToClient(ANode.Handle, lpt_Pos)) then begin //子ウィンドウ F_szWindowSize.Left := lpt_Pos.X; F_szWindowSize.Top := lpt_Pos.Y; end else begin //トップレベルウィンドウ? F_szWindowSize.Left := F_rcBoundsRect.Left; F_szWindowSize.Top := F_rcBoundsRect.Top; end; end; //クラス名 F_sClassName := gfnsClassNameGet(F_hHandle); //ウィンドウテキスト F_sText := gfnsWindowTextGet(F_hHandle); //コントロールID F_iControlID := GetWindowLong(F_hHandle, GWL_ID); //ウィンドウスタイル F_iStyle := GetWindowLong(F_hHandle, GWL_STYLE); //ウィンドウスタイル F_iStyleEx := GetWindowLong(F_hHandle, GWL_EXSTYLE); //拡張ウィンドウスタイル { //親ウィンドウのハンドル //↑で既に取得済み // F_hParentHandle := gfnhParentWindowGet(F_hHandle); //親ウィンドウのクラス名 F_sParentClassName := gfnsClassNameGet(F_hParentHandle); //親ウィンドウのウィンドウテキスト F_sParentText := gfnsWindowTextGet(F_hParentHandle); } //プロセスID GetWindowThreadProcessId(F_hHandle, @F_iProcessID); //実行ファイル名 F_sExeName := gfnsExeNameGet(F_hHandle); //ファイルバージョン F_sFileVersion := gfnsFileVersionGet(F_sExeName); // if (F_bToplevel) then begin if (ANode = nil) then begin // F_iRegionCode := MyMonitors.DesktopRegionCode; F_rgRegion := MyScreenSize.DesktopRegion; end else begin //この処理に結構時間がかかってしまう。 //ウィンドウリージョンを取得 //まず空のリージョンを作成 F_rgRegion := CreateRectRgn(0,0,0,0); //ウィンドウリージョン取得 F_iRegionCode := GetWindowRgn(F_hHandle, F_rgRegion); end; // end else begin // F_rgRegion := 0; // F_iRegionCode := Windows.ERROR; // end; F_bVisible := True; end; destructor T_WinItem.Destroy; begin Clear; F_Childs.Free; inherited; end; procedure T_WinItem.Clear; var i: Integer; begin for i := F_GetCount-1 downto 0 do begin Self.Delete(i); end; F_Childs.Clear; DeleteObject(F_rgRegion); end; procedure T_WinItem.Delete(iIndex: integer); begin T_WinItem(F_Childs[iIndex]).Free; F_Childs.Delete(iIndex); end; procedure T_WinItem.Add(AItem: T_WinItem); begin F_Childs.Add(AItem); end; function T_WinItem.FindWindowItem(hWindow: HWND): T_WinItem; //自身と自身の子ウィンドウアイテム中からhWindowのハンドルを持つウィンドウの親ウィンドウのアイテムを返す。 var i: Integer; l_Node: T_WinItem; begin if (Self.Handle = hWindow) then begin Result := Self; end else begin // Result := nil; for i := Self.Count-1 downto 0 do begin l_Node := Self.Items[i]; //最後に追加したノードから探す if (l_Node.Handle = hWindow) then begin Result := l_Node; Exit; end else if (l_Node.Count > 0) then begin //子ノードから探す Result := l_Node.FindWindowItem(hWindow); if (Result <> nil) then begin Exit; end; end; end; Result := Self; end; end; function T_WinItem.F_GetParent: T_WinItem; begin if (F_Parent = nil) then begin Result := Self; end else begin Result := F_Parent; end; end; function T_WinItem.F_GetCount: Integer; begin Result := F_Childs.Count; end; function T_WinItem.F_GetChild(iIndex: Integer): T_WinItem; begin Result := T_WinItem(F_Childs.Items[iIndex]); end; //------------------------------------------------------------------------------ { T_WinList } function FEnumChildProc(hWindow: HWND; ANode: T_WinItem): Bool; stdcall; //子ウィンドウを列挙する var lh_Parent: HWND; l_Item, l_ParentNode: T_WinItem; lrc_Rect: TRect; begin { 子ウィンドウの列挙はフラット(孫ウィンドウを子ウィンドウの列挙中に列挙するわけでは ない)なのでトップレベルウィンドウの場合と違い非可視ウィンドウや範囲外のウィンドウ であっても除外できない。 そのためT_WinItemにVisibleプロパティを設けて非可視ウィンドウや範囲外のウィンドウ はVisibleをFalseにしてHandleだけをセットする。 } lh_Parent := gfnhParentWindowGet(hWindow); //myDebug.gpcDebug([lh_Parent, gfnsClassNameGet(lh_Parent), hWindow, gfnsClassNameGet(hWindow)]); l_ParentNode := ANode.FindWindowItem(lh_Parent); lrc_Rect := gfnrcWindowRectGet(hWindow); l_Item := T_WinItem.Create(l_ParentNode, hWindow, lrc_Rect, False); l_ParentNode.Add(l_Item); Application.ProcessMessages; Result := True; end; function FEnumWindowsProc(hWindow: HWND; ARoot: T_WinItem):BOOL; stdcall; //トップレベルウィンドウを列挙する var l_Item: T_WinItem; lrc_Rect: TRect; begin if (IsWindowVisible(hWindow)) //ウィンドウは可視 // and not(IsIconic(hWindow)) //NG サブウィンドウが最小化されていた場合に対応できない //最小化されていない then begin lrc_Rect := gfnrcWindowRectGet(hWindow); // if (RectInRegion(MyScreenSize.DesktopRegion, lrc_Rect)) // if (gfnbRectInRect(MyScreenSize.DesktopRect, lrc_Rect)) if ((gfniRectWidth(lrc_Rect) > 0) and (gfniRectHeight(lrc_Rect) > 0)) and (MyScreenSize.RectInDesktopRect(lrc_Rect)) then begin { myDebug.gpcDebug([ IntToStr(hWindow) ,gfnsClassNameGet(hWindow) ,gfnsWindowTextGet(hWindow) ]); } //デスクトップの範囲内 l_Item := T_WinItem.Create(ARoot, hWindow, lrc_Rect, True); if (l_Item.Visible) then begin ARoot.Add(l_Item); EnumChildWindows(hWindow, @FEnumChildProc, Integer(l_Item)); end else begin l_Item.Free; end; end; end; Application.ProcessMessages; Result := True; end; constructor T_WinList.Create; begin inherited; FbAeroThemeEnabled := gfnbIsAeroThemeEnabled; //とりあえずF_Rootを作っておく F_Root := T_WinItem.Create(nil, GetDesktopWindow, MyScreenSize.DesktopRect, True); EnumWindows(@FEnumWindowsProc, LPARAM(F_Root)); end; destructor T_WinList.Destroy; begin F_Root.Free; inherited; end; procedure T_WinList.Add(AWinItem: T_WinItem); begin F_Root.Add(AWinItem); end; function T_WinList.FindWindowItem(hWindow: HWND): T_WinItem; //ウィンドウハンドルがhWindowであるアイテムをリストから探索して返す。 function lfn_FindItem(ANode: T_WinItem; hHandle: HWND): T_WinItem; var i: Integer; l_Node: T_WinItem; begin Result := nil; if (ANode.Handle = hHandle) then begin Result := ANode; end else begin for i := ANode.Count-1 downto 0 do begin l_Node := ANode.Items[i]; //最後に追加したノードから探す if (l_Node.Handle = hHandle) then begin Result := l_Node; Break; end else if (l_Node.Count > 0) then begin //子ノードから探す Result := lfn_FindItem(l_Node, hHandle); if (Result <> nil) then begin Break; end; end; end; end; end; begin Result := lfn_FindItem(F_Root, hWindow); end; function T_WinList.FindWindowItem(ptPos: TPoint; bIgnoreLayered: Boolean): T_WinItem; //スクリーン座標ptPos上にある一番上のアイテムをリストから探索して返す。 (* function lfn_FindChildItem(ANode: T_WinItem; ptPos: TPoint): T_WinItem; var i: Integer; l_Node: T_WinItem; begin Result := nil; for i := 0 to ANode.Count-1 do begin l_Node := ANode.Items[i]; //ANodeは子ウィンドウ。 //子ウィンドウの探索に入るということは少なくともその親ウィンドウの範囲内 //にかかっているということになるのでResultの初期値はANodeになる。 //myDebug.gpcDebug([i, l_Node.Handle, l_Node.WinClassName, l_Node.Text, l_Node.Visible]); if (l_Node.Visible) then begin if (PtInRect(l_Node.BoundsRect, ptPos)) then begin //ClientToScreenRectではない Result := lfn_FindChildItem(l_Node, ptPos); if (Result = nil) then begin Result := l_Node; end; Exit; end; end; end; end; *) function lfn_FindItem(ANode: T_WinItem; ptPos: TPoint; bIgnore: Boolean): T_WinItem; var i: Integer; l_Node: T_WinItem; lpt_Pos: TPoint; begin Result := nil; for i := 0 to ANode.Count-1 do begin l_Node := ANode.Items[i]; if (bIgnore) //自身をキャプチャしない。 and (gfnbStyleCheck(l_Node.StyleEx, WS_EX_LAYERED)) //ANodeはレイヤードウィンドウ。 then begin //ANodeはトップレベルウィンドウ。 //レイヤードウィンドウは表示されないので判定から除外。 Continue; end; lpt_Pos.X := ptPos.X - l_Node.BoundsRect.Left; lpt_Pos.Y := ptPos.Y - l_Node.BoundsRect.Top; if ((l_Node.RegionCode <> ERROR) and (PtInRegion(l_Node.Region, lpt_Pos.X, lpt_Pos.Y))) //リージョンで判定 or ((l_Node.RegionCode = ERROR) and (PtInRect(l_Node.BoundsRect, ptPos))) //Rectで判定 then begin //ptPosがトップレベルウィンドウ内にあった。 if (l_Node.ClientSize.Width = 0) or (l_Node.ClientSize.Height = 0) then begin //クライアントサイズが0だった。 Result := l_Node; end else begin // Result := lfn_FindChildItem(l_Node, ptPos); Result := lfn_FindItem(l_Node, ptPos, False); if (Result = nil) then begin Result := l_Node; end; end; Exit; end; end; end; begin Result := lfn_FindItem(F_Root, ptPos, bIgnoreLayered); if (Result = nil) then begin //本来ここにくることはない。 Result := F_Root.Items[F_Root.Count-1]; end; end; end.