/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Win32k subsystem * PURPOSE: Miscellaneous User functions * FILE: subsystems/win32/win32k/ntuser/misc.c * PROGRAMER: Ge van Geldorp (ge@gse.nl) */ #include DBG_DEFAULT_CHANNEL(UserMisc); SHORT FASTCALL UserGetLanguageID(VOID) { HANDLE KeyHandle; OBJECT_ATTRIBUTES ObAttr; // http://support.microsoft.com/kb/324097 ULONG Ret = 0x409; // English PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo; ULONG Size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH*sizeof(WCHAR); UNICODE_STRING Language; RtlInitUnicodeString( &Language, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language"); InitializeObjectAttributes( &ObAttr, &Language, OBJ_CASE_INSENSITIVE, NULL, NULL); if ( NT_SUCCESS(ZwOpenKey(&KeyHandle, KEY_READ, &ObAttr))) { pKeyInfo = ExAllocatePoolWithTag(PagedPool, Size, TAG_STRING); if ( pKeyInfo ) { RtlInitUnicodeString(&Language, L"Default"); if ( NT_SUCCESS(ZwQueryValueKey( KeyHandle, &Language, KeyValuePartialInformation, pKeyInfo, Size, &Size)) ) { RtlInitUnicodeString(&Language, (PWSTR)pKeyInfo->Data); RtlUnicodeStringToInteger(&Language, 16, &Ret); } ExFreePoolWithTag(pKeyInfo, TAG_STRING); } ZwClose(KeyHandle); } TRACE("Language ID = %x\n",Ret); return (SHORT) Ret; } HBRUSH FASTCALL GetControlColor( PWND pwndParent, PWND pwnd, HDC hdc, UINT CtlMsg) { HBRUSH hBrush; if (!pwndParent) pwndParent = pwnd; if ( pwndParent->head.pti->ppi != PsGetCurrentProcessWin32Process()) { return (HBRUSH)IntDefWindowProc( pwndParent, CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd), FALSE); } hBrush = (HBRUSH)co_IntSendMessage( UserHMGetHandle(pwndParent), CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd)); if (!hBrush || !GreIsHandleValid(hBrush)) { hBrush = (HBRUSH)IntDefWindowProc( pwndParent, CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd), FALSE); } return hBrush; } HBRUSH FASTCALL GetControlBrush( PWND pwnd, HDC hdc, UINT ctlType) { PWND pwndParent = IntGetParent(pwnd); return GetControlColor( pwndParent, pwnd, hdc, ctlType); } HBRUSH APIENTRY NtUserGetControlBrush( HWND hwnd, HDC hdc, UINT ctlType) { PWND pwnd; HBRUSH hBrush = NULL; UserEnterExclusive(); if ( (pwnd = UserGetWindowObject(hwnd)) && ((ctlType - WM_CTLCOLORMSGBOX) < CTLCOLOR_MAX) && hdc ) { hBrush = GetControlBrush(pwnd, hdc, ctlType); } UserLeave(); return hBrush; } /* * Called from PaintRect, works almost like wine PaintRect16 but returns hBrush. */ HBRUSH APIENTRY NtUserGetControlColor( HWND hwndParent, HWND hwnd, HDC hdc, UINT CtlMsg) // Wine PaintRect: WM_CTLCOLORMSGBOX + hbrush { PWND pwnd, pwndParent = NULL; HBRUSH hBrush = NULL; UserEnterExclusive(); if ( (pwnd = UserGetWindowObject(hwnd)) && ((CtlMsg - WM_CTLCOLORMSGBOX) < CTLCOLOR_MAX) && hdc ) { if (hwndParent) pwndParent = UserGetWindowObject(hwndParent); hBrush = GetControlColor( pwndParent, pwnd, hdc, CtlMsg); } UserLeave(); return hBrush; } /* * @unimplemented */ DWORD_PTR APIENTRY NtUserGetThreadState( DWORD Routine) { DWORD_PTR ret = 0; TRACE("Enter NtUserGetThreadState\n"); if (Routine != THREADSTATE_GETTHREADINFO) { UserEnterShared(); } else { UserEnterExclusive(); } switch (Routine) { case THREADSTATE_GETTHREADINFO: GetW32ThreadInfo(); break; case THREADSTATE_FOCUSWINDOW: ret = (DWORD_PTR)IntGetThreadFocusWindow(); break; case THREADSTATE_CAPTUREWINDOW: /* FIXME: Should use UserEnterShared */ ret = (DWORD_PTR)IntGetCapture(); break; case THREADSTATE_PROGMANWINDOW: ret = (DWORD_PTR)GetW32ThreadInfo()->pDeskInfo->hProgmanWindow; break; case THREADSTATE_TASKMANWINDOW: ret = (DWORD_PTR)GetW32ThreadInfo()->pDeskInfo->hTaskManWindow; break; case THREADSTATE_ACTIVEWINDOW: ret = (DWORD_PTR)UserGetActiveWindow(); break; case THREADSTATE_INSENDMESSAGE: { PUSER_SENT_MESSAGE Message = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->pusmCurrent; ERR("THREADSTATE_INSENDMESSAGE\n"); ret = ISMEX_NOSEND; if (Message) { if (Message->SenderQueue) ret = ISMEX_SEND; else { if (Message->CompletionCallback) ret = ISMEX_CALLBACK; else ret = ISMEX_NOTIFY; } /* If ReplyMessage */ if (Message->QS_Flags & QS_SMRESULT) ret |= ISMEX_REPLIED; } break; } case THREADSTATE_GETMESSAGETIME: ret = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->timeLast; break; case THREADSTATE_UPTIMELASTREAD: { PTHREADINFO pti; LARGE_INTEGER LargeTickCount; pti = PsGetCurrentThreadWin32Thread(); KeQueryTickCount(&LargeTickCount); pti->MessageQueue->LastMsgRead = LargeTickCount.u.LowPart; pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart; } break; case THREADSTATE_GETINPUTSTATE: ret = LOWORD(IntGetQueueStatus(QS_POSTMESSAGE|QS_TIMER|QS_PAINT|QS_SENDMESSAGE|QS_INPUT)) & (QS_KEY | QS_MOUSEBUTTON); break; case THREADSTATE_FOREGROUNDTHREAD: ret = (gpqForeground == GetW32ThreadInfo()->MessageQueue); break; case THREADSTATE_GETCURSOR: ret = (DWORD_PTR) (GetW32ThreadInfo()->MessageQueue->CursorObject ? UserHMGetHandle(GetW32ThreadInfo()->MessageQueue->CursorObject) : 0); break; } TRACE("Leave NtUserGetThreadState, ret=%i\n", ret); UserLeave(); return ret; } DWORD APIENTRY NtUserSetThreadState( DWORD Set, DWORD Flags) { PTHREADINFO pti; DWORD Ret = 0; // Test the only flags user can change. if (Set & ~(QF_FF10STATUS|QF_DIALOGACTIVE|QF_TABSWITCHING|QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) return 0; if (Flags & ~(QF_FF10STATUS|QF_DIALOGACTIVE|QF_TABSWITCHING|QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) return 0; UserEnterExclusive(); pti = PsGetCurrentThreadWin32Thread(); if (pti->MessageQueue) { Ret = pti->MessageQueue->QF_flags; // Get the queue flags. if (Set) pti->MessageQueue->QF_flags |= (Set&Flags); // Set the queue flags. else { if (Flags) pti->MessageQueue->QF_flags &= ~Flags; // Clr the queue flags. } } UserLeave(); return Ret; } UINT APIENTRY NtUserGetDoubleClickTime(VOID) { UINT Result; TRACE("Enter NtUserGetDoubleClickTime\n"); UserEnterShared(); // FIXME: Check if this works on non-interactive winsta Result = gspv.iDblClickTime; TRACE("Leave NtUserGetDoubleClickTime, ret=%i\n", Result); UserLeave(); return Result; } BOOL APIENTRY NtUserGetGUIThreadInfo( DWORD idThread, /* If NULL use foreground thread */ LPGUITHREADINFO lpgui) { NTSTATUS Status; PTHRDCARETINFO CaretInfo; GUITHREADINFO SafeGui; PDESKTOP Desktop; PUSER_MESSAGE_QUEUE MsgQueue; PTHREADINFO W32Thread; PETHREAD Thread = NULL; DECLARE_RETURN(BOOLEAN); TRACE("Enter NtUserGetGUIThreadInfo\n"); UserEnterShared(); Status = MmCopyFromCaller(&SafeGui, lpgui, sizeof(DWORD)); if(!NT_SUCCESS(Status)) { SetLastNtError(Status); RETURN( FALSE); } if(SafeGui.cbSize != sizeof(GUITHREADINFO)) { EngSetLastError(ERROR_INVALID_PARAMETER); RETURN( FALSE); } if (idThread) { Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread); if(!NT_SUCCESS(Status)) { EngSetLastError(ERROR_ACCESS_DENIED); RETURN( FALSE); } W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread; Desktop = W32Thread->rpdesk; } else { /* Get the foreground thread */ Thread = PsGetCurrentThread(); W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread; Desktop = W32Thread->rpdesk; } if (!Thread || !Desktop ) { if(idThread && Thread) ObDereferenceObject(Thread); EngSetLastError(ERROR_ACCESS_DENIED); RETURN( FALSE); } if ( W32Thread->MessageQueue ) MsgQueue = W32Thread->MessageQueue; else { if ( Desktop ) MsgQueue = Desktop->ActiveMessageQueue; } CaretInfo = MsgQueue->CaretInfo; SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0); if (MsgQueue->MenuOwner) SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState; if (MsgQueue->MoveSize) SafeGui.flags |= GUI_INMOVESIZE; /* FIXME: Add flag GUI_16BITTASK */ SafeGui.hwndActive = MsgQueue->spwndActive ? UserHMGetHandle(MsgQueue->spwndActive) : 0; SafeGui.hwndFocus = MsgQueue->spwndFocus ? UserHMGetHandle(MsgQueue->spwndFocus) : 0; SafeGui.hwndCapture = MsgQueue->spwndCapture ? UserHMGetHandle(MsgQueue->spwndCapture) : 0; SafeGui.hwndMenuOwner = MsgQueue->MenuOwner; SafeGui.hwndMoveSize = MsgQueue->MoveSize; SafeGui.hwndCaret = CaretInfo->hWnd; SafeGui.rcCaret.left = CaretInfo->Pos.x; SafeGui.rcCaret.top = CaretInfo->Pos.y; SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx; SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy; if (idThread) ObDereferenceObject(Thread); Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO)); if(!NT_SUCCESS(Status)) { SetLastNtError(Status); RETURN( FALSE); } RETURN( TRUE); CLEANUP: TRACE("Leave NtUserGetGUIThreadInfo, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } DWORD APIENTRY NtUserGetGuiResources( HANDLE hProcess, DWORD uiFlags) { PEPROCESS Process; PPROCESSINFO W32Process; NTSTATUS Status; DWORD Ret = 0; DECLARE_RETURN(DWORD); TRACE("Enter NtUserGetGuiResources\n"); UserEnterShared(); Status = ObReferenceObjectByHandle(hProcess, PROCESS_QUERY_INFORMATION, PsProcessType, ExGetPreviousMode(), (PVOID*)&Process, NULL); if(!NT_SUCCESS(Status)) { SetLastNtError(Status); RETURN( 0); } W32Process = (PPROCESSINFO)Process->Win32Process; if(!W32Process) { ObDereferenceObject(Process); EngSetLastError(ERROR_INVALID_PARAMETER); RETURN( 0); } switch(uiFlags) { case GR_GDIOBJECTS: { Ret = (DWORD)W32Process->GDIHandleCount; break; } case GR_USEROBJECTS: { Ret = (DWORD)W32Process->UserHandleCount; break; } default: { EngSetLastError(ERROR_INVALID_PARAMETER); break; } } ObDereferenceObject(Process); RETURN( Ret); CLEANUP: TRACE("Leave NtUserGetGuiResources, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } VOID FASTCALL IntSetWindowState(PWND pWnd, UINT Flag) { UINT bit; if (gptiCurrent->ppi != pWnd->head.pti->ppi) return; bit = 1 << LOWORD(Flag); TRACE("SWS %x\n",bit); switch(HIWORD(Flag)) { case 0: pWnd->state |= bit; break; case 1: pWnd->state2 |= bit; break; case 2: pWnd->ExStyle2 |= bit; break; } } VOID FASTCALL IntClearWindowState(PWND pWnd, UINT Flag) { UINT bit; if (gptiCurrent->ppi != pWnd->head.pti->ppi) return; bit = 1 << LOWORD(Flag); TRACE("CWS %x\n",bit); switch(HIWORD(Flag)) { case 0: pWnd->state &= ~bit; break; case 1: pWnd->state2 &= ~bit; break; case 2: pWnd->ExStyle2 &= ~bit; break; } } NTSTATUS FASTCALL IntSafeCopyUnicodeString(PUNICODE_STRING Dest, PUNICODE_STRING Source) { NTSTATUS Status; PWSTR Src; Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING)); if(!NT_SUCCESS(Status)) { return Status; } if(Dest->Length > 0x4000) { return STATUS_UNSUCCESSFUL; } Src = Dest->Buffer; Dest->Buffer = NULL; Dest->MaximumLength = Dest->Length; if(Dest->Length > 0 && Src) { Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING); if(!Dest->Buffer) { return STATUS_NO_MEMORY; } Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length); if(!NT_SUCCESS(Status)) { ExFreePoolWithTag(Dest->Buffer, TAG_STRING); Dest->Buffer = NULL; return Status; } return STATUS_SUCCESS; } /* String is empty */ return STATUS_SUCCESS; } NTSTATUS FASTCALL IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest, PUNICODE_STRING Source) { NTSTATUS Status; PWSTR Src; Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING)); if(!NT_SUCCESS(Status)) { return Status; } if(Dest->Length > 0x4000) { return STATUS_UNSUCCESSFUL; } Src = Dest->Buffer; Dest->Buffer = NULL; Dest->MaximumLength = 0; if(Dest->Length > 0 && Src) { Dest->MaximumLength = Dest->Length + sizeof(WCHAR); Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING); if(!Dest->Buffer) { return STATUS_NO_MEMORY; } Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length); if(!NT_SUCCESS(Status)) { ExFreePoolWithTag(Dest->Buffer, TAG_STRING); Dest->Buffer = NULL; return Status; } /* Make sure the string is null-terminated */ Src = (PWSTR)((PBYTE)Dest->Buffer + Dest->Length); *Src = L'\0'; return STATUS_SUCCESS; } /* String is empty */ return STATUS_SUCCESS; } void UserDbgAssertThreadInfo(BOOL showCaller) { PTEB Teb; PPROCESSINFO ppi; PCLIENTINFO pci; PTHREADINFO pti; ppi = PsGetCurrentProcessWin32Process(); pti = PsGetCurrentThreadWin32Thread(); Teb = NtCurrentTeb(); pci = GetWin32ClientInfo(); ASSERT(Teb); ASSERT(pti); ASSERT(pti->ppi == ppi); ASSERT(pti->pClientInfo == pci); ASSERT(Teb->Win32ThreadInfo == pti); ASSERT(pci->ppi == ppi); ASSERT(pci->fsHooks == pti->fsHooks); ASSERT(pci->ulClientDelta == DesktopHeapGetUserDelta()); if (pti->pcti && pci->pDeskInfo) ASSERT(pci->pClientThreadInfo == (PVOID)((ULONG_PTR)pti->pcti - pci->ulClientDelta)); if (pti->KeyboardLayout) ASSERT(pci->hKL == pti->KeyboardLayout->hkl); if(pti->rpdesk != NULL) ASSERT(pti->pDeskInfo == pti->rpdesk->pDeskInfo); /*too bad we still get this assertion*/ /* ASSERT(pci->dwTIFlags == pti->TIF_flags); */ if(pci->dwTIFlags != pti->TIF_flags) { ERR("pci->dwTIFlags(0x%x) doesn't match pti->TIF_flags(0x%x)\n", pci->dwTIFlags, pti->TIF_flags); if(showCaller) { DbgPrint("Caller:\n"); KeRosDumpStackFrames(NULL, 10); } pci->dwTIFlags = pti->TIF_flags; } } void NTAPI UserDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments) { UserDbgAssertThreadInfo(FALSE); } ULONG_PTR NTAPI UserDbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult) { /* Make sure that the first syscall is NtUserInitialize */ /* too bad this fails */ //ASSERT(gbInitialized); UserDbgAssertThreadInfo(TRUE); return ulResult; } PPROCESSINFO GetW32ProcessInfo(VOID) { return (PPROCESSINFO)PsGetCurrentProcessWin32Process(); } PTHREADINFO GetW32ThreadInfo(VOID) { UserDbgAssertThreadInfo(TRUE); return (PTHREADINFO)PsGetCurrentThreadWin32Thread(); } /* EOF */