Click here to Skip to main content
15,885,757 members
Articles / Programming Languages / C#

Logging Active Window Titles

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
1 Oct 2012CPOL3 min read 33.4K   1.5K   13   3
Keep on forgetting what you did an hour ago? Get some hints from your past window titles!

Introduction 

Have you ever ran into the situation where you can't remember what you did a few hours ago and you need to create your time sheet entries for the day? The window titles of the various applications running on your windows desktop often give great hints and reminders on what you have been doing. This console application uses a few PInvoke calls to periodically log information on the currently active window to the console.

Background  

At time cockpit, we have an application that tracks hints (something we refer to as a signal) from various sources, such as the changed files, the available wireless networks, active windows, when user input happened, etc. When the time comes that you need a little reminder, the application presents this information in a calendar. Of course all of this is encrypted to ensure the privacy of the user. The active window title tracker is the one that most of the time saves my neck so I thought we should share that code along with a sample application in case you wanted to do something similar.

Using the code 

Most of the code in the sample deals with retrieving the current foreground window using GetForegroundWindow and its associated process. Using PInvoke, it is easy to call this Win32 method using the following snippet (the other functions will be explained below): 

C#
private class NativeMethods
{
  DllImport("user32.dll")]
  public static extern IntPtr GetForegroundWindow();
 
  [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
  public static extern int GetWindowThreadProcessId(IntPtr windowHandle, out int processId);
 
  [DllImport("user32.dll")]
  public static extern int GetWindowText(int hWnd, StringBuilder text, int count);
}      

While those attributes seem cryptic they are easy to find by browsing the pinvoke.net website for the API calls you want to call. 

The first thing the periodic WriteCurrentWindowInformation() function does is to retrieve the handle to the current window title and will only continue if the active id is not a null handle: 

C#
var activeWindowId = NativeMethods.GetForegroundWindow();
if (activeWindowId.Equals(0))
{
  return;
} 

Since in some cases the window title might be empty (some java processes, in particular) we then retrieve the processId that the window handle belongs to using GetWindowThreadProcessId(). We also check this against 0 to assert a valid handle:

C#
int processId;
NativeMethods.GetWindowThreadProcessId(activeWindowId, out processId);
if (processId == 0)
{
  return;
}   

Using the id of the process, we can use the Process.GetProcessById() function to retrieve a Process structure. This structure reveals information such as the name of the process, possibly a file description in the executable or a product name that the window belongs to. 

In the code sample, there are multiple try / catch blocks wrapping accesses to the process information to protect against security exceptions, since admin processes may not allow retrieving such information. Finally, the last two blocks retrieve the window title: If the window title of the Process is empty, we  use the GetWindowText method to retrieve the window title by passing in the window handle of the main window (the surrounding try / catch blocks are omitted for brevity here):  

C#
if (!string.IsNullOrEmpty(foregroundProcess.MainWindowTitle))
{
  windowTitle = foregroundProcess.MainWindowTitle;
}
 
if (string.IsNullOrEmpty(windowTitle))
{
  const int Count = 1024;
  var sb = new StringBuilder(Count);
  NativeMethods.GetWindowText((int)activeWindowId, sb, Count);
  windowTitle = sb.ToString();
}    

We have found that for some processes, the MainWindowTitle sometimes remains empty 

Something to point out is the use of a StringBuilder as a buffer for a return value of a native call. A detailed discussion on PInvoke parameter marshaling can be found in this article.  

Last but not least, the main loop driving the example periodically polls the WriteCurrentWindowInformation() function using a simple call to <a title="Thread.Sleep MSDN documentation" href="http://msdn.microsoft.com/de-de/library/vstudio/d00bd51t.aspx">Thread.Sleep()</a>. 

Points of Interest  

The polling nature of the sample will probably scare some of you off and I agree that it would be nicer to be notified if the current foreground window changes. The approach has been shown here but there are multiple downsides to this: If an application changes the window title, no notification would occur. This happens quite often when files are saved or, e.g. if a different solution is opened from within Visual Studio. 

Another interesting point is that the code provided also delivers a meaningful title for Windows Store apps which were introduced with Windows 8.

While the window / application title is quite useful, at time cockpit we are exploring ways of using UI Automation to find a more specific title as this would allow introspecting the complete control tree, therefore making it possible to retrieve the title of the tab for currently focused document in Visual Studio.  

History 

2012-10-01: Updated points of interest to point to a callback solution. 

2012-10-01: First release of this article. The code presented here has been in production use by the time cockpit's signal trackers for over 3 years now.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer software architects gmbh
Austria Austria
Philipp Aumayr has been working at time cockpit for over 3 years now and enjoys the ongoing c++ renaissance.

Comments and Discussions

 
Praisethanks Pin
Mark7Quest19-Jul-19 6:27
Mark7Quest19-Jul-19 6:27 
GeneralMy vote of 5 Pin
Corral David16-Dec-15 4:19
Corral David16-Dec-15 4:19 
QuestionCodeFile Pin
adis4120-Feb-14 7:11
adis4120-Feb-14 7:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.