UWP apps are wrapped into an other app/process. If this has focus, then try and find the child UWP process.
You will need some P/Invoke methods. Take a look at this class, which provide all the code you need to do the job:
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace Stackoverflow
{
internal struct WINDOWINFO
{
public uint ownerpid;
public uint childpid;
}
public class UwpUtils
{
#region User32
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
/// <summary>
/// Delegate for the EnumChildWindows method
/// </summary>
/// <param name="hWnd">Window handle</param>
/// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
/// <returns>True to continue enumerating, false to bail.</returns>
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowProc lpEnumFunc, IntPtr lParam);
#endregion
#region Kernel32
public const UInt32 PROCESS_QUERY_INFORMATION = 0x400;
public const UInt32 PROCESS_VM_READ = 0x010;
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]StringBuilder lpExeName, ref int lpdwSize);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
UInt32 dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)]
Boolean bInheritHandle,
Int32 dwProcessId
);
#endregion
public static string GetProcessName(IntPtr hWnd)
{
string processName = null;
hWnd = GetForegroundWindow();
if (hWnd == IntPtr.Zero)
return null;
uint pID;
GetWindowThreadProcessId(hWnd, out pID);
IntPtr proc;
if ((proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, (int)pID)) == IntPtr.Zero)
return null;
int capacity = 2000;
StringBuilder sb = new StringBuilder(capacity);
QueryFullProcessImageName(proc, 0, sb, ref capacity);
processName = sb.ToString(0, capacity);
// UWP apps are wrapped in another app called, if this has focus then try and find the child UWP process
if (Path.GetFileName(processName).Equals("ApplicationFrameHost.exe"))
{
processName = UWP_AppName(hWnd, pID);
}
return processName;
}
#region Get UWP Application Name
/// <summary>
/// Find child process for uwp apps, edge, mail, etc.
/// </summary>
/// <param name="hWnd">hWnd</param>
/// <param name="pID">pID</param>
/// <returns>The application name of the UWP.</returns>
private static string UWP_AppName(IntPtr hWnd, uint pID)
{
WINDOWINFO windowinfo = new WINDOWINFO();
windowinfo.ownerpid = pID;
windowinfo.childpid = windowinfo.ownerpid;
IntPtr pWindowinfo = Marshal.AllocHGlobal(Marshal.SizeOf(windowinfo));
Marshal.StructureToPtr(windowinfo, pWindowinfo, false);
EnumWindowProc lpEnumFunc = new EnumWindowProc(EnumChildWindowsCallback);
EnumChildWindows(hWnd, lpEnumFunc, pWindowinfo);
windowinfo = (WINDOWINFO)Marshal.PtrToStructure(pWindowinfo, typeof(WINDOWINFO));
IntPtr proc;
if ((proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, (int)windowinfo.childpid)) == IntPtr.Zero)
return null;
int capacity = 2000;
StringBuilder sb = new StringBuilder(capacity);
QueryFullProcessImageName(proc, 0, sb, ref capacity);
Marshal.FreeHGlobal(pWindowinfo);
return sb.ToString(0, capacity);
}
/// <summary>
/// Callback for enumerating the child windows.
/// </summary>
/// <param name="hWnd">hWnd</param>
/// <param name="lParam">lParam</param>
/// <returns>always <c>true</c>.</returns>
private static bool EnumChildWindowsCallback(IntPtr hWnd, IntPtr lParam)
{
WINDOWINFO info = (WINDOWINFO)Marshal.PtrToStructure(lParam, typeof(WINDOWINFO));
uint pID;
GetWindowThreadProcessId(hWnd, out pID);
if (pID != info.ownerpid)
info.childpid = pID;
Marshal.StructureToPtr(info, lParam, true);
return true;
}
#endregion
}
}
Now, get a handle to the current foreground window using another P/Invoke method
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
Use the return value and call the GetProcessName
method from the code above. You should receive the correct name/path to the process.
Here is a simple Form to test the code:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using StackOverflow;
namespace Stackoverflow.Test
{
public partial class TestForm : Form
{
WinEventDelegate dele = null;
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
public TestForm()
{
InitializeComponent();
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
textBox1.AppendText(GetActiveWindowTitle() + "\n");
}
private string GetActiveWindowTitle()
{
return UwpUtils.GetProcessName(GetForegroundWindow());
}
}
}
You can download the full code, including the example/test on GitHub.
ApplicationFrameHost
owns the parent (root) window for each application, but inside this window it has child window that is owned by the application. You can see this in Spy++. You can get child window of AppFrameHost window and get name from it's process. – Robot