将ApplicationFrameHost托管的UWP应用程序连接到其实际进程

Chr*_*son 9 c# windows wpf winapi uwp

我正在开发一个WPF应用程序来监视我在计算机上的活动.我使用Process.GetProcesses()和一些过滤来获得我感兴趣的过程(例如:计算器)然后我记录他们的StartTime.我也使用WIN32/USER32 API方法GetForegroundWindow()来获取用户正在使用的窗口.

问题是,当Windows是Windows/UWP应用程序时,它们总是由进程ApplicationFrameHost托管.因此,该GetForegroundWindow()方法返回带有标题的窗口(例如:Calculator),但不会返回托管的实际进程.

我需要的是另一种获取前台窗口的方法,包括托管的实际进程,或者某种方式将窗口连接到进程.

谁知道如何实现这一目标?所有的帮助将非常感激.

Chr*_*son 13

我最终找到了一种方法来做到这一点,所以我要回答我自己的问题所以也许未来有同样问题的人会觉得它很有用.

这是具有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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我用来测试它是否可行的类.我在一个简单的控制台程序中使用它,它只写出当前焦点的进程名称:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)