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

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

问题描述

我试图使一个应用程序,它会通知当前播放曲目的
名称和艺术家为我需要监控的曲目变化事件的用户

我用 Winspector ,并发现每当有轨道变化
Spotify的 WM_SETTEXT 消息发送。

有关这一点,我相信我有建立一个挂钩通过我的应用程序来寻找 WM_SETTEXT 通过发送消息其他应用程序。

现在,我面临的问题是,我无法得到任何工作示例code的工作。我读的文件<一个href=\"http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990%28v=vs.85%29.aspx\">setwindowshookex并且也做了一些谷歌搜索,但我真的失去了,因为我有没有C#的背景和处理Windows消息/事件。

所以,如果你们能提供给我一个小型工作code至满脑子都在另一个应用程序或设置钩,你能不能告诉我一些好的文章就如何实现这一目标。


解决方案

下面是一个不同的方法:跳过SetWindowsHook API,而是使用WinEvents ,它使用SetWinEventHook代替。这些都是有点类似于windows钩子,因为都涉及到被调用特定事件的回调函数,但的WinEvents都更容易从C#中使用:您可以将特定的的WinEvents交付断章取义,意为事件发布回到自己的过程,所以你并不需要一个单独的DLL。 (您code确实需要运行名为SetWinEventHook在同一个线程上的消息循环,但是。)

原来,这WinEvent支持事件的类型之一是更名事件,这是由USER32时的HWND改变标题文本,这似乎是你在找什么自动开除。 (的WinEvents也可用于跟踪焦点的变化和各种状态变化; 查看MSDN 获取更多信息)它也被其他发射控制时,他们的内部用户界面的变化 - 例如,通过列表框中的列表项修改的文本,所以我们必须做一些过滤

下面是一些示例code打印出任何HWND在桌面上标题的变化 - 你会看到它打印出通知,任务栏上的变化在时钟的文字,例如。您将要修改这个code过滤只是你在Spotify的跟踪HWND。此外,该code听名字上的所有进程/线程的变化;应使用从目标HWND获得的threadId GetWindowThreadProcessId而只听从那个线程的事件。

还请注意,这是一个脆弱的做法事;如果Spotify的改变是如何显示文本,或改变它的格式,你需要修改code跟上它的变化。

 使用系统;
使用System.Windows;
使用System.Windows.Forms的;
使用System.Runtime.InteropServices;类NameChangeTracker
{
    委托无效WinEventDelegate(IntPtr的hWinEventHook,UINT事件类型,
        IntPtr的HWND,INT idObject,诠释idChild,UINT dwEventThread,UINT dwmsEventTime);    函数[DllImport(user32.dll中)]
    静态外部的IntPtr SetWinEventHook(UINT eventMin,UINT eventMax,IntPtr的
       hmodWinEventProc,WinEventDelegate lpfnWinEventProc,UINT idProcess,
       UINT idThread,UINT dwFlags中);    函数[DllImport(user32.dll中)]
    静态外部布尔UnhookWinEvent(IntPtr的hWinEventHook);    常量UINT EVENT_OBJECT_NAMECHANGE = 0x800C;
    常量UINT WINEVENT_OUTOFCONTEXT = 0;    //需要确保当我们使用它委托没有收集到,
    //将其存储在一个类域是要做到这一点最简单的方法。
    静态WinEventDelegate procDelegate =新WinEventDelegate(WinEventProc);    公共静态无效的主要()
    {
        //监听所有进程/线程当前桌面上名字的变化而改变......
        IntPtr的HHOOK = SetWinEventHook(EVENT_OBJECT_NAMECHANGE,EVENT_OBJECT_NAMECHANGE,IntPtr.Zero,
                procDelegate,0,0,WINEVENT_OUTOFCONTEXT);        //消息框提供了必要的mesage循环SetWinEventHook需要。
        //在真实世界code,使用常规的消息循环(GetMessage函数/的TranslateMessage /
        //在DispatchMessage等或同等学历)。
        的MessageBox.show(跟踪上HWNDs名称的变化,接近消息框退出。);        UnhookWinEvent(HHOOK);
    }    静态无效WinEventProc(IntPtr的hWinEventHook,UINT事件类型,
        IntPtr的HWND,INT idObject,诠释idChild,UINT dwEventThread,UINT dwmsEventTime)
    {
        //过滤掉非HWND namechanges ...(如列表框中的项目)
        如果(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天全站免登陆