在 Windows 消息上设置挂钩 [英] Setting up Hook on Windows messages

查看:22
本文介绍了在 Windows 消息上设置挂钩的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个应用程序,它将通知当前播放曲目的用户的姓名和艺术家,我需要监视 track change event.

我使用了 Winspector 并发现每当在spotify WM_SETTEXT 消息已发送.

为此,我相信我必须通过我的应用程序设置一个 HOOK 以查找其他应用程序发送的 WM_SETTEXT 消息.

现在,我面临的问题是我无法获得任何可用的示例代码.我阅读了 setwindowshookex<的文档/a> 也做了一些谷歌搜索,但我真的迷路了,因为我没有 C# 背景和处理 Windows 消息/事件.

所以,如果你们可以给我提供一个小的工作代码来让我了解在另一个应用程序上设置挂钩,或者如果你能指导我阅读一些关于如何实现这一点的好文章.

这里有一个不同的方法:跳过 SetWindowsHook API,而是使用 WinEvents,使用 SetWinEventHook 代替.它们有点类似于 windows 钩子,因为两者都涉及在特定事件中调用的回调函数,但 WinEvents 在 C# 中更容易使用:您可以指定 WinEvents 是在上下文之外"传递的,这意味着事件被发布回到你自己的进程,所以你不需要单独的 DLL.(不过,您的代码确实需要在调用 SetWinEventHook 的同一线程上运行消息循环.)

事实证明,WinEvent 支持的事件类型之一是名称更改"事件,只要 HWND 的标题文本发生更改,USER32 就会自动触发该事件,这似乎正是您要查找的内容.(WinEvents 还可用于跟踪焦点更改和各种类型的状态更改;参见 MSDN 了解更多信息.)当其他控件的内部 UI 更改时,它也会被其他控件触发 - 例如,当列表项的文本更改时由列表框触发,因此我们必须进行一些过滤.>

下面是一些示例代码,用于在桌面上的任何 HWND 上打印标题更改 - 例如,当任务栏上的时钟中的文本更改时,您会看到它打印出通知.您需要修改此代码以仅过滤您在 Spotify 中跟踪的 HWND.此外,此代码侦听所有进程/线程上的名称更改;您应该使用 GetWindowThreadProcessId 并且只监听来自该线程的事件.

还要注意,这是一种脆弱的方法;如果 Spotify 更改其显示文本的方式,或更改其格式,您需要修改代码以跟上其变化.

使用系统;使用 System.Windows;使用 System.Windows.Forms;使用 System.Runtime.InteropServices;类 NameChangeTracker{委托无效 WinEventDelegate(IntPtr hWinEventHook, uint eventType,IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);[DllImport("user32.dll")]静态外部 IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtrhmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,uint idThread, uint dwFlags);[DllImport("user32.dll")]static extern bool UnhookWinEvent(IntPtr hWinEventHook);const uint EVENT_OBJECT_NAMECHANGE = 0x800C;const uint WINEVENT_OUTOFCONTEXT = 0;//需要确保在我们使用时不收集委托,//将其存储在类字段中是最简单的方法.静态 WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc);public static void Main(){//侦听当前桌面上所有进程/线程的名称更改更改...IntPtr hhook = SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, IntPtr.Zero,procDelegate, 0, 0, WINEVENT_OUTOFCONTEXT);//MessageBox 提供了 SetWinEventHook 所需的必要消息循环.//在实际代码中,使用常规消息循环 (GetMessage/TranslateMessage///DispatchMessage 等或等价物.)MessageBox.Show("跟踪 HWND 上的名称更改,关闭消息框以退出.");UnhookWinEvent(hook);}静态无效 WinEventProc(IntPtr hWinEventHook, uint eventType,IntPtr hwnd、int idObject、int idChild、uint dwEventThread、uint dwmsEventTime){//过滤掉非 HWND 名称更改...(例如列表框中的项目)if(idObject != 0 || idChild != 0){返回;}Console.WriteLine("hwnd 的文本改变了 {0:x8}", hwnd.ToInt32());}}

I am trying to make an application which will notify current playing track's name and artist to the user for that I need to monitor the track change event.

I used Winspector and found out that whenever there is a track change in spotify WM_SETTEXT message is send.

For this I believe I have to set up a HOOK through my application to look for WM_SETTEXT message sent by the other application.

Now, the problem I am facing is I am not able to get any working sample code to work with. I read the documentation of setwindowshookex and also did some googling but am really lost as I have no background of C# and handling windows messages/events.

So, If you guys can provide me a small working code to wrap my head around setting up hook on another application or if you can direct me to some nice article on how to achieve this.

解决方案

Here's a different approach: skip the SetWindowsHook API, and instead use WinEvents, which use SetWinEventHook instead. These are somewhat similar to the windows hooks, in that both involve a callback function that is called at specific events, but WinEvents are far easier to use from C#: you can specific that WinEvents are delivered "out context", meaning the events are posted back to your own process, so you don't need a separate DLL. (Your code does need to run a message loop on the same thread that called SetWinEventHook, however.)

It turns out that one of the type of events that WinEvent supports is a 'name change' event, which is automatically fired by USER32 whenever the title text of a HWND changes, which seems is what you are looking for. (WinEvents can also be used to track focus changes and various types of state changes; see MSDN for more information.) It's also fired by other controls when their internal UI changes - eg by a listbox when the text of a list item changes, so we have to do some filtering.

Here's some sample code that prints out title changes on any HWND on the desktop - you'll see it print out a notification as the text in the clock on the taskbar changes, for example. You'll want to modify this code to filter for just the HWND you're tracking in Spotify. Also, this code listens to name changes on all processes/threads; you should get the threadID from the target HWND using GetWindowThreadProcessId and only listen to events from that thread.

Note also that this is something of a fragile approach; if Spotify changes how it displays the text, or changes the format of it, you'll need to modify your code to keep up with its changes.

using System;
using System.Windows;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class NameChangeTracker
{
    delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
        IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);

    [DllImport("user32.dll")]
    static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
       hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
       uint idThread, uint dwFlags);

    [DllImport("user32.dll")]
    static extern bool UnhookWinEvent(IntPtr hWinEventHook);

    const uint EVENT_OBJECT_NAMECHANGE = 0x800C;
    const uint WINEVENT_OUTOFCONTEXT = 0;

    // Need to ensure delegate is not collected while we're using it,
    // storing it in a class field is simplest way to do this.
    static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc);

    public static void Main()
    {
        // Listen for name change changes across all processes/threads on current desktop...
        IntPtr hhook = SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, IntPtr.Zero,
                procDelegate, 0, 0, WINEVENT_OUTOFCONTEXT);

        // MessageBox provides the necessary mesage loop that SetWinEventHook requires.
        // In real-world code, use a regular message loop (GetMessage/TranslateMessage/
        // DispatchMessage etc or equivalent.)
        MessageBox.Show("Tracking name changes on HWNDs, close message box to exit.");

        UnhookWinEvent(hhook);
    }

    static void WinEventProc(IntPtr hWinEventHook, uint eventType,
        IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
    {
        // filter out non-HWND namechanges... (eg. items within a listbox)
        if(idObject != 0 || idChild != 0)
        {
            return;
        }
        Console.WriteLine("Text of hwnd changed {0:x8}", hwnd.ToInt32()); 
    }
}

这篇关于在 Windows 消息上设置挂钩的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆