API関数のEnumWindowsを使うことで、全てのウィンドウのハンドル(HWND)を取得する事ができる。 EnumWindowsを呼び出すと、コールバックメソッドが呼び出され、存在する個々のウィンドウのHWNDが渡される。

以下の例では、EnumWindows()でウィンドウを列挙し、コールバックメソッド内ではIsWindowVisible()を使って可視ウィンドウかどうかを調べている。 また、個々の可視ウィンドウについて、GetWindowText()を使ってウィンドウのキャプションを、GetWindowThreadProcessId()とProcess.GetProcessByIdを使ってプロセス情報を取得・表示している。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

class Sample {
  [DllImport("user32")]
  private static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, IntPtr lParam);

  // EnumWindowsから呼び出されるコールバック関数WNDENUMPROCのデリゲート
  private delegate bool WNDENUMPROC(IntPtr hWnd, IntPtr lParam);

  [DllImport("user32")]
  private static extern bool IsWindowVisible(IntPtr hWnd);

  [DllImport("user32", CharSet = CharSet.Auto)]
  private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

  [DllImport("user32")]
  private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

  static void Main()
  {
    // ウィンドウの列挙を開始
    EnumWindows(EnumerateWindow, IntPtr.Zero);
  }

  // ウィンドウを列挙するためのコールバックメソッド
  private static bool EnumerateWindow(IntPtr hWnd, IntPtr lParam)
  {
    // ウィンドウが可視かどうか調べる
    if (IsWindowVisible(hWnd))
      // 可視の場合
      PrintCaptionAndProcess(hWnd);

    // ウィンドウの列挙を継続するにはtrueを返す必要がある
    return true;
  }

  // ウィンドウのキャプションとプロセス名を表示する
  private static void PrintCaptionAndProcess(IntPtr hWnd)
  {
    // ウィンドウのキャプションを取得・表示
    StringBuilder caption = new StringBuilder(0x1000);

    GetWindowText(hWnd, caption, caption.Capacity);

    Console.Write("'{0}' ", caption);

    // ウィンドウハンドルからプロセスIDを取得
    int processId;

    GetWindowThreadProcessId(hWnd, out processId);

    // プロセスIDからProcessクラスのインスタンスを取得
    Process p = Process.GetProcessById(processId);

    // プロセス名を表示
    Console.WriteLine("({0})", p.ProcessName);
  }
}
Imports System
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports System.Text

Class Sample
  <DllImport("user32")> _
  Private Shared Function EnumWindows(ByVal lpEnumFunc As WNDENUMPROC, ByVal lParam As IntPtr) As Boolean
  End Function

  ' EnumWindowsから呼び出されるコールバック関数WNDENUMPROCのデリゲート
  Private Delegate Function WNDENUMPROC(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean

  <DllImport("user32")> _
  Private Shared Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
  End Function

  <DllImport("user32", CharSet := CharSet.Auto)> _
  Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As Integer
  End Function

  <DllImport("user32")> _
  Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, <Out> ByRef lpdwProcessId As Integer) As Integer
  End Function

  Public Shared Sub Main()
    ' ウィンドウの列挙を開始
    EnumWindows(AddressOf EnumerateWindow, IntPtr.Zero)
  End Sub

  ' ウィンドウを列挙するためのコールバックメソッド
  Private Shared Function EnumerateWindow(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
    ' ウィンドウが可視かどうか調べる
    If IsWindowVisible(hWnd) Then
      ' 可視の場合
      PrintCaptionAndProcess(hWnd)
    End If

    ' ウィンドウの列挙を継続するにはTrueを返す必要がある
    Return True
  End Function

  ' ウィンドウのキャプションとプロセス名を表示する
  Private Shared Sub PrintCaptionAndProcess(ByVal hWnd As IntPtr)
    ' ウィンドウのキャプションを取得・表示
    Dim caption As New StringBuilder(&h1000)

    GetWindowText(hWnd, caption, caption.Capacity)

    Console.Write("'{0}' ", caption)

    ' ウィンドウハンドルからプロセスIDを取得
    Dim processId As Integer

    GetWindowThreadProcessId(hWnd, processId)

    ' プロセスIDからProcessクラスのインスタンスを取得
    Dim p As Process = Process.GetProcessById(processId)

    ' プロセス名を表示
    Console.WriteLine("({0})", p.ProcessName)
  End Sub
End Class
出力例
'Windows タスク マネージャ' (taskmgr)
'スタート' (explorer)
'' (explorer)
'C:\Windows\system32\cmd.exe - test.exe  ' (cmd)
'test.vb - メモ帳' (notepad)
'test.cs - メモ帳' (notepad)
'D:\' (explorer)
'Program Manager' (explorer)

なお、可視でないウィンドウも列挙するには、IsWindowVisible()の部分を削除すればよい。