C# 用户更改活动进程时引发事件

C# 用户更改活动进程时引发事件,c#,winforms,C#,Winforms,当程序用户将活动窗口更改为其他进程的活动窗口时,是否存在触发事件或创建事件的方法 如果没有这样的事件,什么是最好的方式,使事情是这样的 我目前有一个计时器,每3秒运行一次Process.GetCurrentProcess(),但我正在寻找更好、更高效的方法,我不想降低时间间隔,因为这可能会使程序占用太多资源,或者需要太多时间来不断检查活动进程 我知道有很多Windows内置函数基本上是隐藏的,我没有足够的知识去了解,所以如果有人有类似的想法,如果你能帮助我,那就太好了。我想说的方法之一是使用Wi

当程序用户将活动窗口更改为其他进程的活动窗口时,是否存在触发事件或创建事件的方法

如果没有这样的事件,什么是最好的方式,使事情是这样的

我目前有一个计时器,每3秒运行一次Process.GetCurrentProcess(),但我正在寻找更好、更高效的方法,我不想降低时间间隔,因为这可能会使程序占用太多资源,或者需要太多时间来不断检查活动进程


我知道有很多Windows内置函数基本上是隐藏的,我没有足够的知识去了解,所以如果有人有类似的想法,如果你能帮助我,那就太好了。

我想说的方法之一是使用Windows钩子,即CBT钩子。它听起来更接近于“老好人”Win32 API和通用C/C++人员。同时,据我所知,还有C版本

所以,我们的想法是在每次获得HCBT_ACTIVATE类型的钩子事件(要激活的窗口)时检查当前进程,然后检查拥有该窗口的进程。如果它与之前记忆的流程不匹配,则是时候触发您的事件了。唯一需要记住的是,您自己的操作也可能触发CBT钩子(您必须避免无休止的自行循环!)。

API正是您在这里寻找的。你所需要做的就是在你的应用程序以正确的选项启动时调用它,当用户从当前桌面上运行的任何进程更改焦点时,你应该开始接收通知

[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventProc lpfnWinEventProc, int idProcess, int idThread, uint dwflags);
[DllImport("user32.dll")]
internal static extern int UnhookWinEvent(IntPtr hWinEventHook);
internal delegate void WinEventProc(IntPtr hWinEventHook, uint iEvent, IntPtr hWnd, int      idObject, int idChild, int dwEventThread, int dwmsEventTime);

const uint WINEVENT_OUTOFCONTEXT = 0;
const uint EVENT_SYSTEM_FOREGROUND = 3;
private IntPtr winHook;
private WinEventProc listener;

public void StartListeningForWindowChanges()
{
    listener = new WinEventProc(EventCallback);
    //setting the window hook
    winHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, listener, 0, 0, WINEVENT_OUTOFCONTEXT);
}

public void StopListeningForWindowChanges()
{
    UnhookWinEvent(winHook);
}

private static void EventCallback(IntPtr hWinEventHook, uint iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime)
{
    // handle active window changed!
}

我不知道你说的获取当前流程是什么意思。您是指当前活动窗口吗?因为您的电脑上有多个进程持续运行。;)详细说明它的“原因”。例如,如果你只关心失去焦点,你可能会做出反应。这实际上取决于你想要实现什么,你想要做什么?你正在构建一个多进程应用程序吗
Process.GetCurrentProcess()
将返回调用该方法的当前进程。我还没有使用多进程应用程序的经验,所以没有足够的词汇来表达,因为有一些重要的术语需要首先理解……您可以使用windows挂钩来实现这一点,请参见。。我不太明白你的意思,因为这是我所不知道的,但我会做一些研究。谢谢你的回答!看起来不错,所以我将它作为答案打勾=)我似乎无法启动EventCallback()。我将SetWinEventHooks变量eventMin、eventMax和dwflags更改为uint,以便编译代码,这是为什么?我在应用程序启动时运行startListingForWindowChanges(),并在关闭它之前停止ListingForWindowChanges()。还有什么需要做的吗?@stripe103抱歉,这是我的错,我的签名中混合了
int
/
uint
,而且我更改了签名中的旧枚举类型。。。我已经更新了答案,以便在API要求的地方一致使用
uint
。不用担心,考虑到你回答=)的速度如此之快,我似乎仍然无法启动EventCallBack()。除了运行StartListeningForWindowChanges(),还需要做些什么吗?@stripe103不,上述方法应该可以,只是出于好奇,您是否正在尝试在控制台应用程序中运行此功能?您的应用程序需要运行消息泵(控制台windows不需要)。在WinForms应用程序中尝试一下,如果它仍然不起作用,请告诉我。不用担心:)作为传递范围的API调用的一部分,
SetWinEventHook
可以用来捕获各种错误。在我的示例中,我们仅将该范围限制为trap
EVENT\u SYSTEM\u FOREGROUND
,它只应在前台窗口发生更改时(即新窗口对焦时)通知您。请记住,这将发生在每个窗口,而不是每个进程,因此在同一进程中切换窗口时,您将收到多个通知。