- Add the missing Result return pointed out by Michael Martin.
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / callback.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsys/win32k/ntuser/wndproc.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
8 * REVISION HISTORY:
9 * 06-06-2001 CSH Created
10 * NOTES: Please use the Callback Memory Management functions for
11 * callbacks to make sure, the memory is freed on thread
12 * termination!
13 */
14
15 /* INCLUDES ******************************************************************/
16
17 #include <w32k.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22 /* CALLBACK MEMORY MANAGEMENT ************************************************/
23
24 typedef struct _INT_CALLBACK_HEADER
25 {
26 /* list entry in the THREADINFO structure */
27 LIST_ENTRY ListEntry;
28 }
29 INT_CALLBACK_HEADER, *PINT_CALLBACK_HEADER;
30
31 PVOID FASTCALL
32 IntCbAllocateMemory(ULONG Size)
33 {
34 PINT_CALLBACK_HEADER Mem;
35 PTHREADINFO W32Thread;
36
37 if(!(Mem = ExAllocatePoolWithTag(PagedPool, Size + sizeof(INT_CALLBACK_HEADER),
38 TAG_CALLBACK)))
39 {
40 return NULL;
41 }
42
43 W32Thread = PsGetCurrentThreadWin32Thread();
44 ASSERT(W32Thread);
45
46 /* insert the callback memory into the thread's callback list */
47
48 InsertTailList(&W32Thread->W32CallbackListHead, &Mem->ListEntry);
49
50 return (Mem + 1);
51 }
52
53 VOID FASTCALL
54 IntCbFreeMemory(PVOID Data)
55 {
56 PINT_CALLBACK_HEADER Mem;
57 PTHREADINFO W32Thread;
58
59 ASSERT(Data);
60
61 Mem = ((PINT_CALLBACK_HEADER)Data - 1);
62
63 W32Thread = PsGetCurrentThreadWin32Thread();
64 ASSERT(W32Thread);
65
66 /* remove the memory block from the thread's callback list */
67 RemoveEntryList(&Mem->ListEntry);
68
69 /* free memory */
70 ExFreePoolWithTag(Mem, TAG_CALLBACK);
71 }
72
73 VOID FASTCALL
74 IntCleanupThreadCallbacks(PTHREADINFO W32Thread)
75 {
76 PLIST_ENTRY CurrentEntry;
77 PINT_CALLBACK_HEADER Mem;
78
79 while (!IsListEmpty(&W32Thread->W32CallbackListHead))
80 {
81 CurrentEntry = RemoveHeadList(&W32Thread->W32CallbackListHead);
82 Mem = CONTAINING_RECORD(CurrentEntry, INT_CALLBACK_HEADER,
83 ListEntry);
84
85 /* free memory */
86 ExFreePool(Mem);
87 }
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, PVOID * pWnd)
97 {
98 HWND hWndS = *hWnd;
99 PWINDOW_OBJECT Window = UserGetWindowObject(*hWnd);
100 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
101
102 *hWnd = ClientInfo->CallbackWnd.hWnd;
103 *pWnd = ClientInfo->CallbackWnd.pvWnd;
104
105 ClientInfo->CallbackWnd.hWnd = hWndS;
106 ClientInfo->CallbackWnd.pvWnd = DesktopHeapAddressToUser(Window->Wnd);
107 }
108
109 static VOID
110 IntRestoreTebWndCallback (HWND hWnd, PVOID pWnd)
111 {
112 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
113
114 ClientInfo->CallbackWnd.hWnd = hWnd;
115 ClientInfo->CallbackWnd.pvWnd = pWnd;
116 }
117
118 /* FUNCTIONS *****************************************************************/
119
120 VOID APIENTRY
121 co_IntCallSentMessageCallback(SENDASYNCPROC CompletionCallback,
122 HWND hWnd,
123 UINT Msg,
124 ULONG_PTR CompletionCallbackContext,
125 LRESULT Result)
126 {
127 SENDASYNCPROC_CALLBACK_ARGUMENTS Arguments;
128 PVOID ResultPointer, pWnd;
129 ULONG ResultLength;
130 NTSTATUS Status;
131
132 Arguments.Callback = CompletionCallback;
133 Arguments.Wnd = hWnd;
134 Arguments.Msg = Msg;
135 Arguments.Context = CompletionCallbackContext;
136 Arguments.Result = Result;
137
138 IntSetTebWndCallback (&hWnd, &pWnd);
139
140 UserLeaveCo();
141
142 Status = KeUserModeCallback(USER32_CALLBACK_SENDASYNCPROC,
143 &Arguments,
144 sizeof(SENDASYNCPROC_CALLBACK_ARGUMENTS),
145 &ResultPointer,
146 &ResultLength);
147
148 UserEnterCo();
149
150 IntRestoreTebWndCallback (hWnd, pWnd);
151
152 if (!NT_SUCCESS(Status))
153 {
154 return;
155 }
156 return;
157 }
158
159 LRESULT APIENTRY
160 co_IntCallWindowProc(WNDPROC Proc,
161 BOOLEAN IsAnsiProc,
162 HWND Wnd,
163 UINT Message,
164 WPARAM wParam,
165 LPARAM lParam,
166 INT lParamBufferSize)
167 {
168 WINDOWPROC_CALLBACK_ARGUMENTS StackArguments;
169 PWINDOWPROC_CALLBACK_ARGUMENTS Arguments;
170 NTSTATUS Status;
171 PVOID ResultPointer, pWnd;
172 ULONG ResultLength;
173 ULONG ArgumentLength;
174 LRESULT Result;
175
176 if (0 < lParamBufferSize)
177 {
178 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS) + lParamBufferSize;
179 Arguments = IntCbAllocateMemory(ArgumentLength);
180 if (NULL == Arguments)
181 {
182 DPRINT1("Unable to allocate buffer for window proc callback\n");
183 return -1;
184 }
185 RtlMoveMemory((PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
186 (PVOID) lParam, lParamBufferSize);
187 }
188 else
189 {
190 Arguments = &StackArguments;
191 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS);
192 }
193 Arguments->Proc = Proc;
194 Arguments->IsAnsiProc = IsAnsiProc;
195 Arguments->Wnd = Wnd;
196 Arguments->Msg = Message;
197 Arguments->wParam = wParam;
198 Arguments->lParam = lParam;
199 Arguments->lParamBufferSize = lParamBufferSize;
200 ResultPointer = NULL;
201 ResultLength = ArgumentLength;
202
203 IntSetTebWndCallback (&Wnd, &pWnd);
204
205 UserLeaveCo();
206
207 Status = KeUserModeCallback(USER32_CALLBACK_WINDOWPROC,
208 Arguments,
209 ArgumentLength,
210 &ResultPointer,
211 &ResultLength);
212
213 _SEH2_TRY
214 {
215 /* Simulate old behaviour: copy into our local buffer */
216 RtlMoveMemory(Arguments, ResultPointer, ArgumentLength);
217 }
218 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
219 {
220 Status = _SEH2_GetExceptionCode();
221 }
222 _SEH2_END;
223
224 UserEnterCo();
225
226 IntRestoreTebWndCallback (Wnd, pWnd);
227
228 if (!NT_SUCCESS(Status))
229 {
230 if (0 < lParamBufferSize)
231 {
232 IntCbFreeMemory(Arguments);
233 }
234 return -1;
235 }
236 Result = Arguments->Result;
237
238 if (0 < lParamBufferSize)
239 {
240 RtlMoveMemory((PVOID) lParam,
241 (PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
242 lParamBufferSize);
243 IntCbFreeMemory(Arguments);
244 }
245
246 return Result;
247 }
248
249 HMENU APIENTRY
250 co_IntLoadSysMenuTemplate()
251 {
252 LRESULT Result = 0;
253 NTSTATUS Status;
254 PVOID ResultPointer;
255 ULONG ResultLength;
256
257 ResultPointer = NULL;
258 ResultLength = sizeof(LRESULT);
259
260 UserLeaveCo();
261
262 Status = KeUserModeCallback(USER32_CALLBACK_LOADSYSMENUTEMPLATE,
263 NULL,
264 0,
265 &ResultPointer,
266 &ResultLength);
267 if (NT_SUCCESS(Status))
268 {
269 /* Simulate old behaviour: copy into our local buffer */
270 Result = *(LRESULT*)ResultPointer;
271 }
272
273 UserEnterCo();
274
275 return (HMENU)Result;
276 }
277
278 BOOL APIENTRY
279 co_IntLoadDefaultCursors(VOID)
280 {
281 NTSTATUS Status;
282 PVOID ResultPointer;
283 ULONG ResultLength;
284 BOOL DefaultCursor = TRUE;
285
286 ResultPointer = NULL;
287 ResultLength = sizeof(LRESULT);
288
289 UserLeaveCo();
290
291 Status = KeUserModeCallback(USER32_CALLBACK_LOADDEFAULTCURSORS,
292 &DefaultCursor,
293 sizeof(BOOL),
294 &ResultPointer,
295 &ResultLength);
296
297 UserEnterCo();
298
299 if (!NT_SUCCESS(Status))
300 {
301 return FALSE;
302 }
303 return TRUE;
304 }
305
306 LRESULT APIENTRY
307 co_IntCallHookProc(INT HookId,
308 INT Code,
309 WPARAM wParam,
310 LPARAM lParam,
311 HOOKPROC Proc,
312 BOOLEAN Ansi,
313 PUNICODE_STRING ModuleName)
314 {
315 ULONG ArgumentLength;
316 PVOID Argument;
317 LRESULT Result = 0;
318 NTSTATUS Status;
319 PVOID ResultPointer;
320 ULONG ResultLength;
321 PHOOKPROC_CALLBACK_ARGUMENTS Common;
322 CBT_CREATEWNDW *CbtCreateWnd =NULL;
323 PCHAR Extra;
324 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
325 UNICODE_STRING WindowName;
326 UNICODE_STRING ClassName;
327 PANSI_STRING asWindowName;
328 PANSI_STRING asClassName;
329
330 ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS) - sizeof(WCHAR)
331 + ModuleName->Length;
332 switch(HookId)
333 {
334 case WH_CBT:
335 switch(Code)
336 {
337 case HCBT_CREATEWND:
338 CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
339 ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
340
341 asWindowName = (PANSI_STRING)&WindowName;
342 asClassName = (PANSI_STRING)&ClassName;
343
344 if (Ansi)
345 {
346 RtlInitAnsiString(asWindowName, (PCSZ)CbtCreateWnd->lpcs->lpszName);
347 ArgumentLength += WindowName.Length + sizeof(CHAR);
348 }
349 else
350 {
351 RtlInitUnicodeString(&WindowName, CbtCreateWnd->lpcs->lpszName);
352 ArgumentLength += WindowName.Length + sizeof(WCHAR);
353 }
354
355 if (! IS_ATOM(CbtCreateWnd->lpcs->lpszClass))
356 {
357 if (Ansi)
358 {
359 RtlInitAnsiString(asClassName, (PCSZ)CbtCreateWnd->lpcs->lpszClass);
360 ArgumentLength += ClassName.Length + sizeof(CHAR);
361 }
362 else
363 {
364 RtlInitUnicodeString(&ClassName, CbtCreateWnd->lpcs->lpszClass);
365 ArgumentLength += ClassName.Length + sizeof(WCHAR);
366 }
367 }
368 break;
369
370 case HCBT_MOVESIZE:
371 ArgumentLength += sizeof(RECTL);
372 break;
373 case HCBT_ACTIVATE:
374 ArgumentLength += sizeof(CBTACTIVATESTRUCT);
375 break;
376 case HCBT_CLICKSKIPPED:
377 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
378 break;
379 /* ATM pass on */
380 case HCBT_KEYSKIPPED:
381 case HCBT_MINMAX:
382 case HCBT_SETFOCUS:
383 case HCBT_SYSCOMMAND:
384 /* These types pass through. */
385 case HCBT_DESTROYWND:
386 case HCBT_QS:
387 break;
388 default:
389 DPRINT1("Trying to call unsupported CBT hook %d\n", Code);
390 return 0;
391 }
392 break;
393 case WH_KEYBOARD_LL:
394 ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
395 break;
396 case WH_MOUSE_LL:
397 ArgumentLength += sizeof(MSLLHOOKSTRUCT);
398 break;
399 case WH_MOUSE:
400 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
401 break;
402 case WH_CALLWNDPROC:
403 ArgumentLength += sizeof(CWPSTRUCT);
404 break;
405 case WH_CALLWNDPROCRET:
406 ArgumentLength += sizeof(CWPRETSTRUCT);
407 break;
408 case WH_MSGFILTER:
409 case WH_SYSMSGFILTER:
410 case WH_GETMESSAGE:
411 ArgumentLength += sizeof(MSG);
412 break;
413 case WH_FOREGROUNDIDLE:
414 case WH_KEYBOARD:
415 case WH_SHELL:
416 break;
417 default:
418 DPRINT1("Trying to call unsupported window hook %d\n", HookId);
419 return 0;
420 }
421
422 Argument = IntCbAllocateMemory(ArgumentLength);
423 if (NULL == Argument)
424 {
425 DPRINT1("HookProc callback failed: out of memory\n");
426 return 0;
427 }
428 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
429 Common->HookId = HookId;
430 Common->Code = Code;
431 Common->wParam = wParam;
432 Common->lParam = lParam;
433 Common->Proc = Proc;
434 Common->Ansi = Ansi;
435 Common->ModuleNameLength = ModuleName->Length;
436 memcpy(Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
437 Extra = (PCHAR) Common->ModuleName + Common->ModuleNameLength;
438
439 switch(HookId)
440 {
441 case WH_CBT:
442 switch(Code)
443 {
444 case HCBT_CREATEWND:
445 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
446 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
447 RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) );
448 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
449 Extra = (PCHAR) (CbtCreatewndExtra + 1);
450 RtlCopyMemory(Extra, WindowName.Buffer, WindowName.Length);
451 CbtCreatewndExtra->Cs.lpszName = (LPCWSTR) (Extra - (PCHAR) CbtCreatewndExtra);
452 CbtCreatewndExtra->Cs.lpszClass = ClassName.Buffer;
453 Extra += WindowName.Length;
454 if (Ansi)
455 {
456 *((CHAR *) Extra) = '\0';
457 Extra += sizeof(CHAR);
458 }
459 else
460 {
461 *((WCHAR *) Extra) = L'\0';
462 Extra += sizeof(WCHAR);
463 }
464
465 if (! IS_ATOM(ClassName.Buffer))
466 {
467 RtlCopyMemory(Extra, ClassName.Buffer, ClassName.Length);
468 CbtCreatewndExtra->Cs.lpszClass =
469 (LPCWSTR) MAKELONG(Extra - (PCHAR) CbtCreatewndExtra, 1);
470 Extra += ClassName.Length;
471
472 if (Ansi)
473 *((CHAR *) Extra) = '\0';
474 else
475 *((WCHAR *) Extra) = L'\0';
476 }
477 break;
478 case HCBT_CLICKSKIPPED:
479 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
480 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
481 break;
482 case HCBT_MOVESIZE:
483 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(RECTL));
484 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
485 break;
486 case HCBT_ACTIVATE:
487 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CBTACTIVATESTRUCT));
488 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
489 break;
490 }
491 break;
492 case WH_KEYBOARD_LL:
493 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
494 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
495 break;
496 case WH_MOUSE_LL:
497 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
498 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
499 break;
500 case WH_MOUSE:
501 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
502 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
503 break;
504 case WH_CALLWNDPROC:
505 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT));
506 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
507 break;
508 case WH_CALLWNDPROCRET:
509 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT));
510 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
511 break;
512 case WH_MSGFILTER:
513 case WH_SYSMSGFILTER:
514 case WH_GETMESSAGE:
515 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSG));
516 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
517 // DPRINT1("KHOOK Memory: %x\n",Common);
518 break;
519 case WH_FOREGROUNDIDLE:
520 case WH_KEYBOARD:
521 case WH_SHELL:
522 break;
523 }
524
525 ResultPointer = NULL;
526 ResultLength = sizeof(LRESULT);
527
528 UserLeaveCo();
529
530 Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
531 Argument,
532 ArgumentLength,
533 &ResultPointer,
534 &ResultLength);
535
536 UserEnterCo();
537
538 _SEH2_TRY
539 {
540 ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
541 /* Simulate old behaviour: copy into our local buffer */
542 Result = *(LRESULT*)ResultPointer;
543 }
544 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
545 {
546 Result = 0;
547 }
548 _SEH2_END;
549
550 if (!NT_SUCCESS(Status))
551 {
552 return 0;
553 }
554
555 if (HookId == WH_CBT && Code == HCBT_CREATEWND)
556 {
557 if (CbtCreatewndExtra)
558 {
559 _SEH2_TRY
560 { /*
561 The parameters could have been changed, include the coordinates
562 and dimensions of the window. We copy it back.
563 */
564 CbtCreateWnd->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
565 CbtCreateWnd->lpcs->x = CbtCreatewndExtra->Cs.x;
566 CbtCreateWnd->lpcs->y = CbtCreatewndExtra->Cs.y;
567 CbtCreateWnd->lpcs->cx = CbtCreatewndExtra->Cs.cx;
568 CbtCreateWnd->lpcs->cy = CbtCreatewndExtra->Cs.cy;
569 }
570 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
571 {
572 Result = 0;
573 }
574 _SEH2_END;
575 }
576 }
577
578 if (Argument) IntCbFreeMemory(Argument);
579
580 return Result;
581 }
582
583 //
584 // Events are notifications w/o results.
585 //
586 LRESULT
587 APIENTRY
588 co_IntCallEventProc(HWINEVENTHOOK hook,
589 DWORD event,
590 HWND hWnd,
591 LONG idObject,
592 LONG idChild,
593 DWORD dwEventThread,
594 DWORD dwmsEventTime,
595 WINEVENTPROC Proc)
596 {
597 LRESULT Result = 0;
598 NTSTATUS Status;
599 PEVENTPROC_CALLBACK_ARGUMENTS Common;
600 ULONG ArgumentLength, ResultLength;
601 PVOID Argument, ResultPointer;
602
603 ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
604
605 Argument = IntCbAllocateMemory(ArgumentLength);
606 if (NULL == Argument)
607 {
608 DPRINT1("EventProc callback failed: out of memory\n");
609 return 0;
610 }
611 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
612 Common->hook = hook;
613 Common->event = event;
614 Common->hwnd = hWnd;
615 Common->idObject = idObject;
616 Common->idChild = idChild;
617 Common->dwEventThread = dwEventThread;
618 Common->dwmsEventTime = dwmsEventTime;
619 Common->Proc = Proc;
620
621 ResultPointer = NULL;
622 ResultLength = sizeof(LRESULT);
623
624 UserLeaveCo();
625
626 Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
627 Argument,
628 ArgumentLength,
629 &ResultPointer,
630 &ResultLength);
631
632 UserEnterCo();
633
634 IntCbFreeMemory(Argument);
635
636 if (!NT_SUCCESS(Status))
637 {
638 return 0;
639 }
640
641 return Result;
642 }
643
644 //
645 // Callback Load Menu and results.
646 //
647 HMENU
648 APIENTRY
649 co_IntCallLoadMenu( HINSTANCE hModule,
650 PUNICODE_STRING pMenuName )
651 {
652 LRESULT Result = 0;
653 NTSTATUS Status;
654 PLOADMENU_CALLBACK_ARGUMENTS Common;
655 ULONG ArgumentLength, ResultLength;
656 PVOID Argument, ResultPointer;
657
658 ArgumentLength = sizeof(LOADMENU_CALLBACK_ARGUMENTS);
659
660 ArgumentLength += pMenuName->Length + sizeof(WCHAR);
661
662 Argument = IntCbAllocateMemory(ArgumentLength);
663 if (NULL == Argument)
664 {
665 DPRINT1("LoadMenu callback failed: out of memory\n");
666 return 0;
667 }
668 Common = (PLOADMENU_CALLBACK_ARGUMENTS) Argument;
669
670 // Help Intersource check and MenuName is now 4 bytes + so zero it.
671 RtlZeroMemory(Common, ArgumentLength);
672
673 Common->hModule = hModule;
674 if (pMenuName->Length)
675 RtlCopyMemory(&Common->MenuName, pMenuName->Buffer, pMenuName->Length);
676 else
677 RtlCopyMemory(&Common->MenuName, &pMenuName->Buffer, sizeof(WCHAR));
678
679 ResultPointer = NULL;
680 ResultLength = sizeof(LRESULT);
681
682 UserLeaveCo();
683
684 Status = KeUserModeCallback(USER32_CALLBACK_LOADMENU,
685 Argument,
686 ArgumentLength,
687 &ResultPointer,
688 &ResultLength);
689
690 UserEnterCo();
691
692 Result = *(LRESULT*)ResultPointer;
693
694 IntCbFreeMemory(Argument);
695
696 if (!NT_SUCCESS(Status))
697 {
698 return 0;
699 }
700
701 return (HMENU)Result;
702 }
703
704 NTSTATUS
705 APIENTRY
706 co_IntClientThreadSetup(VOID)
707 {
708 NTSTATUS Status;
709 ULONG ArgumentLength, ResultLength;
710 PVOID Argument, ResultPointer;
711
712 ArgumentLength = ResultLength = 0;
713 Argument = ResultPointer = NULL;
714
715 UserLeaveCo();
716
717 Status = KeUserModeCallback(USER32_CALLBACK_CLIENTTHREADSTARTUP,
718 Argument,
719 ArgumentLength,
720 &ResultPointer,
721 &ResultLength);
722
723 UserEnterCo();
724
725 return Status;
726 }
727
728
729 /* EOF */