WindowTitleWatcher 0.1.2

Allows accessing and watching window titles and states of foreign processes.

Install-Package WindowTitleWatcher -Version 0.1.2
dotnet add package WindowTitleWatcher --version 0.1.2
<PackageReference Include="WindowTitleWatcher" Version="0.1.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add WindowTitleWatcher --version 0.1.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

Usage

After the library has been added to your project, it is available within the namespaces WindowTitleWatcher and WindowTitleWatcher.Util.

Retrieve a title

The simplest way of retrieving a window's information is through WindowTitleWatcher.Util.WindowInfo. Example:

using WindowTitleWatcher.Util;
using System.Diagnostics;
// ...

var window = new WindowInfo(Process.GetProcessById(12345).MainWindowHandle);
Console.WriteLine(window.ProcessId);    // 12345
Console.WriteLine(window.ProcessName);  // "notepad"
Console.WriteLine(window.IsVisible);    // true
Console.WriteLine(window.Title);        // "Untitled - Notepad"

BasicWatcher: Watch for updates

WindowTitleWatcher.BasicWatcher is an extension of the abstract Watcher class and provides facilities for accessing a specific window's title, visibility state, and also whether that window still exists. Events are included that fire when any of the aforementioned properties change.

BasicWatcher instances can be constructed with any of the following:

  • a System.Diagnostics.Process object (whose main window will be chosen)
  • a WindowTitleWatcher.Util.WindowInfo object
  • a window handle in the form of an IntPtr

The watcher can optionally keep its own process alive as long as the watched window exists, although that is not default behavior.

Example:

using WindowTitleWatcher;
using System.Diagnostics;
// ...

var watcher = new BasicWatcher(Process.GetProcessById(12345));
Console.WriteLine(watcher.Title); // log current window title
Console.WriteLine(watcher.IsVisible);

watcher.TitleChanged += (sender, e) =>
{
    Console.WriteLine(e.PreviousTitle + " -> " + e.NewTitle);
};
watcher.VisibilityChanged += (sender, e) =>
{
    Console.WriteLine(watcher.IsVisible ? "shown" : "hidden");
};
watcher.Disposed += (sender, e) =>
{
    Console.WriteLine("Window is disposed and cannot be watched further.");
    // The foreign process has disposed the watched window.
    // At this point, the watcher thread will exit.
};

RecurrentWatcher: Watch windows that might close/reopen

A RecurrentWatcher is used when the watching should not stop after the window's disposal. It will then later reactivate when another window matching some criteria appears.

For this, it uses a generator function supplied by you, which should return quickly as it may be called hundreds of times each second. Its return value should either be a WindowInfo instance (or null if none found at the moment), or, alternatively, an IntPtr to the window handle (or IntPtr.Zero if none found).

using WindowTitleWatcher;
// ...

var watcher = new RecurrentWatcher(() => /* your generator function */);

Window enumeration and filtered lookup

Details about the target window, such as its handle or the process's id (PID), are often unknown. This is why the WindowTitleWatcher.Util.Windows class provides static methods for enumerating all active windows as well as for finding windows matching your criteria.

Example for finding a window for the Notepad application:

using WindowTitleWatcher;
using WindowTitleWatcher.Util;
// ...

WindowInfo window = Windows.FindFirst(w => w.IsVisible && w.ProcessName == "notepad");
if (window != null)
{
    // The window exists, create a watcher:
    BasicWatcher watcher = new BasicWatcher(window);
    // ...
}

Using window lookup with RecurrentWatcher

The most powerful setup is using Windows.FindFirst as a generator for the RecurrentWatcher, as it is able to very reliably watch any window even after it has been closed and only later reopened.

Example:

var watcher = new RecurrentWatcher(() => Windows.FindFirst(w => w.ProcessName == "notepad"));
watcher.TitleChanged += (sender, e) => Console.WriteLine(e.NewTitle);

Usage

After the library has been added to your project, it is available within the namespaces WindowTitleWatcher and WindowTitleWatcher.Util.

Retrieve a title

The simplest way of retrieving a window's information is through WindowTitleWatcher.Util.WindowInfo. Example:

using WindowTitleWatcher.Util;
using System.Diagnostics;
// ...

var window = new WindowInfo(Process.GetProcessById(12345).MainWindowHandle);
Console.WriteLine(window.ProcessId);    // 12345
Console.WriteLine(window.ProcessName);  // "notepad"
Console.WriteLine(window.IsVisible);    // true
Console.WriteLine(window.Title);        // "Untitled - Notepad"

BasicWatcher: Watch for updates

WindowTitleWatcher.BasicWatcher is an extension of the abstract Watcher class and provides facilities for accessing a specific window's title, visibility state, and also whether that window still exists. Events are included that fire when any of the aforementioned properties change.

BasicWatcher instances can be constructed with any of the following:

  • a System.Diagnostics.Process object (whose main window will be chosen)
  • a WindowTitleWatcher.Util.WindowInfo object
  • a window handle in the form of an IntPtr

The watcher can optionally keep its own process alive as long as the watched window exists, although that is not default behavior.

Example:

using WindowTitleWatcher;
using System.Diagnostics;
// ...

var watcher = new BasicWatcher(Process.GetProcessById(12345));
Console.WriteLine(watcher.Title); // log current window title
Console.WriteLine(watcher.IsVisible);

watcher.TitleChanged += (sender, e) =>
{
    Console.WriteLine(e.PreviousTitle + " -> " + e.NewTitle);
};
watcher.VisibilityChanged += (sender, e) =>
{
    Console.WriteLine(watcher.IsVisible ? "shown" : "hidden");
};
watcher.Disposed += (sender, e) =>
{
    Console.WriteLine("Window is disposed and cannot be watched further.");
    // The foreign process has disposed the watched window.
    // At this point, the watcher thread will exit.
};

RecurrentWatcher: Watch windows that might close/reopen

A RecurrentWatcher is used when the watching should not stop after the window's disposal. It will then later reactivate when another window matching some criteria appears.

For this, it uses a generator function supplied by you, which should return quickly as it may be called hundreds of times each second. Its return value should either be a WindowInfo instance (or null if none found at the moment), or, alternatively, an IntPtr to the window handle (or IntPtr.Zero if none found).

using WindowTitleWatcher;
// ...

var watcher = new RecurrentWatcher(() => /* your generator function */);

Window enumeration and filtered lookup

Details about the target window, such as its handle or the process's id (PID), are often unknown. This is why the WindowTitleWatcher.Util.Windows class provides static methods for enumerating all active windows as well as for finding windows matching your criteria.

Example for finding a window for the Notepad application:

using WindowTitleWatcher;
using WindowTitleWatcher.Util;
// ...

WindowInfo window = Windows.FindFirst(w => w.IsVisible && w.ProcessName == "notepad");
if (window != null)
{
    // The window exists, create a watcher:
    BasicWatcher watcher = new BasicWatcher(window);
    // ...
}

Using window lookup with RecurrentWatcher

The most powerful setup is using Windows.FindFirst as a generator for the RecurrentWatcher, as it is able to very reliably watch any window even after it has been closed and only later reopened.

Example:

var watcher = new RecurrentWatcher(() => Windows.FindFirst(w => w.ProcessName == "notepad"));
watcher.TitleChanged += (sender, e) => Console.WriteLine(e.NewTitle);

Release Notes

Added Title property to WindowInfo

Dependencies

This package has no dependencies.

This package is not used by any popular GitHub repositories.

Version History

Version Downloads Last updated
0.1.2 229 8/1/2018
0.1.1 418 7/27/2017
0.1.0 383 6/30/2017