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