This is the first post in a short series. This post covers the determination of what executable is currently in the foreground.
What with all the hubbub regarding “Telemetry” privacy, and the like regarding Windows 10, I actually decided it would be interesting information to have for my own purposes to track some tidbits. In particular, I have decided it would be interesting to chart/track the various foreground applications I have open. How long, for example, do I use Visual Studio? My Web Browser? The Command Prompt? etc. I decided to take the most straightforward approach- a background program that merely logs, every few seconds, what the foreground application is. No need to complicate it too much- write out the data and then that data can be imported.
Even so, I have, however, hemmed and hawwed about whether it would be wise to even share it. Not, mind you, for any IP concerns- but rather whether it is wise to share code and logic that, while I was using it for a benevolent purpose, could easily be used for malicious purposes. It’s something of an ethical dilemma. Should we refrain from sharing code that could be used maliciously? I don’t think so, because pretty much any code can be used for malicious purposes. On the other hand- something like watching every program that is running in the background with no user intervention is something very easily co-opted for purposes against the users consent.
I’ve decided to share the code and it’s engineering anyway. Those seeking to write malicious code will be able to write that malicious code with our without help; there isn’t really a need to censor oneself based on what others might do with the information provided. Even if the road to hell is paved with the best intentions, I’m not the one putting those cobblestone bricks of good intentions onto the roadway, though I am responsible for stretching that analogy beyond the point where it is useful.
Engineering
Now, with that out of the way, we can turn to the program itself. I thought I would compartmentalize particular parts of it into different blog posts. It’s much easier to cover smaller parts of the program likely for the same reason we write code as a series of classes and methods, as it makes things easier to understand overall.
The core seems fairly straightforward- if we want to log foreground applications, we create a background program that uses a timer that will check the foreground program every, say, 5 seconds, and write out the foreground program to a log file. We’ll cover that part later- but to start with, we’ll want to be able to determine what the current foreground process is at any one time.
Retrieving the Foreground Process
Before we get to the plumbing, let’s explore this problem- how do we determine what the current foreground application is at a given time? We can use the GetForegroundWindow() API function to retrieve the foreground Window; we can then use that window hWnd and determine the ProcessID with the GetWindowThreadProcessID() function, and use that ProcessID in a Process.GetProcessByID call. At which point we can retrieve the executable file for the application by using the FileName property of the MainModule of that Process. The first order of business, is the NativeMethods.cs class, as we will be using Win32 API P/Invoke calls. This is, of course, not a strict requirement- realistically we can declare DllImport externals wherever we please, However, in C# it is considered good design to have Native Win32 Calls separated into a separate class as static methods. This makes a lot of sense, so I’ll be doing it here:
1 2 3 4 5 6 7 8 9 |
using System; using System.Runtime.InteropServices; public static class NativeMethods { [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId); } |
With that in place, we can write our function to get the Active Process:
1 2 3 4 5 6 7 8 |
private String GetActiveProcess() { uint procid; IntPtr hWnd = NativeMethods.GetForegroundWindow(); NativeMethods.GetWindowThreadProcessId(hWnd,out procid); Process ForegroundProcess = Process.GetProcessById((int)procid); return retrieve.MainModule.FileName; } |
This isn’t bulletproof, mind you- however, we can do two things to help that. First, we can check for 0 being returned from GetForegroundWindow. We can also check the return value of GetWindowThreadProcessId()- it returns 0 if the provided handle is not a Window Handle, which is a possible race condition. We can also wrap the call to GetProcessById() in an exception handler, to handle the race condition where we retrieve a Process ID but before we retrieve the Process itself, it terminates:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
private String GetActiveProcess() { uint procid; IntPtr hWnd = NativeMethods.GetForegroundWindow(); if(hWnd==IntPtr.Zero) return null; if(!NativeMethods.GetWindowThreadProcessId(hWnd,out procid)) return null; Process ForegroundProcess = null; try { ForegroundProcess = Process.GetProcessById((int)procid); } catch(Exception exx) { return null; } try { return retrieve.MainModule.FileName; } catch(Exception exx) { return retrieve.ProcessName; } } |
Now, this is all well and good. But perhaps we’ve not considered future additions. In particular, perhaps we want to retrieve the Window Text of that foreground Window as well? As it stands we’re returning one string result. If we want to add more information, we can encapsulate the return value into either a struct or a class. In this case, I’ve gone with a class:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class ForegroundProcessResult { public String ExecutablePath {get; set; } public String WindowText {get; set; } public ForegroundProcessResult() { } public ForegroundProcessResult(String pExecutablePath, String pWindowText) { ExecutablePath = pExecutablePath; WindowText = pWindowText; } } |
Here I’ve chosen to add the WindowText. An instance of this class will be used as the return value of the GetActiveProcess() function. But, hold on a second- GetActiveProcess is a terrible name, isn’t it? since an Active Process is effectively one that is running (as opposed to, say, a suspended process). So let’s rename the function to GetForegroundProcess. Meanwhile, we’ll want to add the ability to retrieve the Window Text, as well. We do this by adding the appropriate Win32API functions to our NativeMethods class:
1 2 3 4 5 |
[DllImport("user32.dll")] public static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int GetWindowText(IntPtr hWnd,StringBuilder lpString, int nMaxCount); |
Then we can make appropriate revisions to the GetActiveProcess() method, including giving it a proper name. Furthermore, GetProcessId() doesn’t return null, so my checking for it in the original segment was unnecessary. Instead, we want to catch ArgumentException and InvalidOperationException. In those cases we should return null straight up because we cannot retrieve the Foreground Process at all so any result we give wouldn’t be reliable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
private ForegroundProcessResult GetForegroundProcess() { IntPtr hWnd = NativeMethods.GetForegroundWindow(); uint proc; String AcquiredWindowText = ""; int CaptionLength = NativeMethods.GetWindowTextLength(hWnd); if (CaptionLength > 0) { StringBuilder sbb= new StringBuilder(); int result = NativeMethods.GetWindowText(hWnd, sbb, CaptionLength); AcquiredWindowText = sbb.ToString(); } NativeMethods.GetWindowThreadProcessId(hWnd, out proc); Process retrieve = null; try { retrieve = Process.GetProcessById((int) proc); } catch (ArgumentException ae) { //probably exited. return null; } catch (InvalidOperationException ioe) { //likely a permissions or similar error. return null; } try { return new ForegroundProcessResult(retrieve.MainModule.FileName, AcquiredWindowText); } catch (Exception exx) { return new ForegroundProcessResult(retrieve.ProcessName, AcquiredWindowText); } } |
With these underpinnings in place, we can start to construct the code that makes use of it and polls the active process- and finally, we’ll look into creating a useful UI for the program- such as a Notification Icon that can be used to start or stop the logging, or to configure options such as the delay.
Have something to say about this post? Comment!