5a253ea57a501c73feb65148e26284869488c026
[reactos.git] / reactos / win32ss / user / ntuser / callback.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Callback to usermode support
5 * FILE: subsystems/win32/win32k/ntuser/callback.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
8 * NOTES: Please use the Callback Memory Management functions for
9 * callbacks to make sure, the memory is freed on thread
10 * termination!
11 */
12
13 #include <win32k.h>
14 DBG_DEFAULT_CHANNEL(UserCallback);
15
16
17 /* CALLBACK MEMORY MANAGEMENT ************************************************/
18
19 typedef struct _INT_CALLBACK_HEADER
20 {
21 /* List entry in the THREADINFO structure */
22 LIST_ENTRY ListEntry;
23 }
24 INT_CALLBACK_HEADER, *PINT_CALLBACK_HEADER;
25
26 PVOID FASTCALL
27 IntCbAllocateMemory(ULONG Size)
28 {
29 PINT_CALLBACK_HEADER Mem;
30 PTHREADINFO W32Thread;
31
32 if(!(Mem = ExAllocatePoolWithTag(PagedPool, Size + sizeof(INT_CALLBACK_HEADER),
33 USERTAG_CALLBACK)))
34 {
35 return NULL;
36 }
37
38 W32Thread = PsGetCurrentThreadWin32Thread();
39 ASSERT(W32Thread);
40
41 /* Insert the callback memory into the thread's callback list */
42
43 InsertTailList(&W32Thread->W32CallbackListHead, &Mem->ListEntry);
44
45 return (Mem + 1);
46 }
47
48 VOID FASTCALL
49 IntCbFreeMemory(PVOID Data)
50 {
51 PINT_CALLBACK_HEADER Mem;
52 PTHREADINFO W32Thread;
53
54 ASSERT(Data);
55
56 Mem = ((PINT_CALLBACK_HEADER)Data - 1);
57
58 W32Thread = PsGetCurrentThreadWin32Thread();
59 ASSERT(W32Thread);
60
61 /* Remove the memory block from the thread's callback list */
62 RemoveEntryList(&Mem->ListEntry);
63
64 /* Free memory */
65 ExFreePoolWithTag(Mem, USERTAG_CALLBACK);
66 }
67
68 VOID FASTCALL
69 IntCleanupThreadCallbacks(PTHREADINFO W32Thread)
70 {
71 PLIST_ENTRY CurrentEntry;
72 PINT_CALLBACK_HEADER Mem;
73
74 while (!IsListEmpty(&W32Thread->W32CallbackListHead))
75 {
76 CurrentEntry = RemoveHeadList(&W32Thread->W32CallbackListHead);
77 Mem = CONTAINING_RECORD(CurrentEntry, INT_CALLBACK_HEADER,
78 ListEntry);
79
80 /* Free memory */
81 ExFreePoolWithTag(Mem, USERTAG_CALLBACK);
82 }
83 }
84
85 //
86 // Pass the Current Window handle and pointer to the Client Callback.
87 // This will help user space programs speed up read access with the window object.
88 //
89 static VOID
90 IntSetTebWndCallback (HWND * hWnd, PWND * pWnd, PVOID * pActCtx)
91 {
92 HWND hWndS = *hWnd;
93 PWND Window = UserGetWindowObject(*hWnd);
94 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
95
96 *hWnd = ClientInfo->CallbackWnd.hWnd;
97 *pWnd = ClientInfo->CallbackWnd.pWnd;
98 *pActCtx = ClientInfo->CallbackWnd.pActCtx;
99
100 ClientInfo->CallbackWnd.hWnd = hWndS;
101 ClientInfo->CallbackWnd.pWnd = DesktopHeapAddressToUser(Window);
102 ClientInfo->CallbackWnd.pActCtx = Window->pActCtx;
103 }
104
105 static VOID
106 IntRestoreTebWndCallback (HWND hWnd, PWND pWnd, PVOID pActCtx)
107 {
108 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
109
110 ClientInfo->CallbackWnd.hWnd = hWnd;
111 ClientInfo->CallbackWnd.pWnd = pWnd;
112 ClientInfo->CallbackWnd.pActCtx = pActCtx;
113 }
114
115 /* FUNCTIONS *****************************************************************/
116
117 /* Calls ClientLoadLibrary in user32 */
118 BOOL
119 NTAPI
120 co_IntClientLoadLibrary(PUNICODE_STRING pstrLibName,
121 PUNICODE_STRING pstrInitFunc,
122 BOOL Unload,
123 BOOL ApiHook)
124 {
125 PVOID ResultPointer;
126 ULONG ResultLength;
127 ULONG ArgumentLength;
128 PCLIENT_LOAD_LIBRARY_ARGUMENTS pArguments;
129 NTSTATUS Status;
130 BOOL bResult;
131 ULONG_PTR pLibNameBuffer = 0, pInitFuncBuffer = 0;
132
133 /* Do not allow the desktop thread to do callback to user mode */
134 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
135
136 TRACE("co_IntClientLoadLibrary: %S, %S, %d, %d\n", pstrLibName->Buffer, pstrLibName->Buffer, Unload, ApiHook);
137
138 /* Calculate the size of the argument */
139 ArgumentLength = sizeof(CLIENT_LOAD_LIBRARY_ARGUMENTS);
140 if(pstrLibName)
141 {
142 pLibNameBuffer = ArgumentLength;
143 ArgumentLength += pstrLibName->Length + sizeof(WCHAR);
144 }
145 if(pstrInitFunc)
146 {
147 pInitFuncBuffer = ArgumentLength;
148 ArgumentLength += pstrInitFunc->Length + sizeof(WCHAR);
149 }
150
151 /* Allocate the argument */
152 pArguments = IntCbAllocateMemory(ArgumentLength);
153 if(pArguments == NULL)
154 {
155 return FALSE;
156 }
157
158 /* Fill the argument */
159 pArguments->Unload = Unload;
160 pArguments->ApiHook = ApiHook;
161 if(pstrLibName)
162 {
163 /* Copy the string to the callback memory */
164 pLibNameBuffer += (ULONG_PTR)pArguments;
165 pArguments->strLibraryName.Buffer = (PWCHAR)pLibNameBuffer;
166 pArguments->strLibraryName.MaximumLength = pstrLibName->Length + sizeof(WCHAR);
167 RtlCopyUnicodeString(&pArguments->strLibraryName, pstrLibName);
168
169 /* Fix argument pointer to be relative to the argument */
170 pLibNameBuffer -= (ULONG_PTR)pArguments;
171 pArguments->strLibraryName.Buffer = (PWCHAR)(pLibNameBuffer);
172 }
173 else
174 {
175 RtlZeroMemory(&pArguments->strLibraryName, sizeof(UNICODE_STRING));
176 }
177
178 if(pstrInitFunc)
179 {
180 /* Copy the strings to the callback memory */
181 pInitFuncBuffer += (ULONG_PTR)pArguments;
182 pArguments->strInitFuncName.Buffer = (PWCHAR)pInitFuncBuffer;
183 pArguments->strInitFuncName.MaximumLength = pstrInitFunc->Length + sizeof(WCHAR);
184 RtlCopyUnicodeString(&pArguments->strInitFuncName, pstrInitFunc);
185
186 /* Fix argument pointers to be relative to the argument */
187 pInitFuncBuffer -= (ULONG_PTR)pArguments;
188 pArguments->strInitFuncName.Buffer = (PWCHAR)(pInitFuncBuffer);
189 }
190 else
191 {
192 RtlZeroMemory(&pArguments->strInitFuncName, sizeof(UNICODE_STRING));
193 }
194
195 /* Do the callback */
196 UserLeaveCo();
197
198 Status = KeUserModeCallback(USER32_CALLBACK_CLIENTLOADLIBRARY,
199 pArguments,
200 ArgumentLength,
201 &ResultPointer,
202 &ResultLength);
203
204 UserEnterCo();
205
206 /* Free the argument */
207 IntCbFreeMemory(pArguments);
208
209 if(!NT_SUCCESS(Status))
210 {
211 return FALSE;
212 }
213
214 _SEH2_TRY
215 {
216 /* Probe and copy the usermode result data */
217 ProbeForRead(ResultPointer, sizeof(HMODULE), 1);
218 bResult = *(BOOL*)ResultPointer;
219 }
220 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
221 {
222 bResult = FALSE;
223 }
224 _SEH2_END;
225
226 return bResult;
227 }
228
229 VOID APIENTRY
230 co_IntCallSentMessageCallback(SENDASYNCPROC CompletionCallback,
231 HWND hWnd,
232 UINT Msg,
233 ULONG_PTR CompletionCallbackContext,
234 LRESULT Result)
235 {
236 SENDASYNCPROC_CALLBACK_ARGUMENTS Arguments;
237 PVOID ResultPointer, pActCtx;
238 PWND pWnd;
239 ULONG ResultLength;
240 NTSTATUS Status;
241
242 /* Do not allow the desktop thread to do callback to user mode */
243 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
244
245 Arguments.Callback = CompletionCallback;
246 Arguments.Wnd = hWnd;
247 Arguments.Msg = Msg;
248 Arguments.Context = CompletionCallbackContext;
249 Arguments.Result = Result;
250
251 IntSetTebWndCallback (&hWnd, &pWnd, &pActCtx);
252
253 UserLeaveCo();
254
255 Status = KeUserModeCallback(USER32_CALLBACK_SENDASYNCPROC,
256 &Arguments,
257 sizeof(SENDASYNCPROC_CALLBACK_ARGUMENTS),
258 &ResultPointer,
259 &ResultLength);
260
261 UserEnterCo();
262
263 IntRestoreTebWndCallback (hWnd, pWnd, pActCtx);
264
265 if (!NT_SUCCESS(Status))
266 {
267 return;
268 }
269 return;
270 }
271
272 LRESULT APIENTRY
273 co_IntCallWindowProc(WNDPROC Proc,
274 BOOLEAN IsAnsiProc,
275 HWND Wnd,
276 UINT Message,
277 WPARAM wParam,
278 LPARAM lParam,
279 INT lParamBufferSize)
280 {
281 WINDOWPROC_CALLBACK_ARGUMENTS StackArguments;
282 PWINDOWPROC_CALLBACK_ARGUMENTS Arguments;
283 NTSTATUS Status;
284 PVOID ResultPointer, pActCtx;
285 PWND pWnd;
286 ULONG ResultLength;
287 ULONG ArgumentLength;
288 LRESULT Result;
289
290 /* Do not allow the desktop thread to do callback to user mode */
291 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
292
293 if (0 < lParamBufferSize)
294 {
295 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS) + lParamBufferSize;
296 Arguments = IntCbAllocateMemory(ArgumentLength);
297 if (NULL == Arguments)
298 {
299 ERR("Unable to allocate buffer for window proc callback\n");
300 return -1;
301 }
302 RtlMoveMemory((PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
303 (PVOID) lParam, lParamBufferSize);
304 }
305 else
306 {
307 Arguments = &StackArguments;
308 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS);
309 }
310 Arguments->Proc = Proc;
311 Arguments->IsAnsiProc = IsAnsiProc;
312 Arguments->Wnd = Wnd;
313 Arguments->Msg = Message;
314 Arguments->wParam = wParam;
315 Arguments->lParam = lParam;
316 Arguments->lParamBufferSize = lParamBufferSize;
317 ResultPointer = NULL;
318 ResultLength = ArgumentLength;
319
320 IntSetTebWndCallback (&Wnd, &pWnd, &pActCtx);
321
322 UserLeaveCo();
323
324 Status = KeUserModeCallback(USER32_CALLBACK_WINDOWPROC,
325 Arguments,
326 ArgumentLength,
327 &ResultPointer,
328 &ResultLength);
329
330 _SEH2_TRY
331 {
332 /* Simulate old behaviour: copy into our local buffer */
333 RtlMoveMemory(Arguments, ResultPointer, ArgumentLength);
334 }
335 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
336 {
337 ERR("Failed to copy result from user mode!\n");
338 Status = _SEH2_GetExceptionCode();
339 }
340 _SEH2_END;
341
342 UserEnterCo();
343
344 IntRestoreTebWndCallback (Wnd, pWnd, pActCtx);
345
346 if (!NT_SUCCESS(Status))
347 {
348 ERR("Call to user mode failed!\n");
349 if (0 < lParamBufferSize)
350 {
351 IntCbFreeMemory(Arguments);
352 }
353 return -1;
354 }
355 Result = Arguments->Result;
356
357 if (0 < lParamBufferSize)
358 {
359 RtlMoveMemory((PVOID) lParam,
360 (PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
361 lParamBufferSize);
362 IntCbFreeMemory(Arguments);
363 }
364
365 return Result;
366 }
367
368 HMENU APIENTRY
369 co_IntLoadSysMenuTemplate()
370 {
371 LRESULT Result = 0;
372 NTSTATUS Status;
373 PVOID ResultPointer;
374 ULONG ResultLength;
375
376 /* Do not allow the desktop thread to do callback to user mode */
377 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
378
379 ResultPointer = NULL;
380 ResultLength = sizeof(LRESULT);
381
382 UserLeaveCo();
383
384 Status = KeUserModeCallback(USER32_CALLBACK_LOADSYSMENUTEMPLATE,
385 &ResultPointer,
386 0,
387 &ResultPointer,
388 &ResultLength);
389 if (NT_SUCCESS(Status))
390 {
391 /* Simulate old behaviour: copy into our local buffer */
392 _SEH2_TRY
393 {
394 ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
395 Result = *(LRESULT*)ResultPointer;
396 }
397 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
398 {
399 Result = 0;
400 }
401 _SEH2_END
402 }
403
404 UserEnterCo();
405
406 return (HMENU)Result;
407 }
408
409 extern HCURSOR gDesktopCursor;
410
411 BOOL APIENTRY
412 co_IntLoadDefaultCursors(VOID)
413 {
414 NTSTATUS Status;
415 PVOID ResultPointer;
416 ULONG ResultLength;
417 BOOL DefaultCursor = TRUE;
418
419 /* Do not allow the desktop thread to do callback to user mode */
420 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
421
422 ResultPointer = NULL;
423 ResultLength = sizeof(HCURSOR);
424
425 UserLeaveCo();
426
427 Status = KeUserModeCallback(USER32_CALLBACK_LOADDEFAULTCURSORS,
428 &DefaultCursor,
429 sizeof(BOOL),
430 &ResultPointer,
431 &ResultLength);
432
433 UserEnterCo();
434
435 /* HACK: The desktop class doen't have a proper cursor yet, so set it here */
436 gDesktopCursor = *((HCURSOR*)ResultPointer);
437
438 if (!NT_SUCCESS(Status))
439 {
440 return FALSE;
441 }
442 return TRUE;
443 }
444
445 LRESULT APIENTRY
446 co_IntCallHookProc(INT HookId,
447 INT Code,
448 WPARAM wParam,
449 LPARAM lParam,
450 HOOKPROC Proc,
451 BOOLEAN Ansi,
452 PUNICODE_STRING ModuleName)
453 {
454 ULONG ArgumentLength;
455 PVOID Argument = NULL;
456 LRESULT Result = 0;
457 NTSTATUS Status;
458 PVOID ResultPointer;
459 ULONG ResultLength;
460 PHOOKPROC_CALLBACK_ARGUMENTS Common;
461 CBT_CREATEWNDW *CbtCreateWnd = NULL;
462 PCHAR Extra;
463 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
464 PTHREADINFO pti;
465 PWND pWnd;
466 PMSG pMsg = NULL;
467 BOOL Hit = FALSE;
468 UINT lParamSize = 0;
469
470 ASSERT(Proc);
471 /* Do not allow the desktop thread to do callback to user mode */
472 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
473
474 pti = PsGetCurrentThreadWin32Thread();
475 if (pti->TIF_flags & TIF_INCLEANUP)
476 {
477 ERR("Thread is in cleanup and trying to call hook %d\n", Code);
478 return 0;
479 }
480
481 ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
482
483 switch(HookId)
484 {
485 case WH_CBT:
486 TRACE("WH_CBT: Code %d\n", Code);
487 switch(Code)
488 {
489 case HCBT_CREATEWND:
490 pWnd = UserGetWindowObject((HWND) wParam);
491 if (!pWnd)
492 {
493 ERR("WH_CBT HCBT_CREATEWND wParam bad hWnd!\n");
494 goto Fault_Exit;
495 }
496 TRACE("HCBT_CREATEWND AnsiCreator %s, AnsiHook %s\n", pWnd->state & WNDS_ANSICREATOR ? "True" : "False", Ansi ? "True" : "False");
497 // Due to KsStudio.exe, just pass the callers original pointers
498 // except class which point to kernel space if not an atom.
499 // Found by, Olaf Siejka
500 CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
501 ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
502 break;
503
504 case HCBT_MOVESIZE:
505 ArgumentLength += sizeof(RECTL);
506 break;
507 case HCBT_ACTIVATE:
508 ArgumentLength += sizeof(CBTACTIVATESTRUCT);
509 break;
510 case HCBT_CLICKSKIPPED:
511 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
512 break;
513 /* ATM pass on */
514 case HCBT_KEYSKIPPED:
515 case HCBT_MINMAX:
516 case HCBT_SETFOCUS:
517 case HCBT_SYSCOMMAND:
518 /* These types pass through. */
519 case HCBT_DESTROYWND:
520 case HCBT_QS:
521 break;
522 default:
523 ERR("Trying to call unsupported CBT hook %d\n", Code);
524 goto Fault_Exit;
525 }
526 break;
527 case WH_KEYBOARD_LL:
528 ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
529 break;
530 case WH_MOUSE_LL:
531 ArgumentLength += sizeof(MSLLHOOKSTRUCT);
532 break;
533 case WH_MOUSE:
534 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
535 break;
536 case WH_CALLWNDPROC:
537 {
538 CWPSTRUCT* pCWP = (CWPSTRUCT*) lParam;
539 ArgumentLength += sizeof(CWPSTRUCT);
540 lParamSize = lParamMemorySize(pCWP->message, pCWP->wParam, pCWP->lParam);
541 ArgumentLength += lParamSize;
542 break;
543 }
544 case WH_CALLWNDPROCRET:
545 {
546 CWPRETSTRUCT* pCWPR = (CWPRETSTRUCT*) lParam;
547 ArgumentLength += sizeof(CWPRETSTRUCT);
548 lParamSize = lParamMemorySize(pCWPR->message, pCWPR->wParam, pCWPR->lParam);
549 ArgumentLength += lParamSize;
550 break;
551 }
552 case WH_MSGFILTER:
553 case WH_SYSMSGFILTER:
554 case WH_GETMESSAGE:
555 ArgumentLength += sizeof(MSG);
556 break;
557 case WH_FOREGROUNDIDLE:
558 case WH_KEYBOARD:
559 case WH_SHELL:
560 break;
561 default:
562 ERR("Trying to call unsupported window hook %d\n", HookId);
563 goto Fault_Exit;
564 }
565
566 Argument = IntCbAllocateMemory(ArgumentLength);
567 if (NULL == Argument)
568 {
569 ERR("HookProc callback failed: out of memory\n");
570 goto Fault_Exit;
571 }
572 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
573 Common->HookId = HookId;
574 Common->Code = Code;
575 Common->wParam = wParam;
576 Common->lParam = lParam;
577 Common->Proc = Proc;
578 Common->Ansi = Ansi;
579 Extra = (PCHAR) Common + sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
580
581 switch(HookId)
582 {
583 case WH_CBT:
584 switch(Code)
585 { // Need to remember this is not the first time through! Call Next Hook?
586 case HCBT_CREATEWND:
587 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
588 RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) );
589 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
590 CbtCreatewndExtra->Cs.lpszClass = CbtCreateWnd->lpcs->lpszClass;
591 CbtCreatewndExtra->Cs.lpszName = CbtCreateWnd->lpcs->lpszName;
592 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
593 break;
594 case HCBT_CLICKSKIPPED:
595 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
596 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
597 break;
598 case HCBT_MOVESIZE:
599 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(RECTL));
600 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
601 break;
602 case HCBT_ACTIVATE:
603 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CBTACTIVATESTRUCT));
604 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
605 break;
606 }
607 break;
608 case WH_KEYBOARD_LL:
609 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
610 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
611 break;
612 case WH_MOUSE_LL:
613 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
614 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
615 break;
616 case WH_MOUSE:
617 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
618 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
619 break;
620 case WH_CALLWNDPROC:
621 /* For CALLWNDPROC and CALLWNDPROCRET, we must be wary of the fact that
622 * lParam could be a pointer to a buffer. This buffer must be exported
623 * to user space too */
624 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT));
625 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
626 if(lParamSize)
627 {
628 RtlCopyMemory(Extra + sizeof(CWPSTRUCT), (PVOID)((CWPSTRUCT*)lParam)->lParam, lParamSize);
629 ((CWPSTRUCT*)Extra)->lParam = (LPARAM)lParamSize;
630 }
631 break;
632 case WH_CALLWNDPROCRET:
633 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT));
634 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
635 if(lParamSize)
636 {
637 RtlCopyMemory(Extra + sizeof(CWPRETSTRUCT), (PVOID)((CWPRETSTRUCT*)lParam)->lParam, lParamSize);
638 ((CWPRETSTRUCT*)Extra)->lParam = (LPARAM)lParamSize;
639 }
640 break;
641 case WH_MSGFILTER:
642 case WH_SYSMSGFILTER:
643 case WH_GETMESSAGE:
644 pMsg = (PMSG)lParam;
645 RtlCopyMemory(Extra, (PVOID) pMsg, sizeof(MSG));
646 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
647 break;
648 case WH_FOREGROUNDIDLE:
649 case WH_KEYBOARD:
650 case WH_SHELL:
651 break;
652 }
653
654 ResultPointer = NULL;
655 ResultLength = sizeof(LRESULT);
656
657 UserLeaveCo();
658
659 Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
660 Argument,
661 ArgumentLength,
662 &ResultPointer,
663 &ResultLength);
664
665 UserEnterCo();
666
667 if (ResultPointer)
668 {
669 _SEH2_TRY
670 {
671 ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
672 /* Simulate old behaviour: copy into our local buffer */
673 Result = *(LRESULT*)ResultPointer;
674 }
675 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
676 {
677 Result = 0;
678 Hit = TRUE;
679 }
680 _SEH2_END;
681 }
682 else
683 {
684 ERR("ERROR: Hook ResultPointer 0x%p ResultLength %u\n",ResultPointer,ResultLength);
685 }
686
687 if (!NT_SUCCESS(Status))
688 {
689 ERR("Failure to make Callback! Status 0x%x",Status);
690 goto Fault_Exit;
691 }
692 /* Support write backs... SEH is in UserCallNextHookEx. */
693 switch (HookId)
694 {
695 case WH_CBT:
696 if (Code == HCBT_CREATEWND)
697 {
698 if (CbtCreatewndExtra)
699 {/*
700 The parameters could have been changed, include the coordinates
701 and dimensions of the window. We copy it back.
702 */
703 CbtCreateWnd->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
704 CbtCreateWnd->lpcs->x = CbtCreatewndExtra->Cs.x;
705 CbtCreateWnd->lpcs->y = CbtCreatewndExtra->Cs.y;
706 CbtCreateWnd->lpcs->cx = CbtCreatewndExtra->Cs.cx;
707 CbtCreateWnd->lpcs->cy = CbtCreatewndExtra->Cs.cy;
708 }
709 }
710 break;
711 // "The GetMsgProc hook procedure can examine or modify the message."
712 case WH_GETMESSAGE:
713 if (pMsg)
714 {
715 RtlCopyMemory((PVOID) pMsg, Extra, sizeof(MSG));
716 }
717 break;
718 }
719
720 Fault_Exit:
721 if (Hit)
722 {
723 ERR("Exception CallHookProc HookId %d Code %d\n",HookId,Code);
724 }
725 if (Argument) IntCbFreeMemory(Argument);
726
727 return Result;
728 }
729
730 //
731 // Events are notifications w/o results.
732 //
733 LRESULT
734 APIENTRY
735 co_IntCallEventProc(HWINEVENTHOOK hook,
736 DWORD event,
737 HWND hWnd,
738 LONG idObject,
739 LONG idChild,
740 DWORD dwEventThread,
741 DWORD dwmsEventTime,
742 WINEVENTPROC Proc)
743 {
744 LRESULT Result = 0;
745 NTSTATUS Status;
746 PEVENTPROC_CALLBACK_ARGUMENTS Common;
747 ULONG ArgumentLength, ResultLength;
748 PVOID Argument, ResultPointer;
749
750 ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
751
752 Argument = IntCbAllocateMemory(ArgumentLength);
753 if (NULL == Argument)
754 {
755 ERR("EventProc callback failed: out of memory\n");
756 return 0;
757 }
758 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
759 Common->hook = hook;
760 Common->event = event;
761 Common->hwnd = hWnd;
762 Common->idObject = idObject;
763 Common->idChild = idChild;
764 Common->dwEventThread = dwEventThread;
765 Common->dwmsEventTime = dwmsEventTime;
766 Common->Proc = Proc;
767
768 ResultPointer = NULL;
769 ResultLength = sizeof(LRESULT);
770
771 UserLeaveCo();
772
773 Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
774 Argument,
775 ArgumentLength,
776 &ResultPointer,
777 &ResultLength);
778
779 UserEnterCo();
780
781 IntCbFreeMemory(Argument);
782
783 if (!NT_SUCCESS(Status))
784 {
785 return 0;
786 }
787
788 return Result;
789 }
790
791 //
792 // Callback Load Menu and results.
793 //
794 HMENU
795 APIENTRY
796 co_IntCallLoadMenu( HINSTANCE hModule,
797 PUNICODE_STRING pMenuName )
798 {
799 LRESULT Result = 0;
800 NTSTATUS Status;
801 PLOADMENU_CALLBACK_ARGUMENTS Common;
802 ULONG ArgumentLength, ResultLength;
803 PVOID Argument, ResultPointer;
804
805 ArgumentLength = sizeof(LOADMENU_CALLBACK_ARGUMENTS);
806
807 ArgumentLength += pMenuName->Length + sizeof(WCHAR);
808
809 Argument = IntCbAllocateMemory(ArgumentLength);
810 if (NULL == Argument)
811 {
812 ERR("LoadMenu callback failed: out of memory\n");
813 return 0;
814 }
815 Common = (PLOADMENU_CALLBACK_ARGUMENTS) Argument;
816
817 // Help Intersource check and MenuName is now 4 bytes + so zero it.
818 RtlZeroMemory(Common, ArgumentLength);
819
820 Common->hModule = hModule;
821 if (pMenuName->Length)
822 RtlCopyMemory(&Common->MenuName, pMenuName->Buffer, pMenuName->Length);
823 else
824 RtlCopyMemory(&Common->MenuName, &pMenuName->Buffer, sizeof(WCHAR));
825
826 ResultPointer = NULL;
827 ResultLength = sizeof(LRESULT);
828
829 UserLeaveCo();
830
831 Status = KeUserModeCallback(USER32_CALLBACK_LOADMENU,
832 Argument,
833 ArgumentLength,
834 &ResultPointer,
835 &ResultLength);
836
837 UserEnterCo();
838
839 Result = *(LRESULT*)ResultPointer;
840
841 IntCbFreeMemory(Argument);
842
843 if (!NT_SUCCESS(Status))
844 {
845 return 0;
846 }
847
848 return (HMENU)Result;
849 }
850
851 NTSTATUS
852 APIENTRY
853 co_IntClientThreadSetup(VOID)
854 {
855 NTSTATUS Status;
856 ULONG ArgumentLength, ResultLength;
857 PVOID Argument, ResultPointer;
858
859 /* Do not allow the desktop thread to do callback to user mode */
860 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
861
862 ArgumentLength = ResultLength = 0;
863 Argument = ResultPointer = NULL;
864
865 UserLeaveCo();
866
867 Status = KeUserModeCallback(USER32_CALLBACK_CLIENTTHREADSTARTUP,
868 Argument,
869 ArgumentLength,
870 &ResultPointer,
871 &ResultLength);
872
873 UserEnterCo();
874
875 return Status;
876 }
877
878 BOOL
879 APIENTRY
880 co_IntGetCharsetInfo(LCID Locale, PCHARSETINFO pCs)
881 {
882 NTSTATUS Status;
883 ULONG ArgumentLength, ResultLength;
884 PVOID Argument, ResultPointer;
885 PGET_CHARSET_INFO Common;
886
887 ArgumentLength = sizeof(GET_CHARSET_INFO);
888
889 Argument = IntCbAllocateMemory(ArgumentLength);
890 if (NULL == Argument)
891 {
892 ERR("GetCharsetInfo callback failed: out of memory\n");
893 return 0;
894 }
895 Common = (PGET_CHARSET_INFO) Argument;
896
897 Common->Locale = Locale;
898
899 ResultPointer = NULL;
900 ResultLength = ArgumentLength;
901
902 UserLeaveCo();
903
904 Status = KeUserModeCallback(USER32_CALLBACK_GETCHARSETINFO,
905 Argument,
906 ArgumentLength,
907 &ResultPointer,
908 &ResultLength);
909
910 _SEH2_TRY
911 {
912 /* Need to copy into our local buffer */
913 RtlMoveMemory(Argument, ResultPointer, ArgumentLength);
914 }
915 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
916 {
917 ERR("Failed to copy result from user mode!\n");
918 Status = _SEH2_GetExceptionCode();
919 }
920 _SEH2_END;
921
922 UserEnterCo();
923
924 RtlCopyMemory(pCs, &Common->Cs, sizeof(CHARSETINFO));
925
926 IntCbFreeMemory(Argument);
927
928 if (!NT_SUCCESS(Status))
929 {
930 ERR("GetCharsetInfo Failed!!\n");
931 return FALSE;
932 }
933
934 return TRUE;
935 }
936
937 /* EOF */