xref: /reactos/win32ss/user/ntuser/callback.c (revision 37b2c145)
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 static INT iTheId = -2; // Set it out of range.
513 
514 LRESULT APIENTRY
515 co_IntCallHookProc(INT HookId,
516                    INT Code,
517                    WPARAM wParam,
518                    LPARAM lParam,
519                    HOOKPROC Proc,
520                    INT Mod,
521                    ULONG_PTR offPfn,
522                    BOOLEAN Ansi,
523                    PUNICODE_STRING ModuleName)
524 {
525    ULONG ArgumentLength;
526    PVOID Argument = NULL;
527    LRESULT Result = 0;
528    NTSTATUS Status;
529    PVOID ResultPointer;
530    ULONG ResultLength;
531    PHOOKPROC_CALLBACK_ARGUMENTS Common;
532    CBT_CREATEWNDW *CbtCreateWnd = NULL;
533    PCHAR Extra;
534    PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
535    PTHREADINFO pti;
536    PWND pWnd;
537    PMSG pMsg = NULL;
538    BOOL Hit = FALSE;
539    UINT lParamSize = 0;
540    CWPSTRUCT* pCWP = NULL;
541    CWPRETSTRUCT* pCWPR = NULL;
542 
543    ASSERT(Proc);
544    /* Do not allow the desktop thread to do callback to user mode */
545    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
546 
547    pti = PsGetCurrentThreadWin32Thread();
548    if (pti->TIF_flags & TIF_INCLEANUP)
549    {
550       ERR("Thread is in cleanup and trying to call hook %d\n", Code);
551       return 0;
552    }
553 
554    ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
555 
556    switch(HookId)
557    {
558       case WH_CBT:
559          TRACE("WH_CBT: Code %d\n", Code);
560          switch(Code)
561          {
562             case HCBT_CREATEWND:
563                pWnd = UserGetWindowObject((HWND) wParam);
564                if (!pWnd)
565                {
566                   ERR("WH_CBT HCBT_CREATEWND wParam bad hWnd!\n");
567                   goto Fault_Exit;
568                }
569                TRACE("HCBT_CREATEWND AnsiCreator %s, AnsiHook %s\n", pWnd->state & WNDS_ANSICREATOR ? "True" : "False", Ansi ? "True" : "False");
570               // Due to KsStudio.exe, just pass the callers original pointers
571               // except class which point to kernel space if not an atom.
572               // Found by, Olaf Siejka
573                CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
574                ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
575                break;
576 
577             case HCBT_MOVESIZE:
578                ArgumentLength += sizeof(RECTL);
579                break;
580             case HCBT_ACTIVATE:
581                ArgumentLength += sizeof(CBTACTIVATESTRUCT);
582                break;
583             case HCBT_CLICKSKIPPED:
584                ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
585                break;
586 /*   ATM pass on */
587             case HCBT_KEYSKIPPED:
588             case HCBT_MINMAX:
589             case HCBT_SETFOCUS:
590             case HCBT_SYSCOMMAND:
591 /*   These types pass through. */
592             case HCBT_DESTROYWND:
593             case HCBT_QS:
594                break;
595             default:
596                ERR("Trying to call unsupported CBT hook %d\n", Code);
597                goto Fault_Exit;
598          }
599          break;
600      case WH_KEYBOARD_LL:
601          ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
602          break;
603      case WH_MOUSE_LL:
604          ArgumentLength += sizeof(MSLLHOOKSTRUCT);
605          break;
606      case WH_MOUSE:
607          ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
608          break;
609      case WH_CALLWNDPROC:
610      {
611          pCWP = (CWPSTRUCT*) lParam;
612          ArgumentLength = sizeof(CWP_Struct);
613          if ( pCWP->message == WM_CREATE || pCWP->message == WM_NCCREATE )
614          {
615              lParamSize = sizeof(CREATESTRUCTW);
616          }
617          else
618              lParamSize = lParamMemorySize(pCWP->message, pCWP->wParam, pCWP->lParam);
619          ArgumentLength += lParamSize;
620          break;
621       }
622       case WH_CALLWNDPROCRET:
623       {
624          pCWPR = (CWPRETSTRUCT*) lParam;
625          ArgumentLength = sizeof(CWPR_Struct);
626          if ( pCWPR->message == WM_CREATE || pCWPR->message == WM_NCCREATE )
627          {
628              lParamSize = sizeof(CREATESTRUCTW);
629          }
630          else
631              lParamSize = lParamMemorySize(pCWPR->message, pCWPR->wParam, pCWPR->lParam);
632          ArgumentLength += lParamSize;
633          break;
634       }
635       case WH_MSGFILTER:
636       case WH_SYSMSGFILTER:
637       case WH_GETMESSAGE:
638          ArgumentLength += sizeof(MSG);
639          break;
640       case WH_FOREGROUNDIDLE:
641       case WH_KEYBOARD:
642       case WH_SHELL:
643          break;
644       default:
645          ERR("Trying to call unsupported window hook %d\n", HookId);
646          goto Fault_Exit;
647    }
648 
649    Argument = IntCbAllocateMemory(ArgumentLength);
650    if (NULL == Argument)
651    {
652       ERR("HookProc callback %d failed: out of memory %d\n",HookId,ArgumentLength);
653       goto Fault_Exit;
654    }
655    Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
656    Common->HookId = HookId;
657    Common->Code = Code;
658    Common->wParam = wParam;
659    Common->lParam = lParam;
660    Common->Proc = Proc;
661    Common->Mod = Mod;
662    Common->offPfn = offPfn;
663    Common->Ansi = Ansi;
664    Common->lParamSize = lParamSize;
665    RtlZeroMemory(&Common->ModuleName, sizeof(Common->ModuleName));
666    if (ModuleName->Buffer && ModuleName->Length)
667    {
668       RtlCopyMemory(&Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
669       // If ModuleName->Buffer NULL while in destroy,
670       //    this will make User32:Hook.c complain about not loading the library module.
671       // Fix symptom for CORE-10549.
672    }
673    Extra = (PCHAR) Common + sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
674 
675    switch(HookId)
676    {
677       case WH_CBT:
678          switch(Code)
679          { // Need to remember this is not the first time through! Call Next Hook?
680             case HCBT_CREATEWND:
681                CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
682                RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) );
683                CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
684                CbtCreatewndExtra->Cs.lpszClass   = CbtCreateWnd->lpcs->lpszClass;
685                CbtCreatewndExtra->Cs.lpszName    = CbtCreateWnd->lpcs->lpszName;
686                Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
687                //ERR("HCBT_CREATEWND: hWnd %p Csw %p Name %p Class %p\n", Common->wParam, CbtCreateWnd->lpcs, CbtCreateWnd->lpcs->lpszName, CbtCreateWnd->lpcs->lpszClass);
688                break;
689             case HCBT_CLICKSKIPPED:
690                RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
691                Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
692                break;
693             case HCBT_MOVESIZE:
694                RtlCopyMemory(Extra, (PVOID) lParam, sizeof(RECTL));
695                Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
696                break;
697             case HCBT_ACTIVATE:
698                RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CBTACTIVATESTRUCT));
699                Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
700                break;
701          }
702          break;
703       case WH_KEYBOARD_LL:
704          RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
705          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
706          break;
707       case WH_MOUSE_LL:
708          RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
709          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
710          break;
711       case WH_MOUSE:
712          RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
713          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
714          break;
715       case WH_CALLWNDPROC:
716       {
717          PCWP_Struct pcwps = (PCWP_Struct)Common;
718          RtlCopyMemory( &pcwps->cwps, pCWP, sizeof(CWPSTRUCT));
719          /* For CALLWNDPROC and CALLWNDPROCRET, we must be wary of the fact that
720           * lParam could be a pointer to a buffer. This buffer must be exported
721           * to user space too */
722          if ( lParamSize )
723          {
724              RtlCopyMemory( &pcwps->Extra, (PVOID)pCWP->lParam, lParamSize );
725          }
726       }
727          break;
728       case WH_CALLWNDPROCRET:
729       {
730          PCWPR_Struct pcwprs = (PCWPR_Struct)Common;
731          RtlCopyMemory( &pcwprs->cwprs, pCWPR, sizeof(CWPRETSTRUCT));
732          if ( lParamSize )
733          {
734              RtlCopyMemory( &pcwprs->Extra, (PVOID)pCWPR->lParam, lParamSize );
735          }
736       }
737          break;
738       case WH_MSGFILTER:
739       case WH_SYSMSGFILTER:
740       case WH_GETMESSAGE:
741          pMsg = (PMSG)lParam;
742          RtlCopyMemory(Extra, (PVOID) pMsg, sizeof(MSG));
743          Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
744          break;
745       case WH_FOREGROUNDIDLE:
746       case WH_KEYBOARD:
747       case WH_SHELL:
748          break;
749    }
750 
751    ResultPointer = NULL;
752    ResultLength = ArgumentLength;
753 
754    UserLeaveCo();
755 
756    Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
757                                Argument,
758                                ArgumentLength,
759                                &ResultPointer,
760                                &ResultLength);
761 
762    UserEnterCo();
763 
764    if (!NT_SUCCESS(Status))
765    {
766       if ( iTheId != HookId ) // Hook ID can change.
767       {
768           ERR("Failure to make Callback %d! Status 0x%x ArgumentLength %d\n",HookId,Status,ArgumentLength);
769           iTheId = HookId;
770       }
771       goto Fault_Exit;
772    }
773 
774    if (ResultPointer)
775    {
776       _SEH2_TRY
777       {
778          /* Simulate old behaviour: copy into our local buffer */
779          RtlMoveMemory(Argument, ResultPointer, ArgumentLength);
780          Result = Common->Result;
781       }
782       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
783       {
784          Result = 0;
785          Hit = TRUE;
786       }
787       _SEH2_END;
788    }
789    else
790    {
791       ERR("ERROR: Hook %d Code %d ResultPointer 0x%p ResultLength %u\n",HookId,Code,ResultPointer,ResultLength);
792    }
793 
794    /* Support write backs... SEH is in UserCallNextHookEx. */
795    switch (HookId)
796    {
797       case WH_CBT:
798       {
799          switch (Code)
800          {
801             case HCBT_CREATEWND:
802                if (CbtCreatewndExtra)
803                {/*
804                   The parameters could have been changed, include the coordinates
805                   and dimensions of the window. We copy it back.
806                  */
807                   CbtCreateWnd->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
808                   CbtCreateWnd->lpcs->x  = CbtCreatewndExtra->Cs.x;
809                   CbtCreateWnd->lpcs->y  = CbtCreatewndExtra->Cs.y;
810                   CbtCreateWnd->lpcs->cx = CbtCreatewndExtra->Cs.cx;
811                   CbtCreateWnd->lpcs->cy = CbtCreatewndExtra->Cs.cy;
812                }
813             break;
814             case HCBT_MOVESIZE:
815                if (Extra && lParam)
816                {
817                   RtlCopyMemory((PVOID) lParam, Extra, sizeof(RECTL));
818                }
819             break;
820          }
821       }
822       // "The GetMsgProc hook procedure can examine or modify the message."
823       case WH_GETMESSAGE:
824          if (pMsg)
825          {
826             RtlCopyMemory((PVOID) pMsg, Extra, sizeof(MSG));
827          }
828          break;
829    }
830 
831 Fault_Exit:
832    if (Hit)
833    {
834       ERR("Exception CallHookProc HookId %d Code %d\n",HookId,Code);
835    }
836    if (Argument) IntCbFreeMemory(Argument);
837 
838    return Result;
839 }
840 
841 //
842 // Events are notifications w/o results.
843 //
844 LRESULT
845 APIENTRY
846 co_IntCallEventProc(HWINEVENTHOOK hook,
847                            DWORD event,
848                              HWND hWnd,
849                          LONG idObject,
850                           LONG idChild,
851                    DWORD dwEventThread,
852                    DWORD dwmsEventTime,
853                      WINEVENTPROC Proc,
854                                INT Mod,
855                      ULONG_PTR offPfn)
856 {
857    LRESULT Result = 0;
858    NTSTATUS Status;
859    PEVENTPROC_CALLBACK_ARGUMENTS Common;
860    ULONG ArgumentLength, ResultLength;
861    PVOID Argument, ResultPointer;
862 
863    ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
864 
865    Argument = IntCbAllocateMemory(ArgumentLength);
866    if (NULL == Argument)
867    {
868       ERR("EventProc callback failed: out of memory\n");
869       return 0;
870    }
871    Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
872    Common->hook = hook;
873    Common->event = event;
874    Common->hwnd = hWnd;
875    Common->idObject = idObject;
876    Common->idChild = idChild;
877    Common->dwEventThread = dwEventThread;
878    Common->dwmsEventTime = dwmsEventTime;
879    Common->Proc = Proc;
880    Common->Mod = Mod;
881    Common->offPfn = offPfn;
882 
883    ResultPointer = NULL;
884    ResultLength = sizeof(LRESULT);
885 
886    UserLeaveCo();
887 
888    Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
889                                Argument,
890                                ArgumentLength,
891                                &ResultPointer,
892                                &ResultLength);
893 
894    UserEnterCo();
895 
896    IntCbFreeMemory(Argument);
897 
898    if (!NT_SUCCESS(Status))
899    {
900       return 0;
901    }
902 
903    return Result;
904 }
905 
906 //
907 // Callback Load Menu and results.
908 //
909 HMENU
910 APIENTRY
911 co_IntCallLoadMenu( HINSTANCE hModule,
912                     PUNICODE_STRING pMenuName )
913 {
914    LRESULT Result = 0;
915    NTSTATUS Status;
916    PLOADMENU_CALLBACK_ARGUMENTS Common;
917    ULONG ArgumentLength, ResultLength;
918    PVOID Argument, ResultPointer;
919 
920    ArgumentLength = sizeof(LOADMENU_CALLBACK_ARGUMENTS);
921 
922    ArgumentLength += pMenuName->Length + sizeof(WCHAR);
923 
924    Argument = IntCbAllocateMemory(ArgumentLength);
925    if (NULL == Argument)
926    {
927       ERR("LoadMenu callback failed: out of memory\n");
928       return 0;
929    }
930    Common = (PLOADMENU_CALLBACK_ARGUMENTS) Argument;
931 
932    // Help Intersource check and MenuName is now 4 bytes + so zero it.
933    RtlZeroMemory(Common, ArgumentLength);
934 
935    Common->hModule = hModule;
936    if (pMenuName->Length)
937       RtlCopyMemory(&Common->MenuName, pMenuName->Buffer, pMenuName->Length);
938    else
939       Common->InterSource = pMenuName->Buffer;
940 
941    ResultPointer = NULL;
942    ResultLength = sizeof(LRESULT);
943 
944    UserLeaveCo();
945 
946    Status = KeUserModeCallback(USER32_CALLBACK_LOADMENU,
947                                Argument,
948                                ArgumentLength,
949                                &ResultPointer,
950                                &ResultLength);
951 
952    UserEnterCo();
953 
954    if (NT_SUCCESS(Status))
955    {
956       Result = *(LRESULT*)ResultPointer;
957    }
958    else
959    {
960       Result = 0;
961    }
962 
963    IntCbFreeMemory(Argument);
964 
965    return (HMENU)Result;
966 }
967 
968 NTSTATUS
969 APIENTRY
970 co_IntClientThreadSetup(VOID)
971 {
972    NTSTATUS Status;
973    ULONG ArgumentLength, ResultLength;
974    PVOID Argument, ResultPointer;
975 
976    /* Do not allow the desktop thread to do callback to user mode */
977    ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
978 
979    ArgumentLength = ResultLength = 0;
980    Argument = ResultPointer = NULL;
981 
982    UserLeaveCo();
983 
984    Status = KeUserModeCallback(USER32_CALLBACK_CLIENTTHREADSTARTUP,
985                                Argument,
986                                ArgumentLength,
987                                &ResultPointer,
988                                &ResultLength);
989 
990    UserEnterCo();
991 
992    return Status;
993 }
994 
995 HANDLE FASTCALL
996 co_IntCopyImage(HANDLE hnd, UINT type, INT desiredx, INT desiredy, UINT flags)
997 {
998    HANDLE Handle;
999    NTSTATUS Status;
1000    ULONG ArgumentLength, ResultLength;
1001    PVOID Argument, ResultPointer;
1002    PCOPYIMAGE_CALLBACK_ARGUMENTS Common;
1003 
1004    ArgumentLength = ResultLength = 0;
1005    Argument = ResultPointer = NULL;
1006 
1007    ArgumentLength = sizeof(COPYIMAGE_CALLBACK_ARGUMENTS);
1008 
1009    Argument = IntCbAllocateMemory(ArgumentLength);
1010    if (NULL == Argument)
1011    {
1012       ERR("CopyImage callback failed: out of memory\n");
1013       return 0;
1014    }
1015    Common = (PCOPYIMAGE_CALLBACK_ARGUMENTS) Argument;
1016 
1017    Common->hImage = hnd;
1018    Common->uType = type;
1019    Common->cxDesired = desiredx;
1020    Common->cyDesired = desiredy;
1021    Common->fuFlags = flags;
1022 
1023    UserLeaveCo();
1024 
1025    Status = KeUserModeCallback(USER32_CALLBACK_COPYIMAGE,
1026                                Argument,
1027                                ArgumentLength,
1028                                &ResultPointer,
1029                                &ResultLength);
1030 
1031 
1032    UserEnterCo();
1033 
1034    if (NT_SUCCESS(Status))
1035    {
1036       Handle = *(HANDLE*)ResultPointer;
1037    }
1038    else
1039    {
1040       ERR("CopyImage callback failed!\n");
1041       Handle = NULL;
1042    }
1043 
1044    IntCbFreeMemory(Argument);
1045 
1046    return Handle;
1047 }
1048 
1049 BOOL
1050 APIENTRY
1051 co_IntGetCharsetInfo(LCID Locale, PCHARSETINFO pCs)
1052 {
1053    NTSTATUS Status;
1054    ULONG ArgumentLength, ResultLength;
1055    PVOID Argument, ResultPointer;
1056    PGET_CHARSET_INFO Common;
1057 
1058    ArgumentLength = sizeof(GET_CHARSET_INFO);
1059 
1060    Argument = IntCbAllocateMemory(ArgumentLength);
1061    if (NULL == Argument)
1062    {
1063       ERR("GetCharsetInfo callback failed: out of memory\n");
1064       return 0;
1065    }
1066    Common = (PGET_CHARSET_INFO) Argument;
1067 
1068    Common->Locale = Locale;
1069 
1070    ResultPointer = NULL;
1071    ResultLength = ArgumentLength;
1072 
1073    UserLeaveCo();
1074 
1075    Status = KeUserModeCallback(USER32_CALLBACK_GETCHARSETINFO,
1076                                Argument,
1077                                ArgumentLength,
1078                                &ResultPointer,
1079                                &ResultLength);
1080 
1081    if (NT_SUCCESS(Status))
1082    {
1083       _SEH2_TRY
1084       {
1085          /* Need to copy into our local buffer */
1086          RtlMoveMemory(Argument, ResultPointer, ArgumentLength);
1087       }
1088       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1089       {
1090          ERR("Failed to copy result from user mode!\n");
1091          Status = _SEH2_GetExceptionCode();
1092       }
1093       _SEH2_END;
1094    }
1095 
1096    UserEnterCo();
1097 
1098    RtlCopyMemory(pCs, &Common->Cs, sizeof(CHARSETINFO));
1099 
1100    IntCbFreeMemory(Argument);
1101 
1102    if (!NT_SUCCESS(Status))
1103    {
1104       ERR("GetCharsetInfo Failed!!\n");
1105       return FALSE;
1106    }
1107 
1108    return TRUE;
1109 }
1110 
1111 BOOL FASTCALL
1112 co_IntSetWndIcons(VOID)
1113 {
1114    NTSTATUS Status;
1115    ULONG ArgumentLength, ResultLength;
1116    PVOID Argument, ResultPointer;
1117    PSETWNDICONS_CALLBACK_ARGUMENTS Common;
1118 
1119    ResultPointer = NULL;
1120    ResultLength = ArgumentLength = sizeof(SETWNDICONS_CALLBACK_ARGUMENTS);
1121 
1122    Argument = IntCbAllocateMemory(ArgumentLength);
1123    if (NULL == Argument)
1124    {
1125       ERR("Set Window Icons callback failed: out of memory\n");
1126       return FALSE;
1127    }
1128    Common = (PSETWNDICONS_CALLBACK_ARGUMENTS) Argument;
1129 
1130    UserLeaveCo();
1131 
1132    Status = KeUserModeCallback(USER32_CALLBACK_SETWNDICONS,
1133                                Argument,
1134                                ArgumentLength,
1135                                &ResultPointer,
1136                                &ResultLength);
1137 
1138 
1139    UserEnterCo();
1140 
1141    if (!NT_SUCCESS(Status))
1142    {
1143       ERR("Set Window Icons callback failed!\n");
1144       IntCbFreeMemory(Argument);
1145       return FALSE;
1146    }
1147 
1148    RtlMoveMemory(Common, ResultPointer, ArgumentLength);
1149    gpsi->hIconSmWindows = Common->hIconSmWindows;
1150    gpsi->hIconWindows   = Common->hIconWindows;
1151 
1152    IntLoadSystenIcons(Common->hIconSample,   OIC_SAMPLE);
1153    IntLoadSystenIcons(Common->hIconHand,     OIC_HAND);
1154    IntLoadSystenIcons(Common->hIconQuestion, OIC_QUES);
1155    IntLoadSystenIcons(Common->hIconBang,     OIC_BANG);
1156    IntLoadSystenIcons(Common->hIconNote,     OIC_NOTE);
1157    IntLoadSystenIcons(gpsi->hIconWindows,    OIC_WINLOGO);
1158    IntLoadSystenIcons(gpsi->hIconSmWindows,  OIC_WINLOGO+1);
1159 
1160    ERR("hIconSmWindows %p hIconWindows %p \n",gpsi->hIconSmWindows,gpsi->hIconWindows);
1161 
1162    IntCbFreeMemory(Argument);
1163 
1164    return TRUE;
1165 }
1166 
1167 VOID FASTCALL
1168 co_IntDeliverUserAPC(VOID)
1169 {
1170    ULONG ResultLength;
1171    PVOID ResultPointer;
1172    NTSTATUS Status;
1173    UserLeaveCo();
1174 
1175    Status = KeUserModeCallback(USER32_CALLBACK_DELIVERUSERAPC,
1176                                0,
1177                                0,
1178                                &ResultPointer,
1179                                &ResultLength);
1180 
1181 
1182    UserEnterCo();
1183 
1184    if (!NT_SUCCESS(Status))
1185    {
1186       ERR("Delivering User APC callback failed!\n");
1187    }
1188 }
1189 
1190 VOID FASTCALL
1191 co_IntSetupOBM(VOID)
1192 {
1193    NTSTATUS Status;
1194    ULONG ArgumentLength, ResultLength;
1195    PVOID Argument, ResultPointer;
1196    PSETOBM_CALLBACK_ARGUMENTS Common;
1197 
1198    ResultPointer = NULL;
1199    ResultLength = ArgumentLength = sizeof(SETOBM_CALLBACK_ARGUMENTS);
1200 
1201    Argument = IntCbAllocateMemory(ArgumentLength);
1202    if (NULL == Argument)
1203    {
1204       ERR("Set Window Icons callback failed: out of memory\n");
1205       return;
1206    }
1207    Common = (PSETOBM_CALLBACK_ARGUMENTS) Argument;
1208 
1209    UserLeaveCo();
1210 
1211    Status = KeUserModeCallback(USER32_CALLBACK_SETOBM,
1212                                Argument,
1213                                ArgumentLength,
1214                                &ResultPointer,
1215                                &ResultLength);
1216 
1217 
1218    UserEnterCo();
1219 
1220    if (!NT_SUCCESS(Status))
1221    {
1222       ERR("Set Window Icons callback failed!\n");
1223       IntCbFreeMemory(Argument);
1224       return;
1225    }
1226 
1227    RtlMoveMemory(Common, ResultPointer, ArgumentLength);
1228    RtlCopyMemory(gpsi->oembmi, Common->oembmi, sizeof(gpsi->oembmi));
1229 
1230    IntCbFreeMemory(Argument);
1231 }
1232 
1233 //
1234 //  Called from Kernel GDI sides, no UserLeave/EnterCo required.
1235 //
1236 LRESULT
1237 APIENTRY
1238 co_UserCBClientPrinterThunk( PVOID pkt, INT InSize, PVOID pvOutData, INT OutSize )
1239 {
1240    NTSTATUS Status;
1241    PVOID ResultPointer;
1242 
1243    Status = KeUserModeCallback( USER32_CALLBACK_UMPD,
1244                                 pkt,
1245                                 InSize,
1246                                &ResultPointer,
1247                                (PULONG)&OutSize );
1248 
1249 
1250    if (!NT_SUCCESS(Status))
1251    {
1252       ERR("User UMPD callback failed!\n");
1253       return 1;
1254    }
1255 
1256    if (OutSize) RtlMoveMemory( pvOutData, ResultPointer, OutSize );
1257 
1258    return 0;
1259 }
1260 
1261 /* EOF */
1262