- Add more vista types. Added another window message type, based on winproc.c. Added...
[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 = NULL;
350 UNICODE_STRING WindowName;
351 UNICODE_STRING ClassName;
352 PANSI_STRING asWindowName;
353 PANSI_STRING asClassName;
354
355 ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS) - sizeof(WCHAR)
356 + ModuleName->Length;
357 switch(HookId)
358 {
359 case WH_CBT:
360 switch(Code)
361 {
362 case HCBT_CREATEWND:
363 CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
364 ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
365
366 asWindowName = (PANSI_STRING)&WindowName;
367 asClassName = (PANSI_STRING)&ClassName;
368
369 if (Ansi)
370 {
371 RtlInitAnsiString(asWindowName, (PCSZ)CbtCreateWnd->lpcs->lpszName);
372 ArgumentLength += WindowName.Length + sizeof(CHAR);
373 }
374 else
375 {
376 RtlInitUnicodeString(&WindowName, CbtCreateWnd->lpcs->lpszName);
377 ArgumentLength += WindowName.Length + sizeof(WCHAR);
378 }
379
380 if (! IS_ATOM(CbtCreateWnd->lpcs->lpszClass))
381 {
382 if (Ansi)
383 {
384 RtlInitAnsiString(asClassName, (PCSZ)CbtCreateWnd->lpcs->lpszClass);
385 ArgumentLength += ClassName.Length + sizeof(CHAR);
386 }
387 else
388 {
389 RtlInitUnicodeString(&ClassName, CbtCreateWnd->lpcs->lpszClass);
390 ArgumentLength += ClassName.Length + sizeof(WCHAR);
391 }
392 }
393 break;
394
395 case HCBT_MOVESIZE:
396 ArgumentLength += sizeof(RECTL);
397 break;
398 case HCBT_ACTIVATE:
399 ArgumentLength += sizeof(CBTACTIVATESTRUCT);
400 break;
401 case HCBT_CLICKSKIPPED:
402 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
403 break;
404 /* ATM pass on */
405 case HCBT_KEYSKIPPED:
406 case HCBT_MINMAX:
407 case HCBT_SETFOCUS:
408 case HCBT_SYSCOMMAND:
409 /* These types pass through. */
410 case HCBT_DESTROYWND:
411 case HCBT_QS:
412 break;
413 default:
414 DPRINT1("Trying to call unsupported CBT hook %d\n", Code);
415 return 0;
416 }
417 break;
418 case WH_KEYBOARD_LL:
419 ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
420 break;
421 case WH_MOUSE_LL:
422 ArgumentLength += sizeof(MSLLHOOKSTRUCT);
423 break;
424 case WH_MOUSE:
425 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
426 break;
427 case WH_CALLWNDPROC:
428 ArgumentLength += sizeof(CWPSTRUCT);
429 break;
430 case WH_CALLWNDPROCRET:
431 ArgumentLength += sizeof(CWPRETSTRUCT);
432 break;
433 case WH_MSGFILTER:
434 case WH_SYSMSGFILTER:
435 case WH_GETMESSAGE:
436 ArgumentLength += sizeof(MSG);
437 break;
438 case WH_FOREGROUNDIDLE:
439 case WH_KEYBOARD:
440 case WH_SHELL:
441 break;
442 default:
443 DPRINT1("Trying to call unsupported window hook %d\n", HookId);
444 return 0;
445 }
446
447 Argument = IntCbAllocateMemory(ArgumentLength);
448 if (NULL == Argument)
449 {
450 DPRINT1("HookProc callback failed: out of memory\n");
451 return 0;
452 }
453 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
454 Common->HookId = HookId;
455 Common->Code = Code;
456 Common->wParam = wParam;
457 Common->lParam = lParam;
458 Common->Proc = Proc;
459 Common->Ansi = Ansi;
460 Common->ModuleNameLength = ModuleName->Length;
461 memcpy(Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
462 Extra = (PCHAR) Common->ModuleName + Common->ModuleNameLength;
463
464 switch(HookId)
465 {
466 case WH_CBT:
467 switch(Code)
468 {
469 case HCBT_CREATEWND:
470 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
471 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
472 RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) );
473 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
474 Extra = (PCHAR) (CbtCreatewndExtra + 1);
475 RtlCopyMemory(Extra, WindowName.Buffer, WindowName.Length);
476 CbtCreatewndExtra->Cs.lpszName = (LPCWSTR) (Extra - (PCHAR) CbtCreatewndExtra);
477 CbtCreatewndExtra->Cs.lpszClass = ClassName.Buffer;
478 Extra += WindowName.Length;
479 if (Ansi)
480 {
481 *((CHAR *) Extra) = '\0';
482 Extra += sizeof(CHAR);
483 }
484 else
485 {
486 *((WCHAR *) Extra) = L'\0';
487 Extra += sizeof(WCHAR);
488 }
489
490 if (! IS_ATOM(ClassName.Buffer))
491 {
492 RtlCopyMemory(Extra, ClassName.Buffer, ClassName.Length);
493 CbtCreatewndExtra->Cs.lpszClass =
494 (LPCWSTR) MAKELONG(Extra - (PCHAR) CbtCreatewndExtra, 1);
495 Extra += ClassName.Length;
496
497 if (Ansi)
498 *((CHAR *) Extra) = '\0';
499 else
500 *((WCHAR *) Extra) = L'\0';
501 }
502 break;
503 case HCBT_CLICKSKIPPED:
504 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
505 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
506 break;
507 case HCBT_MOVESIZE:
508 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(RECTL));
509 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
510 break;
511 case HCBT_ACTIVATE:
512 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CBTACTIVATESTRUCT));
513 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
514 break;
515 }
516 break;
517 case WH_KEYBOARD_LL:
518 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
519 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
520 break;
521 case WH_MOUSE_LL:
522 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
523 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
524 break;
525 case WH_MOUSE:
526 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
527 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
528 break;
529 case WH_CALLWNDPROC:
530 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT));
531 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
532 break;
533 case WH_CALLWNDPROCRET:
534 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT));
535 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
536 break;
537 case WH_MSGFILTER:
538 case WH_SYSMSGFILTER:
539 case WH_GETMESSAGE:
540 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSG));
541 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
542 // DPRINT1("KHOOK Memory: %x\n",Common);
543 break;
544 case WH_FOREGROUNDIDLE:
545 case WH_KEYBOARD:
546 case WH_SHELL:
547 break;
548 }
549
550 ResultPointer = NULL;
551 ResultLength = sizeof(LRESULT);
552
553 UserLeaveCo();
554
555 Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
556 Argument,
557 ArgumentLength,
558 &ResultPointer,
559 &ResultLength);
560
561 UserEnterCo();
562
563 _SEH2_TRY
564 {
565 ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
566 /* Simulate old behaviour: copy into our local buffer */
567 Result = *(LRESULT*)ResultPointer;
568 }
569 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
570 {
571 Result = 0;
572 }
573 _SEH2_END;
574
575 if (!NT_SUCCESS(Status))
576 {
577 return 0;
578 }
579
580 if (HookId == WH_CBT && Code == HCBT_CREATEWND)
581 {
582 if (CbtCreatewndExtra)
583 {
584 _SEH2_TRY
585 { /*
586 The parameters could have been changed, include the coordinates
587 and dimensions of the window. We copy it back.
588 */
589 CbtCreateWnd->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
590 CbtCreateWnd->lpcs->x = CbtCreatewndExtra->Cs.x;
591 CbtCreateWnd->lpcs->y = CbtCreatewndExtra->Cs.y;
592 CbtCreateWnd->lpcs->cx = CbtCreatewndExtra->Cs.cx;
593 CbtCreateWnd->lpcs->cy = CbtCreatewndExtra->Cs.cy;
594 }
595 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
596 {
597 Result = 0;
598 }
599 _SEH2_END;
600 }
601 }
602
603 if (Argument) IntCbFreeMemory(Argument);
604
605 return Result;
606 }
607
608 //
609 // Events are notifications w/o results.
610 //
611 LRESULT
612 APIENTRY
613 co_IntCallEventProc(HWINEVENTHOOK hook,
614 DWORD event,
615 HWND hWnd,
616 LONG idObject,
617 LONG idChild,
618 DWORD dwEventThread,
619 DWORD dwmsEventTime,
620 WINEVENTPROC Proc)
621 {
622 LRESULT Result = 0;
623 NTSTATUS Status;
624 PEVENTPROC_CALLBACK_ARGUMENTS Common;
625 ULONG ArgumentLength, ResultLength;
626 PVOID Argument, ResultPointer;
627
628 ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
629
630 Argument = IntCbAllocateMemory(ArgumentLength);
631 if (NULL == Argument)
632 {
633 DPRINT1("EventProc callback failed: out of memory\n");
634 return 0;
635 }
636 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
637 Common->hook = hook;
638 Common->event = event;
639 Common->hwnd = hWnd;
640 Common->idObject = idObject;
641 Common->idChild = idChild;
642 Common->dwEventThread = dwEventThread;
643 Common->dwmsEventTime = dwmsEventTime;
644 Common->Proc = Proc;
645
646 ResultPointer = NULL;
647 ResultLength = sizeof(LRESULT);
648
649 UserLeaveCo();
650
651 Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
652 Argument,
653 ArgumentLength,
654 &ResultPointer,
655 &ResultLength);
656
657 UserEnterCo();
658
659 IntCbFreeMemory(Argument);
660
661 if (!NT_SUCCESS(Status))
662 {
663 return 0;
664 }
665
666 return Result;
667 }
668
669 /* EOF */