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