sync with trunk head (34904)
[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 = 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_KEYBOARD:
397 // case WH_SHELL:
398 break;
399 default:
400 DPRINT1("Trying to call unsupported window hook %d\n", HookId);
401 return 0;
402 }
403
404 Argument = IntCbAllocateMemory(ArgumentLength);
405 if (NULL == Argument)
406 {
407 DPRINT1("HookProc callback failed: out of memory\n");
408 return 0;
409 }
410 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
411 Common->HookId = HookId;
412 Common->Code = Code;
413 Common->wParam = wParam;
414 Common->lParam = lParam;
415 Common->Proc = Proc;
416 Common->Ansi = Ansi;
417 Common->ModuleNameLength = ModuleName->Length;
418 memcpy(Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
419 Extra = (PCHAR) Common->ModuleName + Common->ModuleNameLength;
420
421 switch(HookId)
422 {
423 case WH_CBT:
424 switch(Code)
425 {
426 case HCBT_CREATEWND:
427 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
428 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
429 CbtCreatewndExtra->Cs = *(CbtCreateWnd->lpcs);
430 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
431 Extra = (PCHAR) (CbtCreatewndExtra + 1);
432 RtlCopyMemory(Extra, WindowName->Buffer, WindowName->Length);
433 CbtCreatewndExtra->Cs.lpszName = (LPCWSTR) (Extra - (PCHAR) CbtCreatewndExtra);
434 CbtCreatewndExtra->Cs.lpszClass = ClassName->Buffer;
435 Extra += WindowName->Length;
436 *((WCHAR *) Extra) = L'\0';
437 Extra += sizeof(WCHAR);
438 if (! IS_ATOM(ClassName->Buffer))
439 {
440 RtlCopyMemory(Extra, ClassName->Buffer, ClassName->Length);
441 CbtCreatewndExtra->Cs.lpszClass =
442 (LPCWSTR)(ULONG_PTR) MAKELONG(Extra - (PCHAR) CbtCreatewndExtra, 1);
443 Extra += ClassName->Length;
444 *((WCHAR *) Extra) = L'\0';
445 }
446 break;
447 }
448 break;
449 case WH_KEYBOARD_LL:
450 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
451 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
452 break;
453 case WH_MOUSE_LL:
454 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
455 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
456 break;
457 case WH_MOUSE:
458 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
459 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
460 break;
461 case WH_CALLWNDPROC:
462 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT));
463 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
464 break;
465 case WH_CALLWNDPROCRET:
466 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT));
467 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
468 break;
469 case WH_MSGFILTER:
470 case WH_SYSMSGFILTER:
471 case WH_GETMESSAGE:
472 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSG));
473 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
474 // DPRINT1("KHOOK Memory: %x\n",Common);
475 break;
476 case WH_KEYBOARD:
477 break;
478 // case WH_SHELL:
479 // Extra = lParam;
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 _SEH_TRY
497 {
498 ProbeForRead((PVOID)*(LRESULT*)ResultPointer,
499 sizeof(LRESULT),
500 1);
501 /* Simulate old behaviour: copy into our local buffer */
502 Result = *(LRESULT*)ResultPointer;
503 }
504 _SEH_HANDLE
505 {
506 Result = 0;
507 }
508 _SEH_END;
509
510 IntCbFreeMemory(Argument);
511
512 if (!NT_SUCCESS(Status))
513 {
514 return 0;
515 }
516
517 return Result;
518 }
519
520 LRESULT
521 STDCALL
522 co_IntCallEventProc(HWINEVENTHOOK hook,
523 DWORD event,
524 HWND hWnd,
525 LONG idObject,
526 LONG idChild,
527 DWORD dwEventThread,
528 DWORD dwmsEventTime,
529 WINEVENTPROC Proc)
530 {
531 LRESULT Result;
532 NTSTATUS Status;
533 PEVENTPROC_CALLBACK_ARGUMENTS Common;
534 ULONG ArgumentLength, ResultLength;
535 PVOID Argument, ResultPointer, pWnd;
536
537 ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
538
539 Argument = IntCbAllocateMemory(ArgumentLength);
540 if (NULL == Argument)
541 {
542 DPRINT1("EventProc callback failed: out of memory\n");
543 return 0;
544 }
545 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
546 Common->hook = hook;
547 Common->event = event;
548 Common->hwnd = hWnd;
549 Common->idObject = idObject;
550 Common->idChild = idChild;
551 Common->dwEventThread = dwEventThread;
552 Common->dwmsEventTime = dwmsEventTime;
553 Common->Proc = Proc;
554
555 ResultPointer = NULL;
556 ResultLength = sizeof(LRESULT);
557
558 IntSetTebWndCallback (&hWnd, &pWnd);
559
560 UserLeaveCo();
561
562 Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
563 Argument,
564 ArgumentLength,
565 &ResultPointer,
566 &ResultLength);
567
568 /* Simulate old behaviour: copy into our local buffer */
569 Result = *(LRESULT*)ResultPointer;
570
571 UserEnterCo();
572
573 IntRestoreTebWndCallback (hWnd, pWnd);
574
575 IntCbFreeMemory(Argument);
576
577 if (!NT_SUCCESS(Status))
578 {
579 return 0;
580 }
581
582 return Result;
583 }
584
585 /* EOF */