How to Use Enumwindows to Find Windows with a Specific Caption/Title

How can I use EnumWindows to find windows with a specific caption/title?

Original Answer

Use EnumWindows and enumerate through all the windows, using GetWindowText to get each window's text, then filter it however you want.

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowTextLength(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);

// Delegate to filter which windows to include
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

/// <summary> Get the text for the window pointed to by hWnd </summary>
public static string GetWindowText(IntPtr hWnd)
{
int size = GetWindowTextLength(hWnd);
if (size > 0)
{
var builder = new StringBuilder(size + 1);
GetWindowText(hWnd, builder, builder.Capacity);
return builder.ToString();
}

return String.Empty;
}

/// <summary> Find all windows that match the given filter </summary>
/// <param name="filter"> A delegate that returns true for windows
/// that should be returned and false for windows that should
/// not be returned </param>
public static IEnumerable<IntPtr> FindWindows(EnumWindowsProc filter)
{
IntPtr found = IntPtr.Zero;
List<IntPtr> windows = new List<IntPtr>();

EnumWindows(delegate(IntPtr wnd, IntPtr param)
{
if (filter(wnd, param))
{
// only add the windows that pass the filter
windows.Add(wnd);
}

// but return true here so that we iterate all windows
return true;
}, IntPtr.Zero);

return windows;
}

/// <summary> Find all windows that contain the given title text </summary>
/// <param name="titleText"> The text that the window title must contain. </param>
public static IEnumerable<IntPtr> FindWindowsWithText(string titleText)
{
return FindWindows(delegate(IntPtr wnd, IntPtr param)
{
return GetWindowText(wnd).Contains(titleText);
});
}

For example, to get all of the windows with "Notepad" in the title:

var windows = FindWindowsWithText("Notepad");

Win32Interop.WinHandles

This answer proved popular enough that I created an OSS project, Win32Interop.WinHandles to provide an abstraction over IntPtrs for win32 windows. Using the library, to get all of the windows that contains "Notepad" in the title:

var allNotepadWindows
= TopLevelWindowUtils.FindWindows(wh => wh.GetWindowText().Contains("Notepad"));

Find Window By Caption what is the caption of the window?

The following question addresses how to find out when programs launch. Detecting the launch of a application Also, you can enumerate windows on your machine with a dll import and using EnumWindows. Sample pInvokes that will help you are listed.

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool IsWindowVisible(IntPtr hWnd);

Finding multiple windows with the same title

Call EnumWindows to enumerate top-level windows. For each such window, call GetWindowText to find out its text which you can then compare against your target value.

If you are looking for windows in a specific process, use GetWindowThreadProcessId.

Win32's FindWindow() can find a particular window with the exact title, but what about try.bat - Notepad?

I would follow Eric's advice to use EnumWindows. You can provide Ruby callbacks to Windows API functions through win32-api. Here's an example that was trivially modified from the sample in the win32-api README:

require 'win32/api'
include Win32

# Callback example - Enumerate windows
EnumWindows = API.new('EnumWindows', 'KP', 'L', 'user32')
GetWindowText = API.new('GetWindowText', 'LPI', 'I', 'user32')
EnumWindowsProc = API::Callback.new('LP', 'I'){ |handle, param|
buf = "\0" * 200
GetWindowText.call(handle, buf, 200);

if (!buf.index(param).nil?)
puts "window was found: handle #{handle}"
0 # stop looking after we find it
else
1
end
}

EnumWindows.call(EnumWindowsProc, 'Firefox')

How do I detect if a window of another application is open?

Your method signature is incorrect. It should return IntPtr, not Long.

Try the following:

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr

Private Sub btnCheckWindow_Click(sender As Object, e As EventArgs) Handles btnCheckWindow.Click
Dim result As IntPtr= FindWindow(Nothing, "lkhsdlfhslfh")
If result = IntPtr.Zero Then
MsgBox("Window not found.")
Else
MsgBox("Found it.")
End If
End Sub

Alternatively, you could use <DllImport>, which is the standard way in .NET:

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Private Shared Function FindWindow(
ByVal lpClassName As String,
ByVal lpWindowName As String) As IntPtr
End Function

Note that unless you're dealing with an ancient program, you should probably use a Unicode charset. This means using FindWindowW (instead of FindWindowA) if you go with Declare or CharSet.Unicode if you go with <DllImport>.

Issue with EnumWindows

To get the main window of a process, use the Process.MainWindowHandle property.

To answer your question, you can see exactly what all of the handles are using Spy++.

In short, many applications will create hidden windows to run message loops.

How to get captions of actual windows currently running?

The important information is contained in the MSDN topic describing the taskbar. Essentially you need to enumerate the top-level windows and pick out those that are visible, unowned and have the WS_EX_APPWINDOW window style.

This program shows you how it is done:

program EnumTaskbarWindows;

{$APPTYPE CONSOLE}

uses
SysUtils, Windows;

function EnumWindowsProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
s: string;
IsVisible, IsOwned, IsAppWindow: Boolean;
begin
Result := True;//carry on enumerating

IsVisible := IsWindowVisible(hwnd);
if not IsVisible then
exit;

IsOwned := GetWindow(hwnd, GW_OWNER)<>0;
if IsOwned then
exit;

IsAppWindow := GetWindowLongPtr(hwnd, GWL_STYLE) and WS_EX_APPWINDOW<>0;
if not IsAppWindow then
exit;

SetLength(s, GetWindowTextLength(hwnd));
GetWindowText(hwnd, PChar(s), Length(s)+1);
Writeln(s);
end;

begin
EnumWindows(@EnumWindowsProc, 0);
end.


Related Topics



Leave a reply



Submit