[Win32SS]
[reactos.git] / reactos / win32ss / user / ntuser / misc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Miscellaneous User functions
5 * FILE: subsystems/win32/win32k/ntuser/misc.c
6 * PROGRAMER: Ge van Geldorp (ge@gse.nl)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserMisc);
11
12 SHORT
13 FASTCALL
14 UserGetLanguageID(VOID)
15 {
16 HANDLE KeyHandle;
17 OBJECT_ATTRIBUTES ObAttr;
18 // http://support.microsoft.com/kb/324097
19 ULONG Ret = 0x409; // English
20 PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
21 ULONG Size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH*sizeof(WCHAR);
22 UNICODE_STRING Language;
23
24 RtlInitUnicodeString( &Language,
25 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language");
26
27 InitializeObjectAttributes( &ObAttr,
28 &Language,
29 OBJ_CASE_INSENSITIVE,
30 NULL,
31 NULL);
32
33 if ( NT_SUCCESS(ZwOpenKey(&KeyHandle, KEY_READ, &ObAttr)))
34 {
35 pKeyInfo = ExAllocatePoolWithTag(PagedPool, Size, TAG_STRING);
36 if ( pKeyInfo )
37 {
38 RtlInitUnicodeString(&Language, L"Default");
39
40 if ( NT_SUCCESS(ZwQueryValueKey( KeyHandle,
41 &Language,
42 KeyValuePartialInformation,
43 pKeyInfo,
44 Size,
45 &Size)) )
46 {
47 RtlInitUnicodeString(&Language, (PWSTR)pKeyInfo->Data);
48 RtlUnicodeStringToInteger(&Language, 16, &Ret);
49 }
50 ExFreePoolWithTag(pKeyInfo, TAG_STRING);
51 }
52 ZwClose(KeyHandle);
53 }
54 TRACE("Language ID = %x\n",Ret);
55 return (SHORT) Ret;
56 }
57
58 HBRUSH
59 FASTCALL
60 GetControlColor(
61 PWND pwndParent,
62 PWND pwnd,
63 HDC hdc,
64 UINT CtlMsg)
65 {
66 HBRUSH hBrush;
67
68 if (!pwndParent) pwndParent = pwnd;
69
70 if ( pwndParent->head.pti->ppi != PsGetCurrentProcessWin32Process())
71 {
72 return (HBRUSH)IntDefWindowProc( pwndParent, CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd), FALSE);
73 }
74
75 hBrush = (HBRUSH)co_IntSendMessage( UserHMGetHandle(pwndParent), CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd));
76
77 if (!hBrush || !GreIsHandleValid(hBrush))
78 {
79 hBrush = (HBRUSH)IntDefWindowProc( pwndParent, CtlMsg, (WPARAM)hdc, (LPARAM)UserHMGetHandle(pwnd), FALSE);
80 }
81 return hBrush;
82 }
83
84 HBRUSH
85 FASTCALL
86 GetControlBrush(
87 PWND pwnd,
88 HDC hdc,
89 UINT ctlType)
90 {
91 PWND pwndParent = IntGetParent(pwnd);
92 return GetControlColor( pwndParent, pwnd, hdc, ctlType);
93 }
94
95 HBRUSH
96 APIENTRY
97 NtUserGetControlBrush(
98 HWND hwnd,
99 HDC hdc,
100 UINT ctlType)
101 {
102 PWND pwnd;
103 HBRUSH hBrush = NULL;
104
105 UserEnterExclusive();
106 if ( (pwnd = UserGetWindowObject(hwnd)) &&
107 ((ctlType - WM_CTLCOLORMSGBOX) < CTLCOLOR_MAX) &&
108 hdc )
109 {
110 hBrush = GetControlBrush(pwnd, hdc, ctlType);
111 }
112 UserLeave();
113 return hBrush;
114 }
115
116 /*
117 * Called from PaintRect, works almost like wine PaintRect16 but returns hBrush.
118 */
119 HBRUSH
120 APIENTRY
121 NtUserGetControlColor(
122 HWND hwndParent,
123 HWND hwnd,
124 HDC hdc,
125 UINT CtlMsg) // Wine PaintRect: WM_CTLCOLORMSGBOX + hbrush
126 {
127 PWND pwnd, pwndParent = NULL;
128 HBRUSH hBrush = NULL;
129
130 UserEnterExclusive();
131 if ( (pwnd = UserGetWindowObject(hwnd)) &&
132 ((CtlMsg - WM_CTLCOLORMSGBOX) < CTLCOLOR_MAX) &&
133 hdc )
134 {
135 if (hwndParent) pwndParent = UserGetWindowObject(hwndParent);
136 hBrush = GetControlColor( pwndParent, pwnd, hdc, CtlMsg);
137 }
138 UserLeave();
139 return hBrush;
140 }
141
142 /*
143 * @unimplemented
144 */
145 DWORD_PTR APIENTRY
146 NtUserGetThreadState(
147 DWORD Routine)
148 {
149 DWORD_PTR ret = 0;
150
151 TRACE("Enter NtUserGetThreadState\n");
152 if (Routine != THREADSTATE_GETTHREADINFO)
153 {
154 UserEnterShared();
155 }
156 else
157 {
158 UserEnterExclusive();
159 }
160
161 switch (Routine)
162 {
163 case THREADSTATE_GETTHREADINFO:
164 GetW32ThreadInfo();
165 break;
166 case THREADSTATE_FOCUSWINDOW:
167 ret = (DWORD_PTR)IntGetThreadFocusWindow();
168 break;
169 case THREADSTATE_CAPTUREWINDOW:
170 /* FIXME: Should use UserEnterShared */
171 ret = (DWORD_PTR)IntGetCapture();
172 break;
173 case THREADSTATE_PROGMANWINDOW:
174 ret = (DWORD_PTR)GetW32ThreadInfo()->pDeskInfo->hProgmanWindow;
175 break;
176 case THREADSTATE_TASKMANWINDOW:
177 ret = (DWORD_PTR)GetW32ThreadInfo()->pDeskInfo->hTaskManWindow;
178 break;
179 case THREADSTATE_ACTIVEWINDOW:
180 ret = (DWORD_PTR)UserGetActiveWindow();
181 break;
182 case THREADSTATE_INSENDMESSAGE:
183 {
184 PUSER_SENT_MESSAGE Message =
185 ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->pusmCurrent;
186 ERR("THREADSTATE_INSENDMESSAGE\n");
187
188 ret = ISMEX_NOSEND;
189 if (Message)
190 {
191 if (Message->SenderQueue)
192 ret = ISMEX_SEND;
193 else
194 {
195 if (Message->CompletionCallback)
196 ret = ISMEX_CALLBACK;
197 else
198 ret = ISMEX_NOTIFY;
199 }
200 /* If ReplyMessage */
201 if (Message->QS_Flags & QS_SMRESULT) ret |= ISMEX_REPLIED;
202 }
203
204 break;
205 }
206 case THREADSTATE_GETMESSAGETIME:
207 ret = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->timeLast;
208 break;
209
210 case THREADSTATE_UPTIMELASTREAD:
211 {
212 PTHREADINFO pti;
213 LARGE_INTEGER LargeTickCount;
214 pti = PsGetCurrentThreadWin32Thread();
215 KeQueryTickCount(&LargeTickCount);
216 pti->MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
217 pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
218 }
219 break;
220
221 case THREADSTATE_GETINPUTSTATE:
222 ret = LOWORD(IntGetQueueStatus(QS_POSTMESSAGE|QS_TIMER|QS_PAINT|QS_SENDMESSAGE|QS_INPUT)) & (QS_KEY | QS_MOUSEBUTTON);
223 break;
224
225 case THREADSTATE_FOREGROUNDTHREAD:
226 ret = (gpqForeground == GetW32ThreadInfo()->MessageQueue);
227 break;
228 }
229
230 TRACE("Leave NtUserGetThreadState, ret=%i\n", ret);
231 UserLeave();
232
233 return ret;
234 }
235
236 DWORD
237 APIENTRY
238 NtUserSetThreadState(
239 DWORD Set,
240 DWORD Flags)
241 {
242 PTHREADINFO pti;
243 DWORD Ret = 0;
244 // Test the only flags user can change.
245 if (Set & ~(QF_FF10STATUS|QF_DIALOGACTIVE|QF_TABSWITCHING|QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) return 0;
246 if (Flags & ~(QF_FF10STATUS|QF_DIALOGACTIVE|QF_TABSWITCHING|QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) return 0;
247 UserEnterExclusive();
248 pti = PsGetCurrentThreadWin32Thread();
249 if (pti->MessageQueue)
250 {
251 Ret = pti->MessageQueue->QF_flags; // Get the queue flags.
252 if (Set)
253 pti->MessageQueue->QF_flags |= (Set&Flags); // Set the queue flags.
254 else
255 {
256 if (Flags) pti->MessageQueue->QF_flags &= ~Flags; // Clr the queue flags.
257 }
258 }
259 UserLeave();
260 return Ret;
261 }
262
263 UINT
264 APIENTRY
265 NtUserGetDoubleClickTime(VOID)
266 {
267 UINT Result;
268
269 TRACE("Enter NtUserGetDoubleClickTime\n");
270 UserEnterShared();
271
272 // FIXME: Check if this works on non-interactive winsta
273 Result = gspv.iDblClickTime;
274
275 TRACE("Leave NtUserGetDoubleClickTime, ret=%i\n", Result);
276 UserLeave();
277 return Result;
278 }
279
280 BOOL
281 APIENTRY
282 NtUserGetGUIThreadInfo(
283 DWORD idThread, /* If NULL use foreground thread */
284 LPGUITHREADINFO lpgui)
285 {
286 NTSTATUS Status;
287 PTHRDCARETINFO CaretInfo;
288 GUITHREADINFO SafeGui;
289 PDESKTOP Desktop;
290 PUSER_MESSAGE_QUEUE MsgQueue;
291 PTHREADINFO W32Thread;
292 PETHREAD Thread = NULL;
293
294 DECLARE_RETURN(BOOLEAN);
295
296 TRACE("Enter NtUserGetGUIThreadInfo\n");
297 UserEnterShared();
298
299 Status = MmCopyFromCaller(&SafeGui, lpgui, sizeof(DWORD));
300 if(!NT_SUCCESS(Status))
301 {
302 SetLastNtError(Status);
303 RETURN( FALSE);
304 }
305
306 if(SafeGui.cbSize != sizeof(GUITHREADINFO))
307 {
308 EngSetLastError(ERROR_INVALID_PARAMETER);
309 RETURN( FALSE);
310 }
311
312 if (idThread)
313 {
314 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
315 if(!NT_SUCCESS(Status))
316 {
317 EngSetLastError(ERROR_ACCESS_DENIED);
318 RETURN( FALSE);
319 }
320 W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread;
321 Desktop = W32Thread->rpdesk;
322 }
323 else
324 { /* Get the foreground thread */
325 Thread = PsGetCurrentThread();
326 W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread;
327 Desktop = W32Thread->rpdesk;
328 }
329
330 if (!Thread || !Desktop )
331 {
332 if(idThread && Thread)
333 ObDereferenceObject(Thread);
334 EngSetLastError(ERROR_ACCESS_DENIED);
335 RETURN( FALSE);
336 }
337
338 if ( W32Thread->MessageQueue )
339 MsgQueue = W32Thread->MessageQueue;
340 else
341 {
342 if ( Desktop ) MsgQueue = Desktop->ActiveMessageQueue;
343 }
344
345 CaretInfo = MsgQueue->CaretInfo;
346
347 SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0);
348
349 if (MsgQueue->MenuOwner)
350 SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState;
351
352 if (MsgQueue->MoveSize)
353 SafeGui.flags |= GUI_INMOVESIZE;
354
355 /* FIXME: Add flag GUI_16BITTASK */
356
357 SafeGui.hwndActive = MsgQueue->spwndActive ? UserHMGetHandle(MsgQueue->spwndActive) : 0;
358 SafeGui.hwndFocus = MsgQueue->spwndFocus ? UserHMGetHandle(MsgQueue->spwndFocus) : 0;
359 SafeGui.hwndCapture = MsgQueue->CaptureWindow;
360 SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
361 SafeGui.hwndMoveSize = MsgQueue->MoveSize;
362 SafeGui.hwndCaret = CaretInfo->hWnd;
363
364 SafeGui.rcCaret.left = CaretInfo->Pos.x;
365 SafeGui.rcCaret.top = CaretInfo->Pos.y;
366 SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx;
367 SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy;
368
369 if (idThread)
370 ObDereferenceObject(Thread);
371
372 Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO));
373 if(!NT_SUCCESS(Status))
374 {
375 SetLastNtError(Status);
376 RETURN( FALSE);
377 }
378
379 RETURN( TRUE);
380
381 CLEANUP:
382 TRACE("Leave NtUserGetGUIThreadInfo, ret=%i\n",_ret_);
383 UserLeave();
384 END_CLEANUP;
385 }
386
387
388 DWORD
389 APIENTRY
390 NtUserGetGuiResources(
391 HANDLE hProcess,
392 DWORD uiFlags)
393 {
394 PEPROCESS Process;
395 PPROCESSINFO W32Process;
396 NTSTATUS Status;
397 DWORD Ret = 0;
398 DECLARE_RETURN(DWORD);
399
400 TRACE("Enter NtUserGetGuiResources\n");
401 UserEnterShared();
402
403 Status = ObReferenceObjectByHandle(hProcess,
404 PROCESS_QUERY_INFORMATION,
405 PsProcessType,
406 ExGetPreviousMode(),
407 (PVOID*)&Process,
408 NULL);
409
410 if(!NT_SUCCESS(Status))
411 {
412 SetLastNtError(Status);
413 RETURN( 0);
414 }
415
416 W32Process = (PPROCESSINFO)Process->Win32Process;
417 if(!W32Process)
418 {
419 ObDereferenceObject(Process);
420 EngSetLastError(ERROR_INVALID_PARAMETER);
421 RETURN( 0);
422 }
423
424 switch(uiFlags)
425 {
426 case GR_GDIOBJECTS:
427 {
428 Ret = (DWORD)W32Process->GDIHandleCount;
429 break;
430 }
431 case GR_USEROBJECTS:
432 {
433 Ret = (DWORD)W32Process->UserHandleCount;
434 break;
435 }
436 default:
437 {
438 EngSetLastError(ERROR_INVALID_PARAMETER);
439 break;
440 }
441 }
442
443 ObDereferenceObject(Process);
444
445 RETURN( Ret);
446
447 CLEANUP:
448 TRACE("Leave NtUserGetGuiResources, ret=%i\n",_ret_);
449 UserLeave();
450 END_CLEANUP;
451 }
452
453 VOID FASTCALL
454 IntSetWindowState(PWND pWnd, UINT Flag)
455 {
456 UINT bit;
457 if (gptiCurrent->ppi != pWnd->head.pti->ppi) return;
458 bit = 1 << LOWORD(Flag);
459 TRACE("SWS %x\n",bit);
460 switch(HIWORD(Flag))
461 {
462 case 0:
463 pWnd->state |= bit;
464 break;
465 case 1:
466 pWnd->state2 |= bit;
467 break;
468 case 2:
469 pWnd->ExStyle2 |= bit;
470 break;
471 }
472 }
473
474 VOID FASTCALL
475 IntClearWindowState(PWND pWnd, UINT Flag)
476 {
477 UINT bit;
478 if (gptiCurrent->ppi != pWnd->head.pti->ppi) return;
479 bit = 1 << LOWORD(Flag);
480 TRACE("CWS %x\n",bit);
481 switch(HIWORD(Flag))
482 {
483 case 0:
484 pWnd->state &= ~bit;
485 break;
486 case 1:
487 pWnd->state2 &= ~bit;
488 break;
489 case 2:
490 pWnd->ExStyle2 &= ~bit;
491 break;
492 }
493 }
494
495 NTSTATUS FASTCALL
496 IntSafeCopyUnicodeString(PUNICODE_STRING Dest,
497 PUNICODE_STRING Source)
498 {
499 NTSTATUS Status;
500 PWSTR Src;
501
502 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
503 if(!NT_SUCCESS(Status))
504 {
505 return Status;
506 }
507
508 if(Dest->Length > 0x4000)
509 {
510 return STATUS_UNSUCCESSFUL;
511 }
512
513 Src = Dest->Buffer;
514 Dest->Buffer = NULL;
515 Dest->MaximumLength = Dest->Length;
516
517 if(Dest->Length > 0 && Src)
518 {
519 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
520 if(!Dest->Buffer)
521 {
522 return STATUS_NO_MEMORY;
523 }
524
525 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
526 if(!NT_SUCCESS(Status))
527 {
528 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
529 Dest->Buffer = NULL;
530 return Status;
531 }
532
533
534 return STATUS_SUCCESS;
535 }
536
537 /* String is empty */
538 return STATUS_SUCCESS;
539 }
540
541 NTSTATUS FASTCALL
542 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest,
543 PUNICODE_STRING Source)
544 {
545 NTSTATUS Status;
546 PWSTR Src;
547
548 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
549 if(!NT_SUCCESS(Status))
550 {
551 return Status;
552 }
553
554 if(Dest->Length > 0x4000)
555 {
556 return STATUS_UNSUCCESSFUL;
557 }
558
559 Src = Dest->Buffer;
560 Dest->Buffer = NULL;
561 Dest->MaximumLength = 0;
562
563 if(Dest->Length > 0 && Src)
564 {
565 Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
566 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
567 if(!Dest->Buffer)
568 {
569 return STATUS_NO_MEMORY;
570 }
571
572 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
573 if(!NT_SUCCESS(Status))
574 {
575 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
576 Dest->Buffer = NULL;
577 return Status;
578 }
579
580 /* Make sure the string is null-terminated */
581 Src = (PWSTR)((PBYTE)Dest->Buffer + Dest->Length);
582 *Src = L'\0';
583
584 return STATUS_SUCCESS;
585 }
586
587 /* String is empty */
588 return STATUS_SUCCESS;
589 }
590
591 void UserDbgAssertThreadInfo(BOOL showCaller)
592 {
593 PTEB Teb;
594 PPROCESSINFO ppi;
595 PCLIENTINFO pci;
596 PTHREADINFO pti;
597
598 ppi = PsGetCurrentProcessWin32Process();
599 pti = PsGetCurrentThreadWin32Thread();
600 Teb = NtCurrentTeb();
601 pci = GetWin32ClientInfo();
602
603 ASSERT(Teb);
604 ASSERT(pti);
605 ASSERT(pti->ppi == ppi);
606 ASSERT(pti->pClientInfo == pci);
607 ASSERT(Teb->Win32ThreadInfo == pti);
608 ASSERT(pci->ppi == ppi);
609 ASSERT(pci->fsHooks == pti->fsHooks);
610 ASSERT(pci->ulClientDelta == DesktopHeapGetUserDelta());
611 if (pti->pcti && pci->pDeskInfo)
612 ASSERT(pci->pClientThreadInfo == (PVOID)((ULONG_PTR)pti->pcti - pci->ulClientDelta));
613 if (pti->KeyboardLayout)
614 ASSERT(pci->hKL == pti->KeyboardLayout->hkl);
615 if(pti->rpdesk != NULL)
616 ASSERT(pti->pDeskInfo == pti->rpdesk->pDeskInfo);
617
618 /*too bad we still get this assertion*/
619 /* ASSERT(pci->dwTIFlags == pti->TIF_flags); */
620 if(pci->dwTIFlags != pti->TIF_flags)
621 {
622 ERR("pci->dwTIFlags(0x%x) doesn't match pti->TIF_flags(0x%x)\n", pci->dwTIFlags, pti->TIF_flags);
623 if(showCaller)
624 {
625 DbgPrint("Caller:\n");
626 KeRosDumpStackFrames(NULL, 10);
627 }
628 pci->dwTIFlags = pti->TIF_flags;
629 }
630 }
631
632 void
633 NTAPI
634 UserDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
635 {
636 UserDbgAssertThreadInfo(FALSE);
637 }
638
639 ULONG_PTR
640 NTAPI
641 UserDbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
642 {
643 /* Make sure that the first syscall is NtUserInitialize */
644 /* too bad this fails */
645 //ASSERT(gbInitialized);
646
647 UserDbgAssertThreadInfo(TRUE);
648
649 return ulResult;
650 }
651
652
653 PPROCESSINFO
654 GetW32ProcessInfo(VOID)
655 {
656 return (PPROCESSINFO)PsGetCurrentProcessWin32Process();
657 }
658
659 PTHREADINFO
660 GetW32ThreadInfo(VOID)
661 {
662 UserDbgAssertThreadInfo(TRUE);
663 return (PTHREADINFO)PsGetCurrentThreadWin32Thread();
664 }
665
666 /* EOF */