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
);
13 * Test the Thread to verify and validate it. Hard to the core tests are required.
22 Status
= PsLookupThreadByThreadId(id
, &Thread
);
23 if (!NT_SUCCESS(Status
))
27 if (PsIsThreadTerminating(Thread
))
29 ObDereferenceObject(Thread
);
32 pti
= PsGetThreadWin32Thread(Thread
);
35 ObDereferenceObject(Thread
);
38 // Validate and verify!
41 if (pti
->TIF_flags
& TIF_INCLEANUP
) pti
= NULL
;
42 if (pti
&& !(pti
->TIF_flags
& TIF_GUITHREADINITIALIZED
)) pti
= NULL
;
43 if (PsGetThreadId(Thread
) != id
) pti
= NULL
;
45 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
50 ObDereferenceObject(Thread
);
56 UserGetLanguageID(VOID
)
59 OBJECT_ATTRIBUTES ObAttr
;
60 // http://support.microsoft.com/kb/324097
61 ULONG Ret
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
62 PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo
;
63 ULONG Size
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + MAX_PATH
*sizeof(WCHAR
);
64 UNICODE_STRING Language
;
66 RtlInitUnicodeString( &Language
,
67 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language");
69 InitializeObjectAttributes( &ObAttr
,
71 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
75 if ( NT_SUCCESS(ZwOpenKey(&KeyHandle
, KEY_READ
, &ObAttr
)))
77 pKeyInfo
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_STRING
);
80 RtlInitUnicodeString(&Language
, L
"Default");
82 if ( NT_SUCCESS(ZwQueryValueKey( KeyHandle
,
84 KeyValuePartialInformation
,
89 RtlInitUnicodeString(&Language
, (PWSTR
)pKeyInfo
->Data
);
90 if (!NT_SUCCESS(RtlUnicodeStringToInteger(&Language
, 16, &Ret
)))
92 Ret
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
95 ExFreePoolWithTag(pKeyInfo
, TAG_STRING
);
99 TRACE("Language ID = %x\n",Ret
);
113 if (!pwndParent
) pwndParent
= pwnd
;
115 if ( pwndParent
->head
.pti
->ppi
!= PsGetCurrentProcessWin32Process())
117 return (HBRUSH
)IntDefWindowProc( pwndParent
, CtlMsg
, (WPARAM
)hdc
, (LPARAM
)UserHMGetHandle(pwnd
), FALSE
);
120 hBrush
= (HBRUSH
)co_IntSendMessage( UserHMGetHandle(pwndParent
), CtlMsg
, (WPARAM
)hdc
, (LPARAM
)UserHMGetHandle(pwnd
));
122 if (!hBrush
|| !GreIsHandleValid(hBrush
))
124 hBrush
= (HBRUSH
)IntDefWindowProc( pwndParent
, CtlMsg
, (WPARAM
)hdc
, (LPARAM
)UserHMGetHandle(pwnd
), FALSE
);
136 PWND pwndParent
= IntGetParent(pwnd
);
137 return GetControlColor( pwndParent
, pwnd
, hdc
, ctlType
);
142 NtUserGetControlBrush(
148 HBRUSH hBrush
= NULL
;
150 UserEnterExclusive();
151 if ( (pwnd
= UserGetWindowObject(hwnd
)) &&
152 ((ctlType
- WM_CTLCOLORMSGBOX
) < CTLCOLOR_MAX
) &&
155 hBrush
= GetControlBrush(pwnd
, hdc
, ctlType
);
162 * Called from PaintRect, works almost like wine PaintRect16 but returns hBrush.
166 NtUserGetControlColor(
170 UINT CtlMsg
) // Wine PaintRect: WM_CTLCOLORMSGBOX + hbrush
172 PWND pwnd
, pwndParent
= NULL
;
173 HBRUSH hBrush
= NULL
;
175 UserEnterExclusive();
176 if ( (pwnd
= UserGetWindowObject(hwnd
)) &&
177 ((CtlMsg
- WM_CTLCOLORMSGBOX
) < CTLCOLOR_MAX
) &&
180 if (hwndParent
) pwndParent
= UserGetWindowObject(hwndParent
);
181 hBrush
= GetControlColor( pwndParent
, pwnd
, hdc
, CtlMsg
);
191 NtUserGetThreadState(
196 TRACE("Enter NtUserGetThreadState\n");
197 if (Routine
!= THREADSTATE_GETTHREADINFO
)
203 UserEnterExclusive();
208 case THREADSTATE_GETTHREADINFO
:
211 case THREADSTATE_FOCUSWINDOW
:
212 ret
= (DWORD_PTR
)IntGetThreadFocusWindow();
214 case THREADSTATE_CAPTUREWINDOW
:
215 /* FIXME: Should use UserEnterShared */
216 ret
= (DWORD_PTR
)IntGetCapture();
218 case THREADSTATE_PROGMANWINDOW
:
219 ret
= (DWORD_PTR
)GetW32ThreadInfo()->pDeskInfo
->hProgmanWindow
;
221 case THREADSTATE_TASKMANWINDOW
:
222 ret
= (DWORD_PTR
)GetW32ThreadInfo()->pDeskInfo
->hTaskManWindow
;
224 case THREADSTATE_ACTIVEWINDOW
:
225 ret
= (DWORD_PTR
)UserGetActiveWindow();
227 case THREADSTATE_INSENDMESSAGE
:
229 PUSER_SENT_MESSAGE Message
=
230 ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->pusmCurrent
;
231 TRACE("THREADSTATE_INSENDMESSAGE\n");
236 if (Message
->ptiSender
)
240 if (Message
->CompletionCallback
)
241 ret
= ISMEX_CALLBACK
;
245 /* If ReplyMessage */
246 if (Message
->QS_Flags
& QS_SMRESULT
) ret
|= ISMEX_REPLIED
;
251 case THREADSTATE_GETMESSAGETIME
:
252 ret
= ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->timeLast
;
255 case THREADSTATE_UPTIMELASTREAD
:
258 LARGE_INTEGER LargeTickCount
;
259 pti
= PsGetCurrentThreadWin32Thread();
260 KeQueryTickCount(&LargeTickCount
);
261 pti
->timeLast
= LargeTickCount
.u
.LowPart
;
262 pti
->pcti
->tickLastMsgChecked
= LargeTickCount
.u
.LowPart
;
266 case THREADSTATE_GETINPUTSTATE
:
267 ret
= LOWORD(IntGetQueueStatus(QS_POSTMESSAGE
|QS_TIMER
|QS_PAINT
|QS_SENDMESSAGE
|QS_INPUT
)) & (QS_KEY
| QS_MOUSEBUTTON
);
270 case THREADSTATE_FOREGROUNDTHREAD
:
271 ret
= (gpqForeground
== GetW32ThreadInfo()->MessageQueue
);
273 case THREADSTATE_GETCURSOR
:
274 ret
= (DWORD_PTR
) (GetW32ThreadInfo()->MessageQueue
->CursorObject
?
275 UserHMGetHandle(GetW32ThreadInfo()->MessageQueue
->CursorObject
) : 0);
277 case THREADSTATE_GETMESSAGEEXTRAINFO
:
278 ret
= (DWORD_PTR
)MsqGetMessageExtraInfo();
282 TRACE("Leave NtUserGetThreadState, ret=%lu\n", ret
);
290 NtUserSetThreadState(
296 // Test the only flags user can change.
297 if (Set
& ~(QF_FF10STATUS
|QF_DIALOGACTIVE
|QF_TABSWITCHING
|QF_FMENUSTATUS
|QF_FMENUSTATUSBREAK
)) return 0;
298 if (Flags
& ~(QF_FF10STATUS
|QF_DIALOGACTIVE
|QF_TABSWITCHING
|QF_FMENUSTATUS
|QF_FMENUSTATUSBREAK
)) return 0;
299 UserEnterExclusive();
300 pti
= PsGetCurrentThreadWin32Thread();
301 if (pti
->MessageQueue
)
303 Ret
= pti
->MessageQueue
->QF_flags
; // Get the queue flags.
305 pti
->MessageQueue
->QF_flags
|= (Set
&Flags
); // Set the queue flags.
308 if (Flags
) pti
->MessageQueue
->QF_flags
&= ~Flags
; // Clr the queue flags.
317 NtUserGetDoubleClickTime(VOID
)
321 TRACE("Enter NtUserGetDoubleClickTime\n");
324 // FIXME: Check if this works on non-interactive winsta
325 Result
= gspv
.iDblClickTime
;
327 TRACE("Leave NtUserGetDoubleClickTime, ret=%u\n", Result
);
334 NtUserGetGUIThreadInfo(
335 DWORD idThread
, /* If NULL use foreground thread */
336 LPGUITHREADINFO lpgui
)
339 PTHRDCARETINFO CaretInfo
;
340 GUITHREADINFO SafeGui
;
342 PUSER_MESSAGE_QUEUE MsgQueue
;
343 PTHREADINFO W32Thread
;
344 PETHREAD Thread
= NULL
;
346 DECLARE_RETURN(BOOLEAN
);
348 TRACE("Enter NtUserGetGUIThreadInfo\n");
351 Status
= MmCopyFromCaller(&SafeGui
, lpgui
, sizeof(DWORD
));
352 if(!NT_SUCCESS(Status
))
354 SetLastNtError(Status
);
358 if(SafeGui
.cbSize
!= sizeof(GUITHREADINFO
))
360 EngSetLastError(ERROR_INVALID_PARAMETER
);
366 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)idThread
, &Thread
);
367 if(!NT_SUCCESS(Status
))
369 EngSetLastError(ERROR_ACCESS_DENIED
);
372 W32Thread
= (PTHREADINFO
)Thread
->Tcb
.Win32Thread
;
373 Desktop
= W32Thread
->rpdesk
;
375 if (!Thread
|| !Desktop
)
378 ObDereferenceObject(Thread
);
379 EngSetLastError(ERROR_ACCESS_DENIED
);
383 if ( W32Thread
->MessageQueue
)
384 MsgQueue
= W32Thread
->MessageQueue
;
387 if ( Desktop
) MsgQueue
= Desktop
->ActiveMessageQueue
;
391 { /* Get the foreground thread */
392 /* FIXME: Handle NULL queue properly? */
393 MsgQueue
= IntGetFocusMessageQueue();
396 EngSetLastError(ERROR_ACCESS_DENIED
);
401 CaretInfo
= &MsgQueue
->CaretInfo
;
403 SafeGui
.flags
= (CaretInfo
->Visible
? GUI_CARETBLINKING
: 0);
405 if (W32Thread->pMenuState->pGlobalPopupMenu)
407 SafeGui.flags |= GUI_INMENUMODE;
409 if (W32Thread->pMenuState->pGlobalPopupMenu->spwndNotify)
410 SafeGui.hwndMenuOwner = UserHMGetHandle(W32Thread->pMenuState->pGlobalPopupMenu->spwndNotify);
412 if (W32Thread->pMenuState->pGlobalPopupMenu->fHasMenuBar)
414 if (W32Thread->pMenuState->pGlobalPopupMenu->fIsSysMenu)
416 SafeGui.flags |= GUI_SYSTEMMENUMODE;
421 SafeGui.flags |= GUI_POPUPMENUMODE;
425 SafeGui
.hwndMenuOwner
= MsgQueue
->MenuOwner
;
427 if (MsgQueue
->MenuOwner
)
428 SafeGui
.flags
|= GUI_INMENUMODE
| MsgQueue
->MenuState
;
430 if (MsgQueue
->MoveSize
)
431 SafeGui
.flags
|= GUI_INMOVESIZE
;
433 /* FIXME: Add flag GUI_16BITTASK */
435 SafeGui
.hwndActive
= MsgQueue
->spwndActive
? UserHMGetHandle(MsgQueue
->spwndActive
) : 0;
436 SafeGui
.hwndFocus
= MsgQueue
->spwndFocus
? UserHMGetHandle(MsgQueue
->spwndFocus
) : 0;
437 SafeGui
.hwndCapture
= MsgQueue
->spwndCapture
? UserHMGetHandle(MsgQueue
->spwndCapture
) : 0;
438 SafeGui
.hwndMoveSize
= MsgQueue
->MoveSize
;
439 SafeGui
.hwndCaret
= CaretInfo
->hWnd
;
441 SafeGui
.rcCaret
.left
= CaretInfo
->Pos
.x
;
442 SafeGui
.rcCaret
.top
= CaretInfo
->Pos
.y
;
443 SafeGui
.rcCaret
.right
= SafeGui
.rcCaret
.left
+ CaretInfo
->Size
.cx
;
444 SafeGui
.rcCaret
.bottom
= SafeGui
.rcCaret
.top
+ CaretInfo
->Size
.cy
;
447 ObDereferenceObject(Thread
);
449 Status
= MmCopyToCaller(lpgui
, &SafeGui
, sizeof(GUITHREADINFO
));
450 if(!NT_SUCCESS(Status
))
452 SetLastNtError(Status
);
459 TRACE("Leave NtUserGetGUIThreadInfo, ret=%u\n",_ret_
);
467 NtUserGetGuiResources(
472 PPROCESSINFO W32Process
;
475 DECLARE_RETURN(DWORD
);
477 TRACE("Enter NtUserGetGuiResources\n");
480 Status
= ObReferenceObjectByHandle(hProcess
,
481 PROCESS_QUERY_INFORMATION
,
487 if(!NT_SUCCESS(Status
))
489 SetLastNtError(Status
);
493 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
496 ObDereferenceObject(Process
);
497 EngSetLastError(ERROR_INVALID_PARAMETER
);
505 Ret
= (DWORD
)W32Process
->GDIHandleCount
;
510 Ret
= (DWORD
)W32Process
->UserHandleCount
;
515 EngSetLastError(ERROR_INVALID_PARAMETER
);
520 ObDereferenceObject(Process
);
525 TRACE("Leave NtUserGetGuiResources, ret=%lu\n",_ret_
);
531 IntSetWindowState(PWND pWnd
, UINT Flag
)
534 if (gptiCurrent
->ppi
!= pWnd
->head
.pti
->ppi
) return;
535 bit
= 1 << LOWORD(Flag
);
536 TRACE("SWS %x\n",bit
);
546 pWnd
->ExStyle2
|= bit
;
552 IntClearWindowState(PWND pWnd
, UINT Flag
)
555 if (gptiCurrent
->ppi
!= pWnd
->head
.pti
->ppi
) return;
556 bit
= 1 << LOWORD(Flag
);
557 TRACE("CWS %x\n",bit
);
564 pWnd
->state2
&= ~bit
;
567 pWnd
->ExStyle2
&= ~bit
;
573 IntSafeCopyUnicodeString(PUNICODE_STRING Dest
,
574 PUNICODE_STRING Source
)
579 Status
= MmCopyFromCaller(Dest
, Source
, sizeof(UNICODE_STRING
));
580 if(!NT_SUCCESS(Status
))
585 if(Dest
->Length
> 0x4000)
587 return STATUS_UNSUCCESSFUL
;
592 Dest
->MaximumLength
= Dest
->Length
;
594 if(Dest
->Length
> 0 && Src
)
596 Dest
->Buffer
= ExAllocatePoolWithTag(PagedPool
, Dest
->MaximumLength
, TAG_STRING
);
599 return STATUS_NO_MEMORY
;
602 Status
= MmCopyFromCaller(Dest
->Buffer
, Src
, Dest
->Length
);
603 if(!NT_SUCCESS(Status
))
605 ExFreePoolWithTag(Dest
->Buffer
, TAG_STRING
);
611 return STATUS_SUCCESS
;
614 /* String is empty */
615 return STATUS_SUCCESS
;
619 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest
,
620 PUNICODE_STRING Source
)
625 Status
= MmCopyFromCaller(Dest
, Source
, sizeof(UNICODE_STRING
));
626 if(!NT_SUCCESS(Status
))
631 if(Dest
->Length
> 0x4000)
633 return STATUS_UNSUCCESSFUL
;
638 Dest
->MaximumLength
= 0;
640 if(Dest
->Length
> 0 && Src
)
642 Dest
->MaximumLength
= Dest
->Length
+ sizeof(WCHAR
);
643 Dest
->Buffer
= ExAllocatePoolWithTag(PagedPool
, Dest
->MaximumLength
, TAG_STRING
);
646 return STATUS_NO_MEMORY
;
649 Status
= MmCopyFromCaller(Dest
->Buffer
, Src
, Dest
->Length
);
650 if(!NT_SUCCESS(Status
))
652 ExFreePoolWithTag(Dest
->Buffer
, TAG_STRING
);
657 /* Make sure the string is null-terminated */
658 Src
= (PWSTR
)((PBYTE
)Dest
->Buffer
+ Dest
->Length
);
661 return STATUS_SUCCESS
;
664 /* String is empty */
665 return STATUS_SUCCESS
;
668 void UserDbgAssertThreadInfo(BOOL showCaller
)
675 ppi
= PsGetCurrentProcessWin32Process();
676 pti
= PsGetCurrentThreadWin32Thread();
677 Teb
= NtCurrentTeb();
678 pci
= GetWin32ClientInfo();
682 ASSERT(pti
->ppi
== ppi
);
683 ASSERT(pti
->pClientInfo
== pci
);
684 ASSERT(Teb
->Win32ThreadInfo
== pti
);
685 ASSERT(pci
->ppi
== ppi
);
686 ASSERT(pci
->fsHooks
== pti
->fsHooks
);
687 ASSERT(pci
->ulClientDelta
== DesktopHeapGetUserDelta());
688 if (pti
->pcti
&& pci
->pDeskInfo
)
689 ASSERT(pci
->pClientThreadInfo
== (PVOID
)((ULONG_PTR
)pti
->pcti
- pci
->ulClientDelta
));
690 if (pti
->pcti
&& IsListEmpty(&pti
->SentMessagesListHead
))
691 ASSERT((pti
->pcti
->fsChangeBits
& QS_SENDMESSAGE
) == 0);
692 if (pti
->KeyboardLayout
)
693 ASSERT(pci
->hKL
== pti
->KeyboardLayout
->hkl
);
694 if(pti
->rpdesk
!= NULL
)
695 ASSERT(pti
->pDeskInfo
== pti
->rpdesk
->pDeskInfo
);
697 /*too bad we still get this assertion*/
699 // Why? Not all flags are passed to the user and doing so could crash the system........
701 /* ASSERT(pci->dwTIFlags == pti->TIF_flags); */
702 /* if(pci->dwTIFlags != pti->TIF_flags)
704 ERR("pci->dwTIFlags(0x%x) doesn't match pti->TIF_flags(0x%x)\n", pci->dwTIFlags, pti->TIF_flags);
707 DbgPrint("Caller:\n");
708 KeRosDumpStackFrames(NULL, 10);
710 pci->dwTIFlags = pti->TIF_flags;
717 UserDbgPreServiceHook(ULONG ulSyscallId
, PULONG_PTR pulArguments
)
719 UserDbgAssertThreadInfo(FALSE
);
724 UserDbgPostServiceHook(ULONG ulSyscallId
, ULONG_PTR ulResult
)
726 /* Make sure that the first syscall is NtUserInitialize */
727 /* too bad this fails */
728 // ASSERT(gpepCSRSS);
730 UserDbgAssertThreadInfo(TRUE
);
737 GetW32ProcessInfo(VOID
)
739 return (PPROCESSINFO
)PsGetCurrentProcessWin32Process();
743 GetW32ThreadInfo(VOID
)
745 UserDbgAssertThreadInfo(TRUE
);
746 return (PTHREADINFO
)PsGetCurrentThreadWin32Thread();