- Rewrite HOOKs, Implement CallNextHookEx and fix prototype for NtUserCallNextHookEx...
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / callback.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 classes
24 * FILE: subsys/win32k/ntuser/wndproc.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
27 * REVISION HISTORY:
28 * 06-06-2001 CSH Created
29 * NOTES: Please use the Callback Memory Management functions for
30 * callbacks to make sure, the memory is freed on thread
31 * termination!
32 */
33
34 /* INCLUDES ******************************************************************/
35
36 #include <w32k.h>
37
38 #define NDEBUG
39 #include <debug.h>
40
41 /* CALLBACK MEMORY MANAGEMENT ************************************************/
42
43 typedef struct _INT_CALLBACK_HEADER
44 {
45 /* list entry in the W32THREAD structure */
46 LIST_ENTRY ListEntry;
47 }
48 INT_CALLBACK_HEADER, *PINT_CALLBACK_HEADER;
49
50 PVOID FASTCALL
51 IntCbAllocateMemory(ULONG Size)
52 {
53 PINT_CALLBACK_HEADER Mem;
54 PW32THREAD W32Thread;
55
56 if(!(Mem = ExAllocatePoolWithTag(PagedPool, Size + sizeof(INT_CALLBACK_HEADER),
57 TAG_CALLBACK)))
58 {
59 return NULL;
60 }
61
62 W32Thread = PsGetCurrentThreadWin32Thread();
63 ASSERT(W32Thread);
64
65 /* insert the callback memory into the thread's callback list */
66
67 InsertTailList(&W32Thread->W32CallbackListHead, &Mem->ListEntry);
68
69 return (Mem + 1);
70 }
71
72 VOID FASTCALL
73 IntCbFreeMemory(PVOID Data)
74 {
75 PINT_CALLBACK_HEADER Mem;
76 PW32THREAD W32Thread;
77
78 ASSERT(Data);
79
80 Mem = ((PINT_CALLBACK_HEADER)Data - 1);
81
82 W32Thread = PsGetCurrentThreadWin32Thread();
83 ASSERT(W32Thread);
84
85 /* remove the memory block from the thread's callback list */
86 RemoveEntryList(&Mem->ListEntry);
87
88 /* free memory */
89 ExFreePool(Mem);
90 }
91
92 VOID FASTCALL
93 IntCleanupThreadCallbacks(PW32THREAD W32Thread)
94 {
95 PLIST_ENTRY CurrentEntry;
96 PINT_CALLBACK_HEADER Mem;
97
98 while (!IsListEmpty(&W32Thread->W32CallbackListHead))
99 {
100 CurrentEntry = RemoveHeadList(&W32Thread->W32CallbackListHead);
101 Mem = CONTAINING_RECORD(CurrentEntry, INT_CALLBACK_HEADER,
102 ListEntry);
103
104 /* free memory */
105 ExFreePool(Mem);
106 }
107 }
108
109
110 //
111 // Pass the Current Window handle and pointer to the Client Callback.
112 // This will help user space programs speed up read access with the window object.
113 //
114 static VOID
115 IntSetTebWndCallback (HWND * hWnd, PVOID * pWnd)
116 {
117 HWND hWndS = *hWnd;
118 PWINDOW_OBJECT Window = UserGetWindowObject(*hWnd);
119 PW32CLIENTINFO ClientInfo = GetWin32ClientInfo();
120
121 *hWnd = ClientInfo->hWND;
122 *pWnd = ClientInfo->pvWND;
123
124 ClientInfo->hWND = hWndS;
125 ClientInfo->pvWND = DesktopHeapAddressToUser(Window->Wnd);
126 }
127
128 static VOID
129 IntRestoreTebWndCallback (HWND hWnd, PVOID pWnd)
130 {
131 PW32CLIENTINFO ClientInfo = GetWin32ClientInfo();
132
133 ClientInfo->hWND = hWnd;
134 ClientInfo->pvWND = pWnd;
135 }
136
137 /* FUNCTIONS *****************************************************************/
138
139 VOID STDCALL
140 co_IntCallSentMessageCallback(SENDASYNCPROC CompletionCallback,
141 HWND hWnd,
142 UINT Msg,
143 ULONG_PTR CompletionCallbackContext,
144 LRESULT Result)
145 {
146 SENDASYNCPROC_CALLBACK_ARGUMENTS Arguments;
147 PVOID ResultPointer, pWnd;
148 ULONG ResultLength;
149 NTSTATUS Status;
150
151 Arguments.Callback = CompletionCallback;
152 Arguments.Wnd = hWnd;
153 Arguments.Msg = Msg;
154 Arguments.Context = CompletionCallbackContext;
155 Arguments.Result = Result;
156
157 IntSetTebWndCallback (&hWnd, &pWnd);
158
159 UserLeaveCo();
160
161 Status = KeUserModeCallback(USER32_CALLBACK_SENDASYNCPROC,
162 &Arguments,
163 sizeof(SENDASYNCPROC_CALLBACK_ARGUMENTS),
164 &ResultPointer,
165 &ResultLength);
166
167 UserEnterCo();
168
169 IntRestoreTebWndCallback (hWnd, pWnd);
170
171 if (!NT_SUCCESS(Status))
172 {
173 return;
174 }
175 return;
176 }
177
178 LRESULT STDCALL
179 co_IntCallWindowProc(WNDPROC Proc,
180 BOOLEAN IsAnsiProc,
181 HWND Wnd,
182 UINT Message,
183 WPARAM wParam,
184 LPARAM lParam,
185 INT lParamBufferSize)
186 {
187 WINDOWPROC_CALLBACK_ARGUMENTS StackArguments;
188 PWINDOWPROC_CALLBACK_ARGUMENTS Arguments;
189 NTSTATUS Status;
190 PVOID ResultPointer, pWnd;
191 ULONG ResultLength;
192 ULONG ArgumentLength;
193 LRESULT Result;
194
195 if (0 < lParamBufferSize)
196 {
197 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS) + lParamBufferSize;
198 Arguments = IntCbAllocateMemory(ArgumentLength);
199 if (NULL == Arguments)
200 {
201 DPRINT1("Unable to allocate buffer for window proc callback\n");
202 return -1;
203 }
204 RtlMoveMemory((PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
205 (PVOID) lParam, lParamBufferSize);
206 }
207 else
208 {
209 Arguments = &StackArguments;
210 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS);
211 }
212 Arguments->Proc = Proc;
213 Arguments->IsAnsiProc = IsAnsiProc;
214 Arguments->Wnd = Wnd;
215 Arguments->Msg = Message;
216 Arguments->wParam = wParam;
217 Arguments->lParam = lParam;
218 Arguments->lParamBufferSize = lParamBufferSize;
219 ResultPointer = NULL;
220 ResultLength = ArgumentLength;
221
222 IntSetTebWndCallback (&Wnd, &pWnd);
223
224 UserLeaveCo();
225
226 Status = KeUserModeCallback(USER32_CALLBACK_WINDOWPROC,
227 Arguments,
228 ArgumentLength,
229 &ResultPointer,
230 &ResultLength);
231
232 _SEH_TRY
233 {
234 /* Simulate old behaviour: copy into our local buffer */
235 RtlMoveMemory(Arguments, ResultPointer, ArgumentLength);
236 }
237 _SEH_HANDLE
238 {
239 Status = _SEH_GetExceptionCode();
240 }
241 _SEH_END;
242
243 UserEnterCo();
244
245 IntRestoreTebWndCallback (Wnd, pWnd);
246
247 if (!NT_SUCCESS(Status))
248 {
249 if (0 < lParamBufferSize)
250 {
251 IntCbFreeMemory(Arguments);
252 }
253 return -1;
254 }
255 Result = Arguments->Result;
256
257 if (0 < lParamBufferSize)
258 {
259 RtlMoveMemory((PVOID) lParam,
260 (PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
261 lParamBufferSize);
262 IntCbFreeMemory(Arguments);
263 }
264
265 return Result;
266 }
267
268 HMENU STDCALL
269 co_IntLoadSysMenuTemplate()
270 {
271 LRESULT Result;
272 NTSTATUS Status;
273 PVOID ResultPointer;
274 ULONG ResultLength;
275
276 ResultPointer = NULL;
277 ResultLength = sizeof(LRESULT);
278
279 UserLeaveCo();
280
281 Status = KeUserModeCallback(USER32_CALLBACK_LOADSYSMENUTEMPLATE,
282 NULL,
283 0,
284 &ResultPointer,
285 &ResultLength);
286
287 /* Simulate old behaviour: copy into our local buffer */
288 Result = *(LRESULT*)ResultPointer;
289
290 UserEnterCo();
291
292 if (!NT_SUCCESS(Status))
293 {
294 return(0);
295 }
296 return (HMENU)Result;
297 }
298
299 BOOL STDCALL
300 co_IntLoadDefaultCursors(VOID)
301 {
302 LRESULT Result;
303 NTSTATUS Status;
304 PVOID ResultPointer;
305 ULONG ResultLength;
306 BOOL DefaultCursor = TRUE;
307
308 ResultPointer = NULL;
309 ResultLength = sizeof(LRESULT);
310
311 UserLeaveCo();
312
313 Status = KeUserModeCallback(USER32_CALLBACK_LOADDEFAULTCURSORS,
314 &DefaultCursor,
315 sizeof(BOOL),
316 &ResultPointer,
317 &ResultLength);
318
319 /* Simulate old behaviour: copy into our local buffer */
320 Result = *(LRESULT*)ResultPointer;
321
322 UserEnterCo();
323
324 if (!NT_SUCCESS(Status))
325 {
326 return FALSE;
327 }
328 return TRUE;
329 }
330
331 LRESULT STDCALL
332 co_IntCallHookProc(INT HookId,
333 INT Code,
334 WPARAM wParam,
335 LPARAM lParam,
336 HOOKPROC Proc,
337 BOOLEAN Ansi,
338 PUNICODE_STRING ModuleName)
339 {
340 ULONG ArgumentLength;
341 PVOID Argument;
342 LRESULT Result;
343 NTSTATUS Status;
344 PVOID ResultPointer;
345 ULONG ResultLength;
346 PHOOKPROC_CALLBACK_ARGUMENTS Common;
347 CBT_CREATEWNDW *CbtCreateWnd =NULL;
348 PCHAR Extra;
349 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra ;
350 PUNICODE_STRING WindowName = NULL;
351 PUNICODE_STRING ClassName = NULL;
352
353 ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS) - sizeof(WCHAR)
354 + ModuleName->Length;
355 switch(HookId)
356 {
357 case WH_CBT:
358 switch(Code)
359 {
360 case HCBT_CREATEWND:
361 CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
362 ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
363 WindowName = (PUNICODE_STRING) (CbtCreateWnd->lpcs->lpszName);
364 ArgumentLength += WindowName->Length + sizeof(WCHAR);
365 ClassName = (PUNICODE_STRING) (CbtCreateWnd->lpcs->lpszClass);
366 if (! IS_ATOM(ClassName->Buffer))
367 {
368 ArgumentLength += ClassName->Length + sizeof(WCHAR);
369 }
370 break;
371 default:
372 DPRINT1("Trying to call unsupported CBT hook %d\n", Code);
373 return 0;
374 }
375 break;
376 case WH_KEYBOARD_LL:
377 ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
378 break;
379 case WH_MOUSE_LL:
380 ArgumentLength += sizeof(MSLLHOOKSTRUCT);
381 break;
382 case WH_MSGFILTER:
383 case WH_SYSMSGFILTER:
384 case WH_GETMESSAGE:
385 ArgumentLength += sizeof(MSG);
386 break;
387 // case WH_SHELL:
388 // break;
389 default:
390 DPRINT1("Trying to call unsupported window hook %d\n", HookId);
391 return 0;
392 }
393
394 Argument = IntCbAllocateMemory(ArgumentLength);
395 if (NULL == Argument)
396 {
397 DPRINT1("HookProc callback failed: out of memory\n");
398 return 0;
399 }
400 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
401 Common->HookId = HookId;
402 Common->Code = Code;
403 Common->wParam = wParam;
404 Common->lParam = lParam;
405 Common->Proc = Proc;
406 Common->Ansi = Ansi;
407 Common->ModuleNameLength = ModuleName->Length;
408 memcpy(Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
409 Extra = (PCHAR) Common->ModuleName + Common->ModuleNameLength;
410
411 switch(HookId)
412 {
413 case WH_CBT:
414 switch(Code)
415 {
416 case HCBT_CREATEWND:
417 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
418 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
419 CbtCreatewndExtra->Cs = *(CbtCreateWnd->lpcs);
420 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
421 Extra = (PCHAR) (CbtCreatewndExtra + 1);
422 RtlCopyMemory(Extra, WindowName->Buffer, WindowName->Length);
423 CbtCreatewndExtra->Cs.lpszName = (LPCWSTR) (Extra - (PCHAR) CbtCreatewndExtra);
424 CbtCreatewndExtra->Cs.lpszClass = ClassName->Buffer;
425 Extra += WindowName->Length;
426 *((WCHAR *) Extra) = L'\0';
427 Extra += sizeof(WCHAR);
428 if (! IS_ATOM(ClassName->Buffer))
429 {
430 RtlCopyMemory(Extra, ClassName->Buffer, ClassName->Length);
431 CbtCreatewndExtra->Cs.lpszClass =
432 (LPCWSTR) MAKELONG(Extra - (PCHAR) CbtCreatewndExtra, 1);
433 Extra += ClassName->Length;
434 *((WCHAR *) Extra) = L'\0';
435 }
436 break;
437 }
438 break;
439 case WH_KEYBOARD_LL:
440 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
441 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
442 break;
443 case WH_MOUSE_LL:
444 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
445 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
446 break;
447 case WH_MSGFILTER:
448 case WH_SYSMSGFILTER:
449 case WH_GETMESSAGE:
450 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSG));
451 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
452 DPRINT1("KHOOK Memory: %x\n",Common);
453 break;
454 // case WH_SHELL:
455 // Extra = lParam;
456 // break;
457 }
458
459 ResultPointer = NULL;
460 ResultLength = sizeof(LRESULT);
461
462 UserLeaveCo();
463
464 Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
465 Argument,
466 ArgumentLength,
467 &ResultPointer,
468 &ResultLength);
469
470 /* Simulate old behaviour: copy into our local buffer */
471 Result = *(LRESULT*)ResultPointer;
472
473 UserEnterCo();
474
475 IntCbFreeMemory(Argument);
476
477 if (!NT_SUCCESS(Status))
478 {
479 return 0;
480 }
481
482 return Result;
483 }
484
485 LRESULT
486 STDCALL
487 co_IntCallEventProc(HWINEVENTHOOK hook,
488 DWORD event,
489 HWND hWnd,
490 LONG idObject,
491 LONG idChild,
492 DWORD dwEventThread,
493 DWORD dwmsEventTime,
494 WINEVENTPROC Proc)
495 {
496 LRESULT Result;
497 NTSTATUS Status;
498 PEVENTPROC_CALLBACK_ARGUMENTS Common;
499 ULONG ArgumentLength, ResultLength;
500 PVOID Argument, ResultPointer, pWnd;
501
502 ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
503
504 Argument = IntCbAllocateMemory(ArgumentLength);
505 if (NULL == Argument)
506 {
507 DPRINT1("EventProc callback failed: out of memory\n");
508 return 0;
509 }
510 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
511 Common->hook = hook;
512 Common->event = event;
513 Common->hwnd = hWnd;
514 Common->idObject = idObject;
515 Common->idChild = idChild;
516 Common->dwEventThread = dwEventThread;
517 Common->dwmsEventTime = dwmsEventTime;
518 Common->Proc = Proc;
519
520 ResultPointer = NULL;
521 ResultLength = sizeof(LRESULT);
522
523 IntSetTebWndCallback (&hWnd, &pWnd);
524
525 UserLeaveCo();
526
527 Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
528 Argument,
529 ArgumentLength,
530 &ResultPointer,
531 &ResultLength);
532
533 /* Simulate old behaviour: copy into our local buffer */
534 Result = *(LRESULT*)ResultPointer;
535
536 UserEnterCo();
537
538 IntRestoreTebWndCallback (hWnd, pWnd);
539
540 IntCbFreeMemory(Argument);
541
542 if (!NT_SUCCESS(Status))
543 {
544 return 0;
545 }
546
547 return Result;
548 }
549
550 /* EOF */