Merge trunk head (r41474)
[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 THREADINFO 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 PTHREADINFO 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 PTHREADINFO 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 ExFreePoolWithTag(Mem, TAG_CALLBACK);
90 }
91
92 VOID FASTCALL
93 IntCleanupThreadCallbacks(PTHREADINFO 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 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
120
121 *hWnd = ClientInfo->CallbackWnd.hWnd;
122 *pWnd = ClientInfo->CallbackWnd.pvWnd;
123
124 ClientInfo->CallbackWnd.hWnd = hWndS;
125 ClientInfo->CallbackWnd.pvWnd = DesktopHeapAddressToUser(Window->Wnd);
126 }
127
128 static VOID
129 IntRestoreTebWndCallback (HWND hWnd, PVOID pWnd)
130 {
131 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
132
133 ClientInfo->CallbackWnd.hWnd = hWnd;
134 ClientInfo->CallbackWnd.pvWnd = pWnd;
135 }
136
137 /* FUNCTIONS *****************************************************************/
138
139 VOID APIENTRY
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 APIENTRY
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 _SEH2_TRY
233 {
234 /* Simulate old behaviour: copy into our local buffer */
235 RtlMoveMemory(Arguments, ResultPointer, ArgumentLength);
236 }
237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
238 {
239 Status = _SEH2_GetExceptionCode();
240 }
241 _SEH2_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 APIENTRY
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 APIENTRY
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 APIENTRY
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 = 0;
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_MOUSE:
383 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
384 break;
385 case WH_CALLWNDPROC:
386 ArgumentLength += sizeof(CWPSTRUCT);
387 break;
388 case WH_CALLWNDPROCRET:
389 ArgumentLength += sizeof(CWPRETSTRUCT);
390 break;
391 case WH_MSGFILTER:
392 case WH_SYSMSGFILTER:
393 case WH_GETMESSAGE:
394 ArgumentLength += sizeof(MSG);
395 break;
396 case WH_FOREGROUNDIDLE:
397 case WH_KEYBOARD:
398 case WH_SHELL:
399 break;
400 default:
401 DPRINT1("Trying to call unsupported window hook %d\n", HookId);
402 return 0;
403 }
404
405 Argument = IntCbAllocateMemory(ArgumentLength);
406 if (NULL == Argument)
407 {
408 DPRINT1("HookProc callback failed: out of memory\n");
409 return 0;
410 }
411 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
412 Common->HookId = HookId;
413 Common->Code = Code;
414 Common->wParam = wParam;
415 Common->lParam = lParam;
416 Common->Proc = Proc;
417 Common->Ansi = Ansi;
418 Common->ModuleNameLength = ModuleName->Length;
419 memcpy(Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
420 Extra = (PCHAR) Common->ModuleName + Common->ModuleNameLength;
421
422 switch(HookId)
423 {
424 case WH_CBT:
425 switch(Code)
426 {
427 case HCBT_CREATEWND:
428 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
429 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
430 CbtCreatewndExtra->Cs = *(CbtCreateWnd->lpcs);
431 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
432 Extra = (PCHAR) (CbtCreatewndExtra + 1);
433 RtlCopyMemory(Extra, WindowName->Buffer, WindowName->Length);
434 CbtCreatewndExtra->Cs.lpszName = (LPCWSTR) (Extra - (PCHAR) CbtCreatewndExtra);
435 CbtCreatewndExtra->Cs.lpszClass = ClassName->Buffer;
436 Extra += WindowName->Length;
437 *((WCHAR *) Extra) = L'\0';
438 Extra += sizeof(WCHAR);
439 if (! IS_ATOM(ClassName->Buffer))
440 {
441 RtlCopyMemory(Extra, ClassName->Buffer, ClassName->Length);
442 CbtCreatewndExtra->Cs.lpszClass =
443 (LPCWSTR)(ULONG_PTR) MAKELONG(Extra - (PCHAR) CbtCreatewndExtra, 1);
444 Extra += ClassName->Length;
445 *((WCHAR *) Extra) = L'\0';
446 }
447 break;
448 }
449 break;
450 case WH_KEYBOARD_LL:
451 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
452 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
453 break;
454 case WH_MOUSE_LL:
455 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
456 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
457 break;
458 case WH_MOUSE:
459 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
460 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
461 break;
462 case WH_CALLWNDPROC:
463 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT));
464 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
465 break;
466 case WH_CALLWNDPROCRET:
467 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT));
468 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
469 break;
470 case WH_MSGFILTER:
471 case WH_SYSMSGFILTER:
472 case WH_GETMESSAGE:
473 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSG));
474 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
475 // DPRINT1("KHOOK Memory: %x\n",Common);
476 break;
477 case WH_FOREGROUNDIDLE:
478 case WH_KEYBOARD:
479 case WH_SHELL:
480 break;
481 }
482
483 ResultPointer = NULL;
484 ResultLength = sizeof(LRESULT);
485
486 UserLeaveCo();
487
488 Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
489 Argument,
490 ArgumentLength,
491 &ResultPointer,
492 &ResultLength);
493
494 UserEnterCo();
495
496 _SEH2_TRY
497 {
498 ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
499 /* Simulate old behaviour: copy into our local buffer */
500 Result = *(LRESULT*)ResultPointer;
501 }
502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
503 {
504 Result = 0;
505 }
506 _SEH2_END;
507
508 if (!NT_SUCCESS(Status))
509 {
510 return 0;
511 }
512
513 if (Argument) IntCbFreeMemory(Argument);
514
515 return Result;
516 }
517
518 LRESULT
519 APIENTRY
520 co_IntCallEventProc(HWINEVENTHOOK hook,
521 DWORD event,
522 HWND hWnd,
523 LONG idObject,
524 LONG idChild,
525 DWORD dwEventThread,
526 DWORD dwmsEventTime,
527 WINEVENTPROC Proc)
528 {
529 LRESULT Result;
530 NTSTATUS Status;
531 PEVENTPROC_CALLBACK_ARGUMENTS Common;
532 ULONG ArgumentLength, ResultLength;
533 PVOID Argument, ResultPointer, pWnd;
534
535 ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
536
537 Argument = IntCbAllocateMemory(ArgumentLength);
538 if (NULL == Argument)
539 {
540 DPRINT1("EventProc callback failed: out of memory\n");
541 return 0;
542 }
543 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
544 Common->hook = hook;
545 Common->event = event;
546 Common->hwnd = hWnd;
547 Common->idObject = idObject;
548 Common->idChild = idChild;
549 Common->dwEventThread = dwEventThread;
550 Common->dwmsEventTime = dwmsEventTime;
551 Common->Proc = Proc;
552
553 ResultPointer = NULL;
554 ResultLength = sizeof(LRESULT);
555
556 IntSetTebWndCallback (&hWnd, &pWnd);
557
558 UserLeaveCo();
559
560 Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
561 Argument,
562 ArgumentLength,
563 &ResultPointer,
564 &ResultLength);
565
566 /* Simulate old behaviour: copy into our local buffer */
567 Result = *(LRESULT*)ResultPointer;
568
569 UserEnterCo();
570
571 IntRestoreTebWndCallback (hWnd, pWnd);
572
573 IntCbFreeMemory(Argument);
574
575 if (!NT_SUCCESS(Status))
576 {
577 return 0;
578 }
579
580 return Result;
581 }
582
583 /* EOF */