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