Connecting UWP applications hosted by ApplicationFrameHost to their actual processes

I am working on a WPF application to monitor my activities on my computer. I use Process.GetProcesses() and some filtering to get the processes that interest me (example: Calculator), after which I write their StartTime. I also use the WIN32 / USER32 GetForegroundWindow() API method to get the window that the user is using.

The problem is that when Windows is a Windows / UWP application, they are always hosted in the ApplicationFrameHost process. Thus, the GetForegroundWindow() method returns this window with a title (example: Calculator), but is not a real placement process.

I need either another way to get the foreground window, which includes hosting the real process, or somehow connect the window to the process.

Who knows how to do this? All help would be really appreciated.

+8
source share
2 answers

In the end, I found a way to do this, so I'm going to answer my own question, so maybe someone in the future with the same problem might find it useful.

This is a class with WinApiFunctions:

 public class WinAPIFunctions { //Used to get Handle for Foreground Window [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr GetForegroundWindow(); //Used to get ID of any Window [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); public delegate bool WindowEnumProc(IntPtr hwnd, IntPtr lparam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc callback, IntPtr lParam); public static int GetWindowProcessId(IntPtr hwnd) { int pid; GetWindowThreadProcessId(hwnd, out pid); return pid; } public static IntPtr GetforegroundWindow() { return GetForegroundWindow(); } } 

And this is the class that I used to check if it would work. I used it in a simple console program that simply writes the name of a process that has the current focus:

 class FindHostedProcess { public Timer MyTimer { get; set; } private Process _realProcess; public FindHostedProcess() { MyTimer = new Timer(TimerCallback, null, 0, 1000); Console.ReadKey(); } private void TimerCallback(object state) { var foregroundProcess = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(WinAPIFunctions.GetforegroundWindow())); if (foregroundProcess.ProcessName == "ApplicationFrameHost") { foregroundProcess = GetRealProcess(foregroundProcess); } Console.WriteLine(foregroundProcess.ProcessName); } private Process GetRealProcess(Process foregroundProcess) { WinAPIFunctions.EnumChildWindows(foregroundProcess.MainWindowHandle, ChildWindowCallback, IntPtr.Zero); return _realProcess; } private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam) { var process = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(hwnd)); if (process.ProcessName != "ApplicationFrameHost") { _realProcess = process; } return true; } } 
+10
source

Chris, there is an alternative way that I discovered while trying to apply your solution to a related problem . While trying to analyze how ApplicationFrameHost.exe -related works, I came across a documented way to get the true foreground window / thread and its process by passing 0 instead of the actual thread id in GetGUIThreadInfo .

It may not work fully for the scenarios of your problem, but I felt that it could be a useful contribution for people of the future who might face the same problems ;-)

Here is an example of how this can be applied (pseudo-C ++ 'ish code):

 GUITHREADINFO gti = { sizeof(GUITHREADINFO) }; GetGUIThreadInfo(0, &gti); // <- note the '0' DWORD processId = 0; GetWindowThreadProcessId(gti.hwndFocus, &processId); const auto procName = Util::GetProcessName(processId); 

This solved my problem (getting the actual keyboard layout + finding a real foreground window) for all the more or less common applications that I tested with.

+1
source

All Articles