尝试了很多东西,但在我的任务栏被破坏和桌面 UI 上的其他超自然效果中,我无法让它始终如一地工作。

首先尝试使用开放式库 http://mwinapi.sourceforge.net/。尽管它作为用于枚举窗口和其他东西的 OO 层工作得很好。它不能正确地做钩子(Hook)

下一站是 Dino E.'s post on Windows Hooks in the .Net framework 。我最终编写了自己的类型,因为我正在理解文本并试图让它发挥作用。

我的目的是让这个应用程序运行并让它能够在运行 时记录所有创建的窗口。呼唤所有人的眼球...

更新: 被截断,因为显然你是 can't write global windows hooks in .Net/托管代码(除了一些低级鼠标或键盘 Hook )

所以我切换到C++。仍然所有的 WinAPI 调用都返回有效的句柄,但我没有看到我的过滤器函数被调用 - 似乎没有收到任何通知。仍然不起作用...有人可以发现错误。

void CWinHookFacade::Hook()
{
    HMODULE hCurrentDll = LoadLibrary(_T("[Path to my hook dll]"));
    m_HookHandle = SetWindowsHookEx(WH_CBT,
        FilterFunctionForHook,
        hCurrentDll,
        0);
    if (m_HookHandle == NULL)
    {
        throw new std::exception("Unable to hook");
    }

}
void CWinHookFacade::Unhook()
{
    if (!UnhookWindowsHookEx(m_HookHandle))
    {
        throw new std::exception("Unhook failed!");
    }
    m_HookHandle = NULL;
}

LRESULT CWinHookFacade::FilterFunctionForHook(int code, WPARAM wParam, LPARAM lParam)
{
    if (code >= 0)
    {
        switch(code)
        {
        case HCBT_CREATEWND:
            wprintf(_T("Created Window"));
            break;
        case HCBT_ACTIVATE:
            wprintf(_T("Activated Window"));
            break;
        case HCBT_DESTROYWND:
            wprintf(_T("Destroy Window"));
            break;
        }
    }

    return CallNextHookEx(m_HookHandle, code, wParam, lParam);
}

客户端 exe 像这样调用 Hook_DLL
int _tmain(int argc, _TCHAR* argv[])
{
    CWinHookFacade::Hook();
    getchar();
    CWinHookFacade::Unhook();
}

最佳答案

我认为你遇到的问题是因为你试图在 C# 中实现一个钩子(Hook)函数。基于 SetWindowsHookEx() 上的 pinvoke.net's documentation ,它说你不能这样做 - 钩子(Hook)过程必须在一个非托管的 DLL 中。否则,这将通过消息循环将您的 DLL 加载到所有正在运行的进程中,从而导致在每个进程中加载​​和启动 CLR。这不仅需要很长时间,而且将 CLR 注入(inject)所有进程可能不是最好的主意。另外,如果一个进程已经有一个与你的 DLL 所针对的不同的正在运行的 CLR,会发生什么?

最好的方法是将此代码移动到非托管 C++ DLL,并使用某种进程间通信将钩子(Hook)过程拦截的数据发送回应用程序。

更新

首先(这可能不会导致您的问题),为什么要调用 LoadLibrary() 来获取 DLL 的 HINSTANCE?调用 GetModuleHandle() 可能会更好,因为您的 DLL 已经加载。

至于为什么你的钩子(Hook)程序从来没有被调用过——你是如何验证这一点的?由于您正在挂接系统中的所有 GUI 线程,这意味着您的 DLL 需要加载到所有 GUI 进程中。您可能看不到调用 wprintf() 的结果,因为其他进程没有显示输出的控制台窗口。

要验证您的 DLL 是否已正确加载,请使用列出进程加载的 DLL 的程序(我喜欢 Process Explorer )。您可以使用查找|查找句柄或 DLL 菜单项以搜索您的 DLL 的名称 - 它应该显示在所有带有消息循环的进程中。

一旦您确认您的 DLL 已加载,要查看您的钩子(Hook)是否被调用,您可以将调试器附加到另一个进程(例如记事本),然后在您的钩子(Hook)函数中设置断点。每当有消息发送到 CBT 钩子(Hook)时,它就会消失。如果您不想使用调试器,那么您可以将对 wprintf() 的调用更改为 OutputDebugString() 并运行类似 DebugView 的实用程序来监视结果。

最后,由于您的钩子(Hook)函数是在另一个进程的上下文中调用的,因此您的 m_HookHandle 变量在那里将无效。您应该将其存储在 shared data segment 中,以便您的 DLL 的所有加载实例都具有相同的值。

关于c# - 如何添加系统 "windows hook"以便在创建/激活窗口时收到通知?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/964564/

10-15 06:08