Как добавить системный «оконный хук», чтобы получать уведомления о создании / активации окон? - PullRequest
5 голосов
/ 08 июня 2009

Перепробовал кучу вещей, но я не могу заставить его работать стабильно из-за обстрела панели задач и других сверхъестественных эффектов на моем настольном интерфейсе.

Пробовал сначала с использованием открытой библиотеки http://mwinapi.sourceforge.net/. Хотя он прекрасно работал как слой ОО для перечисления окон и прочего. Это не могло сделать крюки должным образом

Следующая остановка была Пост Дино Э. по Windows Hooks в .Net framework . Я закончил тем, что писал свой собственный тип, поскольку я понимал текст и пытался заставить это работать.

Мое намерение состоит в том, чтобы это приложение работало и оно могло регистрировать все созданные окна, пока оно работает . Обзывая все глазные яблоки ...

Обновление: Отрезано, поскольку, очевидно, вы не можете написать глобальные хуки окон в .Net / управляемом коде (за исключением некоторых низкоуровневых хуков мыши или клавиатуры)

Итак, я перешел на 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();
}

Ответы [ 2 ]

5 голосов
/ 08 июня 2009

Я думаю, что у вас проблемы, потому что вы пытаетесь реализовать функцию ловушки в C #. Основываясь на документации pinvoke.net на SetWindowsHookEx(), он говорит, что вы не можете сделать это - процедура подключения должна быть в неуправляемой DLL. В противном случае это приведет к загрузке вашей DLL во все запущенные процессы с помощью цикла сообщений, что, в свою очередь, приведет к загрузке и запуску CLR в каждом процессе. Это не только займет много времени, но внедрение CLR во все процессы, вероятно, не лучшая идея. Кроме того, что произойдет, если у процесса уже есть работающий CLR, отличный от того, на котором была построена ваша DLL?

Наилучшим подходом было бы переместить этот код в неуправляемую DLL-библиотеку C ++ и использовать какое-то межпроцессное взаимодействие для отправки данных, перехваченных процедурой ловушки, обратно в ваше приложение.

Обновление

Во-первых (и это, вероятно, не вызывает вашей проблемы), почему вы звоните LoadLibrary(), чтобы получить HINSTANCE вашей DLL? Вероятно, было бы лучше вызвать GetModuleHandle () , поскольку ваша DLL уже загружена.

А почему ваша процедура ловушки никогда не вызывается - как вы это проверили? Поскольку вы перехватываете все потоки GUI в системе, это означает, что ваша DLL должна быть загружена во все процессы GUI. Вполне вероятно, что вы не увидите результатов вызова wprintf(), потому что другие процессы не имеют консольного окна для отображения вывода.

Чтобы убедиться, что ваша DLL загружена правильно, используйте программу, в которой перечислены библиотеки DLL, загруженные процессом (мне нравится Process Explorer ). Вы можете использовать Find | Найдите элемент меню Handle или DLL для поиска имени вашей DLL - оно должно отображаться во всех процессах с циклом сообщений.

После того, как вы проверили, что ваша DLL загружена, чтобы увидеть, вызвана ли ваша ловушка, вы можете присоединить отладчик к другому процессу (например, «Блокнот»), а затем установить точку останова в своей функции ловушки. Это должно происходить всякий раз, когда сообщение отправляется на крючок CBT. Если вы не хотите использовать отладчик, вы можете изменить вызовы на wprintf() на OutputDebugString () и запустить утилиту, подобную DebugView , для мониторинга результатов.

Наконец, поскольку ваша подключаемая функция вызывается в контексте другого процесса, ваша переменная m_HookHandle там не будет действительной. Вы должны хранить его в сегменте общих данных , чтобы все загруженные экземпляры вашей DLL имели одинаковое значение.

3 голосов
/ 16 июня 2009

Наконец прибил этот. Написал это как сообщение в блоге на случай, если кому-то понадобится это в будущем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...