More hook implementations.
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / hook.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * PURPOSE: Window hooks
23 * FILE: subsys/win32k/ntuser/hook.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * REVISION HISTORY:
26 * 06-06-2001 CSH Created
27 * NOTE: Most of this code was adapted from Wine,
28 * Copyright (C) 2002 Alexandre Julliard
29 */
30
31 #include <w32k.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 #define HOOKID_TO_INDEX(HookId) (HookId - WH_MINHOOK)
37 #define HOOKID_TO_FLAG(HookId) (1 << ((HookId) + 1))
38
39 static PHOOKTABLE GlobalHooks;
40 DWORD Bogus_SrvEventActivity = 0;
41
42
43 /* PRIVATE FUNCTIONS *********************************************************/
44
45 static
46 DWORD
47 FASTCALL
48 GetMaskFromEvent(DWORD Event)
49 {
50 DWORD Ret = 0;
51
52 if ( Event > EVENT_OBJECT_STATECHANGE )
53 {
54 if ( Event == EVENT_OBJECT_LOCATIONCHANGE ) return SRV_EVENT_LOCATIONCHANGE;
55 if ( Event == EVENT_OBJECT_NAMECHANGE ) return SRV_EVENT_NAMECHANGE;
56 if ( Event == EVENT_OBJECT_VALUECHANGE ) return SRV_EVENT_VALUECHANGE;
57 return SRV_EVENT_CREATE;
58 }
59
60 if ( Event == EVENT_OBJECT_STATECHANGE ) return SRV_EVENT_STATECHANGE;
61
62 Ret = SRV_EVENT_RUNNING;
63
64 if ( Event < EVENT_SYSTEM_MENUSTART ) return SRV_EVENT_CREATE;
65
66 if ( Event <= EVENT_SYSTEM_MENUPOPUPEND )
67 {
68 Ret = SRV_EVENT_MENU;
69 }
70 else
71 {
72 if ( Event <= EVENT_CONSOLE_CARET-1 ) return SRV_EVENT_CREATE;
73 if ( Event <= EVENT_CONSOLE_END_APPLICATION ) return SRV_EVENT_END_APPLICATION;
74 if ( Event != EVENT_OBJECT_FOCUS ) return SRV_EVENT_CREATE;
75 }
76 return Ret;
77 }
78
79 /* create a new hook table */
80 static PHOOKTABLE
81 IntAllocHookTable(void)
82 {
83 PHOOKTABLE Table;
84 UINT i;
85
86 Table = ExAllocatePoolWithTag(PagedPool, sizeof(HOOKTABLE), TAG_HOOK);
87 if (NULL != Table)
88 {
89 for (i = 0; i < NB_HOOKS; i++)
90 {
91 InitializeListHead(&Table->Hooks[i]);
92 Table->Counts[i] = 0;
93 }
94 }
95
96 return Table;
97 }
98
99
100 PHOOK FASTCALL IntGetHookObject(HHOOK hHook)
101 {
102 PHOOK Hook;
103
104 if (!hHook)
105 {
106 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE);
107 return NULL;
108 }
109
110 Hook = (PHOOK)UserGetObject(gHandleTable, hHook, otHook);
111 if (!Hook)
112 {
113 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE);
114 return NULL;
115 }
116
117 ASSERT(USER_BODY_TO_HEADER(Hook)->RefCount >= 0);
118
119 USER_BODY_TO_HEADER(Hook)->RefCount++;
120
121 return Hook;
122 }
123
124
125
126 /* create a new hook and add it to the specified table */
127 static PHOOK
128 IntAddHook(PETHREAD Thread, int HookId, BOOLEAN Global, PWINSTATION_OBJECT WinStaObj)
129 {
130 PW32THREAD W32Thread;
131 PHOOK Hook;
132 PHOOKTABLE Table = Global ? GlobalHooks : MsqGetHooks(((PW32THREAD)Thread->Tcb.Win32Thread)->MessageQueue);
133 HANDLE Handle;
134
135 if (NULL == Table)
136 {
137 Table = IntAllocHookTable();
138 if (NULL == Table)
139 {
140 return NULL;
141 }
142 if (Global)
143 {
144 GlobalHooks = Table;
145 }
146 else
147 {
148 MsqSetHooks(((PW32THREAD)Thread->Tcb.Win32Thread)->MessageQueue, Table);
149 }
150 }
151
152 Hook = UserCreateObject(gHandleTable, &Handle, otHook, sizeof(HOOK));
153 if (NULL == Hook)
154 {
155 return NULL;
156 }
157
158 Hook->Self = Handle;
159 Hook->Thread = Thread;
160 Hook->HookId = HookId;
161
162 W32Thread = ((PW32THREAD)Thread->Tcb.Win32Thread);
163 ASSERT(W32Thread != NULL);
164 W32Thread->Hooks |= HOOKID_TO_FLAG(HookId);
165 if (W32Thread->ThreadInfo != NULL)
166 W32Thread->ThreadInfo->Hooks = W32Thread->Hooks;
167
168 RtlInitUnicodeString(&Hook->ModuleName, NULL);
169
170 InsertHeadList(&Table->Hooks[HOOKID_TO_INDEX(HookId)], &Hook->Chain);
171
172 return Hook;
173 }
174
175 /* get the hook table that a given hook belongs to */
176 static PHOOKTABLE FASTCALL
177 IntGetTable(PHOOK Hook)
178 {
179 if (NULL == Hook->Thread || WH_KEYBOARD_LL == Hook->HookId ||
180 WH_MOUSE_LL == Hook->HookId)
181 {
182 return GlobalHooks;
183 }
184
185 return MsqGetHooks(((PW32THREAD)Hook->Thread->Tcb.Win32Thread)->MessageQueue);
186 }
187
188 /* get the first hook in the chain */
189 static PHOOK FASTCALL
190 IntGetFirstHook(PHOOKTABLE Table, int HookId)
191 {
192 PLIST_ENTRY Elem = Table->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
193 return Elem == &Table->Hooks[HOOKID_TO_INDEX(HookId)]
194 ? NULL : CONTAINING_RECORD(Elem, HOOK, Chain);
195 }
196
197 /* find the first non-deleted hook in the chain */
198 static PHOOK FASTCALL
199 IntGetFirstValidHook(PHOOKTABLE Table, int HookId)
200 {
201 PHOOK Hook;
202 PLIST_ENTRY Elem;
203
204 Hook = IntGetFirstHook(Table, HookId);
205 while (NULL != Hook && NULL == Hook->Proc)
206 {
207 Elem = Hook->Chain.Flink;
208 Hook = (Elem == &Table->Hooks[HOOKID_TO_INDEX(HookId)]
209 ? NULL : CONTAINING_RECORD(Elem, HOOK, Chain));
210 }
211
212 return Hook;
213 }
214
215 /* find the next hook in the chain, skipping the deleted ones */
216 static PHOOK FASTCALL
217 IntGetNextHook(PHOOK Hook)
218 {
219 PHOOKTABLE Table = IntGetTable(Hook);
220 int HookId = Hook->HookId;
221 PLIST_ENTRY Elem;
222
223 Elem = Hook->Chain.Flink;
224 while (Elem != &Table->Hooks[HOOKID_TO_INDEX(HookId)])
225 {
226 Hook = CONTAINING_RECORD(Elem, HOOK, Chain);
227 if (NULL != Hook->Proc)
228 {
229 return Hook;
230 }
231 }
232
233 if (NULL != GlobalHooks && Table != GlobalHooks) /* now search through the global table */
234 {
235 return IntGetFirstValidHook(GlobalHooks, HookId);
236 }
237
238 return NULL;
239 }
240
241 /* free a hook, removing it from its chain */
242 static VOID FASTCALL
243 IntFreeHook(PHOOKTABLE Table, PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
244 {
245 RemoveEntryList(&Hook->Chain);
246 RtlFreeUnicodeString(&Hook->ModuleName);
247
248 /* Dereference thread if required */
249 if (Hook->Flags & HOOK_THREAD_REFERENCED)
250 {
251 ObDereferenceObject(Hook->Thread);
252 }
253
254 /* Close handle */
255 UserDeleteObject(Hook->Self, otHook);
256 }
257
258 /* remove a hook, freeing it if the chain is not in use */
259 static VOID
260 IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj, BOOL TableAlreadyLocked)
261 {
262 PW32THREAD W32Thread;
263 PHOOKTABLE Table = IntGetTable(Hook);
264
265 ASSERT(NULL != Table);
266 if (NULL == Table)
267 {
268 return;
269 }
270
271 W32Thread = ((PW32THREAD)Hook->Thread->Tcb.Win32Thread);
272 ASSERT(W32Thread != NULL);
273 W32Thread->Hooks &= ~HOOKID_TO_FLAG(Hook->HookId);
274 if (W32Thread->ThreadInfo != NULL)
275 W32Thread->ThreadInfo->Hooks = W32Thread->Hooks;
276
277 if (0 != Table->Counts[HOOKID_TO_INDEX(Hook->HookId)])
278 {
279 Hook->Proc = NULL; /* chain is in use, just mark it and return */
280 }
281 else
282 {
283 IntFreeHook(Table, Hook, WinStaObj);
284 }
285 }
286
287 /* release a hook chain, removing deleted hooks if the use count drops to 0 */
288 static VOID FASTCALL
289 IntReleaseHookChain(PHOOKTABLE Table, int HookId, PWINSTATION_OBJECT WinStaObj)
290 {
291 PLIST_ENTRY Elem;
292 PHOOK HookObj;
293
294 if (NULL == Table)
295 {
296 return;
297 }
298
299 /* use count shouldn't already be 0 */
300 ASSERT(0 != Table->Counts[HOOKID_TO_INDEX(HookId)]);
301 if (0 == Table->Counts[HOOKID_TO_INDEX(HookId)])
302 {
303 return;
304 }
305 if (0 == --Table->Counts[HOOKID_TO_INDEX(HookId)])
306 {
307 Elem = Table->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
308 while (Elem != &Table->Hooks[HOOKID_TO_INDEX(HookId)])
309 {
310 HookObj = CONTAINING_RECORD(Elem, HOOK, Chain);
311 Elem = Elem->Flink;
312 if (NULL == HookObj->Proc)
313 {
314 IntFreeHook(Table, HookObj, WinStaObj);
315 }
316 }
317 }
318 }
319
320 static LRESULT FASTCALL
321 IntCallLowLevelHook(INT HookId, INT Code, WPARAM wParam, LPARAM lParam, PHOOK Hook)
322 {
323 NTSTATUS Status;
324 ULONG_PTR uResult;
325
326 /* FIXME should get timeout from
327 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
328 Status = co_MsqSendMessage(((PW32THREAD)Hook->Thread->Tcb.Win32Thread)->MessageQueue, (HWND) Code, HookId,
329 wParam, lParam, 5000, TRUE, TRUE, &uResult);
330
331 return NT_SUCCESS(Status) ? uResult : 0;
332 }
333
334 LRESULT FASTCALL
335 co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
336 {
337 PHOOK Hook;
338 PW32THREAD Win32Thread;
339 PHOOKTABLE Table;
340 LRESULT Result;
341 PWINSTATION_OBJECT WinStaObj;
342 NTSTATUS Status;
343
344 ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK);
345
346 Win32Thread = PsGetCurrentThreadWin32Thread();
347 if (NULL == Win32Thread)
348 {
349 Table = NULL;
350 }
351 else
352 {
353 Table = MsqGetHooks(Win32Thread->MessageQueue);
354 }
355
356 if (NULL == Table || ! (Hook = IntGetFirstValidHook(Table, HookId)))
357 {
358 /* try global table */
359 Table = GlobalHooks;
360 if (NULL == Table || ! (Hook = IntGetFirstValidHook(Table, HookId)))
361 {
362 return 0; /* no hook set */
363 }
364 }
365
366 if (Hook->Thread != PsGetCurrentThread()
367 && (WH_KEYBOARD_LL == HookId || WH_MOUSE_LL == HookId))
368 {
369 DPRINT("Calling hook in owning thread\n");
370 return IntCallLowLevelHook(HookId, Code, wParam, lParam, Hook);
371 }
372
373 if (Hook->Thread != PsGetCurrentThread())
374 {
375 DPRINT1("Calling hooks in other threads not implemented yet");
376 return 0;
377 }
378
379 Table->Counts[HOOKID_TO_INDEX(HookId)]++;
380 if (Table != GlobalHooks && GlobalHooks != NULL)
381 {
382 GlobalHooks->Counts[HOOKID_TO_INDEX(HookId)]++;
383 }
384
385 Result = co_IntCallHookProc(HookId, Code, wParam, lParam, Hook->Proc,
386 Hook->Ansi, &Hook->ModuleName);
387
388 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
389 KernelMode,
390 0,
391 &WinStaObj);
392
393 if (! NT_SUCCESS(Status))
394 {
395 DPRINT1("Invalid window station????\n");
396 }
397 else
398 {
399 IntReleaseHookChain(MsqGetHooks(PsGetCurrentThreadWin32Thread()->MessageQueue), HookId, WinStaObj);
400 IntReleaseHookChain(GlobalHooks, HookId, WinStaObj);
401 ObDereferenceObject(WinStaObj);
402 }
403
404 return Result;
405 }
406
407 VOID FASTCALL
408 HOOK_DestroyThreadHooks(PETHREAD Thread)
409 {
410 int HookId;
411 PLIST_ENTRY Elem;
412 PHOOK HookObj;
413 PWINSTATION_OBJECT WinStaObj;
414 NTSTATUS Status;
415
416 if (NULL != GlobalHooks)
417 {
418 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
419 KernelMode,
420 0,
421 &WinStaObj);
422
423 if (! NT_SUCCESS(Status))
424 {
425 DPRINT1("Invalid window station????\n");
426 return;
427 }
428
429 for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
430 {
431 /* only low-level keyboard/mouse global hooks can be owned by a thread */
432 switch(HookId)
433 {
434 case WH_KEYBOARD_LL:
435 case WH_MOUSE_LL:
436 Elem = GlobalHooks->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
437 while (Elem != &GlobalHooks->Hooks[HOOKID_TO_INDEX(HookId)])
438 {
439 HookObj = CONTAINING_RECORD(Elem, HOOK, Chain);
440 Elem = Elem->Flink;
441 if (HookObj->Thread == Thread)
442 {
443 IntRemoveHook(HookObj, WinStaObj, TRUE);
444 }
445 }
446 break;
447 }
448 }
449
450 ObDereferenceObject(WinStaObj);
451 }
452 }
453
454 LRESULT
455 STDCALL
456 NtUserCallNextHookEx(
457 HHOOK Hook,
458 int Code,
459 WPARAM wParam,
460 LPARAM lParam)
461 {
462 PHOOK HookObj, NextObj;
463 PWINSTATION_OBJECT WinStaObj;
464 NTSTATUS Status;
465 DECLARE_RETURN(LRESULT);
466
467 DPRINT("Enter NtUserCallNextHookEx\n");
468 UserEnterExclusive();
469
470 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
471 KernelMode,
472 0,
473 &WinStaObj);
474
475 if (! NT_SUCCESS(Status))
476 {
477 SetLastNtError(Status);
478 RETURN( FALSE);
479 }
480
481 //Status = UserReferenceObjectByHandle(gHandleTable, Hook,
482 // otHookProc, (PVOID *) &HookObj);
483 ObDereferenceObject(WinStaObj);
484
485 // if (! NT_SUCCESS(Status))
486 // {
487 // DPRINT1("Invalid handle passed to NtUserCallNextHookEx\n");
488 // SetLastNtError(Status);
489 // RETURN( 0);
490 // }
491
492 if (!(HookObj = IntGetHookObject(Hook)))
493 {
494 RETURN(0);
495 }
496
497 ASSERT(Hook == HookObj->Self);
498
499 if (NULL != HookObj->Thread && (HookObj->Thread != PsGetCurrentThread()))
500 {
501 DPRINT1("Thread mismatch\n");
502 UserDereferenceObject(HookObj);
503 SetLastWin32Error(ERROR_INVALID_HANDLE);
504 RETURN( 0);
505 }
506
507 NextObj = IntGetNextHook(HookObj);
508 UserDereferenceObject(HookObj);
509 if (NULL != NextObj)
510 {
511 DPRINT1("Calling next hook not implemented\n");
512 UNIMPLEMENTED
513 SetLastWin32Error(ERROR_NOT_SUPPORTED);
514 RETURN( 0);
515 }
516
517 RETURN( 0);
518
519 CLEANUP:
520 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_);
521 UserLeave();
522 END_CLEANUP;
523 }
524
525 HHOOK
526 STDCALL
527 NtUserSetWindowsHookAW(
528 int idHook,
529 HOOKPROC lpfn,
530 BOOL Ansi)
531 {
532 UNICODE_STRING USModuleName;
533 RtlInitUnicodeString(&USModuleName, NULL);
534 return NtUserSetWindowsHookEx(NULL, &USModuleName, 0, idHook, lpfn, Ansi);
535 }
536
537 HHOOK
538 STDCALL
539 NtUserSetWindowsHookEx(
540 HINSTANCE Mod,
541 PUNICODE_STRING UnsafeModuleName,
542 DWORD ThreadId,
543 int HookId,
544 HOOKPROC HookProc,
545 BOOL Ansi)
546 {
547 PWINSTATION_OBJECT WinStaObj;
548 BOOLEAN Global;
549 PETHREAD Thread;
550 PHOOK Hook;
551 UNICODE_STRING ModuleName;
552 NTSTATUS Status;
553 HHOOK Handle;
554 DECLARE_RETURN(HHOOK);
555
556 DPRINT("Enter NtUserSetWindowsHookEx\n");
557 UserEnterExclusive();
558
559 if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId || NULL == HookProc)
560 {
561 SetLastWin32Error(ERROR_INVALID_PARAMETER);
562 RETURN( NULL);
563 }
564
565 if (ThreadId) /* thread-local hook */
566 {
567 if (HookId == WH_JOURNALRECORD ||
568 HookId == WH_JOURNALPLAYBACK ||
569 HookId == WH_KEYBOARD_LL ||
570 HookId == WH_MOUSE_LL ||
571 HookId == WH_SYSMSGFILTER)
572 {
573 /* these can only be global */
574 SetLastWin32Error(ERROR_INVALID_PARAMETER);
575 RETURN( NULL);
576 }
577 Mod = NULL;
578 Global = FALSE;
579 if (! NT_SUCCESS(PsLookupThreadByThreadId((HANDLE) ThreadId, &Thread)))
580 {
581 DPRINT1("Invalid thread id 0x%x\n", ThreadId);
582 SetLastWin32Error(ERROR_INVALID_PARAMETER);
583 RETURN( NULL);
584 }
585 if (Thread->ThreadsProcess != PsGetCurrentProcess())
586 {
587 ObDereferenceObject(Thread);
588 DPRINT1("Can't specify thread belonging to another process\n");
589 SetLastWin32Error(ERROR_INVALID_PARAMETER);
590 RETURN( NULL);
591 }
592 }
593 else /* system-global hook */
594 {
595 if (HookId == WH_KEYBOARD_LL || HookId == WH_MOUSE_LL)
596 {
597 Mod = NULL;
598 Thread = PsGetCurrentThread();
599 Status = ObReferenceObjectByPointer(Thread,
600 THREAD_ALL_ACCESS,
601 PsThreadType,
602 KernelMode);
603
604 if (! NT_SUCCESS(Status))
605 {
606 SetLastNtError(Status);
607 RETURN( (HANDLE) NULL);
608 }
609 }
610 else if (NULL == Mod)
611 {
612 SetLastWin32Error(ERROR_INVALID_PARAMETER);
613 RETURN( NULL);
614 }
615 else
616 {
617 Thread = NULL;
618 }
619 Global = TRUE;
620 }
621
622 /* We only (partially) support local WH_CBT hooks and
623 * WH_KEYBOARD_LL/WH_MOUSE_LL hooks for now */
624 if ((WH_CBT != HookId || Global)
625 && WH_KEYBOARD_LL != HookId && WH_MOUSE_LL != HookId)
626 {
627 #if 0 /* Removed to get winEmbed working again */
628 UNIMPLEMENTED
629 #else
630 DPRINT1("Not implemented: HookId %d Global %s\n", HookId, Global ? "TRUE" : "FALSE");
631 #endif
632
633 if (NULL != Thread)
634 {
635 ObDereferenceObject(Thread);
636 }
637 SetLastWin32Error(ERROR_NOT_SUPPORTED);
638 RETURN( NULL);
639 }
640
641 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
642 KernelMode,
643 0,
644 &WinStaObj);
645
646 if (! NT_SUCCESS(Status))
647 {
648 if (NULL != Thread)
649 {
650 ObDereferenceObject(Thread);
651 }
652 SetLastNtError(Status);
653 RETURN( (HANDLE) NULL);
654 }
655
656 Hook = IntAddHook(Thread, HookId, Global, WinStaObj);
657 if (NULL == Hook)
658 {
659 if (NULL != Thread)
660 {
661 ObDereferenceObject(Thread);
662 }
663 ObDereferenceObject(WinStaObj);
664 RETURN( NULL);
665 }
666
667 if (NULL != Thread)
668 {
669 Hook->Flags |= HOOK_THREAD_REFERENCED;
670 }
671
672 if (NULL != Mod)
673 {
674 Status = MmCopyFromCaller(&ModuleName, UnsafeModuleName, sizeof(UNICODE_STRING));
675 if (! NT_SUCCESS(Status))
676 {
677 UserDereferenceObject(Hook);
678 IntRemoveHook(Hook, WinStaObj, FALSE);
679 if (NULL != Thread)
680 {
681 ObDereferenceObject(Thread);
682 }
683 ObDereferenceObject(WinStaObj);
684 SetLastNtError(Status);
685 RETURN( NULL);
686 }
687 Hook->ModuleName.Buffer = ExAllocatePoolWithTag(PagedPool,
688 ModuleName.MaximumLength,
689 TAG_HOOK);
690 if (NULL == Hook->ModuleName.Buffer)
691 {
692 UserDereferenceObject(Hook);
693 IntRemoveHook(Hook, WinStaObj, FALSE);
694 if (NULL != Thread)
695 {
696 ObDereferenceObject(Thread);
697 }
698 ObDereferenceObject(WinStaObj);
699 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
700 RETURN( NULL);
701 }
702 Hook->ModuleName.MaximumLength = ModuleName.MaximumLength;
703 Status = MmCopyFromCaller(Hook->ModuleName.Buffer,
704 ModuleName.Buffer,
705 ModuleName.MaximumLength);
706 if (! NT_SUCCESS(Status))
707 {
708 ExFreePool(Hook->ModuleName.Buffer);
709 UserDereferenceObject(Hook);
710 IntRemoveHook(Hook, WinStaObj, FALSE);
711 if (NULL != Thread)
712 {
713 ObDereferenceObject(Thread);
714 }
715 ObDereferenceObject(WinStaObj);
716 SetLastNtError(Status);
717 RETURN( NULL);
718 }
719 Hook->ModuleName.Length = ModuleName.Length;
720 }
721
722 Hook->Proc = HookProc;
723 Hook->Ansi = Ansi;
724 Handle = Hook->Self;
725
726 UserDereferenceObject(Hook);
727 ObDereferenceObject(WinStaObj);
728
729 RETURN( Handle);
730
731 CLEANUP:
732 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_);
733 UserLeave();
734 END_CLEANUP;
735 }
736
737 HWINEVENTHOOK
738 STDCALL
739 NtUserSetWinEventHook(
740 UINT eventMin,
741 UINT eventMax,
742 HMODULE hmodWinEventProc,
743 PUNICODE_STRING puString,
744 WINEVENTPROC lpfnWinEventProc,
745 DWORD idProcess,
746 DWORD idThread,
747 UINT dwflags)
748 {
749
750 Bogus_SrvEventActivity |= GetMaskFromEvent(eventMin); // Fake it out for now.
751 Bogus_SrvEventActivity &= ~GetMaskFromEvent(eventMin);
752 UNIMPLEMENTED
753
754 return 0;
755 }
756
757 BOOL
758 STDCALL
759 NtUserUnhookWindowsHookEx(
760 HHOOK Hook)
761 {
762 PWINSTATION_OBJECT WinStaObj;
763 PHOOK HookObj;
764 NTSTATUS Status;
765 DECLARE_RETURN(BOOL);
766
767 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
768 UserEnterExclusive();
769
770 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
771 KernelMode,
772 0,
773 &WinStaObj);
774
775 if (! NT_SUCCESS(Status))
776 {
777 SetLastNtError(Status);
778 RETURN( FALSE);
779 }
780
781 // Status = UserReferenceObjectByHandle(gHandleTable, Hook,
782 // otHookProc, (PVOID *) &HookObj);
783 if (!(HookObj = IntGetHookObject(Hook)))
784 {
785 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
786 ObDereferenceObject(WinStaObj);
787 // SetLastNtError(Status);
788 RETURN( FALSE);
789 }
790 ASSERT(Hook == HookObj->Self);
791
792 IntRemoveHook(HookObj, WinStaObj, FALSE);
793
794 UserDereferenceObject(HookObj);
795 ObDereferenceObject(WinStaObj);
796
797 RETURN( TRUE);
798
799 CLEANUP:
800 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_);
801 UserLeave();
802 END_CLEANUP;
803 }
804
805 DWORD
806 STDCALL
807 NtUserUnhookWinEvent(
808 HWINEVENTHOOK hWinEventHook)
809 {
810 UNIMPLEMENTED
811
812 return 0;
813 }
814
815 /* EOF */