xref: /reactos/win32ss/user/ntuser/misc.c (revision 3c5a56ed)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Miscellaneous User functions
5  * FILE:             win32ss/user/ntuser/misc.c
6  * PROGRAMER:        Ge van Geldorp (ge@gse.nl)
7  */
8 
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserMisc);
11 
12 
13 /*
14  * NOTE: _scwprintf() is NOT exported by ntoskrnl.exe,
15  * only _vscwprintf() is, so we need to implement it here.
16  * Code comes from sdk/lib/crt/printf/_scwprintf.c .
17  * See also win32ss/user/winsrv/usersrv/harderror.c .
18  */
19 int
20 __cdecl
21 _scwprintf(
22     const wchar_t *format,
23     ...)
24 {
25     int len;
26     va_list args;
27 
28     va_start(args, format);
29     len = _vscwprintf(format, args);
30     va_end(args);
31 
32     return len;
33 }
34 
35 
36 /*
37  * Test the Thread to verify and validate it. Hard to the core tests are required.
38  * Win: PtiFromThreadId
39  */
40 PTHREADINFO
41 FASTCALL
42 IntTID2PTI(HANDLE id)
43 {
44    NTSTATUS Status;
45    PETHREAD Thread;
46    PTHREADINFO pti;
47    Status = PsLookupThreadByThreadId(id, &Thread);
48    if (!NT_SUCCESS(Status))
49    {
50       return NULL;
51    }
52    if (PsIsThreadTerminating(Thread))
53    {
54       ObDereferenceObject(Thread);
55       return NULL;
56    }
57    pti = PsGetThreadWin32Thread(Thread);
58    if (!pti)
59    {
60       ObDereferenceObject(Thread);
61       return NULL;
62    }
63    // Validate and verify!
64    _SEH2_TRY
65    {
66       if (pti->TIF_flags & TIF_INCLEANUP) pti = NULL;
67       if (pti && !(pti->TIF_flags & TIF_GUITHREADINITIALIZED)) pti = NULL;
68       if (PsGetThreadId(Thread) != id) pti = NULL;
69    }
70    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
71    {
72       pti = NULL;
73    }
74    _SEH2_END
75    ObDereferenceObject(Thread);
76    return pti;
77 }
78 
79 DWORD
80 FASTCALL
81 UserGetLanguageToggle(VOID)
82 {
83     NTSTATUS Status;
84     DWORD dwValue = 0;
85 
86     Status = RegReadUserSetting(L"Keyboard Layout\\Toggle", L"Layout Hotkey", REG_SZ, &dwValue, sizeof(dwValue));
87     if (NT_SUCCESS(Status))
88     {
89         dwValue = atoi((char *)&dwValue);
90         TRACE("Layout Hotkey %d\n",dwValue);
91     }
92     return dwValue;
93 }
94 
95 USHORT
96 FASTCALL
97 UserGetLanguageID(VOID)
98 {
99   HANDLE KeyHandle;
100   OBJECT_ATTRIBUTES ObAttr;
101 //  http://support.microsoft.com/kb/324097
102   ULONG Ret = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
103   PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
104   ULONG Size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH*sizeof(WCHAR);
105   UNICODE_STRING Language;
106 
107   RtlInitUnicodeString( &Language,
108     L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language");
109 
110   InitializeObjectAttributes( &ObAttr,
111                               &Language,
112                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
113                               NULL,
114                               NULL);
115 
116   if ( NT_SUCCESS(ZwOpenKey(&KeyHandle, KEY_READ, &ObAttr)))
117   {
118      pKeyInfo = ExAllocatePoolWithTag(PagedPool, Size, TAG_STRING);
119      if ( pKeyInfo )
120      {
121         RtlInitUnicodeString(&Language, L"Default");
122 
123         if ( NT_SUCCESS(ZwQueryValueKey( KeyHandle,
124                                          &Language,
125                         KeyValuePartialInformation,
126                                           pKeyInfo,
127                                               Size,
128                                              &Size)) )
129       {
130         RtlInitUnicodeString(&Language, (PWSTR)pKeyInfo->Data);
131         if (!NT_SUCCESS(RtlUnicodeStringToInteger(&Language, 16, &Ret)))
132         {
133             Ret = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
134         }
135       }
136       ExFreePoolWithTag(pKeyInfo, TAG_STRING);
137     }
138     ZwClose(KeyHandle);
139   }
140   TRACE("Language ID = %x\n",Ret);
141   return (USHORT) Ret;
142 }
143 
144 HBRUSH
145 FASTCALL
146 GetControlColor(
147    PWND pwndParent,
148    PWND pwnd,
149    HDC hdc,
150    UINT CtlMsg)
151 {
152     HBRUSH hBrush;
153 
154     if (!pwndParent) pwndParent = pwnd;
155 
156     if ( pwndParent->head.pti->ppi != PsGetCurrentProcessWin32Process())
157     {
158        return (HBRUSH)IntDefWindowProc( pwndParent, CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd), FALSE);
159     }
160 
161     hBrush = (HBRUSH)co_IntSendMessage( UserHMGetHandle(pwndParent), CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd));
162 
163     if (!hBrush || !GreIsHandleValid(hBrush))
164     {
165        hBrush = (HBRUSH)IntDefWindowProc( pwndParent, CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd), FALSE);
166     }
167     return hBrush;
168 }
169 
170 HBRUSH
171 FASTCALL
172 GetControlBrush(
173    PWND pwnd,
174    HDC  hdc,
175    UINT ctlType)
176 {
177     PWND pwndParent = IntGetParent(pwnd);
178     return GetControlColor( pwndParent, pwnd, hdc, ctlType);
179 }
180 
181 HBRUSH
182 APIENTRY
183 NtUserGetControlBrush(
184    HWND hwnd,
185    HDC  hdc,
186    UINT ctlType)
187 {
188    PWND pwnd;
189    HBRUSH hBrush = NULL;
190 
191    UserEnterExclusive();
192    if ( (pwnd = UserGetWindowObject(hwnd)) &&
193        ((ctlType - WM_CTLCOLORMSGBOX) < CTLCOLOR_MAX) &&
194         hdc )
195    {
196       hBrush = GetControlBrush(pwnd, hdc, ctlType);
197    }
198    UserLeave();
199    return hBrush;
200 }
201 
202 /*
203  * Called from PaintRect, works almost like wine PaintRect16 but returns hBrush.
204  */
205 HBRUSH
206 APIENTRY
207 NtUserGetControlColor(
208    HWND hwndParent,
209    HWND hwnd,
210    HDC hdc,
211    UINT CtlMsg) // Wine PaintRect: WM_CTLCOLORMSGBOX + hbrush
212 {
213    PWND pwnd, pwndParent = NULL;
214    HBRUSH hBrush = NULL;
215 
216    UserEnterExclusive();
217    if ( (pwnd = UserGetWindowObject(hwnd)) &&
218        ((CtlMsg - WM_CTLCOLORMSGBOX) < CTLCOLOR_MAX) &&
219         hdc )
220    {
221       if (hwndParent) pwndParent = UserGetWindowObject(hwndParent);
222       hBrush = GetControlColor( pwndParent, pwnd, hdc, CtlMsg);
223    }
224    UserLeave();
225    return hBrush;
226 }
227 
228 /*
229  * @unimplemented
230  */
231 DWORD_PTR APIENTRY
232 NtUserGetThreadState(
233    DWORD Routine)
234 {
235    DWORD_PTR ret = 0;
236    PTHREADINFO pti;
237 
238    TRACE("Enter NtUserGetThreadState\n");
239    if (Routine != THREADSTATE_GETTHREADINFO)
240    {
241        UserEnterShared();
242    }
243    else
244    {
245        UserEnterExclusive();
246    }
247 
248    pti = PsGetCurrentThreadWin32Thread();
249 
250    switch (Routine)
251    {
252       case THREADSTATE_GETTHREADINFO:
253          ret = TRUE;
254          break;
255       case THREADSTATE_FOCUSWINDOW:
256          ret = (DWORD_PTR)IntGetThreadFocusWindow();
257          break;
258       case THREADSTATE_CAPTUREWINDOW:
259          /* FIXME: Should use UserEnterShared */
260          ret = (DWORD_PTR)IntGetCapture();
261          break;
262       case THREADSTATE_PROGMANWINDOW: /* FIXME: Delete this HACK */
263          ret = (DWORD_PTR)GetW32ThreadInfo()->pDeskInfo->hProgmanWindow;
264          break;
265       case THREADSTATE_TASKMANWINDOW: /* FIXME: Delete this HACK */
266          ret = (DWORD_PTR)GetW32ThreadInfo()->pDeskInfo->hTaskManWindow;
267          break;
268       case THREADSTATE_ACTIVEWINDOW:
269          ret = (DWORD_PTR)UserGetActiveWindow();
270          break;
271       case THREADSTATE_INSENDMESSAGE:
272          {
273            PUSER_SENT_MESSAGE Message =
274                 ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->pusmCurrent;
275            TRACE("THREADSTATE_INSENDMESSAGE\n");
276 
277            ret = ISMEX_NOSEND;
278            if (Message)
279            {
280              if (Message->ptiSender)
281                 ret = ISMEX_SEND;
282              else
283              {
284                 if (Message->CompletionCallback)
285                    ret = ISMEX_CALLBACK;
286                 else
287                    ret = ISMEX_NOTIFY;
288              }
289              /* If ReplyMessage */
290              if (Message->QS_Flags & QS_SMRESULT) ret |= ISMEX_REPLIED;
291            }
292 
293            break;
294          }
295       case THREADSTATE_GETMESSAGETIME:
296          ret = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->timeLast;
297          break;
298 
299       case THREADSTATE_UPTIMELASTREAD:
300          pti->pcti->timeLastRead = EngGetTickCount32();
301          break;
302 
303       case THREADSTATE_GETINPUTSTATE:
304          ret = LOWORD(IntGetQueueStatus(QS_POSTMESSAGE|QS_TIMER|QS_PAINT|QS_SENDMESSAGE|QS_INPUT)) & (QS_KEY | QS_MOUSEBUTTON);
305          break;
306 
307       case THREADSTATE_FOREGROUNDTHREAD:
308          ret = (gpqForeground == GetW32ThreadInfo()->MessageQueue);
309          break;
310       case THREADSTATE_GETCURSOR:
311          ret = (DWORD_PTR) (GetW32ThreadInfo()->MessageQueue->CursorObject ?
312                             UserHMGetHandle(GetW32ThreadInfo()->MessageQueue->CursorObject) : 0);
313          break;
314       case THREADSTATE_GETMESSAGEEXTRAINFO:
315          ret = (DWORD_PTR)MsqGetMessageExtraInfo();
316          break;
317       case THREADSTATE_DEFAULTIMEWINDOW:
318          if (pti->spwndDefaultIme)
319             ret = (ULONG_PTR)UserHMGetHandle(pti->spwndDefaultIme);
320          break;
321       case THREADSTATE_DEFAULTINPUTCONTEXT:
322          if (pti->spDefaultImc)
323              ret = (ULONG_PTR)UserHMGetHandle(pti->spDefaultImc);
324          break;
325       case THREADSTATE_CHANGEBITS:
326          ret = pti->pcti->fsChangeBits;
327          break;
328       case THREADSTATE_IMECOMPATFLAGS:
329          ret = pti->ppi->dwImeCompatFlags;
330          break;
331       case THREADSTATE_OLDKEYBOARDLAYOUT:
332          ret = (ULONG_PTR)pti->hklPrev;
333          break;
334       case THREADSTATE_ISWINLOGON:
335       case THREADSTATE_ISWINLOGON2:
336          ret = (gpidLogon == PsGetCurrentProcessId());
337          break;
338       case THREADSTATE_CHECKCONIME:
339          /* FIXME */
340          break;
341    }
342 
343    TRACE("Leave NtUserGetThreadState, ret=%lu\n", ret);
344    UserLeave();
345 
346    return ret;
347 }
348 
349 DWORD
350 APIENTRY
351 NtUserSetThreadState(
352    DWORD Set,
353    DWORD Flags)
354 {
355    PTHREADINFO pti;
356    DWORD Ret = 0;
357    // Test the only flags user can change.
358    if (Set & ~(QF_FF10STATUS|QF_DIALOGACTIVE|QF_TABSWITCHING|QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) return 0;
359    if (Flags & ~(QF_FF10STATUS|QF_DIALOGACTIVE|QF_TABSWITCHING|QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) return 0;
360    UserEnterExclusive();
361    pti = PsGetCurrentThreadWin32Thread();
362    if (pti->MessageQueue)
363    {
364       Ret = pti->MessageQueue->QF_flags;    // Get the queue flags.
365       if (Set)
366          pti->MessageQueue->QF_flags |= (Set&Flags); // Set the queue flags.
367       else
368       {
369          if (Flags) pti->MessageQueue->QF_flags &= ~Flags; // Clr the queue flags.
370       }
371    }
372    UserLeave();
373    return Ret;
374 }
375 
376 UINT
377 APIENTRY
378 NtUserGetDoubleClickTime(VOID)
379 {
380    UINT Result;
381 
382    TRACE("Enter NtUserGetDoubleClickTime\n");
383    UserEnterShared();
384 
385    // FIXME: Check if this works on non-interactive winsta
386    Result = gspv.iDblClickTime;
387 
388    TRACE("Leave NtUserGetDoubleClickTime, ret=%u\n", Result);
389    UserLeave();
390    return Result;
391 }
392 
393 BOOL
394 APIENTRY
395 NtUserGetGUIThreadInfo(
396    DWORD idThread, /* If NULL use foreground thread */
397    LPGUITHREADINFO lpgui)
398 {
399    NTSTATUS Status;
400    PTHRDCARETINFO CaretInfo;
401    GUITHREADINFO SafeGui;
402    PDESKTOP Desktop;
403    PUSER_MESSAGE_QUEUE MsgQueue;
404    PTHREADINFO W32Thread, pti;
405 
406    DECLARE_RETURN(BOOLEAN);
407 
408    TRACE("Enter NtUserGetGUIThreadInfo\n");
409    UserEnterShared();
410 
411    Status = MmCopyFromCaller(&SafeGui, lpgui, sizeof(DWORD));
412    if(!NT_SUCCESS(Status))
413    {
414       SetLastNtError(Status);
415       RETURN( FALSE);
416    }
417 
418    if(SafeGui.cbSize != sizeof(GUITHREADINFO))
419    {
420       EngSetLastError(ERROR_INVALID_PARAMETER);
421       RETURN( FALSE);
422    }
423 
424    if (idThread)
425    {
426       pti = PsGetCurrentThreadWin32Thread();
427 
428       // Validate Tread ID
429       W32Thread = IntTID2PTI((HANDLE)(DWORD_PTR)idThread);
430 
431       if ( !W32Thread )
432       {
433           EngSetLastError(ERROR_ACCESS_DENIED);
434           RETURN( FALSE);
435       }
436 
437       Desktop = W32Thread->rpdesk;
438 
439       // Check Desktop and it must be the same as current.
440       if ( !Desktop || Desktop != pti->rpdesk )
441       {
442           EngSetLastError(ERROR_ACCESS_DENIED);
443           RETURN( FALSE);
444       }
445 
446       if ( W32Thread->MessageQueue )
447         MsgQueue = W32Thread->MessageQueue;
448       else
449       {
450         MsgQueue = Desktop->ActiveMessageQueue;
451       }
452    }
453    else
454    {  /* Get the foreground thread */
455       /* FIXME: Handle NULL queue properly? */
456       MsgQueue = IntGetFocusMessageQueue();
457       if(!MsgQueue)
458       {
459         EngSetLastError(ERROR_ACCESS_DENIED);
460         RETURN( FALSE);
461       }
462    }
463 
464    CaretInfo = &MsgQueue->CaretInfo;
465 
466    SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0);
467 /*
468    if (W32Thread->pMenuState->pGlobalPopupMenu)
469    {
470        SafeGui.flags |= GUI_INMENUMODE;
471 
472        if (W32Thread->pMenuState->pGlobalPopupMenu->spwndNotify)
473           SafeGui.hwndMenuOwner = UserHMGetHandle(W32Thread->pMenuState->pGlobalPopupMenu->spwndNotify);
474 
475        if (W32Thread->pMenuState->pGlobalPopupMenu->fHasMenuBar)
476        {
477           if (W32Thread->pMenuState->pGlobalPopupMenu->fIsSysMenu)
478           {
479              SafeGui.flags |= GUI_SYSTEMMENUMODE;
480           }
481        }
482        else
483        {
484           SafeGui.flags |= GUI_POPUPMENUMODE;
485        }
486    }
487  */
488    SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
489 
490    if (MsgQueue->MenuOwner)
491       SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState;
492 
493    if (MsgQueue->MoveSize)
494       SafeGui.flags |= GUI_INMOVESIZE;
495 
496    /* FIXME: Add flag GUI_16BITTASK */
497 
498    SafeGui.hwndActive = MsgQueue->spwndActive ? UserHMGetHandle(MsgQueue->spwndActive) : 0;
499    SafeGui.hwndFocus = MsgQueue->spwndFocus ? UserHMGetHandle(MsgQueue->spwndFocus) : 0;
500    SafeGui.hwndCapture = MsgQueue->spwndCapture ? UserHMGetHandle(MsgQueue->spwndCapture) : 0;
501    SafeGui.hwndMoveSize = MsgQueue->MoveSize;
502    SafeGui.hwndCaret = CaretInfo->hWnd;
503 
504    SafeGui.rcCaret.left = CaretInfo->Pos.x;
505    SafeGui.rcCaret.top = CaretInfo->Pos.y;
506    SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx;
507    SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy;
508 
509    Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO));
510    if(!NT_SUCCESS(Status))
511    {
512       SetLastNtError(Status);
513       RETURN( FALSE);
514    }
515 
516    RETURN( TRUE);
517 
518 CLEANUP:
519    TRACE("Leave NtUserGetGUIThreadInfo, ret=%u\n",_ret_);
520    UserLeave();
521    END_CLEANUP;
522 }
523 
524 
525 DWORD
526 APIENTRY
527 NtUserGetGuiResources(
528    HANDLE hProcess,
529    DWORD uiFlags)
530 {
531    PEPROCESS Process;
532    PPROCESSINFO W32Process;
533    NTSTATUS Status;
534    DWORD Ret = 0;
535    DECLARE_RETURN(DWORD);
536 
537    TRACE("Enter NtUserGetGuiResources\n");
538    UserEnterShared();
539 
540    Status = ObReferenceObjectByHandle(hProcess,
541                                       PROCESS_QUERY_INFORMATION,
542                                       *PsProcessType,
543                                       ExGetPreviousMode(),
544                                       (PVOID*)&Process,
545                                       NULL);
546 
547    if(!NT_SUCCESS(Status))
548    {
549       SetLastNtError(Status);
550       RETURN( 0);
551    }
552 
553    W32Process = (PPROCESSINFO)Process->Win32Process;
554    if(!W32Process)
555    {
556       ObDereferenceObject(Process);
557       EngSetLastError(ERROR_INVALID_PARAMETER);
558       RETURN( 0);
559    }
560 
561    switch(uiFlags)
562    {
563       case GR_GDIOBJECTS:
564          {
565             Ret = (DWORD)W32Process->GDIHandleCount;
566             break;
567          }
568       case GR_USEROBJECTS:
569          {
570             Ret = (DWORD)W32Process->UserHandleCount;
571             break;
572          }
573       default:
574          {
575             EngSetLastError(ERROR_INVALID_PARAMETER);
576             break;
577          }
578    }
579 
580    ObDereferenceObject(Process);
581 
582    RETURN( Ret);
583 
584 CLEANUP:
585    TRACE("Leave NtUserGetGuiResources, ret=%lu\n",_ret_);
586    UserLeave();
587    END_CLEANUP;
588 }
589 
590 VOID FASTCALL
591 IntSetWindowState(PWND pWnd, UINT Flag)
592 {
593    UINT bit;
594    if (gptiCurrent->ppi != pWnd->head.pti->ppi) return;
595    bit = 1 << LOWORD(Flag);
596    TRACE("SWS %x\n",bit);
597    switch(HIWORD(Flag))
598    {
599       case 0:
600           pWnd->state |= bit;
601           break;
602       case 1:
603           pWnd->state2 |= bit;
604           break;
605       case 2:
606           pWnd->ExStyle2 |= bit;
607           break;
608    }
609 }
610 
611 VOID FASTCALL
612 IntClearWindowState(PWND pWnd, UINT Flag)
613 {
614    UINT bit;
615    if (gptiCurrent->ppi != pWnd->head.pti->ppi) return;
616    bit = 1 << LOWORD(Flag);
617    TRACE("CWS %x\n",bit);
618    switch(HIWORD(Flag))
619    {
620       case 0:
621           pWnd->state &= ~bit;
622           break;
623       case 1:
624           pWnd->state2 &= ~bit;
625           break;
626       case 2:
627           pWnd->ExStyle2 &= ~bit;
628           break;
629    }
630 }
631 
632 NTSTATUS FASTCALL
633 IntSafeCopyUnicodeString(PUNICODE_STRING Dest,
634                          PUNICODE_STRING Source)
635 {
636    NTSTATUS Status;
637    PWSTR Src;
638 
639    Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
640    if(!NT_SUCCESS(Status))
641    {
642       return Status;
643    }
644 
645    if(Dest->Length > 0x4000)
646    {
647       return STATUS_UNSUCCESSFUL;
648    }
649 
650    Src = Dest->Buffer;
651    Dest->Buffer = NULL;
652    Dest->MaximumLength = Dest->Length;
653 
654    if(Dest->Length > 0 && Src)
655    {
656       Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
657       if(!Dest->Buffer)
658       {
659          return STATUS_NO_MEMORY;
660       }
661 
662       Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
663       if(!NT_SUCCESS(Status))
664       {
665          ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
666          Dest->Buffer = NULL;
667          return Status;
668       }
669 
670 
671       return STATUS_SUCCESS;
672    }
673 
674    /* String is empty */
675    return STATUS_SUCCESS;
676 }
677 
678 NTSTATUS FASTCALL
679 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest,
680                                       PUNICODE_STRING Source)
681 {
682    NTSTATUS Status;
683    PWSTR Src;
684 
685    Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
686    if(!NT_SUCCESS(Status))
687    {
688       return Status;
689    }
690 
691    if(Dest->Length > 0x4000)
692    {
693       return STATUS_UNSUCCESSFUL;
694    }
695 
696    Src = Dest->Buffer;
697    Dest->Buffer = NULL;
698    Dest->MaximumLength = 0;
699 
700    if(Dest->Length > 0 && Src)
701    {
702       Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
703       Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
704       if(!Dest->Buffer)
705       {
706          return STATUS_NO_MEMORY;
707       }
708 
709       Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
710       if(!NT_SUCCESS(Status))
711       {
712          ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
713          Dest->Buffer = NULL;
714          return Status;
715       }
716 
717       /* Make sure the string is null-terminated */
718       Src = (PWSTR)((PBYTE)Dest->Buffer + Dest->Length);
719       *Src = L'\0';
720 
721       return STATUS_SUCCESS;
722    }
723 
724    /* String is empty */
725    return STATUS_SUCCESS;
726 }
727 
728 void UserDbgAssertThreadInfo(BOOL showCaller)
729 {
730     PTEB Teb;
731     PPROCESSINFO ppi;
732     PCLIENTINFO pci;
733     PTHREADINFO pti;
734 
735     ppi = PsGetCurrentProcessWin32Process();
736     pti = PsGetCurrentThreadWin32Thread();
737     Teb = NtCurrentTeb();
738     pci = GetWin32ClientInfo();
739 
740     ASSERT(Teb);
741     ASSERT(pti);
742     ASSERT(pti->ppi == ppi);
743     ASSERT(pti->pClientInfo == pci);
744     ASSERT(Teb->Win32ThreadInfo == pti);
745     ASSERT(pci->ppi == ppi);
746     ASSERT(pci->fsHooks == pti->fsHooks);
747     ASSERT(pci->ulClientDelta == DesktopHeapGetUserDelta());
748     if (pti->pcti && pci->pDeskInfo)
749         ASSERT(pci->pClientThreadInfo == (PVOID)((ULONG_PTR)pti->pcti - pci->ulClientDelta));
750     if (pti->KeyboardLayout)
751         ASSERT(pci->hKL == pti->KeyboardLayout->hkl);
752     if(pti->rpdesk != NULL)
753         ASSERT(pti->pDeskInfo == pti->rpdesk->pDeskInfo);
754 
755     /*too bad we still get this assertion*/
756 
757     // Why? Not all flags are passed to the user and doing so could crash the system........
758 
759     /* ASSERT(pci->dwTIFlags == pti->TIF_flags); */
760 /*    if(pci->dwTIFlags != pti->TIF_flags)
761     {
762         ERR("pci->dwTIFlags(0x%x) doesn't match pti->TIF_flags(0x%x)\n", pci->dwTIFlags, pti->TIF_flags);
763         if(showCaller)
764         {
765             DbgPrint("Caller:\n");
766             KeRosDumpStackFrames(NULL, 10);
767         }
768         pci->dwTIFlags = pti->TIF_flags;
769     }
770 */
771 }
772 
773 void
774 NTAPI
775 UserDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
776 {
777     UserDbgAssertThreadInfo(FALSE);
778 }
779 
780 ULONG_PTR
781 NTAPI
782 UserDbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
783 {
784     /* Make sure that the first syscall is NtUserInitialize */
785     /* too bad this fails */
786     // ASSERT(gpepCSRSS);
787 
788     UserDbgAssertThreadInfo(TRUE);
789 
790     return ulResult;
791 }
792 
793 
794 PPROCESSINFO
795 GetW32ProcessInfo(VOID)
796 {
797     return (PPROCESSINFO)PsGetCurrentProcessWin32Process();
798 }
799 
800 PTHREADINFO
801 GetW32ThreadInfo(VOID)
802 {
803     UserDbgAssertThreadInfo(TRUE);
804     return (PTHREADINFO)PsGetCurrentThreadWin32Thread();
805 }
806 
807 
808 NTSTATUS
809 GetProcessLuid(
810     IN PETHREAD Thread OPTIONAL,
811     IN PEPROCESS Process OPTIONAL,
812     OUT PLUID Luid)
813 {
814     NTSTATUS Status;
815     PACCESS_TOKEN Token = NULL;
816     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
817     BOOLEAN CopyOnOpen, EffectiveOnly;
818 
819     if (Thread && Process)
820         return STATUS_INVALID_PARAMETER;
821 
822     /* If nothing has been specified, use the current thread */
823     if (!Thread && !Process)
824         Thread = PsGetCurrentThread();
825 
826     if (Thread)
827     {
828         /* Use a thread token */
829         ASSERT(!Process);
830         Token = PsReferenceImpersonationToken(Thread,
831                                               &CopyOnOpen,
832                                               &EffectiveOnly,
833                                               &ImpersonationLevel);
834 
835         /* If we don't have a thread token, use a process token */
836         if (!Token)
837             Process = PsGetThreadProcess(Thread);
838     }
839     if (!Token && Process)
840     {
841         /* Use a process token */
842         Token = PsReferencePrimaryToken(Process);
843 
844         /* If we don't have a token, fail */
845         if (!Token)
846             return STATUS_NO_TOKEN;
847     }
848     ASSERT(Token);
849 
850     /* Query the LUID */
851     Status = SeQueryAuthenticationIdToken(Token, Luid);
852 
853     /* Get rid of the token and return */
854     ObDereferenceObject(Token);
855     return Status;
856 }
857 
858 /* EOF */
859