【问题标题】:WinProcEvent one or multiple SetWinEventHook callbacks?WinProcEvent 一个或多个 SetWinEventHook 回调?
【发布时间】:2014-02-27 11:47:02
【问题描述】:

是否最好使用相同的 WinEventProc() 回调函数注册多个 SetWinEventHook() 函数,并在函数代码中单独处理每个事件类型,或者尽可能多地处理。

编辑:我发布了三个不同的场景,我想知道哪个是最好的,为什么?

案例 1:单个回调、单个委托、多个钩子

static WinEventDelegate SingleCallbackDelegate = new WinEventDelegate(SingleCallback);

public static void SingleCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
   switch(evenType) :
   case eventId1 : // do work related to event 1
   case eventId2 : // do work related to event 2
   // etc.
}

void SetHooks()
{
    SetWinEventHook(eventId1, eventId1, IntPtr.Zero, SingleCallbackDelegate, 0, 
        0, flags);
    SetWinEventHook(eventId2, eventId2, IntPtr.Zero, SingleCallbackDelegate, 0, 
        0, flags);
}

案例 2:单个回调、多个委托、多个钩子

static WinEventDelegate CallbackDelegate1 = new WinEventDelegate(SingleCallback);

static WinEventDelegate CallbackDelegate2 = new WinEventDelegate(SingleCallback);

public static void SingleCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
   switch(evenType) :
   case eventId1 : // do work related to event 1
   case eventId2 : // do work related to event 2
   // etc.
}

void SetHooks()
{
    SetWinEventHook(eventId1, eventId1, IntPtr.Zero, CallbackDelegate1, 0, 
        0, flags);
    SetWinEventHook(eventId2, eventId2, IntPtr.Zero, CallbackDelegate2, 0, 
        0, flags);
}

案例 3:多个回调、多个委托、多个钩子

static WinEventDelegate CallbackDelegate1 = new WinEventDelegate(Callback1);
public static void Callback1(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
   // do work related to event 1
}

static WinEventDelegate CallbackDelegate2 = new WinEventDelegate(Callback2);
public static void Callback1(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
   // do work related to event 2
}
void SetHooks()
{
    SetWinEventHook(eventId1, eventId1, IntPtr.Zero, CallbackDelegate1, 0, 
        0, flags);
    SetWinEventHook(eventId2, eventId2, IntPtr.Zero, CallbackDelegate2, 0, 
        0, flags);
}

【问题讨论】:

  • @HansPassant 我设法使用相同的回调为不同的事件(EVENT_SYSTEM_FOREGROUND 和 EVENT_OBJECT_NAMECHANGE)注册了钩子。
  • @HansPassant 检查我上次的编辑。
  • @DavidHeffernan 你也可以看看这个吗?

标签: c# .net windows event-handling ui-automation


【解决方案1】:

第二个 sn-p 没有意义,单个委托已经足以传递给多个 SetWinEventHook() 调用。 可能指向第三个 sn-p,由于回调目标方法不同,因此需要不同的委托对象。我能想到的唯一好处是您可以使方法不那么强大或为特定进程或线程自定义回调的行为。

重要的是要记住 SetWinEventHook() 的开销非常,在程序中进行回调会涉及大量开销,这可能会对其他进程的方式产生重大影响在桌面上运行的行为。您在回调中所做的任何需要时间的操作都会使其他进程也没有响应。因此,限制您进行的 SetWinEventHook() 调用的数量自动成为一个强大的优化目标。

您可以在函数声明的方式中看到这一点,它鼓励您使用小范围的 eventMineventMax 值。 Windows 可以使用一个简单的过滤器来确定不需要进行昂贵的回调。如果您的回调确实只对少数事件感兴趣,那么多次调用 SetWinEventHook 确实 是有意义的。你仍然会坚持使用第一个 sn-p,因为 switch 语句应该是次要的。

【讨论】:

  • 实际上我只使用带有 (WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS | WINEVENT_SKIPOWNTHREAD) 标志的 EVENT_SYSTEM_FOREGROUND 和 EVENT_OBJECT_NAMECHANGE(调用 SetWinEventHook() “系统范围”两次)。你还记得我的另一个question,我想避免为所有进程设置 EVENT_OBJECT_NAMECHANGE,但我找不到在同一个线程内创建进程时设置挂钩的方法!所以知道我正在寻找减少足迹/开销和阻止其他进程的每一个技巧。
  • 我没有得到“一个事件报告两次”,因为在代码 sn-ps 中,每个 SetWinEventHook() 都使用不同的 eventId 调用。我不想使用 [eventMin..eventMax],因为它的范围很大 [0x0003..0x800C],我会检测到比我想要的更多的事件
  • 我有兴趣阅读有关您的第二段的更多信息。任何指向进一步阅读?我的代码运行时究竟是什么被阻止了?这样做有什么影响?有什么策略可以缓解这种情况?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多