bb087f074f58d481aab968b60441af0509cc87b7
[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 <win32k.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, PWND * pWnd)
97 {
98 HWND hWndS = *hWnd;
99 PWND Window = UserGetWindowObject(*hWnd);
100 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
101
102 *hWnd = ClientInfo->CallbackWnd.hWnd;
103 *pWnd = ClientInfo->CallbackWnd.pWnd;
104
105 ClientInfo->CallbackWnd.hWnd = hWndS;
106 ClientInfo->CallbackWnd.pWnd = DesktopHeapAddressToUser(Window);
107 }
108
109 static VOID
110 IntRestoreTebWndCallback (HWND hWnd, PWND pWnd)
111 {
112 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
113
114 ClientInfo->CallbackWnd.hWnd = hWnd;
115 ClientInfo->CallbackWnd.pWnd = 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;
129 PWND pWnd;
130 ULONG ResultLength;
131 NTSTATUS Status;
132
133 Arguments.Callback = CompletionCallback;
134 Arguments.Wnd = hWnd;
135 Arguments.Msg = Msg;
136 Arguments.Context = CompletionCallbackContext;
137 Arguments.Result = Result;
138
139 IntSetTebWndCallback (&hWnd, &pWnd);
140
141 UserLeaveCo();
142
143 Status = KeUserModeCallback(USER32_CALLBACK_SENDASYNCPROC,
144 &Arguments,
145 sizeof(SENDASYNCPROC_CALLBACK_ARGUMENTS),
146 &ResultPointer,
147 &ResultLength);
148
149 UserEnterCo();
150
151 IntRestoreTebWndCallback (hWnd, pWnd);
152
153 if (!NT_SUCCESS(Status))
154 {
155 return;
156 }
157 return;
158 }
159
160 LRESULT APIENTRY
161 co_IntCallWindowProc(WNDPROC Proc,
162 BOOLEAN IsAnsiProc,
163 HWND Wnd,
164 UINT Message,
165 WPARAM wParam,
166 LPARAM lParam,
167 INT lParamBufferSize)
168 {
169 WINDOWPROC_CALLBACK_ARGUMENTS StackArguments;
170 PWINDOWPROC_CALLBACK_ARGUMENTS Arguments;
171 NTSTATUS Status;
172 PVOID ResultPointer;
173 PWND pWnd;
174 ULONG ResultLength;
175 ULONG ArgumentLength;
176 LRESULT Result;
177
178 if (0 < lParamBufferSize)
179 {
180 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS) + lParamBufferSize;
181 Arguments = IntCbAllocateMemory(ArgumentLength);
182 if (NULL == Arguments)
183 {
184 DPRINT1("Unable to allocate buffer for window proc callback\n");
185 return -1;
186 }
187 RtlMoveMemory((PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
188 (PVOID) lParam, lParamBufferSize);
189 }
190 else
191 {
192 Arguments = &StackArguments;
193 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS);
194 }
195 Arguments->Proc = Proc;
196 Arguments->IsAnsiProc = IsAnsiProc;
197 Arguments->Wnd = Wnd;
198 Arguments->Msg = Message;
199 Arguments->wParam = wParam;
200 Arguments->lParam = lParam;
201 Arguments->lParamBufferSize = lParamBufferSize;
202 ResultPointer = NULL;
203 ResultLength = ArgumentLength;
204
205 IntSetTebWndCallback (&Wnd, &pWnd);
206
207 UserLeaveCo();
208
209 Status = KeUserModeCallback(USER32_CALLBACK_WINDOWPROC,
210 Arguments,
211 ArgumentLength,
212 &ResultPointer,
213 &ResultLength);
214
215 _SEH2_TRY
216 {
217 /* Simulate old behaviour: copy into our local buffer */
218 RtlMoveMemory(Arguments, ResultPointer, ArgumentLength);
219 }
220 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
221 {
222 Status = _SEH2_GetExceptionCode();
223 }
224 _SEH2_END;
225
226 UserEnterCo();
227
228 IntRestoreTebWndCallback (Wnd, pWnd);
229
230 if (!NT_SUCCESS(Status))
231 {
232 if (0 < lParamBufferSize)
233 {
234 IntCbFreeMemory(Arguments);
235 }
236 return -1;
237 }
238 Result = Arguments->Result;
239
240 if (0 < lParamBufferSize)
241 {
242 RtlMoveMemory((PVOID) lParam,
243 (PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
244 lParamBufferSize);
245 IntCbFreeMemory(Arguments);
246 }
247
248 return Result;
249 }
250
251 HMENU APIENTRY
252 co_IntLoadSysMenuTemplate()
253 {
254 LRESULT Result = 0;
255 NTSTATUS Status;
256 PVOID ResultPointer;
257 ULONG ResultLength;
258
259 ResultPointer = NULL;
260 ResultLength = sizeof(LRESULT);
261
262 UserLeaveCo();
263
264 Status = KeUserModeCallback(USER32_CALLBACK_LOADSYSMENUTEMPLATE,
265 NULL,
266 0,
267 &ResultPointer,
268 &ResultLength);
269 if (NT_SUCCESS(Status))
270 {
271 /* Simulate old behaviour: copy into our local buffer */
272 _SEH2_TRY
273 {
274 ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
275 Result = *(LRESULT*)ResultPointer;
276 }
277 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
278 {
279 Result = 0;
280 }
281 _SEH2_END
282 }
283
284 UserEnterCo();
285
286 return (HMENU)Result;
287 }
288
289 BOOL APIENTRY
290 co_IntLoadDefaultCursors(VOID)
291 {
292 NTSTATUS Status;
293 PVOID ResultPointer;
294 ULONG ResultLength;
295 BOOL DefaultCursor = TRUE;
296
297 ResultPointer = NULL;
298 ResultLength = sizeof(LRESULT);
299
300 UserLeaveCo();
301
302 Status = KeUserModeCallback(USER32_CALLBACK_LOADDEFAULTCURSORS,
303 &DefaultCursor,
304 sizeof(BOOL),
305 &ResultPointer,
306 &ResultLength);
307
308 UserEnterCo();
309
310 if (!NT_SUCCESS(Status))
311 {
312 return FALSE;
313 }
314 return TRUE;
315 }
316
317 LRESULT APIENTRY
318 co_IntCallHookProc(INT HookId,
319 INT Code,
320 WPARAM wParam,
321 LPARAM lParam,
322 HOOKPROC Proc,
323 BOOLEAN Ansi,
324 PUNICODE_STRING ModuleName)
325 {
326 ULONG ArgumentLength;
327 PVOID Argument = NULL;
328 LRESULT Result = 0;
329 NTSTATUS Status;
330 PVOID ResultPointer;
331 ULONG ResultLength;
332 PHOOKPROC_CALLBACK_ARGUMENTS Common;
333 CBT_CREATEWNDW *CbtCreateWnd = NULL;
334 PCHAR Extra;
335 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
336 PTHREADINFO pti;
337 PWND pWnd;
338 PMSG pMsg = NULL;
339 BOOL Hit = FALSE;
340
341 ASSERT(Proc);
342
343 pti = PsGetCurrentThreadWin32Thread();
344 if (pti->TIF_flags & TIF_INCLEANUP)
345 {
346 DPRINT1("Thread is in cleanup and trying to call hook %d\n", Code);
347 return 0;
348 }
349
350 ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
351
352 switch(HookId)
353 {
354 case WH_CBT:
355 DPRINT("WH_CBT: Code %d\n", Code);
356 switch(Code)
357 {
358 case HCBT_CREATEWND:
359 pWnd = UserGetWindowObject((HWND) wParam);
360 if (!pWnd)
361 {
362 DPRINT1("WH_CBT HCBT_CREATEWND wParam bad hWnd!\n");
363 goto Fault_Exit;
364 }
365 DPRINT("HCBT_CREATEWND AnsiCreator %s, AnsiHook %s\n", pWnd->state & WNDS_ANSICREATOR ? "True" : "False", Ansi ? "True" : "False");
366 // Due to KsStudio.exe, just pass the callers original pointers
367 // except class which point to kernel space if not an atom.
368 // Found by, Olaf Siejka
369 CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
370 ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
371 break;
372
373 case HCBT_MOVESIZE:
374 ArgumentLength += sizeof(RECTL);
375 break;
376 case HCBT_ACTIVATE:
377 ArgumentLength += sizeof(CBTACTIVATESTRUCT);
378 break;
379 case HCBT_CLICKSKIPPED:
380 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
381 break;
382 /* ATM pass on */
383 case HCBT_KEYSKIPPED:
384 case HCBT_MINMAX:
385 case HCBT_SETFOCUS:
386 case HCBT_SYSCOMMAND:
387 /* These types pass through. */
388 case HCBT_DESTROYWND:
389 case HCBT_QS:
390 break;
391 default:
392 DPRINT1("Trying to call unsupported CBT hook %d\n", Code);
393 goto Fault_Exit;
394 }
395 break;
396 case WH_KEYBOARD_LL:
397 ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
398 break;
399 case WH_MOUSE_LL:
400 ArgumentLength += sizeof(MSLLHOOKSTRUCT);
401 break;
402 case WH_MOUSE:
403 ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
404 break;
405 case WH_CALLWNDPROC:
406 ArgumentLength += sizeof(CWPSTRUCT);
407 break;
408 case WH_CALLWNDPROCRET:
409 ArgumentLength += sizeof(CWPRETSTRUCT);
410 break;
411 case WH_MSGFILTER:
412 case WH_SYSMSGFILTER:
413 case WH_GETMESSAGE:
414 ArgumentLength += sizeof(MSG);
415 break;
416 case WH_FOREGROUNDIDLE:
417 case WH_KEYBOARD:
418 case WH_SHELL:
419 break;
420 default:
421 DPRINT1("Trying to call unsupported window hook %d\n", HookId);
422 goto Fault_Exit;
423 }
424
425 Argument = IntCbAllocateMemory(ArgumentLength);
426 if (NULL == Argument)
427 {
428 DPRINT1("HookProc callback failed: out of memory\n");
429 goto Fault_Exit;
430 }
431 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
432 Common->HookId = HookId;
433 Common->Code = Code;
434 Common->wParam = wParam;
435 Common->lParam = lParam;
436 Common->Proc = Proc;
437 Common->Ansi = Ansi;
438 Extra = (PCHAR) Common + sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
439
440 switch(HookId)
441 {
442 case WH_CBT:
443 switch(Code)
444 { // Need to remember this is not the first time through! Call Next Hook?
445 case HCBT_CREATEWND:
446 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
447 RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) );
448 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
449 CbtCreatewndExtra->Cs.lpszClass = CbtCreateWnd->lpcs->lpszClass;
450 CbtCreatewndExtra->Cs.lpszName = CbtCreateWnd->lpcs->lpszName;
451 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
452 break;
453 case HCBT_CLICKSKIPPED:
454 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
455 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
456 break;
457 case HCBT_MOVESIZE:
458 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(RECTL));
459 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
460 break;
461 case HCBT_ACTIVATE:
462 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CBTACTIVATESTRUCT));
463 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
464 break;
465 }
466 break;
467 case WH_KEYBOARD_LL:
468 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
469 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
470 break;
471 case WH_MOUSE_LL:
472 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
473 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
474 break;
475 case WH_MOUSE:
476 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
477 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
478 break;
479 case WH_CALLWNDPROC:
480 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT));
481 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
482 break;
483 case WH_CALLWNDPROCRET:
484 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT));
485 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
486 break;
487 case WH_MSGFILTER:
488 case WH_SYSMSGFILTER:
489 case WH_GETMESSAGE:
490 pMsg = (PMSG)lParam;
491 RtlCopyMemory(Extra, (PVOID) pMsg, sizeof(MSG));
492 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
493 break;
494 case WH_FOREGROUNDIDLE:
495 case WH_KEYBOARD:
496 case WH_SHELL:
497 break;
498 }
499
500 ResultPointer = NULL;
501 ResultLength = sizeof(LRESULT);
502
503 UserLeaveCo();
504
505 Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
506 Argument,
507 ArgumentLength,
508 &ResultPointer,
509 &ResultLength);
510
511 UserEnterCo();
512
513 _SEH2_TRY
514 {
515 ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
516 /* Simulate old behaviour: copy into our local buffer */
517 Result = *(LRESULT*)ResultPointer;
518 }
519 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
520 {
521 Result = 0;
522 Hit = TRUE;
523 }
524 _SEH2_END;
525
526 if (!NT_SUCCESS(Status))
527 {
528 DPRINT1("Failure to make Callback! Status 0x%x",Status);
529 goto Fault_Exit;
530 }
531 /* Support write backs... SEH is in UserCallNextHookEx. */
532 switch (HookId)
533 {
534 case WH_CBT:
535 if (Code == HCBT_CREATEWND)
536 {
537 if (CbtCreatewndExtra)
538 {/*
539 The parameters could have been changed, include the coordinates
540 and dimensions of the window. We copy it back.
541 */
542 CbtCreateWnd->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
543 CbtCreateWnd->lpcs->x = CbtCreatewndExtra->Cs.x;
544 CbtCreateWnd->lpcs->y = CbtCreatewndExtra->Cs.y;
545 CbtCreateWnd->lpcs->cx = CbtCreatewndExtra->Cs.cx;
546 CbtCreateWnd->lpcs->cy = CbtCreatewndExtra->Cs.cy;
547 }
548 }
549 break;
550 // "The GetMsgProc hook procedure can examine or modify the message."
551 case WH_GETMESSAGE:
552 if (pMsg)
553 {
554 RtlCopyMemory((PVOID) pMsg, Extra, sizeof(MSG));
555 }
556 break;
557 }
558
559 Fault_Exit:
560 if (Hit)
561 {
562 DPRINT1("Exception CallHookProc HookId %d Code %d\n",HookId,Code);
563 }
564 if (Argument) IntCbFreeMemory(Argument);
565
566 return Result;
567 }
568
569 //
570 // Events are notifications w/o results.
571 //
572 LRESULT
573 APIENTRY
574 co_IntCallEventProc(HWINEVENTHOOK hook,
575 DWORD event,
576 HWND hWnd,
577 LONG idObject,
578 LONG idChild,
579 DWORD dwEventThread,
580 DWORD dwmsEventTime,
581 WINEVENTPROC Proc)
582 {
583 LRESULT Result = 0;
584 NTSTATUS Status;
585 PEVENTPROC_CALLBACK_ARGUMENTS Common;
586 ULONG ArgumentLength, ResultLength;
587 PVOID Argument, ResultPointer;
588
589 ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
590
591 Argument = IntCbAllocateMemory(ArgumentLength);
592 if (NULL == Argument)
593 {
594 DPRINT1("EventProc callback failed: out of memory\n");
595 return 0;
596 }
597 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
598 Common->hook = hook;
599 Common->event = event;
600 Common->hwnd = hWnd;
601 Common->idObject = idObject;
602 Common->idChild = idChild;
603 Common->dwEventThread = dwEventThread;
604 Common->dwmsEventTime = dwmsEventTime;
605 Common->Proc = Proc;
606
607 ResultPointer = NULL;
608 ResultLength = sizeof(LRESULT);
609
610 UserLeaveCo();
611
612 Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
613 Argument,
614 ArgumentLength,
615 &ResultPointer,
616 &ResultLength);
617
618 UserEnterCo();
619
620 IntCbFreeMemory(Argument);
621
622 if (!NT_SUCCESS(Status))
623 {
624 return 0;
625 }
626
627 return Result;
628 }
629
630 //
631 // Callback Load Menu and results.
632 //
633 HMENU
634 APIENTRY
635 co_IntCallLoadMenu( HINSTANCE hModule,
636 PUNICODE_STRING pMenuName )
637 {
638 LRESULT Result = 0;
639 NTSTATUS Status;
640 PLOADMENU_CALLBACK_ARGUMENTS Common;
641 ULONG ArgumentLength, ResultLength;
642 PVOID Argument, ResultPointer;
643
644 ArgumentLength = sizeof(LOADMENU_CALLBACK_ARGUMENTS);
645
646 ArgumentLength += pMenuName->Length + sizeof(WCHAR);
647
648 Argument = IntCbAllocateMemory(ArgumentLength);
649 if (NULL == Argument)
650 {
651 DPRINT1("LoadMenu callback failed: out of memory\n");
652 return 0;
653 }
654 Common = (PLOADMENU_CALLBACK_ARGUMENTS) Argument;
655
656 // Help Intersource check and MenuName is now 4 bytes + so zero it.
657 RtlZeroMemory(Common, ArgumentLength);
658
659 Common->hModule = hModule;
660 if (pMenuName->Length)
661 RtlCopyMemory(&Common->MenuName, pMenuName->Buffer, pMenuName->Length);
662 else
663 RtlCopyMemory(&Common->MenuName, &pMenuName->Buffer, sizeof(WCHAR));
664
665 ResultPointer = NULL;
666 ResultLength = sizeof(LRESULT);
667
668 UserLeaveCo();
669
670 Status = KeUserModeCallback(USER32_CALLBACK_LOADMENU,
671 Argument,
672 ArgumentLength,
673 &ResultPointer,
674 &ResultLength);
675
676 UserEnterCo();
677
678 Result = *(LRESULT*)ResultPointer;
679
680 IntCbFreeMemory(Argument);
681
682 if (!NT_SUCCESS(Status))
683 {
684 return 0;
685 }
686
687 return (HMENU)Result;
688 }
689
690 NTSTATUS
691 APIENTRY
692 co_IntClientThreadSetup(VOID)
693 {
694 NTSTATUS Status;
695 ULONG ArgumentLength, ResultLength;
696 PVOID Argument, ResultPointer;
697
698 ArgumentLength = ResultLength = 0;
699 Argument = ResultPointer = NULL;
700
701 UserLeaveCo();
702
703 Status = KeUserModeCallback(USER32_CALLBACK_CLIENTTHREADSTARTUP,
704 Argument,
705 ArgumentLength,
706 &ResultPointer,
707 &ResultLength);
708
709 UserEnterCo();
710
711 return Status;
712 }
713
714
715 /* EOF */