Перехватчик WH_JOURNALRECORD в Windows (C ++) - обратный вызов никогда не вызывается.

Следующий код доставлял мне некоторые проблемы в течение последних нескольких часов. Я пытаюсь написать небольшую программу (на основе некоторых руководств из Интернета), которая использует обработчик Windows WH_JOURNALRECORD для регистрации нажатий клавиш.

Основной код:

#include "StdAfx.h"
#include <tchar.h>
#include <iostream>
#include <windows.h>

using std::cout;
using std::endl;

int _tmain(int argc, _TCHAR* argv[]) {  
    HINSTANCE hinst = LoadLibrary(_T("testdll3.dll")); 
    typedef void (*Install)();
    typedef void (*Uninstall)();
    Install install = (Install) GetProcAddress(hinst, "install");
    Uninstall uninstall = (Uninstall) GetProcAddress(hinst, "uninstall");

    install();
    int foo;
    std::cin >> foo; 

    cout << "Uninstalling" << endl;
    uninstall();
    return 0;
}

Код DLL:

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

HHOOK hhk;
HHOOK hhk2;


LRESULT CALLBACK journalRecordProc(int code, WPARAM wParam, LPARAM lParam) {  
    FILE * fileLog = fopen("journal.txt", "a+");
    fprintf(fileLog,"loggedJournal\n");
    fclose(fileLog);
    CallNextHookEx(hhk,code,wParam,lParam);
    return 0;
}


LRESULT CALLBACK wireKeyboardProc(int code,WPARAM wParam,LPARAM lParam) {  
 FILE * fileLog = fopen("keyboard.txt", "a+");
 fprintf(fileLog,"loggedKeyboard\n");  
 fclose(fileLog);
 CallNextHookEx(hhk,code,wParam,lParam);
 return 0;
}

extern "C" __declspec(dllexport) void install() {
    HINSTANCE thisDllInstance = LoadLibrary(_T("testdll3.dll"));
    hhk = SetWindowsHookEx(WH_JOURNALRECORD, journalRecordProc, thisDllInstance, NULL);
    hhk2 = SetWindowsHookEx(WH_KEYBOARD, wireKeyboardProc, thisDllInstance, NULL);
}
extern "C" __declspec(dllexport) void uninstall() {
    UnhookWindowsHookEx(hhk); 
    UnhookWindowsHookEx(hhk2); 
}

BOOL WINAPI DllMain(  __in  HINSTANCE hinstDLL, __in  DWORD fdwReason, __in  LPVOID lpvReserved) {
 return TRUE;
}

По какой-то причине ловушка клавиатуры (SetWindowsHookEx (WH_KEYBOARD, wireKeyboardProc, ..)) работает (создается файл 'keyboard.txt'), но ловушка журналирования (SetWindowsHookEx (WH_JOURNALRECORD, journalRecordProc, ...)) не работает. . То есть обратный вызов для ловушки журналирования никогда не вызывается (файл journal.txt никогда не создается).

Я думаю, что это может иметь какое-то отношение к UAC Windows (который я обнаружил при поиске в Интернете), но отключение UAC и запуск программы с правами администратора не помогли.

Я не знаю, что мне теперь делать. Может кто-нибудь помочь мне?

Спасибо

Джорис

Дополнительная информация: я использую Windows 7 + Visual Studio 2010

Изменить: оказалось, что это действительно связано с правами доступа. То есть, начиная с Windows Vista, обработчики журнала (WH_JOURNALRECORD) отключены по соображениям безопасности (см. Также этот сайт). В конце концов, мы использовали совершенно другой подход для обеспечения аналогичной функциональности в нашем приложении (я не буду вдаваться в подробности здесь, так как я редактирую этот вопрос через 1,5 года после того, как я задал этот вопрос, и я не помню всех детали нашего решения).


person Joris    schedule 01.07.2010    source источник


Ответы (3)


Ответ по ссылке в отредактированном вопросе:

http://www.wintellect.com/CS/blogs/jrobbins/archive/2008/08/30/so-you-want-to-set-a-windows-journal-recording-hook-on-vista-it-s-not-почти-as-easy-as-you-think.aspx

  1. Приложение должно запускаться с правами администратора.
  2. Приложение должно запускаться из (подкаталога) c:\program files
  3. Чтобы отключить диалоговое окно UAC, приложение должно иметь цифровую подпись.
    Обратите внимание, что с активным UAC Windows (Vista и выше) не позволит отладить исполняемый файл.

Или ... Можно отключить UAC (полезно при отладке).

Здесь диалоговое окно настроек для Visual Studio проверит, могу ли я получить файл манифеста в формате XML.

image

person Johan    schedule 22.09.2014

WH_JOURNALRECORD отличается от других. Вам не нужно помещать его в DLL, но вам нужно иметь цикл сообщений в вашем приложении, чтобы обработчик мог быть вызван (в контексте вашего приложения). Некоторое время назад я разместил пример на другом сайте: http://forum.4programmers.net/viewtopic.php?p=557297#id557297, ловушка перехватывает WM_MOUSEMOVE в примере и выводит результаты на консоль.

Этот вид ловушки дорог, потому что каждый раз, когда вызывается обратный вызов, контекст выполнения должен переключаться на ваше приложение.

person adf88    schedule 01.07.2010

MSDN утверждает следующее для ловушки Journal Record:

В отличие от большинства других глобальных подключаемых процедур, подключаемые процедуры JournalRecordProc и JournalPlaybackProc всегда вызываются в контексте потока, который устанавливает ловушку.

Если вы переместите обратный вызов для ловушки журнала в исполняемый файл, вызовет ли это его?

Кроме того, не лучше было бы вызвать GetModuleHandle (), а чем LoadLibrary() в install(), поскольку DLL уже загружена?

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

person Andy    schedule 01.07.2010
comment
Мм, я не совсем уверен, что вы имеете в виду. Если вы переместите обратный вызов для ловушки журнала в исполняемый файл, вызовет ли это его? Я пытался не вызывать SetWindowsHookEx и UnhookWindowsHookEx изнутри exe (очевидно, я также скопировал обратные вызовы в exe), но при этом не вызывается обратный вызов (даже обратный вызов WH_KEYBOARD ...). Я также попытался передать обратный вызов как указатель функции из exe в dll, но это не сработало (ошибки времени выполнения). Есть другие идеи? Спасибо - person Joris; 01.07.2010
comment
Я имею в виду, что и SetWindowsHookEx (), и процедура обратного вызова должны быть определены в вашем exe, а не в dll. Это потому, что этот обратный вызов вызывается в вашем приложении, а не в приложении, которое отправило сообщение. - person Andy; 01.07.2010