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)
10 DBG_DEFAULT_CHANNEL(UserMisc
);
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 .
22 const wchar_t *format
,
28 va_start(args
, format
);
29 len
= _vscwprintf(format
, args
);
37 * Test the Thread to verify and validate it. Hard to the core tests are required.
46 Status
= PsLookupThreadByThreadId(id
, &Thread
);
47 if (!NT_SUCCESS(Status
))
51 if (PsIsThreadTerminating(Thread
))
53 ObDereferenceObject(Thread
);
56 pti
= PsGetThreadWin32Thread(Thread
);
59 ObDereferenceObject(Thread
);
62 // Validate and verify!
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
;
69 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
74 ObDereferenceObject(Thread
);
80 UserGetLanguageToggle(VOID
)
85 Status
= RegReadUserSetting(L
"Keyboard Layout\\Toggle", L
"Layout Hotkey", REG_SZ
, &dwValue
, sizeof(dwValue
));
86 if (NT_SUCCESS(Status
))
88 dwValue
= atoi((char *)&dwValue
);
89 TRACE("Layout Hotkey %d\n",dwValue
);
96 UserGetLanguageID(VOID
)
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
;
106 RtlInitUnicodeString( &Language
,
107 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language");
109 InitializeObjectAttributes( &ObAttr
,
111 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
115 if ( NT_SUCCESS(ZwOpenKey(&KeyHandle
, KEY_READ
, &ObAttr
)))
117 pKeyInfo
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_STRING
);
120 RtlInitUnicodeString(&Language
, L
"Default");
122 if ( NT_SUCCESS(ZwQueryValueKey( KeyHandle
,
124 KeyValuePartialInformation
,
129 RtlInitUnicodeString(&Language
, (PWSTR
)pKeyInfo
->Data
);
130 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&Language
, 16, &Ret
)))
132 Ret
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
135 ExFreePoolWithTag(pKeyInfo
, TAG_STRING
);
139 TRACE("Language ID = %x\n",Ret
);
153 if (!pwndParent
) pwndParent
= pwnd
;
155 if ( pwndParent
->head
.pti
->ppi
!= PsGetCurrentProcessWin32Process())
157 return (HBRUSH
)IntDefWindowProc( pwndParent
, CtlMsg
, (WPARAM
)hdc
, (LPARAM
)UserHMGetHandle(pwnd
), FALSE
);
160 hBrush
= (HBRUSH
)co_IntSendMessage( UserHMGetHandle(pwndParent
), CtlMsg
, (WPARAM
)hdc
, (LPARAM
)UserHMGetHandle(pwnd
));
162 if (!hBrush
|| !GreIsHandleValid(hBrush
))
164 hBrush
= (HBRUSH
)IntDefWindowProc( pwndParent
, CtlMsg
, (WPARAM
)hdc
, (LPARAM
)UserHMGetHandle(pwnd
), FALSE
);
176 PWND pwndParent
= IntGetParent(pwnd
);
177 return GetControlColor( pwndParent
, pwnd
, hdc
, ctlType
);
182 NtUserGetControlBrush(
188 HBRUSH hBrush
= NULL
;
190 UserEnterExclusive();
191 if ( (pwnd
= UserGetWindowObject(hwnd
)) &&
192 ((ctlType
- WM_CTLCOLORMSGBOX
) < CTLCOLOR_MAX
) &&
195 hBrush
= GetControlBrush(pwnd
, hdc
, ctlType
);
202 * Called from PaintRect, works almost like wine PaintRect16 but returns hBrush.
206 NtUserGetControlColor(
210 UINT CtlMsg
) // Wine PaintRect: WM_CTLCOLORMSGBOX + hbrush
212 PWND pwnd
, pwndParent
= NULL
;
213 HBRUSH hBrush
= NULL
;
215 UserEnterExclusive();
216 if ( (pwnd
= UserGetWindowObject(hwnd
)) &&
217 ((CtlMsg
- WM_CTLCOLORMSGBOX
) < CTLCOLOR_MAX
) &&
220 if (hwndParent
) pwndParent
= UserGetWindowObject(hwndParent
);
221 hBrush
= GetControlColor( pwndParent
, pwnd
, hdc
, CtlMsg
);
231 NtUserGetThreadState(
236 TRACE("Enter NtUserGetThreadState\n");
237 if (Routine
!= THREADSTATE_GETTHREADINFO
)
243 UserEnterExclusive();
248 case THREADSTATE_GETTHREADINFO
:
251 case THREADSTATE_FOCUSWINDOW
:
252 ret
= (DWORD_PTR
)IntGetThreadFocusWindow();
254 case THREADSTATE_CAPTUREWINDOW
:
255 /* FIXME: Should use UserEnterShared */
256 ret
= (DWORD_PTR
)IntGetCapture();
258 case THREADSTATE_PROGMANWINDOW
:
259 ret
= (DWORD_PTR
)GetW32ThreadInfo()->pDeskInfo
->hProgmanWindow
;
261 case THREADSTATE_TASKMANWINDOW
:
262 ret
= (DWORD_PTR
)GetW32ThreadInfo()->pDeskInfo
->hTaskManWindow
;
264 case THREADSTATE_ACTIVEWINDOW
:
265 ret
= (DWORD_PTR
)UserGetActiveWindow();
267 case THREADSTATE_INSENDMESSAGE
:
269 PUSER_SENT_MESSAGE Message
=
270 ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->pusmCurrent
;
271 TRACE("THREADSTATE_INSENDMESSAGE\n");
276 if (Message
->ptiSender
)
280 if (Message
->CompletionCallback
)
281 ret
= ISMEX_CALLBACK
;
285 /* If ReplyMessage */
286 if (Message
->QS_Flags
& QS_SMRESULT
) ret
|= ISMEX_REPLIED
;
291 case THREADSTATE_GETMESSAGETIME
:
292 ret
= ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->timeLast
;
295 case THREADSTATE_UPTIMELASTREAD
:
298 LARGE_INTEGER LargeTickCount
;
299 pti
= PsGetCurrentThreadWin32Thread();
300 KeQueryTickCount(&LargeTickCount
);
301 pti
->timeLast
= LargeTickCount
.u
.LowPart
;
302 pti
->pcti
->tickLastMsgChecked
= LargeTickCount
.u
.LowPart
;
306 case THREADSTATE_GETINPUTSTATE
:
307 ret
= LOWORD(IntGetQueueStatus(QS_POSTMESSAGE
|QS_TIMER
|QS_PAINT
|QS_SENDMESSAGE
|QS_INPUT
)) & (QS_KEY
| QS_MOUSEBUTTON
);
310 case THREADSTATE_FOREGROUNDTHREAD
:
311 ret
= (gpqForeground
== GetW32ThreadInfo()->MessageQueue
);
313 case THREADSTATE_GETCURSOR
:
314 ret
= (DWORD_PTR
) (GetW32ThreadInfo()->MessageQueue
->CursorObject
?
315 UserHMGetHandle(GetW32ThreadInfo()->MessageQueue
->CursorObject
) : 0);
317 case THREADSTATE_GETMESSAGEEXTRAINFO
:
318 ret
= (DWORD_PTR
)MsqGetMessageExtraInfo();
322 TRACE("Leave NtUserGetThreadState, ret=%lu\n", ret
);
330 NtUserSetThreadState(
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
)
343 Ret
= pti
->MessageQueue
->QF_flags
; // Get the queue flags.
345 pti
->MessageQueue
->QF_flags
|= (Set
&Flags
); // Set the queue flags.
348 if (Flags
) pti
->MessageQueue
->QF_flags
&= ~Flags
; // Clr the queue flags.
357 NtUserGetDoubleClickTime(VOID
)
361 TRACE("Enter NtUserGetDoubleClickTime\n");
364 // FIXME: Check if this works on non-interactive winsta
365 Result
= gspv
.iDblClickTime
;
367 TRACE("Leave NtUserGetDoubleClickTime, ret=%u\n", Result
);
374 NtUserGetGUIThreadInfo(
375 DWORD idThread
, /* If NULL use foreground thread */
376 LPGUITHREADINFO lpgui
)
379 PTHRDCARETINFO CaretInfo
;
380 GUITHREADINFO SafeGui
;
382 PUSER_MESSAGE_QUEUE MsgQueue
;
383 PTHREADINFO W32Thread
;
384 PETHREAD Thread
= NULL
;
386 DECLARE_RETURN(BOOLEAN
);
388 TRACE("Enter NtUserGetGUIThreadInfo\n");
391 Status
= MmCopyFromCaller(&SafeGui
, lpgui
, sizeof(DWORD
));
392 if(!NT_SUCCESS(Status
))
394 SetLastNtError(Status
);
398 if(SafeGui
.cbSize
!= sizeof(GUITHREADINFO
))
400 EngSetLastError(ERROR_INVALID_PARAMETER
);
406 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)idThread
, &Thread
);
407 if(!NT_SUCCESS(Status
))
409 EngSetLastError(ERROR_ACCESS_DENIED
);
412 W32Thread
= (PTHREADINFO
)Thread
->Tcb
.Win32Thread
;
413 Desktop
= W32Thread
->rpdesk
;
415 if (!Thread
|| !Desktop
)
418 ObDereferenceObject(Thread
);
419 EngSetLastError(ERROR_ACCESS_DENIED
);
423 if ( W32Thread
->MessageQueue
)
424 MsgQueue
= W32Thread
->MessageQueue
;
427 if ( Desktop
) MsgQueue
= Desktop
->ActiveMessageQueue
;
431 { /* Get the foreground thread */
432 /* FIXME: Handle NULL queue properly? */
433 MsgQueue
= IntGetFocusMessageQueue();
436 EngSetLastError(ERROR_ACCESS_DENIED
);
441 CaretInfo
= &MsgQueue
->CaretInfo
;
443 SafeGui
.flags
= (CaretInfo
->Visible
? GUI_CARETBLINKING
: 0);
445 if (W32Thread->pMenuState->pGlobalPopupMenu)
447 SafeGui.flags |= GUI_INMENUMODE;
449 if (W32Thread->pMenuState->pGlobalPopupMenu->spwndNotify)
450 SafeGui.hwndMenuOwner = UserHMGetHandle(W32Thread->pMenuState->pGlobalPopupMenu->spwndNotify);
452 if (W32Thread->pMenuState->pGlobalPopupMenu->fHasMenuBar)
454 if (W32Thread->pMenuState->pGlobalPopupMenu->fIsSysMenu)
456 SafeGui.flags |= GUI_SYSTEMMENUMODE;
461 SafeGui.flags |= GUI_POPUPMENUMODE;
465 SafeGui
.hwndMenuOwner
= MsgQueue
->MenuOwner
;
467 if (MsgQueue
->MenuOwner
)
468 SafeGui
.flags
|= GUI_INMENUMODE
| MsgQueue
->MenuState
;
470 if (MsgQueue
->MoveSize
)
471 SafeGui
.flags
|= GUI_INMOVESIZE
;
473 /* FIXME: Add flag GUI_16BITTASK */
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
;
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
;
487 ObDereferenceObject(Thread
);
489 Status
= MmCopyToCaller(lpgui
, &SafeGui
, sizeof(GUITHREADINFO
));
490 if(!NT_SUCCESS(Status
))
492 SetLastNtError(Status
);
499 TRACE("Leave NtUserGetGUIThreadInfo, ret=%u\n",_ret_
);
507 NtUserGetGuiResources(
512 PPROCESSINFO W32Process
;
515 DECLARE_RETURN(DWORD
);
517 TRACE("Enter NtUserGetGuiResources\n");
520 Status
= ObReferenceObjectByHandle(hProcess
,
521 PROCESS_QUERY_INFORMATION
,
527 if(!NT_SUCCESS(Status
))
529 SetLastNtError(Status
);
533 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
536 ObDereferenceObject(Process
);
537 EngSetLastError(ERROR_INVALID_PARAMETER
);
545 Ret
= (DWORD
)W32Process
->GDIHandleCount
;
550 Ret
= (DWORD
)W32Process
->UserHandleCount
;
555 EngSetLastError(ERROR_INVALID_PARAMETER
);
560 ObDereferenceObject(Process
);
565 TRACE("Leave NtUserGetGuiResources, ret=%lu\n",_ret_
);
571 IntSetWindowState(PWND pWnd
, UINT Flag
)
574 if (gptiCurrent
->ppi
!= pWnd
->head
.pti
->ppi
) return;
575 bit
= 1 << LOWORD(Flag
);
576 TRACE("SWS %x\n",bit
);
586 pWnd
->ExStyle2
|= bit
;
592 IntClearWindowState(PWND pWnd
, UINT Flag
)
595 if (gptiCurrent
->ppi
!= pWnd
->head
.pti
->ppi
) return;
596 bit
= 1 << LOWORD(Flag
);
597 TRACE("CWS %x\n",bit
);
604 pWnd
->state2
&= ~bit
;
607 pWnd
->ExStyle2
&= ~bit
;
613 IntSafeCopyUnicodeString(PUNICODE_STRING Dest
,
614 PUNICODE_STRING Source
)
619 Status
= MmCopyFromCaller(Dest
, Source
, sizeof(UNICODE_STRING
));
620 if(!NT_SUCCESS(Status
))
625 if(Dest
->Length
> 0x4000)
627 return STATUS_UNSUCCESSFUL
;
632 Dest
->MaximumLength
= Dest
->Length
;
634 if(Dest
->Length
> 0 && Src
)
636 Dest
->Buffer
= ExAllocatePoolWithTag(PagedPool
, Dest
->MaximumLength
, TAG_STRING
);
639 return STATUS_NO_MEMORY
;
642 Status
= MmCopyFromCaller(Dest
->Buffer
, Src
, Dest
->Length
);
643 if(!NT_SUCCESS(Status
))
645 ExFreePoolWithTag(Dest
->Buffer
, TAG_STRING
);
651 return STATUS_SUCCESS
;
654 /* String is empty */
655 return STATUS_SUCCESS
;
659 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest
,
660 PUNICODE_STRING Source
)
665 Status
= MmCopyFromCaller(Dest
, Source
, sizeof(UNICODE_STRING
));
666 if(!NT_SUCCESS(Status
))
671 if(Dest
->Length
> 0x4000)
673 return STATUS_UNSUCCESSFUL
;
678 Dest
->MaximumLength
= 0;
680 if(Dest
->Length
> 0 && Src
)
682 Dest
->MaximumLength
= Dest
->Length
+ sizeof(WCHAR
);
683 Dest
->Buffer
= ExAllocatePoolWithTag(PagedPool
, Dest
->MaximumLength
, TAG_STRING
);
686 return STATUS_NO_MEMORY
;
689 Status
= MmCopyFromCaller(Dest
->Buffer
, Src
, Dest
->Length
);
690 if(!NT_SUCCESS(Status
))
692 ExFreePoolWithTag(Dest
->Buffer
, TAG_STRING
);
697 /* Make sure the string is null-terminated */
698 Src
= (PWSTR
)((PBYTE
)Dest
->Buffer
+ Dest
->Length
);
701 return STATUS_SUCCESS
;
704 /* String is empty */
705 return STATUS_SUCCESS
;
708 void UserDbgAssertThreadInfo(BOOL showCaller
)
715 ppi
= PsGetCurrentProcessWin32Process();
716 pti
= PsGetCurrentThreadWin32Thread();
717 Teb
= NtCurrentTeb();
718 pci
= GetWin32ClientInfo();
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
);
737 /*too bad we still get this assertion*/
739 // Why? Not all flags are passed to the user and doing so could crash the system........
741 /* ASSERT(pci->dwTIFlags == pti->TIF_flags); */
742 /* if(pci->dwTIFlags != pti->TIF_flags)
744 ERR("pci->dwTIFlags(0x%x) doesn't match pti->TIF_flags(0x%x)\n", pci->dwTIFlags, pti->TIF_flags);
747 DbgPrint("Caller:\n");
748 KeRosDumpStackFrames(NULL, 10);
750 pci->dwTIFlags = pti->TIF_flags;
757 UserDbgPreServiceHook(ULONG ulSyscallId
, PULONG_PTR pulArguments
)
759 UserDbgAssertThreadInfo(FALSE
);
764 UserDbgPostServiceHook(ULONG ulSyscallId
, ULONG_PTR ulResult
)
766 /* Make sure that the first syscall is NtUserInitialize */
767 /* too bad this fails */
768 // ASSERT(gpepCSRSS);
770 UserDbgAssertThreadInfo(TRUE
);
777 GetW32ProcessInfo(VOID
)
779 return (PPROCESSINFO
)PsGetCurrentProcessWin32Process();
783 GetW32ThreadInfo(VOID
)
785 UserDbgAssertThreadInfo(TRUE
);
786 return (PTHREADINFO
)PsGetCurrentThreadWin32Thread();
792 IN PETHREAD Thread OPTIONAL
,
793 IN PEPROCESS Process OPTIONAL
,
797 PACCESS_TOKEN Token
= NULL
;
798 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
799 BOOLEAN CopyOnOpen
, EffectiveOnly
;
801 if (Thread
&& Process
)
802 return STATUS_INVALID_PARAMETER
;
804 /* If nothing has been specified, use the current thread */
805 if (!Thread
&& !Process
)
806 Thread
= PsGetCurrentThread();
810 /* Use a thread token */
812 Token
= PsReferenceImpersonationToken(Thread
,
815 &ImpersonationLevel
);
817 /* If we don't have a thread token, use a process token */
819 Process
= PsGetThreadProcess(Thread
);
821 if (!Token
&& Process
)
823 /* Use a process token */
824 Token
= PsReferencePrimaryToken(Process
);
826 /* If we don't have a token, fail */
828 return STATUS_NO_TOKEN
;
833 Status
= SeQueryAuthenticationIdToken(Token
, Luid
);
835 /* Get rid of the token and return */
836 ObDereferenceObject(Token
);