Странное поведение крючка 32/64 бит

Я использую местный хук (WH_KEYBOARD) со словом MS (OpusApp). Ну, насколько я знаю, 32-битное приложение с 32bit DLL должен работать только с 32bit target applications, Странно то, что программа работает только с 64-битными приложениями!!! Вот только с 64bits APPS! Например, it works with IE 64 but not with IE 32! Приложение и dll 32-битные скомпилированы с radstudio XE2, Я подтвердил версию в PE заголовок. В 32-битных ОС приложение и dll не работают.

Я не нашел решений в сети и не вижу отправной точки для решения этой странной проблемы.

Код DLL:

// Exported functions

extern "C" __declspec(dllexport)bool __stdcall InstallMouseHook(unsigned long, void *);

extern "C" __declspec(dllexport)bool __stdcall RemoveMouseHook();

// Callback Procedure Declaration

LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam);

// Global variables

HHOOK HookHandle;
HINSTANCE DllInstance;
typedef void (__stdcall *CALLIT)(int,WPARAM,LPARAM);
CALLIT callIt = NULL;

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
  DllInstance=hinst;
  return 1;
}

bool __stdcall InstallMouseHook(unsigned long pid, void *function)
{

     callIt = ( CALLIT ) function;

     if (function == NULL) {

        ShowMessage("function is null!");

     } else if (callIt == NULL) {

        ShowMessage("callIt is null!");

     }  

     HookHandle=SetWindowsHookEx(WH_KEYBOARD ,reinterpret_cast<HOOKPROC> (HookProc),DllInstance,pid);

    if (HookHandle==NULL)return false;

    else return true;

}

bool __stdcall  RemoveMouseHook()
{
  if(UnhookWindowsHookEx(HookHandle)==0)
  {
    return false;
  }
  else return true;
}

LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
    if (code<0) {
        return CallNextHookEx(HookHandle,code,wParam,lParam);
    }

    if (callIt != NULL) {
        callIt(code,wParam,lParam);
    } else {
        ShowMessage("HookProc - no function to execute OR 32/64 bits problem!");
    }

  //Call the next hook in the chain
  return CallNextHookEx(HookHandle,code,wParam,lParam);
}

Вызывающий код EXE:

void __fastcall TfrmMouseHook::btnHookAppDllClick(TObject *Sender)
{
    HWND hWindow;
    unsigned long pid;

    String s = "MouseHookDLL.dll";
    DllHandle=LoadLibrary(s.w_str());
    MOUSEHOOKFCT_2 InstHook=reinterpret_cast<MOUSEHOOKFCT_2> (GetProcAddress(DllHandle,"InstallMouseHook"));

    hWindow = FindWindow(ComboBox1->Text.w_str(),NULL);

    if (!hWindow) {
        msg("hWindow fail");
        return;
    }

    pid = GetWindowThreadProcessId(hWindow ,0);
    if (!pid) {
       msg("pid fail");
       return;
    }

    if(!InstHook(pid, (void *) callIt )) {
        msg("Unable to install  hook!");
    } else {
        msg(" #### hook INSTALLED! ####");
    }


}

CALLIT callIt(code,wParam,lParam) {
    frmMouseHook->msg("hook callit: code="+IntToStr(code) +" wparam="+IntToStr(wParam)+" lparam="+IntToStr(lParam) );
}



   Call IT is a function pointer to a hooker app function.

    Any ideas will be very wellcome!

2 ответа

Для 32-битного приложения физически невозможно установить 32-битную подключаемую DLL-библиотеку и запустить ее в 64-битных процессах. 32-битная DLL просто не может быть внедрена в 64-битный процесс. Период. MSDN говорит об этом в нескольких местах, в том числе в документации SetWindowsHookEx():

SetWindowsHookEx может использоваться для внедрения DLL в другой процесс. 32-битная DLL не может быть введена в 64-битный процесс, а 64-битная DLL не может быть внедрена в 32-битный процесс. Если приложение требует использования хуков в других процессах, требуется, чтобы 32-разрядное приложение вызывало SetWindowsHookEx для внедрения 32-разрядной DLL в 32-разрядные процессы, а 64-разрядное приложение вызывало SetWindowsHookEx для внедрения 64-разрядного DLL в 64-битных процессах. 32-битные и 64-битные библиотеки DLL должны иметь разные имена.

Поскольку хуки выполняются в контексте приложения, они должны соответствовать "разрядности" приложения. Если 32-битное приложение устанавливает глобальный хук в 64-битной Windows, 32-битный хук внедряется в каждый 32-битный процесс (применяются обычные границы безопасности). В 64-битном процессе потоки по-прежнему помечаются как "подключенные". Однако, поскольку 32-разрядное приложение должно запускать код подключения, система выполняет его в контексте приложения подключения; в частности, в потоке, который называется SetWindowsHookEx. Это означает, что приложение перехвата должно продолжать качать сообщения, иначе оно может заблокировать нормальное функционирование 64-битных процессов.

Если 64-битное приложение устанавливает глобальный хук в 64-битной Windows, 64-битный хук внедряется в каждый 64-битный процесс, в то время как все 32-битные процессы используют обратный вызов для перехватывающего приложения.

Тот факт, что вы говорите, что ваше приложение и DLL не работают на 32-битных версиях ОС, предполагает, что ваш код перехвата с самого начала имеет недостатки. Но вы не показали достаточно кода для диагностики того или иного способа.

Что случается? Помимо того, что MSDN или кто-либо еще говорит, что в XE6 есть какая-то ошибка, компиляция DLL в более новых версиях IDE приводит к тому, что это поведение исчезает, на самом деле, новая DLL дает сбой и ничего не перехватывает.

Как заметил Реми, в тесте я передал указатель на функцию в DLL, что было неправильно, но когда Embarcadero добавил не то, что сделал, вроде бы заработало.

К настоящему времени, и я знаю, что люди разозлятся, я поместил оба метода (неправильный и правильный хуки) в одну и ту же DLL и в свое приложение и... сошёл с ума... мог подключиться к 32- и 64-битному приложению всего лишь одна DLL.

Не верите? Установите XE6 и попробуйте!

И работает в Windows 10, а также в Windows 7.

Другие вопросы по тегам