xref: /reactos/win32ss/user/ntuser/callback.c (revision ebaf247c)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Callback to usermode support
5  * FILE:             win32ss/user/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    W32Thread = PsGetCurrentThreadWin32Thread();
55    ASSERT(W32Thread);
56 
57    if (W32Thread->TIF_flags & TIF_INCLEANUP)
58    {
59       ERR("CbFM Thread is already in cleanup\n");
60       return;
61    }
62 
63    ASSERT(Data);
64 
65    Mem = ((PINT_CALLBACK_HEADER)Data - 1);
66 
67    /* Remove the memory block from the thread's callback list */
68    RemoveEntryList(&Mem->ListEntry);
69 
70    /* Free memory */
71    ExFreePoolWithTag(Mem, USERTAG_CALLBACK);
72 }
73 
74 VOID FASTCALL
75 IntCleanupThreadCallbacks(PTHREADINFO W32Thread)
76 {
77    PLIST_ENTRY CurrentEntry;
78    PINT_CALLBACK_HEADER Mem;
79 
80    while (!IsListEmpty(&W32Thread->W32CallbackListHead))
81    {
82       CurrentEntry = RemoveHeadList(&W32Thread->W32CallbackListHead);
83       Mem = CONTAINING_RECORD(CurrentEntry, INT_CALLBACK_HEADER,
84                               ListEntry);
85 
86       /* Free memory */
87       ExFreePoolWithTag(Mem, USERTAG_CALLBACK);
88    }
89 }
90 
91 //
92 // Pass the Current Window handle and pointer to the Client Callback.
93 // This will help user space programs speed up read access with the window object.
94 //
95 static VOID
96 IntSetTebWndCallback (HWND * hWnd, PWND * pWnd, PVOID * pActCtx)
97 {
98   HWND hWndS = *hWnd;
99   PWND Window = UserGetWindowObject(*hWnd);
100   PCLIENTINFO ClientInfo = GetWin32ClientInfo();
101 
102   *hWnd = ClientInfo->CallbackWnd.hWnd;
103   *pWnd = ClientInfo->CallbackWnd.pWnd;
104   *pActCtx = ClientInfo->CallbackWnd.pActCtx;
105 
106   if (Window)
107   {
108      ClientInfo->CallbackWnd.hWnd = hWndS;
109      ClientInfo->CallbackWnd.pWnd = DesktopHeapAddressToUser(Window);
110      ClientInfo->CallbackWnd.pActCtx = Window->pActCtx;
111   }
112   else //// What if Dispatching WM_SYS/TIMER with NULL window? Fix AbiWord Crash when sizing.
113   {
114      ClientInfo->CallbackWnd.hWnd = hWndS;
115      ClientInfo->CallbackWnd.pWnd = Window;
116      ClientInfo->CallbackWnd.pActCtx = 0;
117   }
118 }
119 
120 static VOID
121 IntRestoreTebWndCallback (HWND hWnd, PWND pWnd, PVOID pActCtx)
122 {
123   PCLIENTINFO ClientInfo = GetWin32ClientInfo();
124 
125   ClientInfo->CallbackWnd.hWnd = hWnd;
126   ClientInfo->CallbackWnd.pWnd = pWnd;
127   ClientInfo->CallbackWnd.pActCtx = pActCtx;
128 }
129 
130 /* FUNCTIONS *****************************************************************/
131 
132 /* Calls ClientLoadLibrary in user32 */
133 BOOL
134 NTAPI
135 co_IntClientLoadLibrary(PUNICODE_STRING pstrLibName,
136                         PUNICODE_STRING pstrInitFunc,
137                         BOOL Unload,
138                         BOOL ApiHook)
139 {
140    PVOID ResultPointer;
141    ULONG ResultLength;
142    ULONG ArgumentLength;
143    PCLIENT_LOAD_LIBRARY_ARGUMENTS pArguments;
144    NTSTATUS Status;
145    BOOL bResult;
146    ULONG_PTR pLibNameBuffer = 0, pInitFuncBuffer = 0;
147 
148    /* Do not allow the desktop thread to do callback to user mode */
149    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
150 
151    TRACE("co_IntClientLoadLibrary: %S, %S, %d, %d\n", pstrLibName->Buffer, pstrLibName->Buffer, Unload, ApiHook);
152 
153    /* Calculate the size of the argument */
154    ArgumentLength = sizeof(CLIENT_LOAD_LIBRARY_ARGUMENTS);
155    if(pstrLibName)
156    {
157        pLibNameBuffer = ArgumentLength;
158        ArgumentLength += pstrLibName->Length + sizeof(WCHAR);
159    }
160    if(pstrInitFunc)
161    {
162        pInitFuncBuffer = ArgumentLength;
163        ArgumentLength += pstrInitFunc->Length + sizeof(WCHAR);
164    }
165 
166    /* Allocate the argument */
167    pArguments = IntCbAllocateMemory(ArgumentLength);
168    if(pArguments == NULL)
169    {
170        return FALSE;
171    }
172 
173    /* Fill the argument */
174    pArguments->Unload = Unload;
175    pArguments->ApiHook = ApiHook;
176    if(pstrLibName)
177    {
178        /* Copy the string to the callback memory */
179        pLibNameBuffer += (ULONG_PTR)pArguments;
180        pArguments->strLibraryName.Buffer = (PWCHAR)pLibNameBuffer;
181        pArguments->strLibraryName.MaximumLength = pstrLibName->Length + sizeof(WCHAR);
182        RtlCopyUnicodeString(&pArguments->strLibraryName, pstrLibName);
183 
184        /* Fix argument pointer to be relative to the argument */
185        pLibNameBuffer -= (ULONG_PTR)pArguments;
186        pArguments->strLibraryName.Buffer = (PWCHAR)(pLibNameBuffer);
187    }
188    else
189    {
190        RtlZeroMemory(&pArguments->strLibraryName, sizeof(UNICODE_STRING));
191    }
192 
193    if(pstrInitFunc)
194    {
195        /* Copy the strings to the callback memory */
196        pInitFuncBuffer += (ULONG_PTR)pArguments;
197        pArguments->strInitFuncName.Buffer = (PWCHAR)pInitFuncBuffer;
198        pArguments->strInitFuncName.MaximumLength = pstrInitFunc->Length + sizeof(WCHAR);
199        RtlCopyUnicodeString(&pArguments->strInitFuncName, pstrInitFunc);
200 
201        /* Fix argument pointers to be relative to the argument */
202        pInitFuncBuffer -= (ULONG_PTR)pArguments;
203        pArguments->strInitFuncName.Buffer = (PWCHAR)(pInitFuncBuffer);
204    }
205    else
206    {
207        RtlZeroMemory(&pArguments->strInitFuncName, sizeof(UNICODE_STRING));
208    }
209 
210    /* Do the callback */
211    UserLeaveCo();
212 
213    Status = KeUserModeCallback(USER32_CALLBACK_CLIENTLOADLIBRARY,
214                                pArguments,
215                                ArgumentLength,
216                                &ResultPointer,
217                                &ResultLength);
218 
219    UserEnterCo();
220 
221    /* Free the argument */
222    IntCbFreeMemory(pArguments);
223 
224    if(!NT_SUCCESS(Status))
225    {
226        return FALSE;
227    }
228 
229    _SEH2_TRY
230    {
231        /* Probe and copy the usermode result data */
232        ProbeForRead(ResultPointer, sizeof(HMODULE), 1);
233        bResult = *(BOOL*)ResultPointer;
234    }
235    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
236    {
237        bResult = FALSE;
238    }
239    _SEH2_END;
240 
241    return bResult;
242 }
243 
244 VOID APIENTRY
245 co_IntCallSentMessageCallback(SENDASYNCPROC CompletionCallback,
246                               HWND hWnd,
247                               UINT Msg,
248                               ULONG_PTR CompletionCallbackContext,
249                               LRESULT Result)
250 {
251    SENDASYNCPROC_CALLBACK_ARGUMENTS Arguments;
252    PVOID ResultPointer, pActCtx;
253    PWND pWnd;
254    ULONG ResultLength;
255    NTSTATUS Status;
256 
257    /* Do not allow the desktop thread to do callback to user mode */
258    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
259 
260    Arguments.Callback = CompletionCallback;
261    Arguments.Wnd = hWnd;
262    Arguments.Msg = Msg;
263    Arguments.Context = CompletionCallbackContext;
264    Arguments.Result = Result;
265 
266    IntSetTebWndCallback (&hWnd, &pWnd, &pActCtx);
267 
268    UserLeaveCo();
269 
270    Status = KeUserModeCallback(USER32_CALLBACK_SENDASYNCPROC,
271                                &Arguments,
272                                sizeof(SENDASYNCPROC_CALLBACK_ARGUMENTS),
273                                &ResultPointer,
274                                &ResultLength);
275 
276    UserEnterCo();
277 
278    IntRestoreTebWndCallback (hWnd, pWnd, pActCtx);
279 
280    if (!NT_SUCCESS(Status))
281    {
282       ERR("KeUserModeCallback failed with %lx\n", Status);
283       return;
284    }
285    return;
286 }
287 
288 LRESULT APIENTRY
289 co_IntCallWindowProc(WNDPROC Proc,
290                      BOOLEAN IsAnsiProc,
291                      HWND Wnd,
292                      UINT Message,
293                      WPARAM wParam,
294                      LPARAM lParam,
295                      INT lParamBufferSize)
296 {
297    WINDOWPROC_CALLBACK_ARGUMENTS StackArguments;
298    PWINDOWPROC_CALLBACK_ARGUMENTS Arguments;
299    NTSTATUS Status;
300    PVOID ResultPointer, pActCtx;
301    PWND pWnd;
302    ULONG ResultLength;
303    ULONG ArgumentLength;
304    LRESULT Result;
305 
306    TRACE("co_IntCallWindowProc(Proc %p, IsAnsiProc: %s, Wnd %p, Message %u, wParam %Iu, lParam %Id, lParamBufferSize %d)\n",
307        Proc, IsAnsiProc ? "TRUE" : "FALSE", Wnd, Message, wParam, lParam, lParamBufferSize);
308 
309    /* Do not allow the desktop thread to do callback to user mode */
310    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
311 
312    if (lParamBufferSize != -1)
313    {
314       ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS) + lParamBufferSize;
315       Arguments = IntCbAllocateMemory(ArgumentLength);
316       if (NULL == Arguments)
317       {
318          ERR("Unable to allocate buffer for window proc callback\n");
319          return -1;
320       }
321       RtlMoveMemory((PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
322                     (PVOID) lParam, lParamBufferSize);
323    }
324    else
325    {
326       Arguments = &StackArguments;
327       ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS);
328    }
329    Arguments->Proc = Proc;
330    Arguments->IsAnsiProc = IsAnsiProc;
331    Arguments->Wnd = Wnd;
332    Arguments->Msg = Message;
333    Arguments->wParam = wParam;
334    Arguments->lParam = lParam;
335    Arguments->lParamBufferSize = lParamBufferSize;
336    ResultPointer = NULL;
337    ResultLength = ArgumentLength;
338 
339    IntSetTebWndCallback (&Wnd, &pWnd, &pActCtx);
340 
341    UserLeaveCo();
342 
343    Status = KeUserModeCallback(USER32_CALLBACK_WINDOWPROC,
344                                Arguments,
345                                ArgumentLength,
346                                &ResultPointer,
347                                &ResultLength);
348    if (!NT_SUCCESS(Status))
349    {
350       ERR("Error Callback to User space Status %lx Message %d\n",Status,Message);
351       UserEnterCo();
352       return 0;
353    }
354 
355    _SEH2_TRY
356    {
357       /* Simulate old behaviour: copy into our local buffer */
358       RtlMoveMemory(Arguments, ResultPointer, ArgumentLength);
359    }
360    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
361    {
362       ERR("Failed to copy result from user mode, Message %u lParam size %d!\n", Message, lParamBufferSize);
363       Status = _SEH2_GetExceptionCode();
364    }
365    _SEH2_END;
366 
367    UserEnterCo();
368 
369    IntRestoreTebWndCallback (Wnd, pWnd, pActCtx);
370 
371    if (!NT_SUCCESS(Status))
372    {
373      ERR("Call to user mode failed! 0x%08lx\n",Status);
374       if (lParamBufferSize != -1)
375       {
376          IntCbFreeMemory(Arguments);
377       }
378       return -1;
379    }
380    Result = Arguments->Result;
381 
382    if (lParamBufferSize != -1)
383    {
384       PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
385       // Is this message being processed from inside kernel space?
386       BOOL InSendMessage = (pti->pcti->CTI_flags & CTI_INSENDMESSAGE);
387 
388       TRACE("Copy lParam Message %u lParam %d!\n", Message, lParam);
389       switch (Message)
390       {
391           default:
392             TRACE("Don't copy lParam, Message %u Size %d lParam %d!\n", Message, lParamBufferSize, lParam);
393             break;
394           // Write back to user/kernel space. Also see g_MsgMemory.
395           case WM_CREATE:
396           case WM_GETMINMAXINFO:
397           case WM_GETTEXT:
398           case WM_NCCALCSIZE:
399           case WM_NCCREATE:
400           case WM_STYLECHANGING:
401           case WM_WINDOWPOSCHANGING:
402           case WM_SIZING:
403           case WM_MOVING:
404           case WM_MEASUREITEM:
405           case WM_NEXTMENU:
406             TRACE("Copy lParam, Message %u Size %d lParam %d!\n", Message, lParamBufferSize, lParam);
407             if (InSendMessage)
408                // Copy into kernel space.
409                RtlMoveMemory((PVOID) lParam,
410                              (PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
411                               lParamBufferSize);
412             else
413             {
414              _SEH2_TRY
415              { // Copy into user space.
416                RtlMoveMemory((PVOID) lParam,
417                              (PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
418                               lParamBufferSize);
419              }
420              _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
421              {
422                 ERR("Failed to copy lParam to user space, Message %u!\n", Message);
423              }
424              _SEH2_END;
425             }
426             break;
427       }
428       IntCbFreeMemory(Arguments);
429    }
430 
431    return Result;
432 }
433 
434 HMENU APIENTRY
435 co_IntLoadSysMenuTemplate(VOID)
436 {
437    LRESULT Result = 0;
438    NTSTATUS Status;
439    PVOID ResultPointer;
440    ULONG ResultLength;
441 
442    /* Do not allow the desktop thread to do callback to user mode */
443    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
444 
445    ResultPointer = NULL;
446    ResultLength = sizeof(LRESULT);
447 
448    UserLeaveCo();
449 
450    Status = KeUserModeCallback(USER32_CALLBACK_LOADSYSMENUTEMPLATE,
451                                &ResultPointer,
452                                0,
453                                &ResultPointer,
454                                &ResultLength);
455    if (NT_SUCCESS(Status))
456    {
457       /* Simulate old behaviour: copy into our local buffer */
458       _SEH2_TRY
459       {
460         ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
461         Result = *(LRESULT*)ResultPointer;
462       }
463       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
464       {
465         Result = 0;
466       }
467       _SEH2_END;
468    }
469 
470    UserEnterCo();
471 
472    return (HMENU)Result;
473 }
474 
475 extern HCURSOR gDesktopCursor;
476 
477 BOOL APIENTRY
478 co_IntLoadDefaultCursors(VOID)
479 {
480    NTSTATUS Status;
481    PVOID ResultPointer;
482    ULONG ResultLength;
483    BOOL DefaultCursor = TRUE;
484 
485    /* Do not allow the desktop thread to do callback to user mode */
486    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
487 
488    ResultPointer = NULL;
489    ResultLength = sizeof(HCURSOR);
490 
491    UserLeaveCo();
492 
493    Status = KeUserModeCallback(USER32_CALLBACK_LOADDEFAULTCURSORS,
494                                &DefaultCursor,
495                                sizeof(BOOL),
496                                &ResultPointer,
497                                &ResultLength);
498 
499    UserEnterCo();
500 
501    if (!NT_SUCCESS(Status))
502    {
503       return FALSE;
504    }
505 
506    /* HACK: The desktop class doen't have a proper cursor yet, so set it here */
507     gDesktopCursor = *((HCURSOR*)ResultPointer);
508 
509    return TRUE;
510 }
511 
512 LRESULT APIENTRY
513 co_IntCallHookProc(INT HookId,
514                    INT Code,
515                    WPARAM wParam,
516                    LPARAM lParam,
517                    HOOKPROC Proc,
518                    INT Mod,
519                    ULONG_PTR offPfn,
520                    BOOLEAN Ansi,
521                    PUNICODE_STRING ModuleName)
522 {
523    ULONG ArgumentLength;
524    PVOID Argument = NULL;
525    LRESULT Result = 0;
526    NTSTATUS Status;
527    PVOID ResultPointer;
528    ULONG ResultLength;
529    PHOOKPROC_CALLBACK_ARGUMENTS Common;
530    CBT_CREATEWNDW *CbtCreateWnd = NULL;
531    PCHAR Extra;
532    PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
533    PTHREADINFO pti;
534    PWND pWnd;
535    PMSG pMsg = NULL;
536    BOOL Hit = FALSE;
537    UINT lParamSize = 0;
538 
539    ASSERT(Proc);
540    /* Do not allow the desktop thread to do callback to user mode */
541    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
542 
543    pti = PsGetCurrentThreadWin32Thread();
544    if (pti->TIF_flags & TIF_INCLEANUP)
545    {
546       ERR("Thread is in cleanup and trying to call hook %d\n", Code);
547       return 0;
548    }
549 
550    ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
551 
552    switch(HookId)
553    {
554       case WH_CBT:
555          TRACE("WH_CBT: Code %d\n", Code);
556          switch(Code)
557          {
558             case HCBT_CREATEWND:
559                pWnd = UserGetWindowObject((HWND) wParam);
560                if (!pWnd)
561                {
562                   ERR("WH_CBT HCBT_CREATEWND wParam bad hWnd!\n");
563                   goto Fault_Exit;
564                }
565                TRACE("HCBT_CREATEWND AnsiCreator %s, AnsiHook %s\n", pWnd->state & WNDS_ANSICREATOR ? "True" : "False", Ansi ? "True" : "False");
566               // Due to KsStudio.exe, just pass the callers original pointers
567               // except class which point to kernel space if not an atom.
568               // Found by, Olaf Siejka
569                CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
570                ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
571                break;
572 
573             case HCBT_MOVESIZE:
574                ArgumentLength += sizeof(RECTL);
575                break;
576             case HCBT_ACTIVATE:
577                ArgumentLength += sizeof(CBTACTIVATESTRUCT);
578                break;
579             case HCBT_CLICKSKIPPED:
580                ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
581                break;
582 /*   ATM pass on */
583             case HCBT_KEYSKIPPED:
584             case HCBT_MINMAX:
585             case HCBT_SETFOCUS:
586             case HCBT_SYSCOMMAND:
587 /*   These types pass through. */
588             case HCBT_DESTROYWND:
589             case HCBT_QS:
590                break;
591             default:
592                ERR("Trying to call unsupported CBT hook %d\n", Code);
593                goto Fault_Exit;
594          }
595          break;
596       case WH_KEYBOARD_LL:
597          ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
598          break;
599       case WH_MOUSE_LL:
600          ArgumentLength += sizeof(MSLLHOOKSTRUCT);
601          break;
602       case WH_MOUSE:
603          ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
604          break;
605      case WH_CALLWNDPROC:
606      {
607          CWPSTRUCT* pCWP = (CWPSTRUCT*) lParam;
608          ArgumentLength += sizeof(CWPSTRUCT);
609          lParamSize = lParamMemorySize(pCWP->message, pCWP->wParam, pCWP->lParam);
610          ArgumentLength += lParamSize;
611          break;
612       }
613       case WH_CALLWNDPROCRET:
614       {
615          CWPRETSTRUCT* pCWPR = (CWPRETSTRUCT*) lParam;
616          ArgumentLength += sizeof(CWPRETSTRUCT);
617          lParamSize = lParamMemorySize(pCWPR->message, pCWPR->wParam, pCWPR->lParam);
618          ArgumentLength += lParamSize;
619          break;
620       }
621       case WH_MSGFILTER:
622       case WH_SYSMSGFILTER:
623       case WH_GETMESSAGE:
624          ArgumentLength += sizeof(MSG);
625          break;
626       case WH_FOREGROUNDIDLE:
627       case WH_KEYBOARD:
628       case WH_SHELL:
629          break;
630       default:
631          ERR("Trying to call unsupported window hook %d\n", HookId);
632          goto Fault_Exit;
633    }
634 
635    Argument = IntCbAllocateMemory(ArgumentLength);
636    if (NULL == Argument)
637    {
638       ERR("HookProc callback failed: out of memory\n");
639       goto Fault_Exit;
640    }
641    Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
642    Common->HookId = HookId;
643    Common->Code = Code;
644    Common->wParam = wParam;
645    Common->lParam = lParam;
646    Common->Proc = Proc;
647    Common->Mod = Mod;
648    Common->offPfn = offPfn;
649    Common->Ansi = Ansi;
650    RtlZeroMemory(&Common->ModuleName, sizeof(Common->ModuleName));
651    if (ModuleName->Buffer && ModuleName->Length)
652    {
653       RtlCopyMemory(&Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
654       // If ModuleName->Buffer NULL while in destroy,
655       //    this will make User32:Hook.c complain about not loading the library module.
656       // Fix symptom for CORE-10549.
657    }
658    Extra = (PCHAR) Common + sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
659 
660    switch(HookId)
661    {
662       case WH_CBT:
663          switch(Code)
664          { // Need to remember this is not the first time through! Call Next Hook?
665             case HCBT_CREATEWND:
666                CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
667                RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) );
668                CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
669                CbtCreatewndExtra->Cs.lpszClass = CbtCreateWnd->lpcs->lpszClass;
670                CbtCreatewndExtra->Cs.lpszName = CbtCreateWnd->lpcs->lpszName;
671                Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
672                break;
673             case HCBT_CLICKSKIPPED:
674                RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
675                Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
676                break;
677             case HCBT_MOVESIZE:
678                RtlCopyMemory(Extra, (PVOID) lParam, sizeof(RECTL));
679                Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
680                break;
681             case HCBT_ACTIVATE:
682                RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CBTACTIVATESTRUCT));
683                Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
684                break;
685          }
686          break;
687       case WH_KEYBOARD_LL:
688          RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
689          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
690          break;
691       case WH_MOUSE_LL:
692          RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
693          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
694          break;
695       case WH_MOUSE:
696          RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
697          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
698          break;
699       case WH_CALLWNDPROC:
700          /* For CALLWNDPROC and CALLWNDPROCRET, we must be wary of the fact that
701           * lParam could be a pointer to a buffer. This buffer must be exported
702           * to user space too */
703          RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT));
704          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
705          if(lParamSize)
706          {
707              RtlCopyMemory(Extra + sizeof(CWPSTRUCT), (PVOID)((CWPSTRUCT*)lParam)->lParam, lParamSize);
708              ((CWPSTRUCT*)Extra)->lParam = (LPARAM)lParamSize;
709          }
710          break;
711       case WH_CALLWNDPROCRET:
712          RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT));
713          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
714          if(lParamSize)
715          {
716              RtlCopyMemory(Extra + sizeof(CWPRETSTRUCT), (PVOID)((CWPRETSTRUCT*)lParam)->lParam, lParamSize);
717              ((CWPRETSTRUCT*)Extra)->lParam = (LPARAM)lParamSize;
718          }
719          break;
720       case WH_MSGFILTER:
721       case WH_SYSMSGFILTER:
722       case WH_GETMESSAGE:
723          pMsg = (PMSG)lParam;
724          RtlCopyMemory(Extra, (PVOID) pMsg, sizeof(MSG));
725          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
726          break;
727       case WH_FOREGROUNDIDLE:
728       case WH_KEYBOARD:
729       case WH_SHELL:
730          break;
731    }
732 
733    ResultPointer = NULL;
734    ResultLength = ArgumentLength;
735 
736    UserLeaveCo();
737 
738    Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
739                                Argument,
740                                ArgumentLength,
741                                &ResultPointer,
742                                &ResultLength);
743 
744    UserEnterCo();
745 
746    if (!NT_SUCCESS(Status))
747    {
748       ERR("Failure to make Callback! Status 0x%x\n",Status);
749       goto Fault_Exit;
750    }
751 
752    if (ResultPointer)
753    {
754       _SEH2_TRY
755       {
756          /* Simulate old behaviour: copy into our local buffer */
757          RtlMoveMemory(Argument, ResultPointer, ArgumentLength);
758          Result = Common->Result;
759       }
760       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
761       {
762          Result = 0;
763          Hit = TRUE;
764       }
765       _SEH2_END;
766    }
767    else
768    {
769       ERR("ERROR: Hook %d Code %d ResultPointer 0x%p ResultLength %u\n",HookId,Code,ResultPointer,ResultLength);
770    }
771 
772    /* Support write backs... SEH is in UserCallNextHookEx. */
773    switch (HookId)
774    {
775       case WH_CBT:
776       {
777          switch (Code)
778          {
779             case HCBT_CREATEWND:
780                if (CbtCreatewndExtra)
781                {/*
782                   The parameters could have been changed, include the coordinates
783                   and dimensions of the window. We copy it back.
784                  */
785                   CbtCreateWnd->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
786                   CbtCreateWnd->lpcs->x  = CbtCreatewndExtra->Cs.x;
787                   CbtCreateWnd->lpcs->y  = CbtCreatewndExtra->Cs.y;
788                   CbtCreateWnd->lpcs->cx = CbtCreatewndExtra->Cs.cx;
789                   CbtCreateWnd->lpcs->cy = CbtCreatewndExtra->Cs.cy;
790                }
791             break;
792             case HCBT_MOVESIZE:
793                if (Extra && lParam)
794                {
795                   RtlCopyMemory((PVOID) lParam, Extra, sizeof(RECTL));
796                }
797             break;
798          }
799       }
800       // "The GetMsgProc hook procedure can examine or modify the message."
801       case WH_GETMESSAGE:
802          if (pMsg)
803          {
804             RtlCopyMemory((PVOID) pMsg, Extra, sizeof(MSG));
805          }
806          break;
807    }
808 
809 Fault_Exit:
810    if (Hit)
811    {
812       ERR("Exception CallHookProc HookId %d Code %d\n",HookId,Code);
813    }
814    if (Argument) IntCbFreeMemory(Argument);
815 
816    return Result;
817 }
818 
819 //
820 // Events are notifications w/o results.
821 //
822 LRESULT
823 APIENTRY
824 co_IntCallEventProc(HWINEVENTHOOK hook,
825                            DWORD event,
826                              HWND hWnd,
827                          LONG idObject,
828                           LONG idChild,
829                    DWORD dwEventThread,
830                    DWORD dwmsEventTime,
831                      WINEVENTPROC Proc,
832                                INT Mod,
833                      ULONG_PTR offPfn)
834 {
835    LRESULT Result = 0;
836    NTSTATUS Status;
837    PEVENTPROC_CALLBACK_ARGUMENTS Common;
838    ULONG ArgumentLength, ResultLength;
839    PVOID Argument, ResultPointer;
840 
841    ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
842 
843    Argument = IntCbAllocateMemory(ArgumentLength);
844    if (NULL == Argument)
845    {
846       ERR("EventProc callback failed: out of memory\n");
847       return 0;
848    }
849    Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
850    Common->hook = hook;
851    Common->event = event;
852    Common->hwnd = hWnd;
853    Common->idObject = idObject;
854    Common->idChild = idChild;
855    Common->dwEventThread = dwEventThread;
856    Common->dwmsEventTime = dwmsEventTime;
857    Common->Proc = Proc;
858    Common->Mod = Mod;
859    Common->offPfn = offPfn;
860 
861    ResultPointer = NULL;
862    ResultLength = sizeof(LRESULT);
863 
864    UserLeaveCo();
865 
866    Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
867                                Argument,
868                                ArgumentLength,
869                                &ResultPointer,
870                                &ResultLength);
871 
872    UserEnterCo();
873 
874    IntCbFreeMemory(Argument);
875 
876    if (!NT_SUCCESS(Status))
877    {
878       return 0;
879    }
880 
881    return Result;
882 }
883 
884 //
885 // Callback Load Menu and results.
886 //
887 HMENU
888 APIENTRY
889 co_IntCallLoadMenu( HINSTANCE hModule,
890                     PUNICODE_STRING pMenuName )
891 {
892    LRESULT Result = 0;
893    NTSTATUS Status;
894    PLOADMENU_CALLBACK_ARGUMENTS Common;
895    ULONG ArgumentLength, ResultLength;
896    PVOID Argument, ResultPointer;
897 
898    ArgumentLength = sizeof(LOADMENU_CALLBACK_ARGUMENTS);
899 
900    ArgumentLength += pMenuName->Length + sizeof(WCHAR);
901 
902    Argument = IntCbAllocateMemory(ArgumentLength);
903    if (NULL == Argument)
904    {
905       ERR("LoadMenu callback failed: out of memory\n");
906       return 0;
907    }
908    Common = (PLOADMENU_CALLBACK_ARGUMENTS) Argument;
909 
910    // Help Intersource check and MenuName is now 4 bytes + so zero it.
911    RtlZeroMemory(Common, ArgumentLength);
912 
913    Common->hModule = hModule;
914    if (pMenuName->Length)
915       RtlCopyMemory(&Common->MenuName, pMenuName->Buffer, pMenuName->Length);
916    else
917       Common->InterSource = pMenuName->Buffer;
918 
919    ResultPointer = NULL;
920    ResultLength = sizeof(LRESULT);
921 
922    UserLeaveCo();
923 
924    Status = KeUserModeCallback(USER32_CALLBACK_LOADMENU,
925                                Argument,
926                                ArgumentLength,
927                                &ResultPointer,
928                                &ResultLength);
929 
930    UserEnterCo();
931 
932    if (NT_SUCCESS(Status))
933    {
934       Result = *(LRESULT*)ResultPointer;
935    }
936    else
937    {
938       Result = 0;
939    }
940 
941    IntCbFreeMemory(Argument);
942 
943    return (HMENU)Result;
944 }
945 
946 NTSTATUS
947 APIENTRY
948 co_IntClientThreadSetup(VOID)
949 {
950    NTSTATUS Status;
951    ULONG ArgumentLength, ResultLength;
952    PVOID Argument, ResultPointer;
953 
954    /* Do not allow the desktop thread to do callback to user mode */
955    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
956 
957    ArgumentLength = ResultLength = 0;
958    Argument = ResultPointer = NULL;
959 
960    UserLeaveCo();
961 
962    Status = KeUserModeCallback(USER32_CALLBACK_CLIENTTHREADSTARTUP,
963                                Argument,
964                                ArgumentLength,
965                                &ResultPointer,
966                                &ResultLength);
967 
968    UserEnterCo();
969 
970    return Status;
971 }
972 
973 HANDLE FASTCALL
974 co_IntCopyImage(HANDLE hnd, UINT type, INT desiredx, INT desiredy, UINT flags)
975 {
976    HANDLE Handle;
977    NTSTATUS Status;
978    ULONG ArgumentLength, ResultLength;
979    PVOID Argument, ResultPointer;
980    PCOPYIMAGE_CALLBACK_ARGUMENTS Common;
981 
982    ArgumentLength = ResultLength = 0;
983    Argument = ResultPointer = NULL;
984 
985    ArgumentLength = sizeof(COPYIMAGE_CALLBACK_ARGUMENTS);
986 
987    Argument = IntCbAllocateMemory(ArgumentLength);
988    if (NULL == Argument)
989    {
990       ERR("CopyImage callback failed: out of memory\n");
991       return 0;
992    }
993    Common = (PCOPYIMAGE_CALLBACK_ARGUMENTS) Argument;
994 
995    Common->hImage = hnd;
996    Common->uType = type;
997    Common->cxDesired = desiredx;
998    Common->cyDesired = desiredy;
999    Common->fuFlags = flags;
1000 
1001    UserLeaveCo();
1002 
1003    Status = KeUserModeCallback(USER32_CALLBACK_COPYIMAGE,
1004                                Argument,
1005                                ArgumentLength,
1006                                &ResultPointer,
1007                                &ResultLength);
1008 
1009 
1010    UserEnterCo();
1011 
1012    if (NT_SUCCESS(Status))
1013    {
1014       Handle = *(HANDLE*)ResultPointer;
1015    }
1016    else
1017    {
1018       ERR("CopyImage callback failed!\n");
1019       Handle = NULL;
1020    }
1021 
1022    IntCbFreeMemory(Argument);
1023 
1024    return Handle;
1025 }
1026 
1027 BOOL
1028 APIENTRY
1029 co_IntGetCharsetInfo(LCID Locale, PCHARSETINFO pCs)
1030 {
1031    NTSTATUS Status;
1032    ULONG ArgumentLength, ResultLength;
1033    PVOID Argument, ResultPointer;
1034    PGET_CHARSET_INFO Common;
1035 
1036    ArgumentLength = sizeof(GET_CHARSET_INFO);
1037 
1038    Argument = IntCbAllocateMemory(ArgumentLength);
1039    if (NULL == Argument)
1040    {
1041       ERR("GetCharsetInfo callback failed: out of memory\n");
1042       return 0;
1043    }
1044    Common = (PGET_CHARSET_INFO) Argument;
1045 
1046    Common->Locale = Locale;
1047 
1048    ResultPointer = NULL;
1049    ResultLength = ArgumentLength;
1050 
1051    UserLeaveCo();
1052 
1053    Status = KeUserModeCallback(USER32_CALLBACK_GETCHARSETINFO,
1054                                Argument,
1055                                ArgumentLength,
1056                                &ResultPointer,
1057                                &ResultLength);
1058 
1059    if (NT_SUCCESS(Status))
1060    {
1061       _SEH2_TRY
1062       {
1063          /* Need to copy into our local buffer */
1064          RtlMoveMemory(Argument, ResultPointer, ArgumentLength);
1065       }
1066       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1067       {
1068          ERR("Failed to copy result from user mode!\n");
1069          Status = _SEH2_GetExceptionCode();
1070       }
1071       _SEH2_END;
1072    }
1073 
1074    UserEnterCo();
1075 
1076    RtlCopyMemory(pCs, &Common->Cs, sizeof(CHARSETINFO));
1077 
1078    IntCbFreeMemory(Argument);
1079 
1080    if (!NT_SUCCESS(Status))
1081    {
1082       ERR("GetCharsetInfo Failed!!\n");
1083       return FALSE;
1084    }
1085 
1086    return TRUE;
1087 }
1088 
1089 BOOL FASTCALL
1090 co_IntSetWndIcons(VOID)
1091 {
1092    NTSTATUS Status;
1093    ULONG ArgumentLength, ResultLength;
1094    PVOID Argument, ResultPointer;
1095    PSETWNDICONS_CALLBACK_ARGUMENTS Common;
1096 
1097    ResultPointer = NULL;
1098    ResultLength = ArgumentLength = sizeof(SETWNDICONS_CALLBACK_ARGUMENTS);
1099 
1100    Argument = IntCbAllocateMemory(ArgumentLength);
1101    if (NULL == Argument)
1102    {
1103       ERR("Set Window Icons callback failed: out of memory\n");
1104       return FALSE;
1105    }
1106    Common = (PSETWNDICONS_CALLBACK_ARGUMENTS) Argument;
1107 
1108    UserLeaveCo();
1109 
1110    Status = KeUserModeCallback(USER32_CALLBACK_SETWNDICONS,
1111                                Argument,
1112                                ArgumentLength,
1113                                &ResultPointer,
1114                                &ResultLength);
1115 
1116 
1117    UserEnterCo();
1118 
1119    if (!NT_SUCCESS(Status))
1120    {
1121       ERR("Set Window Icons callback failed!\n");
1122       IntCbFreeMemory(Argument);
1123       return FALSE;
1124    }
1125 
1126    RtlMoveMemory(Common, ResultPointer, ArgumentLength);
1127    gpsi->hIconSmWindows = Common->hIconSmWindows;
1128    gpsi->hIconWindows   = Common->hIconWindows;
1129 
1130    IntLoadSystenIcons(Common->hIconSample,   OIC_SAMPLE);
1131    IntLoadSystenIcons(Common->hIconHand,     OIC_HAND);
1132    IntLoadSystenIcons(Common->hIconQuestion, OIC_QUES);
1133    IntLoadSystenIcons(Common->hIconBang,     OIC_BANG);
1134    IntLoadSystenIcons(Common->hIconNote,     OIC_NOTE);
1135    IntLoadSystenIcons(gpsi->hIconWindows,    OIC_WINLOGO);
1136    IntLoadSystenIcons(gpsi->hIconSmWindows,  OIC_WINLOGO+1);
1137 
1138    ERR("hIconSmWindows %p hIconWindows %p \n",gpsi->hIconSmWindows,gpsi->hIconWindows);
1139 
1140    IntCbFreeMemory(Argument);
1141 
1142    return TRUE;
1143 }
1144 
1145 VOID FASTCALL
1146 co_IntDeliverUserAPC(VOID)
1147 {
1148    ULONG ResultLength;
1149    PVOID ResultPointer;
1150    NTSTATUS Status;
1151    UserLeaveCo();
1152 
1153    Status = KeUserModeCallback(USER32_CALLBACK_DELIVERUSERAPC,
1154                                0,
1155                                0,
1156                                &ResultPointer,
1157                                &ResultLength);
1158 
1159 
1160    UserEnterCo();
1161 
1162    if (!NT_SUCCESS(Status))
1163    {
1164       ERR("Delivering User APC callback failed!\n");
1165    }
1166 }
1167 
1168 VOID FASTCALL
1169 co_IntSetupOBM(VOID)
1170 {
1171    NTSTATUS Status;
1172    ULONG ArgumentLength, ResultLength;
1173    PVOID Argument, ResultPointer;
1174    PSETOBM_CALLBACK_ARGUMENTS Common;
1175 
1176    ResultPointer = NULL;
1177    ResultLength = ArgumentLength = sizeof(SETOBM_CALLBACK_ARGUMENTS);
1178 
1179    Argument = IntCbAllocateMemory(ArgumentLength);
1180    if (NULL == Argument)
1181    {
1182       ERR("Set Window Icons callback failed: out of memory\n");
1183       return;
1184    }
1185    Common = (PSETOBM_CALLBACK_ARGUMENTS) Argument;
1186 
1187    UserLeaveCo();
1188 
1189    Status = KeUserModeCallback(USER32_CALLBACK_SETOBM,
1190                                Argument,
1191                                ArgumentLength,
1192                                &ResultPointer,
1193                                &ResultLength);
1194 
1195 
1196    UserEnterCo();
1197 
1198    if (!NT_SUCCESS(Status))
1199    {
1200       ERR("Set Window Icons callback failed!\n");
1201       IntCbFreeMemory(Argument);
1202       return;
1203    }
1204 
1205    RtlMoveMemory(Common, ResultPointer, ArgumentLength);
1206    RtlCopyMemory(gpsi->oembmi, Common->oembmi, sizeof(gpsi->oembmi));
1207 
1208    IntCbFreeMemory(Argument);
1209 }
1210 
1211 //
1212 //  Called from Kernel GDI sides, no UserLeave/EnterCo required.
1213 //
1214 LRESULT
1215 APIENTRY
1216 co_UserCBClientPrinterThunk( PVOID pkt, INT InSize, PVOID pvOutData, INT OutSize )
1217 {
1218    NTSTATUS Status;
1219 
1220    Status = KeUserModeCallback(USER32_CALLBACK_UMPD,
1221                                pkt,
1222                                InSize,
1223                                pvOutData,
1224                                (PULONG)&OutSize);
1225 
1226 
1227    if (!NT_SUCCESS(Status))
1228    {
1229       ERR("User UMPD callback failed!\n");
1230       return 1;
1231    }
1232 
1233    return 0;
1234 }
1235 
1236 /* EOF */
1237