|
|||
IntroductionMany IE add-ins are using Windows Hook mechanism to monitor message traffic for mouse messages and to perform their intended task related with mouse activities. Since the global hook slows down the system performance drastically, the thread-specific hook will be used in most cases. IE, on the other hand, is a multi-threaded SDI application. That is, each IE instance will be running in its own thread under the same process address space as long as the new instance of IE is created from the same process address space. (You can still create a new IE in new process address space by double-clicking the IE icon in Desktop again, or run command prompt and type "IExplore.exe"). Now, take a look at MSDN to check the hook API function's prototype: HHOOK SetWindowsHookEx( int idHook, // hook type HOOKPROC lpfn, // hook procedure HINSTANCE hMod, // handle to application instance DWORD dwThreadId // thread identifier ); You can find that the third parameter of the function is thread identifier and it must be provided, otherwise it will monitor all existing threads running in the same desktop as the calling thread (and this is called as "global Windows hook", right?). In order to install the mouse hook, we call LRESULT CALLBACK MouseProc( int nCode, // hook code WPARAM wParam, // message identifier LPARAM lParam) // mouse coordinates { if (nCode == HC_ACTION) { if (lParam) { MOUSEHOOKSTRUCT *pMH = reinterpret_cast<MOUSEHOOKSTRUCT *>(lParam); switch (wParam) { case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_MOUSEWHEEL: // do something break; default: break; } } } return ::CallNextHookEx(g_hHook, nCode, wParam, lParam); } To make a window hook chain mechanism work correctly, you should call LRESULT CallNextHookEx( HHOOK hhk, // handle to current hook int nCode, // hook code passed to hook procedure WPARAM wParam, // value passed to hook procedure LPARAM lParam // value passed to hook procedure ); At this point, you will be able to see the necessity of the global map structure to find out the appropriate thread-specific But, isn't this very similar to Implementation NoteI think you might be already tired with my bad English, so I will give you references here to help you understand of what the assembly thunk is and how it does its magic.
The core of my thunking implementation is shown below: mov eax, dword ptr [esp+0Ch] // 8B 44 24 0C mov [pThis->;lParam], eax // A3 [DWORD pThis->lParam] mov dword ptr [esp+0Ch], [pThis] // C7 44 24 0C [DWORD pThis] jmp [MouseProc addr] // E9 [DWORD MouseProc addr] I changed the The Now, new LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { CMouseProcHook *pThis = reinterpret_cast<CMouseProcHook *>(lParam); lParam = pThis->GetLPARAM(); if (nCode == HC_ACTION) { if (lParam) { MOUSEHOOKSTRUCT *pMH = reinterpret_cast<MOUSEHOOKSTRUCT *>(lParam); switch (wParam) { case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_MOUSEWHEEL: // do something break; default: break; } } } return ::CallNextHookEx(pThis->GetHHOOK(), nCode, wParam, lParam); } The last thing I should mention is a map structure used in my codes. The map is only here to avoid a multiple hook installation and to remove an already installed hook procedure from a hook chain. And the rest of the story goes the same as Using codeWhen you compile the source code, it will automatically register the output DLL file in JaeWook Choi |