Странное поведение крючка 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.