[Win32ss]
[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 INT Mod,
452 ULONG_PTR offPfn,
453 BOOLEAN Ansi,
454 PUNICODE_STRING ModuleName)
455 {
456 ULONG ArgumentLength;
457 PVOID Argument = NULL;
458 LRESULT Result = 0;
459 NTSTATUS Status;
460 PVOID ResultPointer;
461 ULONG ResultLength;
462 PHOOKPROC_CALLBACK_ARGUMENTS Common;
463 CBT_CREATEWNDW *CbtCreateWnd = NULL;
464 PCHAR Extra;
465 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
466 PTHREADINFO pti;
467 PWND pWnd;
468 PMSG pMsg = NULL;
469 BOOL Hit = FALSE;
470 UINT lParamSize = 0;
471
472 ASSERT(Proc);
473 /* Do not allow the desktop thread to do callback to user mode */
474 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
475
476 pti = PsGetCurrentThreadWin32Thread();
477 if (pti->TIF_flags & TIF_INCLEANUP)
478 {
479 ERR("Thread is in cleanup and trying to call hook %d\n", Code);
480 return 0;
481 }
482
483 ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
484
485 switch(HookId)
486 {
487 case WH_CBT:
488 TRACE("WH_CBT: Code %d\n", Code);
489 switch(Code)
490 {
491 case HCBT_CREATEWND:
492 pWnd = UserGetWindowObject((HWND) wParam);
493 if (!pWnd)
494 {
495 ERR("WH_CBT HCBT_CREATEWND wParam bad hWnd!\n");
496 goto Fault_Exit;
497 }
498 TRACE("HCBT_CREATEWND AnsiCreator %s, AnsiHook %s\n", pWnd->state & WNDS_ANSICREATOR ? "True" : "False", Ansi ? "True" : "False");
499 // Due to KsStudio.exe, just pass the callers original pointers
500 // except class which point to kernel space if not an atom.
501 // Found by, Olaf Siejka
502 CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
503 ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
504 break;
505
506 case HCBT_MOVESIZE:
507 ArgumentLength += sizeof(RECTL);
508 break;
509 case HCBT_ACTIVATE:
510 ArgumentLength += sizeof(CBTACTIVATESTRUCT);
511 break;
512 case HCBT_CLICKSKIPPED:
513 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
514 break;
515 /* ATM pass on */
516 case HCBT_KEYSKIPPED:
517 case HCBT_MINMAX:
518 case HCBT_SETFOCUS:
519 case HCBT_SYSCOMMAND:
520 /* These types pass through. */
521 case HCBT_DESTROYWND:
522 case HCBT_QS:
523 break;
524 default:
525 ERR("Trying to call unsupported CBT hook %d\n", Code);
526 goto Fault_Exit;
527 }
528 break;
529 case WH_KEYBOARD_LL:
530 ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
531 break;
532 case WH_MOUSE_LL:
533 ArgumentLength += sizeof(MSLLHOOKSTRUCT);
534 break;
535 case WH_MOUSE:
536 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
537 break;
538 case WH_CALLWNDPROC:
539 {
540 CWPSTRUCT* pCWP = (CWPSTRUCT*) lParam;
541 ArgumentLength += sizeof(CWPSTRUCT);
542 lParamSize = lParamMemorySize(pCWP->message, pCWP->wParam, pCWP->lParam);
543 ArgumentLength += lParamSize;
544 break;
545 }
546 case WH_CALLWNDPROCRET:
547 {
548 CWPRETSTRUCT* pCWPR = (CWPRETSTRUCT*) lParam;
549 ArgumentLength += sizeof(CWPRETSTRUCT);
550 lParamSize = lParamMemorySize(pCWPR->message, pCWPR->wParam, pCWPR->lParam);
551 ArgumentLength += lParamSize;
552 break;
553 }
554 case WH_MSGFILTER:
555 case WH_SYSMSGFILTER:
556 case WH_GETMESSAGE:
557 ArgumentLength += sizeof(MSG);
558 break;
559 case WH_FOREGROUNDIDLE:
560 case WH_KEYBOARD:
561 case WH_SHELL:
562 break;
563 default:
564 ERR("Trying to call unsupported window hook %d\n", HookId);
565 goto Fault_Exit;
566 }
567
568 Argument = IntCbAllocateMemory(ArgumentLength);
569 if (NULL == Argument)
570 {
571 ERR("HookProc callback failed: out of memory\n");
572 goto Fault_Exit;
573 }
574 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
575 Common->HookId = HookId;
576 Common->Code = Code;
577 Common->wParam = wParam;
578 Common->lParam = lParam;
579 Common->Proc = Proc;
580 Common->Mod = Mod;
581 Common->offPfn = offPfn;
582 Common->Ansi = Ansi;
583 RtlZeroMemory(&Common->ModuleName, sizeof(Common->ModuleName));
584 RtlCopyMemory(&Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
585 Extra = (PCHAR) Common + sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
586
587 switch(HookId)
588 {
589 case WH_CBT:
590 switch(Code)
591 { // Need to remember this is not the first time through! Call Next Hook?
592 case HCBT_CREATEWND:
593 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
594 RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) );
595 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
596 CbtCreatewndExtra->Cs.lpszClass = CbtCreateWnd->lpcs->lpszClass;
597 CbtCreatewndExtra->Cs.lpszName = CbtCreateWnd->lpcs->lpszName;
598 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
599 break;
600 case HCBT_CLICKSKIPPED:
601 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
602 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
603 break;
604 case HCBT_MOVESIZE:
605 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(RECTL));
606 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
607 break;
608 case HCBT_ACTIVATE:
609 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CBTACTIVATESTRUCT));
610 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
611 break;
612 }
613 break;
614 case WH_KEYBOARD_LL:
615 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
616 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
617 break;
618 case WH_MOUSE_LL:
619 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
620 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
621 break;
622 case WH_MOUSE:
623 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
624 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
625 break;
626 case WH_CALLWNDPROC:
627 /* For CALLWNDPROC and CALLWNDPROCRET, we must be wary of the fact that
628 * lParam could be a pointer to a buffer. This buffer must be exported
629 * to user space too */
630 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT));
631 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
632 if(lParamSize)
633 {
634 RtlCopyMemory(Extra + sizeof(CWPSTRUCT), (PVOID)((CWPSTRUCT*)lParam)->lParam, lParamSize);
635 ((CWPSTRUCT*)Extra)->lParam = (LPARAM)lParamSize;
636 }
637 break;
638 case WH_CALLWNDPROCRET:
639 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT));
640 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
641 if(lParamSize)
642 {
643 RtlCopyMemory(Extra + sizeof(CWPRETSTRUCT), (PVOID)((CWPRETSTRUCT*)lParam)->lParam, lParamSize);
644 ((CWPRETSTRUCT*)Extra)->lParam = (LPARAM)lParamSize;
645 }
646 break;
647 case WH_MSGFILTER:
648 case WH_SYSMSGFILTER:
649 case WH_GETMESSAGE:
650 pMsg = (PMSG)lParam;
651 RtlCopyMemory(Extra, (PVOID) pMsg, sizeof(MSG));
652 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
653 break;
654 case WH_FOREGROUNDIDLE:
655 case WH_KEYBOARD:
656 case WH_SHELL:
657 break;
658 }
659
660 ResultPointer = NULL;
661 ResultLength = sizeof(LRESULT);
662
663 UserLeaveCo();
664
665 Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
666 Argument,
667 ArgumentLength,
668 &ResultPointer,
669 &ResultLength);
670
671 UserEnterCo();
672
673 if (ResultPointer)
674 {
675 _SEH2_TRY
676 {
677 ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
678 /* Simulate old behaviour: copy into our local buffer */
679 Result = *(LRESULT*)ResultPointer;
680 }
681 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
682 {
683 Result = 0;
684 Hit = TRUE;
685 }
686 _SEH2_END;
687 }
688 else
689 {
690 ERR("ERROR: Hook ResultPointer 0x%p ResultLength %u\n",ResultPointer,ResultLength);
691 }
692
693 if (!NT_SUCCESS(Status))
694 {
695 ERR("Failure to make Callback! Status 0x%x",Status);
696 goto Fault_Exit;
697 }
698 /* Support write backs... SEH is in UserCallNextHookEx. */
699 switch (HookId)
700 {
701 case WH_CBT:
702 if (Code == HCBT_CREATEWND)
703 {
704 if (CbtCreatewndExtra)
705 {/*
706 The parameters could have been changed, include the coordinates
707 and dimensions of the window. We copy it back.
708 */
709 CbtCreateWnd->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
710 CbtCreateWnd->lpcs->x = CbtCreatewndExtra->Cs.x;
711 CbtCreateWnd->lpcs->y = CbtCreatewndExtra->Cs.y;
712 CbtCreateWnd->lpcs->cx = CbtCreatewndExtra->Cs.cx;
713 CbtCreateWnd->lpcs->cy = CbtCreatewndExtra->Cs.cy;
714 }
715 }
716 break;
717 // "The GetMsgProc hook procedure can examine or modify the message."
718 case WH_GETMESSAGE:
719 if (pMsg)
720 {
721 RtlCopyMemory((PVOID) pMsg, Extra, sizeof(MSG));
722 }
723 break;
724 }
725
726 Fault_Exit:
727 if (Hit)
728 {
729 ERR("Exception CallHookProc HookId %d Code %d\n",HookId,Code);
730 }
731 if (Argument) IntCbFreeMemory(Argument);
732
733 return Result;
734 }
735
736 //
737 // Events are notifications w/o results.
738 //
739 LRESULT
740 APIENTRY
741 co_IntCallEventProc(HWINEVENTHOOK hook,
742 DWORD event,
743 HWND hWnd,
744 LONG idObject,
745 LONG idChild,
746 DWORD dwEventThread,
747 DWORD dwmsEventTime,
748 WINEVENTPROC Proc)
749 {
750 LRESULT Result = 0;
751 NTSTATUS Status;
752 PEVENTPROC_CALLBACK_ARGUMENTS Common;
753 ULONG ArgumentLength, ResultLength;
754 PVOID Argument, ResultPointer;
755
756 ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
757
758 Argument = IntCbAllocateMemory(ArgumentLength);
759 if (NULL == Argument)
760 {
761 ERR("EventProc callback failed: out of memory\n");
762 return 0;
763 }
764 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
765 Common->hook = hook;
766 Common->event = event;
767 Common->hwnd = hWnd;
768 Common->idObject = idObject;
769 Common->idChild = idChild;
770 Common->dwEventThread = dwEventThread;
771 Common->dwmsEventTime = dwmsEventTime;
772 Common->Proc = Proc;
773
774 ResultPointer = NULL;
775 ResultLength = sizeof(LRESULT);
776
777 UserLeaveCo();
778
779 Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
780 Argument,
781 ArgumentLength,
782 &ResultPointer,
783 &ResultLength);
784
785 UserEnterCo();
786
787 IntCbFreeMemory(Argument);
788
789 if (!NT_SUCCESS(Status))
790 {
791 return 0;
792 }
793
794 return Result;
795 }
796
797 //
798 // Callback Load Menu and results.
799 //
800 HMENU
801 APIENTRY
802 co_IntCallLoadMenu( HINSTANCE hModule,
803 PUNICODE_STRING pMenuName )
804 {
805 LRESULT Result = 0;
806 NTSTATUS Status;
807 PLOADMENU_CALLBACK_ARGUMENTS Common;
808 ULONG ArgumentLength, ResultLength;
809 PVOID Argument, ResultPointer;
810
811 ArgumentLength = sizeof(LOADMENU_CALLBACK_ARGUMENTS);
812
813 ArgumentLength += pMenuName->Length + sizeof(WCHAR);
814
815 Argument = IntCbAllocateMemory(ArgumentLength);
816 if (NULL == Argument)
817 {
818 ERR("LoadMenu callback failed: out of memory\n");
819 return 0;
820 }
821 Common = (PLOADMENU_CALLBACK_ARGUMENTS) Argument;
822
823 // Help Intersource check and MenuName is now 4 bytes + so zero it.
824 RtlZeroMemory(Common, ArgumentLength);
825
826 Common->hModule = hModule;
827 if (pMenuName->Length)
828 RtlCopyMemory(&Common->MenuName, pMenuName->Buffer, pMenuName->Length);
829 else
830 RtlCopyMemory(&Common->MenuName, &pMenuName->Buffer, sizeof(WCHAR));
831
832 ResultPointer = NULL;
833 ResultLength = sizeof(LRESULT);
834
835 UserLeaveCo();
836
837 Status = KeUserModeCallback(USER32_CALLBACK_LOADMENU,
838 Argument,
839 ArgumentLength,
840 &ResultPointer,
841 &ResultLength);
842
843 UserEnterCo();
844
845 Result = *(LRESULT*)ResultPointer;
846
847 IntCbFreeMemory(Argument);
848
849 if (!NT_SUCCESS(Status))
850 {
851 return 0;
852 }
853
854 return (HMENU)Result;
855 }
856
857 NTSTATUS
858 APIENTRY
859 co_IntClientThreadSetup(VOID)
860 {
861 NTSTATUS Status;
862 ULONG ArgumentLength, ResultLength;
863 PVOID Argument, ResultPointer;
864
865 /* Do not allow the desktop thread to do callback to user mode */
866 ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
867
868 ArgumentLength = ResultLength = 0;
869 Argument = ResultPointer = NULL;
870
871 UserLeaveCo();
872
873 Status = KeUserModeCallback(USER32_CALLBACK_CLIENTTHREADSTARTUP,
874 Argument,
875 ArgumentLength,
876 &ResultPointer,
877 &ResultLength);
878
879 UserEnterCo();
880
881 return Status;
882 }
883
884
885 HANDLE FASTCALL
886 co_IntCopyImage(HANDLE hnd, UINT type, INT desiredx, INT desiredy, UINT flags)
887 {
888 HANDLE Handle;
889 NTSTATUS Status;
890 ULONG ArgumentLength, ResultLength;
891 PVOID Argument, ResultPointer;
892 PCOPYIMAGE_CALLBACK_ARGUMENTS Common;
893
894 ArgumentLength = ResultLength = 0;
895 Argument = ResultPointer = NULL;
896
897 ArgumentLength = sizeof(COPYIMAGE_CALLBACK_ARGUMENTS);
898
899 Argument = IntCbAllocateMemory(ArgumentLength);
900 if (NULL == Argument)
901 {
902 ERR("CopyImage callback failed: out of memory\n");
903 return 0;
904 }
905 Common = (PCOPYIMAGE_CALLBACK_ARGUMENTS) Argument;
906
907 Common->hImage = hnd;
908 Common->uType = type;
909 Common->cxDesired = desiredx;
910 Common->cyDesired = desiredy;
911 Common->fuFlags = flags;
912
913 UserLeaveCo();
914
915 Status = KeUserModeCallback(USER32_CALLBACK_COPYIMAGE,
916 Argument,
917 ArgumentLength,
918 &ResultPointer,
919 &ResultLength);
920
921
922 UserEnterCo();
923
924 Handle = *(HANDLE*)ResultPointer;
925
926 IntCbFreeMemory(Argument);
927
928 if (!NT_SUCCESS(Status))
929 {
930 ERR("CopyImage callback failed!\n");
931 return 0;
932 }
933
934 return Handle;
935 }
936
937 BOOL
938 APIENTRY
939 co_IntGetCharsetInfo(LCID Locale, PCHARSETINFO pCs)
940 {
941 NTSTATUS Status;
942 ULONG ArgumentLength, ResultLength;
943 PVOID Argument, ResultPointer;
944 PGET_CHARSET_INFO Common;
945
946 ArgumentLength = sizeof(GET_CHARSET_INFO);
947
948 Argument = IntCbAllocateMemory(ArgumentLength);
949 if (NULL == Argument)
950 {
951 ERR("GetCharsetInfo callback failed: out of memory\n");
952 return 0;
953 }
954 Common = (PGET_CHARSET_INFO) Argument;
955
956 Common->Locale = Locale;
957
958 ResultPointer = NULL;
959 ResultLength = ArgumentLength;
960
961 UserLeaveCo();
962
963 Status = KeUserModeCallback(USER32_CALLBACK_GETCHARSETINFO,
964 Argument,
965 ArgumentLength,
966 &ResultPointer,
967 &ResultLength);
968
969 _SEH2_TRY
970 {
971 /* Need to copy into our local buffer */
972 RtlMoveMemory(Argument, ResultPointer, ArgumentLength);
973 }
974 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
975 {
976 ERR("Failed to copy result from user mode!\n");
977 Status = _SEH2_GetExceptionCode();
978 }
979 _SEH2_END;
980
981 UserEnterCo();
982
983 RtlCopyMemory(pCs, &Common->Cs, sizeof(CHARSETINFO));
984
985 IntCbFreeMemory(Argument);
986
987 if (!NT_SUCCESS(Status))
988 {
989 ERR("GetCharsetInfo Failed!!\n");
990 return FALSE;
991 }
992
993 return TRUE;
994 }
995
996 /* EOF */