2008年1月10日木曜日

タスクバーに表示されたウィンドウの取得の違い(C#)

タスクバーに表示されたウィンドウ(下の図のような)を取得しようと思ったが、意外に難しい。




とりあえず、C#のProcessクラスを使ってみる。
(ちなみに、IDEは"Microsoft Visual C# 2008 Express Edition"です)

foreach (Process p in Process.GetProcesses())
{
  // ウィンドウを持つプロセスのみをコンソールに表示
  if (p.MainWindowHandle != IntPtr.Zero)
  {
    Console.WriteLine(p.ProcessName + " : " + p.MainWindowTitle);
  }
}

これを実行すると、ウィンドウを持つプロセスが全て表示される。

しかし、ウィンドウが非表示のプロセスも表示されてしまう。

さらに、フォルダはエクスプローラが1つだけ表示される。
(元々、エクスプローラにフォルダを読み込んでるだけだから当然と言えば当然)


別の方法でやってみる。今度はWin 32を利用する。

// "DllImport"用に名前空間の修飾省略定義を行う
using System.Runtime.InteropServices;

// コールバックメソッドのデリゲート
private delegate int EnumerateWindowsCallback(IntPtr hWnd, int lParam);

// EnumWindows API関数の宣言
[DllImport("user32.dll", EntryPoint = "EnumWindows")]
private static extern int EnumWindows(EnumerateWindowsCallback lpEnumFunc, int lParam);

// GetWindowText API関数の宣言
[DllImport("user32.dll", EntryPoint = "GetWindowText", CharSet = CharSet.Auto)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCoun//

// IsWindowVisible API関数の宣言
[DllImport("user32.dll", EntryPoint = "IsWindowVisible")]
private static extern int IsWindowVisible(IntPtr hWnd);

// ウィンドウを列挙するためのコールバックメソッド
public static int EnumerateWindows(IntPtr hWnd, int lParam)
{
  const int BUFFER_SIZE = 0x1000;
  StringBuilder sb = new StringBuilder(BUFFER_SIZE);

  // ウィンドウが可視の場合
  if (IsWindowVisible(hWnd) != 0)
  {
    // ウィンドウのキャプションを取得
    if (GetWindowText(hWnd, sb, BUFFER_SIZE) != 0)
    {
      Console.WriteLine(sb);
    }
  }
  // 列挙を継続するには0以外を返す必要がある
  return 1;
}

実行は

EnumWindows(new EnumerateWindowsCallback(EnumerateWindows), 0);
と叩くだけ。

これだと、表示されているウィンドウのみが、コンソールに出力される。
(実際に出力されるのは、ウィンドウのタイトル)
"タスク マネージャ"の"アプリケーション"に表示されているものが取得できる。

しかし、今度は"Program Manager"というタイトルのウィンドウも出力される。
こいつは一体なんだ?
色々試してみると、どうやらデスクトップアイコンを管理しているらしい。
他にも何か管理(Managerだからね)してるかもしれない。


まとめると、
ウィンドウの表示・非表示に関わらず、取得したい場合はC#で。
ウィンドウが表示されているもののみを取得したい場合はWin32で。

2種類の方法は状況に応じて使い分けると良さそうだ。(もしくは混合する)


参照:smdn/プログラミングとか趣味のいろいろ

0 件のコメント: