【问题标题】:Find the Current Windows Application查找当前的 Windows 应用程序
【发布时间】:2009-02-03 00:10:11
【问题描述】:

我正在尝试编写我希望是一个简单的应用程序跟踪器。也就是说,每当新应用程序启动或正在运行的应用程序成为当前应用程序时,我想记录该事件并开始计时它的时间“在顶部”。

我有列出所有当前正在运行的应用程序的代码,以及一些告诉我顶部窗口的代码(自然是我的测试控制台应用程序)。

我认为我缺少的是要监视的 Windows 事件流或其他东西。

我正在使用 .NET(首选 C#)。

有任何提示、提示或作弊可用吗?

谢谢 - 乔纳森

【问题讨论】:

    标签: c# windows


    【解决方案1】:

    我认为最好的方法是使用 Windows“钩子”(即SetWindowsHookEx)。这些允许您连接到 Windows 核心功能,特别是有一个名为 WH_CALLWNDPROC 的函数,它在系统中的任何窗口收到消息时调用用户函数。

    您可以使用它来全局侦听将窗口置于前台的消息,和/或用于用户交互(鼠标、键盘)的消息。

    但是,这是一个原始的 Windows API 函数,主要用于 C/C++ Windows DLL。您可以在 C# 中实现它,但这是您可能不想打开的一大堆蠕虫。但是打开它可能是完成您所要求的最佳方式。

    【讨论】:

      【解决方案2】:

      我不确定是否有办法挂钩 Windows 事件,但只需定期轮询 System.Diagnostics.Process.GetProcesses()(例如 100 毫秒)并寻找新的/删除的进程(通过进程 ID 进行比较) 应该做的工作。此外,Process.StartTime 将为您提供流程开始的时间。

      警告:与基于事件的方法相比,此方法可能需要更多的处理(我不知道)。不会观察到在每次轮询之间开始和结束的进程,但是对于相当高的轮询频率来说,这种情况确实应该很少见(也许你甚至都不关心这些进程)。说到这里,这些都是小问题,我建议您至少测试一下这个解决方案,因为它相当简单。

      【讨论】:

      • 虽然,如果该民意调查碰巧捕捉到特定应用程序,例如 MSN Messenger,在连续两次民意调查中,看起来用户(假设这是为了跟踪员工)在 MSN 上花费时间,当可能他们只是碰巧在错误的时间被轮询了两次。
      • 我想你误会了。轮询将以相对较高的频率(> 1Hz)发生。我不会想象这会占用太多处理器资源。诚然,它可能并不理想,但它是一个有效的解决方案,除非 OP 没有提到某些其他要求。
      • 是的,我确实误解了你的意图。虽然,我认为我这样做是因为我本能地排除了以足够高的频率进行轮询以产生那些伪立即结果的不玩“好”。
      • 是的,我想这有点模棱两可。答案已被编辑以澄清这一点。
      【解决方案3】:

      这越来越成为一个 SO 问题,被否决的答案是正确的。 SetWindowsHookEx() 确实需要能够捕获激活的窗口获得的 WM_ACTIVATE 消息。但这需要一个 WH_CALLWNDPROC 或 WH_SHELL 钩子,这些钩子无法在 C# 中实现。捕捉这些需要在每个进程中注入一个 DLL,托管程序集不能注入另一个进程。无法初始化 CLR。​​

      +1 诺多林让他回到 0,这就是我能做的。 OP 需要用非托管 C/C++ 编写代码,创建 DLL 并使用标准 IPC 机制(如管道或套接字)来通知主机应用程序。或者投票,更容易。

      【讨论】:

      • 是的,需要 DLL 注入来创建通知/事件系统(据我所知)。最好尽可能避免 DLL 注入(这是相当讨厌的东西),但如果你真的想这样做,请查看 Sourceforge 上的控制台项目 - sourceforge.net/projects/console)。
      • (续) Console 项目使用共享内存在主机进程和子控制台进程之间进行通信,这很有效,但也不太好处理。 @nobugz,感谢您的支持。
      • 您实际上可以按照我的建议使用托管代码和“EasyHook”库:codeplex.com/easyhook
      【解决方案4】:

      我曾经写过一个小应用程序来记录我自己的工作习惯。我所做的是定期调用GetForegroundWindow()(每 5 秒左右)并记录正在运行的应用程序。您可以从窗口句柄中获取大量信息,不仅是标题,还包括创建它的实际进程。

      【讨论】:

        【解决方案5】:

        这是我使用 Java 的 JNA 所做的:

        final HWND child = User32Ext.INSTANCE.GetForegroundWindow();
        final int length = User32.INSTANCE.GetWindowTextLength(child) * 2;
        final byte[] buffer = new byte[length];
        User32.INSTANCE.GetWindowText(child, buffer, length);
        title = new String(buffer, Charset.forName("UTF-16LE"));
        

        其中 User32Ext 是我所做的扩展,因为 User32(在 JNA 的发行版中)没有以下接口:

        LRESULT callback(int nCode, WPARAM wParam, LPARAM lParam);
        

        我会定期轮询活动窗口,因为我无法使用http://msdn.microsoft.com/en-us/library/ms997537.aspx 中提到的 HCBT_SETFOCUS 挂钩,如果有人提出解决方案,我会非常感兴趣。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-12-16
          • 2012-12-03
          • 1970-01-01
          • 1970-01-01
          • 2012-05-25
          • 2012-09-27
          • 1970-01-01
          • 2017-09-23
          相关资源
          最近更新 更多