|
Delphi Programming / Object Pascal
[掲載 2012年03月08日] [更新 2015年04月28日] Delphi サンプルプログラム集 |
645_ウィンドウの階層のツリー表示 |
動作確認等 |
Windows XP(SP3) + Delphi XE Pro
Windows 7 U64(SP1) + Delphi XE Pro |
|
645_WindowTree.zip [1,907 KB] 2012年05月23日版 (EXE 同梱) |
- 2012年03月18日
- システム関係ダイアログの場合の記事を追加
- 2012年05月10日
- マイクロソフト提供ツールの紹介記事を追加
- クラス名をコピーする機能を付けた
- 2012年05月23日
- 対象ウィンドウを囲む枠線を表示するサンプルを追加
- 2015年04月28日
- ツール関係の記事を [679_他のアプリの操作とUI Automation 関係インターフェイス] に移動
|
01_ウィンドウの階層をツリー表示してクラス名を調べる |
Halbow 資料館にある同名のサンプルを,Delphi 2009 以降の開発環境でも使用可能にしたものです.
実際には,そのサンプルで使用している Windows の情報を取得する関数類の修正だけですが,コードを少し整備して,リサイズ等の機能を追加しています.関数類の名前は一切変更していません.
このプログラムは機能も単純で,しかもリアルタイムで情報を取得するわけではありませんが,筆者は結構重宝しています.特に,起動中のアプリやプログラムのウインドウのクラス名を調べたり,ダイアログのコントロールの ID 値を調べる時に使用しています.
コードの詳しい説明は,Halbow 資料館の記事を参考にしてください.
|
|
図1
設計時画面 |
|
図2
実行画面例
- 自ウィンドウを選択
- マウスの右ボタンクリックのメニューでクラス名のコピーが可能
|
リスト1
プロジェクトのソースコード
MainFormOnTaskbar を False にする |
program Project1;
uses
Forms,
Main in 'Main.pas' {Form1},
WinSearch in 'WinSearch.pas';
{$R *.RES}
begin
Application.Initialize;
//Delphi2007以上
{$IF CompilerVersion > 18.49}
Application.MainFormOnTaskbar := False;
{$IFEND}
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
unit Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
TreeView1: TTreeView;
Splitter1: TSplitter;
Panel3: TPanel;
Panel1: TPanel;
ListView1: TListView;
Panel2: TPanel;
Splitter2: TSplitter;
Panel6: TPanel;
Panel4: TPanel;
ListView2: TListView;
Panel5: TPanel;
Label3: TLabel;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private 宣言 }
IniFileName : String;
public
procedure EnumChildren(Node:TTreeNode);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
uses WinSearch, IniFiles;
//=============================================================================
// 本フォーム作成時の処理
// 情報表示用のTTreeViewとTListViewの位置とサイズの設定値をiniファイルから読み
// 出して設定
//
// このサンプルプログラムは,Project1.dprのMainFormTaskbarを
// Application.MainFormOnTaskbar := False;
// としないと,アプリケーションウィンドウだけを単独検出してしまうので注意
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
//---------------------------------------------------------------------------
procedure ListViewColumnAdd(LV: TListView; ACaption: String; AWidth: Integer);
var
LVColumn : TListColumn;
begin
LVColumn := LV.Columns.Add;
LVColumn.Caption := ACaption;
LVColumn.Width := AWidth;
end;
//---------------------------------------------------------------------------
var
AIni : TInifile;
FormTop : Integer;
FormLeft : Integer;
FormWidth : Integer;
FormHeight : Integer;
InfoPaneWidth : Integer;
ClassItemWidth : Integer;
ClassExpWidth : Integer;
WinItemWidth : Integer;
WinExpWidth : Integer;
begin
ListView1.ViewStyle := vsReport;
ListView1.RowSelect := True;
ListView2.ViewStyle := vsReport;
ListView2.RowSelect := True;
FormTop := 0;
FormLeft := 0;
FormWidth := 0;
FormHeight := 0;
InfoPaneWidth := 0;
ClassItemWidth := 0;
ClassExpWidth := 0;
WinItemWidth := 0;
WinExpWidth := 0;
IniFileName := ChangeFileExt(ParamStr(0),'.ini');
AIni := TIniFile.Create(IniFileName);
try
try
FormTop := AIni.ReadInteger('PosSize', 'FormTop', 0);
FormLeft := Aini.ReadInteger('PosSize', 'FormLeft', 0);
FormWidth := Aini.ReadInteger('PosSize', 'FormWidth', 0);
FormHeight := Aini.ReadInteger('PosSize', 'FormHeight', 0);
InfoPaneWidth := Aini.ReadInteger('PosSize', 'InfoPaneWidth', 0);
ClassItemWidth := Aini.ReadInteger('PosSize', 'ClassItemWidth', 0);
ClassExpWidth := Aini.ReadInteger('PosSize', 'ClassExpWidth', 0);
WinItemWidth := Aini.ReadInteger('PosSize', 'WinItemWidth', 0);
WinExpWidth := Aini.ReadInteger('PosSize', 'WinExpWidth', 0);
except
end;
finally
FreeAndNil(AIni);
end;
if (FormWidth * FormHeight) = 0 then begin
Self.Position := poMainFormCenter;
end else begin
Self.Position := poDesigned;
Self.Top := FormTop;
Self.Left := FormLeft;
Self.Width := FormWidth;
Self.Height := FormHeight;
end;
if InfoPaneWidth <> 0 then Panel3.Width := InfoPaneWidth;
if ClassItemWidth = 0 then ClassItemWidth := 90;
if ClassExpWidth = 0 then ClassExpWidth := 140;
if WinItemWidth = 0 then WinItemWidth := 90;
if WinExpWidth = 0 then WinExpWidth := 140;
ListViewColumnAdd(ListView1, ' 項 目', ClassItemWidth);
ListViewColumnAdd(ListView1, ' 内 容', ClassExpWidth);
ListViewColumnAdd(ListView2, ' 項 目', WinItemWidth);
ListViewColumnAdd(ListView2, ' 内 容', WinExpWidth);
end;
//=============================================================================
// フォームを閉じる時はiniファイルへ位置やサイズを保存
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
AIni : TInifile;
begin
AIni := TIniFile.Create(IniFileName);
try
try
AIni.WriteInteger ('PosSize', 'FormTop', Self.Top);
Aini.WriteInteger ('PosSize', 'FormLeft', Self.Left);
Aini.WriteInteger ('PosSize', 'FormWidth', Self.Width);
Aini.WriteInteger ('PosSize', 'FormHeight', Self.Height);
Aini.WriteInteger ('PosSize', 'InfoPaneWidth', Panel3.Width);
Aini.WriteInteger ('PosSize', 'ClassItemWidth', ListView1.Column[0].Width);
Aini.WriteInteger ('PosSize', 'ClassExpWidth', ListView1.Column[1].Width);
Aini.WriteInteger ('PosSize', 'WinItemWidth', ListView2.Column[0].Width);
Aini.WriteInteger ('PosSize', 'WinExpWidth', ListView2.Column[1].Width);
except
end;
finally
FreeAndNil(AIni);
end;
end;
//=============================================================================
// トップレベルのウィンドウを取得してツリービューに表示
// この時点では子ウィンドウ等は検索しない
// 各ノードにウィンドウハンドルを代入しておく
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
WA : THWndArray;
i : Integer;
Num : Integer;
StrItem : String;
StrClass : String;
StrText : String;
begin
TreeView1.Items.Clear;
Num := WinSearch.EnumVisbleNoOwnedWindows(WA);
Label3.Caption := IntToStr(Num);
if Num > 0 then begin
for i := 1 to Num do begin
StrClass := WinSearch.GetClassNameStr(WA[i]);
StrText := WinSearch.GetWindowTextStr(WA[i]);
StrItem := Format('%s ...... %s', [StrClass, StrText]);
TreeView1.Items.AddObject(nil, StrItem, Pointer(WA[i]));
end;
end;
end;
//=============================================================================
// 引数のノードに格納してあるウィンドウハンドルのウィンドウの全ての子ウィンド
// ウを,この関数自身を再帰的に呼び出して(再帰処理)ツリービューに階層表示
//=============================================================================
procedure TForm1.EnumChildren(Node: TTreeNode);
var
WA : THWndArray;
i : Integer;
Num : Integer;
S : String;
TN : TTreeNode;
StrItem : String;
begin
if Node.Count > 0 then exit;
Num := WinSearch.EnumDirectChildren(WA, HWND(Node.Data));
if Num > 0 then begin
for i := 1 to Num do begin
if IsWindowVisible(WA[i]) then S := '' else S := '$';
StrItem := WinSearch.GetClassNameStr(WA[i]) + S;
TN := TreeView1.Items.AddChildObject(Node, StrItem, Pointer(WA[i]));
EnumChildren(TN);
end;
end;
Num := WinSearch.EnumDirectOwnedWindows(WA, HWND(Node.Data));
if Num > 0 then begin
for i := 1 to Num do begin
if IsWindowVisible(WA[i]) then S := '' else S := '$';
StrItem := '*' + WinSearch.GetClassNameStr(WA[i]) + S;
TN := TreeView1.Items.AddChildObject(Node, StrItem, Pointer(WA[i]));
EnumChildren(TN);
end;
end;
end;
//=============================================================================
// ツリービューのノードの項目名部分をクリックしたら子ウィンドウを列挙
// 一度展開すると,ツリーを閉じても前の情報のまま
// 新しい情報にするには,[Button1]をクリックして再取得する必要あり
//=============================================================================
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin
if (Node.Level = 0) and (Node.Count = 0) then begin
EnumChildren(Node);
Node.Expand(True);
end;
ListView1.Items.Clear;
WinSearch.ClassInfos(ListView1, HWND(Node.Data));
ListView2.Items.Clear;
WinSearch.WindowInfos(ListView2, HWND(Node.Data));
end;
end.
上のサンプルプログラムでは,次のユニットを使用しています.
このコードでは,整数型 (HWND 型)の 配列にウィドウのハンドル値を格納するようにしていますが,下記の [05_コールバック関数の引数 - TList] のように TList を使用してもいいかも知れません. |
リスト3
上のコードで使用しているユニット
ウィンドウのハンドルやクラス情報を取得するための関数類を収めたユニット |
unit WinSearch;
interface
uses
Windows, Messages, SysUtils, Classes, ComCtrls, Forms;
type
//ウィンドウハンドル値の格納用配列
//最初の要素(0)はカウンタとして使用
THWndArray = array[0..500] of HWND;
PHWndArray = ^THWndArray;
function IsChildWindow(Handle: HWND): Boolean;
function GetClassNameStr(hWindow: HWND): String;
function GetWindowTextStr(hWindow: HWND): String;
procedure ClassInfos(LV: TListView; hWindow: HWND);
procedure WindowInfos(LV: TListView; hWindow: HWND);
function IsOwnedWindow(hWindow: HWND): Boolean;
function AEnumWindows(var WA: THWndArray): Integer;
function EnumVisbleNoOwnedWindows(var WA: THWndArray): Integer;
function EnumVisibleNoOwnedWindowAsZOrder(var WA: THWndArray): Integer;
function EnumWindowsOfClassNameAsZOrder(var WA: THWndArray;
ClassName: String): Integer;
function AEnumThreadWindows(var WA: THWndArray; OneOfHandles: HWND): Integer;
function AEnumChildWindows(var WA: THWndArray; hParent: HWND): Integer;
function FindChildOfClass(hParent: HWND; ClassName: String): HWND;
function EnumDirectChildren(var WA: THWndArray; hParent: HWND): Integer;
function GetMostTopLevelWindow(hWindow: HWND): HWND;
function EnumDirectOwnedWindows(var WA: THWndArray; hOwner: HWND): Integer;
implementation
//=============================================================================
// 引数のウィンドウが子ウィンドウかを調査
// 子ウィンドウは,そのウィンドウスタイルにWS_CHILDを含んでいることを利用
//=============================================================================
function IsChildWindow(Handle: HWND): Boolean;
begin
Result := (GetWindowLong(Handle, GWL_STYLE) and WS_CHILD) <> 0;
end;
//=============================================================================
// ウィンドウのクラス名を取得する関数
//=============================================================================
function GetClassNameStr(hWindow: HWND): String;
var
Buffer : array[0..MAX_PATH-1] of Char;
Len : Integer;
begin
System.FillChar(Buffer, SizeOf(Buffer), #0);
Len := Windows.GetClassName(hWindow, Buffer, Length(Buffer));
if Len > 0 then Result := Buffer else Result := '';
end;
//=============================================================================
// ウィンドウのタイトルを取得する関数
//=============================================================================
function GetWindowTextStr(hWindow: HWND): String;
var
Buffer : array[0..MAX_PATH-1] of Char;
Len : Integer;
begin
System.FillChar(Buffer, SizeOf(Buffer), #0);
Len := Windows.GetWindowText(hWindow, Buffer, Length(Buffer));
if Len > 0 then Result := Buffer else Result := '';
end;
//=============================================================================
// ウィンドウのクラス情報をリストビューに追加
//=============================================================================
procedure ClassInfos(LV: TListView; hWindow: HWND);
//---------------------------------------------------------------------------
procedure ListViewItemAdd(LV: TListView; ACaption, SubItem: String);
var
LVItem : TListItem;
begin
LVItem := LV.Items.Add;
LVItem.Caption := ACaption;
LVItem.SubItems.Text := SubItem;
end;
//---------------------------------------------------------------------------
var
WC : TWndClass;
S : String;
Value : Integer;
FmtStr : String;
begin
S := GetClassNameStr(hWindow);
ListViewItemAdd (LV, 'ClassName', S);
Windows.GetClassInfo(hInstance, PChar(S), WC);
Value := Windows.GetClassLong(hWindow, GCL_STYLE);
FmtStr := Format('$%.8x', [Value, 8]);
ListViewItemAdd (LV, 'Style', FmtStr);
Value := Windows.GetClassLong(hWindow, GCL_WNDPROC);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'WndProc', FmtStr);
Value := Windows.GetClassLong(hWindow, GCL_HMODULE);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'hModule', FmtStr);
Value := Windows.GetClassLong(hWindow, GCL_CBCLSEXTRA);
FmtStr := Format('$%.8x bytes', [Value]);
ListViewItemAdd (LV, 'ClsExtra', FmtStr);
Value := Windows.GetClassLong(hWindow, GCL_CBWNDEXTRA);
FmtStr := Format('$%.8x bytes', [Value]);
ListViewItemAdd (LV, 'WndExtra', FmtStr);
Value := Windows.GetClassLong(hWindow, GCL_HICON);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'hIcon', FmtStr);
Value := Windows.GetClassLong(hWindow, GCL_HBRBACKGROUND);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'hBrush', FmtStr);
Value := Windows.GetClassLong(hWindow, GCL_HCURSOR);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'hCursor', FmtStr);
end;
//=============================================================================
// ウィンドウの各種情報をリストビューに追加
//=============================================================================
procedure WindowInfos(LV: TListView; hWindow: HWND);
//---------------------------------------------------------------------------
procedure ListViewItemAdd(LV: TListView; ACaption, SubItem: String);
var
LVItem : TListItem;
begin
LVItem := LV.Items.Add;
LVItem.Caption := ACaption;
LVItem.SubItems.Text := SubItem;
end;
//---------------------------------------------------------------------------
var
Value : Integer;
FmtStr : String;
begin
ListViewItemAdd (LV, 'TEXT', GetWindowTextStr(hWindow));
FmtStr := Format('$%.8x (%d)', [hWindow, hWindow]);
ListViewItemAdd (LV, 'HANDLE', FmtStr);
Value := Windows.GetWindowLong(hWindow, GWL_EXSTYLE);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'EXSTYLE', FmtStr);
Value := Windows.GetWindowLong(hWindow, GWL_STYLE);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'STYLE', FmtStr);
Value := Windows.GetWindowLong(hWindow, GWL_WNDPROC);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'WNDPROC', FmtStr);
Value := Windows.GetWindowLong(hWindow, GWL_HINSTANCE);
FmtStr := Format('$%.8x', [Value]);
ListViewItemAdd (LV, 'HINSTANCE', FmtStr);
Value := Windows.GetWindowLong(hWindow, GWL_HWNDPARENT);
FmtStr := Format('$%.8x (%d)', [Value, Value]);
ListViewItemAdd (LV, 'HWNDPARENT', FmtStr);
Value := Windows.GetWindowLong(hWindow, GWL_ID);
FmtStr := Format('$%.8x (%d)', [Value, Value]);
ListViewItemAdd(LV, 'ID', FmtStr);
end;
//=============================================================================
// 引数のウィンドウがオーナーウィンドウであるかを調査
//=============================================================================
function IsOwnedWindow(hWindow: HWND): Boolean;
begin
Result := Windows.GetWindow(hWindow, GW_OWNER) <> 0;
end;
//-----------------------------------------------------------------------------
// EnumWindowsのコールバック関数
//-----------------------------------------------------------------------------
function EnumWndProc(hWindow: HWND; lData: LPARAM): BOOL; stdcall;
var
pWA : PHWndArray;
begin
pWA := PHWndArray(lData);
pWA^[0] := pWA^[0] + 1;
pWA^[pWA^[0]] := hWindow;
Result := True;
end;
//=============================================================================
// EnumWindowsのラッパー
// 全てのトップレベルウィンドウの列挙
//=============================================================================
function AEnumWindows(var WA: THWndArray): Integer;
begin
WA[0] := 0;
EnumWindows(@EnumWndProc, LPARAM(@WA));
Result := WA[0];
end;
//-----------------------------------------------------------------------------
// EnumWindowsのコールバック関数
//-----------------------------------------------------------------------------
function EnumVisbleNoOwnedWndProc(hWindow: HWND; lData: LPARAM): BOOL; stdcall;
var
pWA : PHWndArray;
begin
Result := True;
if IsOwnedWindow(hWindow) then exit;
if not Windows.IsWindowVisible(hWindow) then exit;
pWA := PHWndArray(lData);
pWA^[0] := pWA^[0] + 1;
pWA^[pWA^[0]] := hWindow;
end;
//=============================================================================
// 可視で所有されていないトップレベルウィンドウの列挙
//=============================================================================
function EnumVisbleNoOwnedWindows(var WA: THWndArray): Integer;
begin
WA[0] := 0;
EnumWindows(@EnumVisbleNoOwnedWndProc, LPARAM(@WA));
Result := WA[0];
end;
//=============================================================================
// 上のGetWindow版
// Z-Orderの高い方から列挙する
//=============================================================================
function EnumVisibleNoOwnedWindowAsZOrder(var WA: THWndArray): Integer;
var
hWindow : HWND;
begin
WA[0] := 0;
hWindow := GetWindow(Application.Handle, GW_HWNDFIRST);
while (hWindow <> 0) do begin
if (not IsOwnedWindow(hWindow)) and
Windows.IsWindowVisible(hWindow) then begin
WA[0] := WA[0] + 1;
WA[WA[0]] := hWindow;
end;
hWindow := Windows.GetWindow(hWindow, GW_HWNDNEXT);
end;
Result := WA[0];
end;
//=============================================================================
// ClassNameのウィンドウをZ-Orderの高い方から列挙する
//=============================================================================
function EnumWindowsOfClassNameAsZOrder(var WA: THWndArray;
ClassName: String): Integer;
var
hWindow : HWND;
begin
WA[0] := 0;
hWindow := Windows.GetWindow(Application.Handle, GW_HWNDFIRST);
while (hWindow <> 0) do begin
if (not IsOwnedWindow(hWindow)) and
Windows.IsWindowVisible(hWindow) and
(UpperCase(GetClassNameStr(hWindow)) = UpperCase(ClassName)) then begin
WA[0] := WA[0] + 1;
WA[WA[0]] := hWindow;
end;
hWindow := Windows.GetWindow(hWindow, GW_HWNDNEXT);
end;
Result := WA[0];
end;
//-----------------------------------------------------------------------------
// EnumThreadWindowsのコールバック関数
//-----------------------------------------------------------------------------
function EnumThreadWndProc(hWindow: HWND; lData: LPARAM): BOOL; stdcall;
var
pWA : PHWndArray;
begin
pWA := PHWndArray(lData);
pWA^[0] := pWA^[0] + 1;
pWA^[pWA^[0]] := hWindow;
Result := True;
end;
//=============================================================================
// EnumThreadWindows() のラッパー
// スレッド内のトップレベルウィンドウの列挙
//=============================================================================
function AEnumThreadWindows(var WA: THWndArray; OneOfHandles: HWND): Integer;
begin
WA[0] := 0;
EnumThreadWindows(Windows.GetWindowThreadProcessId(OneOfHandles,
nil),
@EnumThreadWndProc,
LPARAM(@WA));
Result := WA[0];
end;
//-----------------------------------------------------------------------------
// EnumChildWindowsのコールバック関数
//-----------------------------------------------------------------------------
function EnumChildWndProc(hWindow: HWND; lData: LPARAM): BOOL; stdcall;
var
pWA : PHWndArray;
begin
pWA := PHWndArray(lData);
pWA^[0] := pWA^[0] + 1;
pWA^[pWA^[0]] := hWindow;
Result := True;
end;
//=============================================================================
// EnumChildWindows() のラッパー
// 子,孫,ひ孫,...全部列挙
//=============================================================================
function AEnumChildWindows(var WA: THWndArray; hParent: HWND): Integer;
begin
WA[0] := 0;
EnumChildWindows(hParent, @EnumChildWndProc, LPARAM(@WA));
Result := WA[0];
end;
//=============================================================================
// 上で列挙したうち,特定のクラス名のもののハンドルを返す
//=============================================================================
function FindChildOfClass(hParent: HWND; ClassName: String): HWND;
var
WA : THWndArray;
i : Integer;
Num : Integer;
begin
Result := 0;
Num := AEnumChildWindows(WA, hParent);
if Num > 0 then begin
for i := 1 to Num do begin
if UpperCase(GetClassNameStr(WA[i])) = UpperCase(ClassName) then begin
Result := WA[i];
break;
end;
end;
end;
end;
//=============================================================================
// 直接の子ウィンドウのみ列挙する
//=============================================================================
function EnumDirectChildren(var WA: THWndArray; hParent: HWND): Integer;
var
hWindow : HWND;
begin
WA[0] := 0;
hWindow := Windows.GetWindow(hParent, GW_CHILD);
while (hWindow <> 0) do begin
WA[0] := WA[0] + 1;
WA[WA[0]] := hWindow;
hWindow := Windows.GetWindow(hWindow, GW_HWNDNEXT);
end;
Result := WA[0];
end;
//=============================================================================
// 任意のウィンドウから最上位のトップレベルウィンドウを取得する
//=============================================================================
function GetMostTopLevelWindow(hWindow: HWND): HWND;
var
hAncestor : HWND;
hPrev : HWND;
begin
hPrev := hWindow;
hAncestor := Windows.GetParent(hPrev);
while hAncestor <> 0 do begin
hPrev := hAncestor;
hAncestor := Windows.GetParent(hPrev);
end;
hAncestor := hPrev;
while hAncestor <> 0 do begin
hPrev := hAncestor;
hAncestor := Windows.GetWindow(hPrev, GW_OWNER);
end;
Result := hPrev;
end;
//=============================================================================
// 直接のOwnedウィンドウを列挙する
//=============================================================================
function EnumDirectOwnedWindows(var WA: THWndArray; hOwner: HWND): Integer;
var
WWA : THWndArray;
i : Integer;
Num : Integer;
begin
Result := 0;
Num := AEnumThreadWindows(WWA, hOwner);
if Num > 0 then begin
for i := 1 to Num do begin
if Windows.GetWindow(WWA[i], GW_OWNER) = hOwner then begin
Inc(Result);
WA[Result] := WWA[i];
end;
end;
end;
end;
end.
マウスカーソル下のウィンドウのハンドル取得のサンプルが,下記のリンクの記事にあります. |
図は IE (InternetExplorer) 8.0 の印刷の設定の際に現れる [ページ設定] ダイアログです.
このようなダイアログを遠隔操作するには,これらのウィンドウハンドルや入力項目の ID 値が必要となります.このダイアログのウィンドウのオーナーはシステムです,上のプログラムではオーナーを持つウィンドウはツリー表示しません. |
|
図3
IE 8.0の[ページ設定] |
これらのウィンドウをツリー表示で表示するには,コールバック関数の EnumVisbleNoOwnedWndProc を次のリストのコードのように修正します.修正して実行した結果が下図です.
このウィンドウの階層のツリー表示プログラムでウィンドウハンドルやID値がわかれば,[016_プリンタ設定ダイアログの遠隔操作] のように,ダイアログの遠隔操作ができるようになります. |
|
図4
[ページ設定] ウィンドウ |
リスト4
システム関係ダイアログ等も検出してツリーに含める方法
IsOwnedWindow (hWindow) then exit; を削除,またはコメントアウトする |
//-----------------------------------------------------------------------------
// EnumWindowsのコールバック関数
//-----------------------------------------------------------------------------
function EnumVisbleNoOwnedWndProc(hWindow: HWND; lData: LPARAM): BOOL; stdcall;
var
pWA : PHWndArray;
begin
Result := True;
// if IsOwnedWindow(hWindow) then exit;
if not Windows.IsWindowVisible(hWindow) then exit;
pWA := PHWndArray(lData);
pWA^[0] := pWA^[0] + 1;
pWA^[pWA^[0]] := hWindow;
end;
ウィンドウのツリー表示部で,ウィンドウを選択すると,そのウィンドウを囲む枠線を表示させるようにしたサンプルです.非表示のウィドウの時は表示しません.
枠線の表示には,WindowRectForm という別のフォームを使用しています.このフォームには,常に最前面に表示するためのコードを追加しています.追加したコードは,uses 部と,TreeView1 のOnChange イベントだけです. |
|
図5
ウィンドウを囲む枠線を表示 |
リスト5
ウィンドウを囲む枠線を表示するコードを追加 |
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
var
RectWnd : TRect;
RectWidth : Integer;
RectHeight : Integer;
LineWidth : Integer;
LineColor : TColor;
begin
if (Node.Level = 0) and (Node.Count = 0) then begin
EnumChildren(Node);
Node.Expand(True);
end;
ListView1.Items.Clear;
WinSearch.ClassInfos(ListView1, HWND(Node.Data));
ListView2.Items.Clear;
WinSearch.WindowInfos(ListView2, HWND(Node.Data));
if ListView1.Items.Count > 0 then ListView1.PopupMenu := PopupMenu1;
//TreeViewの選択したNodeに該当するウィンドウを囲む枠線を表示
//必要なければ以下を全て削除する
if TreeView1.Selected = nil then begin
WindowRectForm.Visible := False;
end else begin
if not Assigned(WindowRectForm) then begin
WindowRectForm := TWindowRectForm.Create(Self);
end;
//対象のウィンドウが非表示の時は枠を表示しない
if IsWindowVisible(HWND(Node.Data)) then begin
WindowRectForm.Refresh;
WindowRectForm.Visible := True;
GetWindowRect(HWND(Node.Data), RectWnd);
LineWidth := 4;
LineColor := clRed;
//サイズと位置を設定し最前面に表示する
RectWnd.Left := RectWnd.Left - LineWidth;
RectWnd.Top := RectWnd.Top - LineWidth;
RectWnd.Right := RectWnd.Right + LineWidth;
RectWnd.Bottom := RectWnd.Bottom + LineWidth;
RectWidth := RectWnd.Right - RectWnd.Left;
RectHeight := RectWnd.Bottom - RectWnd.Top;
WindowRectForm.SetBounds(RectWnd.Left, RectWnd.Top, RectWidth, RectHeight);
//枠線を描画
with WindowRectForm do begin
Canvas.Pen.Color := LineColor;
Canvas.Pen.Width := LineWidth;
Canvas.MoveTo(LineWidth, LineWidth);
Canvas.LineTo(Width - LineWidth, LineWidth);
Canvas.LineTo(Width - LineWidth, Height - LineWidth);
Canvas.LineTo(LineWidth, Height - LineWidth);
Canvas.LineTo(LineWidth, LineWidth);
end;
WindowRectForm.Update;
end else begin
WindowRectForm.Visible := False;
end;
end;
end;
|