Title: List desktop windows in C#
This program uses several API functions to list the windows running on the system's desktop. To make reusing the code easier, I made the key routines static in a static class so you don't need to instantiate the class to use them.
The following code shows API definitions used by the program. These tell C# which libraries contain the indicated methods.
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "GetWindowText",
ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowText(IntPtr hWnd,
StringBuilder lpWindowText, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "EnumDesktopWindows",
ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool EnumDesktopWindows(IntPtr hDesktop,
EnumDelegate lpEnumCallbackFunction, IntPtr lParam);
// Define the callback delegate's type.
private delegate bool EnumDelegate(IntPtr hWnd, int lParam);
Most of these are fairly straightforward, if a bit complicated. As long as you don't try to understand every detail, you should be okay. Note: The PInvoke.NET website is a great place to learn API declarations.
The last entry shown above defines a delegate named EnumDelegate to be a method that takes IntPtr and int parameters and that returns a bool. A delegate is basically a data type for a method with the indicated signature. If you look at the EnumDesktopWindows API function declaration, you'll see that one of its parameters is an EnumDelegate.
The following code shows the main API calls.
// Save window titles and handles in these lists.
private static List<IntPtr> WindowHandles;
private static List<string> WindowTitles;
// Return a list of the desktop windows' handles and titles.
public static void GetDesktopWindowHandlesAndTitles(
out List<IntPtr> handles, out List<string> titles)
{
WindowHandles = new List<IntPtr>();
WindowTitles = new List<string>();
if (!EnumDesktopWindows(IntPtr.Zero, FilterCallback,
IntPtr.Zero))
{
handles = null;
titles = null;
}
else
{
handles = WindowHandles;
titles = WindowTitles;
}
}
This code defines lists to hold the windows' handles and titles. It then calls the EnumDesktopWindows API function. That function returns true if it is successful and false otherwise. If the function returns false, then the GetDesktopWindowHandlesAndTitles method returns null lists. If the API function returns true, then the method returns the values it found.
So where exactly in this code do the windows' handles and titles get entered into the WindowHandles and WindowTitles collections? This happens through a callback method.
When the code calls EnumDesktopWindows, it passes as a parameter the following FilterCallback method. The EnumDesktopWindows API function calls FilterCallback for each of the desktop windows it finds.
// We use this function to filter windows.
// This version selects visible windows that have titles.
private static bool FilterCallback(IntPtr hWnd, int lParam)
{
// Get the window's title.
StringBuilder sb_title = new StringBuilder(1024);
int length = GetWindowText(hWnd, sb_title, sb_title.Capacity);
string title = sb_title.ToString();
// If the window is visible and has a title, save it.
if (IsWindowVisible(hWnd) &&
string.IsNullOrEmpty(title) == false)
{
WindowHandles.Add(hWnd);
WindowTitles.Add(title);
}
// Return true to indicate that we
// should continue enumerating windows.
return true;
}
The FilterCallback method inspects the windows found by the EnumDesktopWindows API function and it can then do something with them. In this example, the method gets the window's title and calls the IsWindowVisible API function to see if the window is visible. If the window is visible and has a non-blank title, the method saves the window's handle and title in the WindowHandles and WindowTitles lists.
The main program uses the following code to display the current desktop windows.
// Display a list of the desktop windows' titles.
private void ShowDesktopWindows()
{
List<IntPtr> handles;
List<string> titles;
DesktopWindowsStuff.GetDesktopWindowHandlesAndTitles(
out handles, out titles);
lstWindows.DataSource = titles;
}
This code calls the GetDesktopWindowHandlesAndTitles method. It then displays the result by setting the lstWindows ListBox control's DataSource property equal to the returned list of titles.
Download the example to experiment with it and to see additional details.
|