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