【问题标题】:Windows 8 taskmanager app history in C#C# 中的 Windows 8 任务管理器应用历史记录
【发布时间】:2013-04-22 18:44:36
【问题描述】:

我正在尝试从 C# 访问应用程序历史记录。我想提供与任务管理器中相同的信息,但我找不到 api/example。当然我实现了一个桌面应用程序。

指定问题:我对 CPU/RAM 不感兴趣。我唯一想得到的就是时间。

更新 要准确显示我正在谈论的内容,请查看此屏幕:

【问题讨论】:

    标签: c# winapi windows-8


    【解决方案1】:

    不支持获取此信息的方法。对不起。

    【讨论】:

    • 不。我不会让你做一些不受支持的事情来欺骗你的客户。
    【解决方案2】:

    问题的描述缺少您所说的 Metro Apps 的详细信息。该解决方案相当于Process.TotalProcessorTime,但适用于 Metro Apps。

    不幸的是,您无法获得该信息,因为正如您所说,应用程序正在另一个进程 (WWAHost.exe) 中运行。 Metro 的设计有点像电话——你不能以同样的方式直接操纵系统。 Windows 运行时中没有直接的“进程”(请参阅​​here),这反过来意味着进程类无法移植......

    【讨论】:

    • 对于这个答案,我应该给你-1。如果任务管理器不可能做到这一点。您是对的,WinRT 不可能,但 WinApi 必须有可能。我的问题被 Windows 8 标记,我写了关于应用程序历史和任务管理器的文章。你是对的,图片链接丢失了,但你的答案仍然不正确
    • 我尽力提供帮助。如果某事不可能,并不一定意味着答案是错误的。我包括参考资料,并花了很多时间试图找出解决方案,这些就是我想出的答案。很抱歉未能提供符合您期望的解决方案。
    • 但是有可能是因为任务管理器显示了这个信息。我可以理解微软隐藏了这个 API 但他们使用它
    • @Garath “我可以理解微软隐藏了这个 API,但他们使用了它”。任务管理器与操作系统的集成比您的应用程序所允许的要紧密得多。它也是一个桌面应用程序,可能是用 C 或 C++ 编写并直接连接到操作系统,而不是用更高级别的 C# 编写的 Windows 8 应用程序。
    • 如果任务管理器可以调用某些系统函数,我的 c# 代码也可以使用 pinvoke 调用它。 C#可以直接调用winwin32api。无论如何,从 C 访问对我来说已经足够了
    【解决方案3】:

    我假设The only thing I would like to get is Time. 是指每个进程的开始和结束时间

    最好的方法是你必须自己建立这段历史。如果您仅在应用程序运行时才需要历史记录,那么您只需执行下面的代码,否则如果您希望在某个时间段内构建历史记录,即使您的应用程序已关闭,请尝试创建一个为您完成这项工作的 Windows 服务。假设您知道如何创建、编译和安装 Windows 服务项目,以下是您需要执行的步骤:

    获取正在运行的进程信息:

    using System;
    using System.Diagnostics;
    
    public static class ProcessStart
    {
        Process[] runningProcesses;
        var processesStartTimes = new Dictionary<int, Datetime>();
        var processesExitTimes = new Dictionary<int, Datetime>();
    
        static ProcessStart()
        {
            // This will get current running processes
            runningProcesses = Process.GetProcesses();
            foreach (var p in processes)
            {
                p.Exited += new EventHandler(ProcessExited);
                processesStartTimes.Add(p.Id, p.StartTime);
            }
        }
    
        private void ProcessExited(object sender, System.EventArgs e)
        {
            var p = (Process)sender;
            processesExitTimes.Add(p.Id, p.ExitTime);
        }
    }
    

    开始新的流程

    您需要创建一个新的Timer 对象并每隔一秒运行一次以检查新创建的进程。我复制了上面的代码并对其进行了扩展:

    public static class ProcessStart
    {
        Process[] runningProcesses;
        var processesStartTimes = new Dictionary<int, Datetime>();
        var processesExitTimes = new Dictionary<int, Datetime>();
        var updateTimer = new Timer(1000);
    
        static ProcessStart()
        {
            // This will get current running processes
            runningProcesses = Process.GetProcesses();
            foreach (var p in processes)
            {
                p.Exited += new EventHandler(ProcessExited);
                processesStartTimes.Add(p.Id, p.StartTime);
            }
            updateTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        }
    
        private void ProcessExited(object sender, System.EventArgs e)
        {
            var p = (Process)sender;
            processesExitTimes.Add(p.Id, p.ExitTime);
        }
    
        private static void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            runningProcesses = Process.GetProcesses();
            foreach (var p in processes)
            {
                // This will only add the processes that are not added yet
                if (!processesStartTimes.Keys.Contains(p.Id))
                {
                    p.Exited += new EventHandler(ProcessExited);
                    processesStartTimes.Add(p.Id, p.StartTime);
                }
            }
        }
    }
    

    最后:

    然后您需要使用System.Diagnostics.Process 类。这应该是获取有关 Windows 进程所需的所有信息的最佳方式。它将授予您访问各种属性和方法的权限。这是官方的 MSDN 赞:

    Process Class

    编辑:

    从您的评论中可以看出,您对 CPU 运行特定进程所花费的时间感兴趣。同样的System.Diagnostics.Process 类也包含该信息。这可以使用Process.PrivilegedProcessorTime 属性找到。此属性的 MSDN 描述是:

    一个 TimeSpan,表示进程在操作系统内核中运行代码所花费的时间。

    更多信息Here

    编辑 2:

    以下 2 个属性也可以满足您的需求:

    Process.UserProcessorTime : Here

    一个 TimeSpan,指示相关进程在进程的应用程序部分(而不是操作系统核心)内运行代码所花费的时间。

    Process.TotalProcessorTime : Here

    一个 TimeSpan,指示相关进程使用 CPU 所花费的时间。该值是UserProcessorTimePrivilegedProcessorTime 的总和。

    【讨论】:

    • 你误解了我的问题。我想在 Windows 8 的任务管理器中显示相同的信息。我在谈论这个功能:cdn3.pcadvisor.co.uk/cmsdata/features/3422276/… 此外,Windows 8 中的所有 Metro 应用程序都托管在名为 wwahost 的进程中
    • 尽我所能理解您的单行问题导致否决票?嗯..有趣
    • 就在您提供的图片中:您在哪里看到Time
    • 投反对票是意外抱歉。在您编辑答案之前,我无法更改它
    【解决方案4】:

    我对此进行了一些研究,因为我发现 Metro 应用程序如何集成到现有流程结构中很有趣。

    正如其他人在这里指出的那样,不可能以漂亮的受支持的 API 方式获取您想要的信息。 但是,每个应用程序都是作为不同的进程启动的,对于进程,有已知的方法来获取运行时间、cpu 时间等。

    如果您找到与您的 Windows 8 应用程序对应的进程,您将能够获得所需的信息。

    有些应用真的很容易被发现。它们只是一个可执行文件,就像任何其他具有适当进程名称和描述的桌面应用程序一样。 例如这张图片中的“Map”、“Windows Reader”和“Microsoft Camera Application”:

    其他一些应用程序更难发现。它们托管在由wwahost.exe 执行程序启动的进程中。我只能通过查看模块列表来发现应用程序名称。 这是Bing 应用程序:

    要枚举进程中的模块和映射文件,您可以使用 WinAPI VirtualQueryExGetMappedFileName

    然后您要查找位于%programfiles%\WindowsApps 的文件。这是 Windows 为其应用程序保存所有应用程序文件的文件夹。

    每个应用都有一个.pri 文件。此文件包含应用程序的二进制元数据。您可以使用它从托管它的进程中查找应用程序的名称。在与 .pri 文件相同的文件夹中,有一个 AppxManifest.xml,您可以在其中找到有关该应用程序的各种附加信息。

    我会试着总结一下我的写作:

    • 使用 WinAPI 枚举进程并获取您需要的所有信息(运行时间、cpu 时间等)。
    • 枚举每个进程的映射文件并查找ressources.pri。该文件所在的目录中包含应用名称。
    • 作为奖励阅读AppxManifest.xml 文件以获取有关应用程序的更多信息。您可能需要管理员权限或其他权限才能读取此文件。

    【讨论】:

    • 不错的答案!那将是他能得到的最好的结果,但仍然不会让他获得每个模块的 CPU 时间,这是他正在寻找的信息。这仅提供模块或“进程”列表
    • 有了这些信息,我可以创建自己的统计数据,这可能是我能得到的最好的数据:)
    • 我假设 Windows 8 任务管理器也“仅”从应用程序的主机进程获取 CPU 时间。由于每个应用程序都会产生一个新进程,我也不明白为什么这些值应该不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    相关资源
    最近更新 更多