Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将ApplicationFrameHost托管的UWP应用程序连接到其实际进程_C#_Wpf_Windows_Winapi_Uwp - Fatal编程技术网

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

C# 将ApplicationFrameHost托管的UWP应用程序连接到其实际进程,c#,wpf,windows,winapi,uwp,C#,Wpf,Windows,Winapi,Uwp,我正在开发一个WPF应用程序来监视我在计算机上的活动。我使用Process.GetProcesses()和一些过滤来获取我感兴趣的进程(例如:计算器),然后记录它们的开始时间。我还使用WIN32/User32API方法GetForegroundWindow()获取用户正在使用的窗口 问题是,当窗口是windows/UWP应用程序时,它们总是由process ApplicationFrameHost托管。因此GetForegroundWindow()方法返回带有标题的窗口(例如:Calculato

我正在开发一个WPF应用程序来监视我在计算机上的活动。我使用
Process.GetProcesses()
和一些过滤来获取我感兴趣的进程(例如:计算器),然后记录它们的开始时间。我还使用WIN32/User32API方法
GetForegroundWindow()
获取用户正在使用的窗口

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

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


有人知道如何做到这一点吗?非常感谢您的帮助。

我最终找到了一种方法,因此我将回答我自己的问题,以便将来可能会有人遇到同样的问题时发现它很有用

这是一个包含WinAPI函数的类:

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();
    }
}
这是我用来测试它是否有效的类。我在一个简单的控制台程序中使用了它,该程序只写出具有当前焦点的进程的名称:

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;
    }
}

克里斯,我发现了另一种方法来应用你的解决方案。当我试图分析与
ApplicationFrameHost.exe
相关的东西是如何工作的时,我偶然发现了一种有文档记录的方法,通过将
0
而不是实际的线程ID传递给

它可能不完全适用于您的问题的边缘案例场景,但我觉得这可能会对未来可能面临相同问题的人做出有益的贡献;-)

下面是如何应用此功能的示例(伪C++代码):

GUITHREADINFO gti={sizeof(GUITHREADINFO)};

GetGuitThreadInfo(0,>i);// 基本上,如果活动窗口处于全屏模式,您提供的答案也会失败

例如,如果您的Skype应用程序与Microsoft Remote Desktop一起打开,则 活动模式下,在全屏模式下,
EnumChildWindows
将返回SkypeApp而不是RDPClient

要解决这个问题,你应该遵循Ivanmoskalev建议的解决方法

看看这个:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);

public static IntPtr getThreadWindowHandle(uint dwThreadId)
{
    IntPtr hWnd;

    // Get Window Handle and title from Thread
    var guiThreadInfo = new GUITHREADINFO();
    guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo);

    GetGUIThreadInfo(dwThreadId, ref guiThreadInfo);

    hWnd = guiThreadInfo.hwndFocus;
    //some times while changing the focus between different windows, it returns Zero so we would return the Active window in that case
    if (hWnd == IntPtr.Zero)
    {
        hWnd = guiThreadInfo.hwndActive;
    }
    return hWnd;
}

[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr windowHandle, out int processId);

static void Main(string[] args)
{
    var current = getThreadWindowHandle(0);
    int processId = 0;
    GetWindowThreadProcessId(current, out processId);
    var foregroundProcess = GetActiveProcess(processId);
}

private static Process GetActiveProcess(int activeWindowProcessId)
{
    Process foregroundProcess = null;
    try
    {
        foregroundProcess = Process.GetProcessById(activeWindowProcessId);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
    if (string.IsNullOrWhiteSpace(GetProcessNameSafe(foregroundProcess)))
    {
        var msg = "Process name is empty.";
        Console.WriteLine(msg);
    }
    return foregroundProcess;
}
与Chris Johnsson的代码大致相同,只是我没有使用过程,因为它在UWP应用程序上运行得不太好

启动代码:

new Timer(TimerCallback, null, 0, 1000);

void TimerCallback(object state)
{
    var process = new ProcessUtils.FindHostedProcess().Process;
    string name = string.Empty;

    if (process.IsPackaged)
    {
        var apps = process.GetAppDiagnosticInfos();
        if (apps.Count > 0)
            name = apps.First().AppInfo.DisplayInfo.DisplayName;
        else
            name = System.IO.Path.GetFileNameWithoutExtension(process.ExecutableFileName);
    }
    else
        name = System.IO.Path.GetFileNameWithoutExtension(process.ExecutableFileName);

    Debug.WriteLine(name);
}
以及FindHostedProcess类,我在其中使用ProcessDiagnosticInfo而不是Process

public class FindHostedProcess
{
    public ProcessDiagnosticInfo Process { get; private set; }

    public FindHostedProcess()
    {
        var foregroundProcessID = WinAPIFunctions.GetforegroundWindow();
        Process = ProcessDiagnosticInfo.TryGetForProcessId((uint)WinAPIFunctions.GetWindowProcessId(foregroundProcessID));

        // Get real process
        if (Process.ExecutableFileName == "ApplicationFrameHost.exe")
            WinAPIFunctions.EnumChildWindows(foregroundProcessID, ChildWindowCallback, IntPtr.Zero);
    }

    private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam)
    {
        var process = ProcessDiagnosticInfo.TryGetForProcessId((uint)WinAPIFunctions.GetWindowProcessId(hwnd));

        if (process.ExecutableFileName != "ApplicationFrameHost.exe")
            Process = process;

        return true;
    }
}

最后重新使用Chris Johnson的WinAPIFunctions类。

你是一个英雄!!我为此苦苦挣扎。
public class FindHostedProcess
{
    public ProcessDiagnosticInfo Process { get; private set; }

    public FindHostedProcess()
    {
        var foregroundProcessID = WinAPIFunctions.GetforegroundWindow();
        Process = ProcessDiagnosticInfo.TryGetForProcessId((uint)WinAPIFunctions.GetWindowProcessId(foregroundProcessID));

        // Get real process
        if (Process.ExecutableFileName == "ApplicationFrameHost.exe")
            WinAPIFunctions.EnumChildWindows(foregroundProcessID, ChildWindowCallback, IntPtr.Zero);
    }

    private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam)
    {
        var process = ProcessDiagnosticInfo.TryGetForProcessId((uint)WinAPIFunctions.GetWindowProcessId(hwnd));

        if (process.ExecutableFileName != "ApplicationFrameHost.exe")
            Process = process;

        return true;
    }
}