Synchronize with trunk r58457.
[reactos.git] / 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 case THREADSTATE_GETCURSOR:
229 ret = (DWORD_PTR) (GetW32ThreadInfo()->MessageQueue->CursorObject ?
230 UserHMGetHandle(GetW32ThreadInfo()->MessageQueue->CursorObject) : 0);
231 break;
232 }
233
234 TRACE("Leave NtUserGetThreadState, ret=%i\n", ret);
235 UserLeave();
236
237 return ret;
238 }
239
240 DWORD
241 APIENTRY
242 NtUserSetThreadState(
243 DWORD Set,
244 DWORD Flags)
245 {
246 PTHREADINFO pti;
247 DWORD Ret = 0;
248 // Test the only flags user can change.
249 if (Set & ~(QF_FF10STATUS|QF_DIALOGACTIVE|QF_TABSWITCHING|QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) return 0;
250 if (Flags & ~(QF_FF10STATUS|QF_DIALOGACTIVE|QF_TABSWITCHING|QF_FMENUSTATUS|QF_FMENUSTATUSBREAK)) return 0;
251 UserEnterExclusive();
252 pti = PsGetCurrentThreadWin32Thread();
253 if (pti->MessageQueue)
254 {
255 Ret = pti->MessageQueue->QF_flags; // Get the queue flags.
256 if (Set)
257 pti->MessageQueue->QF_flags |= (Set&Flags); // Set the queue flags.
258 else
259 {
260 if (Flags) pti->MessageQueue->QF_flags &= ~Flags; // Clr the queue flags.
261 }
262 }
263 UserLeave();
264 return Ret;
265 }
266
267 UINT
268 APIENTRY
269 NtUserGetDoubleClickTime(VOID)
270 {
271 UINT Result;
272
273 TRACE("Enter NtUserGetDoubleClickTime\n");
274 UserEnterShared();
275
276 // FIXME: Check if this works on non-interactive winsta
277 Result = gspv.iDblClickTime;
278
279 TRACE("Leave NtUserGetDoubleClickTime, ret=%i\n", Result);
280 UserLeave();
281 return Result;
282 }
283
284 BOOL
285 APIENTRY
286 NtUserGetGUIThreadInfo(
287 DWORD idThread, /* If NULL use foreground thread */
288 LPGUITHREADINFO lpgui)
289 {
290 NTSTATUS Status;
291 PTHRDCARETINFO CaretInfo;
292 GUITHREADINFO SafeGui;
293 PDESKTOP Desktop;
294 PUSER_MESSAGE_QUEUE MsgQueue;
295 PTHREADINFO W32Thread;
296 PETHREAD Thread = NULL;
297
298 DECLARE_RETURN(BOOLEAN);
299
300 TRACE("Enter NtUserGetGUIThreadInfo\n");
301 UserEnterShared();
302
303 Status = MmCopyFromCaller(&SafeGui, lpgui, sizeof(DWORD));
304 if(!NT_SUCCESS(Status))
305 {
306 SetLastNtError(Status);
307 RETURN( FALSE);
308 }
309
310 if(SafeGui.cbSize != sizeof(GUITHREADINFO))
311 {
312 EngSetLastError(ERROR_INVALID_PARAMETER);
313 RETURN( FALSE);
314 }
315
316 if (idThread)
317 {
318 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
319 if(!NT_SUCCESS(Status))
320 {
321 EngSetLastError(ERROR_ACCESS_DENIED);
322 RETURN( FALSE);
323 }
324 W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread;
325 Desktop = W32Thread->rpdesk;
326 }
327 else
328 { /* Get the foreground thread */
329 Thread = PsGetCurrentThread();
330 W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread;
331 Desktop = W32Thread->rpdesk;
332 }
333
334 if (!Thread || !Desktop )
335 {
336 if(idThread && Thread)
337 ObDereferenceObject(Thread);
338 EngSetLastError(ERROR_ACCESS_DENIED);
339 RETURN( FALSE);
340 }
341
342 if ( W32Thread->MessageQueue )
343 MsgQueue = W32Thread->MessageQueue;
344 else
345 {
346 if ( Desktop ) MsgQueue = Desktop->ActiveMessageQueue;
347 }
348
349 CaretInfo = MsgQueue->CaretInfo;
350
351 SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0);
352
353 if (MsgQueue->MenuOwner)
354 SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState;
355
356 if (MsgQueue->MoveSize)
357 SafeGui.flags |= GUI_INMOVESIZE;
358
359 /* FIXME: Add flag GUI_16BITTASK */
360
361 SafeGui.hwndActive = MsgQueue->spwndActive ? UserHMGetHandle(MsgQueue->spwndActive) : 0;
362 SafeGui.hwndFocus = MsgQueue->spwndFocus ? UserHMGetHandle(MsgQueue->spwndFocus) : 0;
363 SafeGui.hwndCapture = MsgQueue->spwndCapture ? UserHMGetHandle(MsgQueue->spwndCapture) : 0;
364 SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
365 SafeGui.hwndMoveSize = MsgQueue->MoveSize;
366 SafeGui.hwndCaret = CaretInfo->hWnd;
367
368 SafeGui.rcCaret.left = CaretInfo->Pos.x;
369 SafeGui.rcCaret.top = CaretInfo->Pos.y;
370 SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx;
371 SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy;
372
373 if (idThread)
374 ObDereferenceObject(Thread);
375
376 Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO));
377 if(!NT_SUCCESS(Status))
378 {
379 SetLastNtError(Status);
380 RETURN( FALSE);
381 }
382
383 RETURN( TRUE);
384
385 CLEANUP:
386 TRACE("Leave NtUserGetGUIThreadInfo, ret=%i\n",_ret_);
387 UserLeave();
388 END_CLEANUP;
389 }
390
391
392 DWORD
393 APIENTRY
394 NtUserGetGuiResources(
395 HANDLE hProcess,
396 DWORD uiFlags)
397 {
398 PEPROCESS Process;
399 PPROCESSINFO W32Process;
400 NTSTATUS Status;
401 DWORD Ret = 0;
402 DECLARE_RETURN(DWORD);
403
404 TRACE("Enter NtUserGetGuiResources\n");
405 UserEnterShared();
406
407 Status = ObReferenceObjectByHandle(hProcess,
408 PROCESS_QUERY_INFORMATION,
409 PsProcessType,
410 ExGetPreviousMode(),
411 (PVOID*)&Process,
412 NULL);
413
414 if(!NT_SUCCESS(Status))
415 {
416 SetLastNtError(Status);
417 RETURN( 0);
418 }
419
420 W32Process = (PPROCESSINFO)Process->Win32Process;
421 if(!W32Process)
422 {
423 ObDereferenceObject(Process);
424 EngSetLastError(ERROR_INVALID_PARAMETER);
425 RETURN( 0);
426 }
427
428 switch(uiFlags)
429 {
430 case GR_GDIOBJECTS:
431 {
432 Ret = (DWORD)W32Process->GDIHandleCount;
433 break;
434 }
435 case GR_USEROBJECTS:
436 {
437 Ret = (DWORD)W32Process->UserHandleCount;
438 break;
439 }
440 default:
441 {
442 EngSetLastError(ERROR_INVALID_PARAMETER);
443 break;
444 }
445 }
446
447 ObDereferenceObject(Process);
448
449 RETURN( Ret);
450
451 CLEANUP:
452 TRACE("Leave NtUserGetGuiResources, ret=%i\n",_ret_);
453 UserLeave();
454 END_CLEANUP;
455 }
456
457 VOID FASTCALL
458 IntSetWindowState(PWND pWnd, UINT Flag)
459 {
460 UINT bit;
461 if (gptiCurrent->ppi != pWnd->head.pti->ppi) return;
462 bit = 1 << LOWORD(Flag);
463 TRACE("SWS %x\n",bit);
464 switch(HIWORD(Flag))
465 {
466 case 0:
467 pWnd->state |= bit;
468 break;
469 case 1:
470 pWnd->state2 |= bit;
471 break;
472 case 2:
473 pWnd->ExStyle2 |= bit;
474 break;
475 }
476 }
477
478 VOID FASTCALL
479 IntClearWindowState(PWND pWnd, UINT Flag)
480 {
481 UINT bit;
482 if (gptiCurrent->ppi != pWnd->head.pti->ppi) return;
483 bit = 1 << LOWORD(Flag);
484 TRACE("CWS %x\n",bit);
485 switch(HIWORD(Flag))
486 {
487 case 0:
488 pWnd->state &= ~bit;
489 break;
490 case 1:
491 pWnd->state2 &= ~bit;
492 break;
493 case 2:
494 pWnd->ExStyle2 &= ~bit;
495 break;
496 }
497 }
498
499 NTSTATUS FASTCALL
500 IntSafeCopyUnicodeString(PUNICODE_STRING Dest,
501 PUNICODE_STRING Source)
502 {
503 NTSTATUS Status;
504 PWSTR Src;
505
506 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
507 if(!NT_SUCCESS(Status))
508 {
509 return Status;
510 }
511
512 if(Dest->Length > 0x4000)
513 {
514 return STATUS_UNSUCCESSFUL;
515 }
516
517 Src = Dest->Buffer;
518 Dest->Buffer = NULL;
519 Dest->MaximumLength = Dest->Length;
520
521 if(Dest->Length > 0 && Src)
522 {
523 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
524 if(!Dest->Buffer)
525 {
526 return STATUS_NO_MEMORY;
527 }
528
529 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
530 if(!NT_SUCCESS(Status))
531 {
532 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
533 Dest->Buffer = NULL;
534 return Status;
535 }
536
537
538 return STATUS_SUCCESS;
539 }
540
541 /* String is empty */
542 return STATUS_SUCCESS;
543 }
544
545 NTSTATUS FASTCALL
546 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest,
547 PUNICODE_STRING Source)
548 {
549 NTSTATUS Status;
550 PWSTR Src;
551
552 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
553 if(!NT_SUCCESS(Status))
554 {
555 return Status;
556 }
557
558 if(Dest->Length > 0x4000)
559 {
560 return STATUS_UNSUCCESSFUL;
561 }
562
563 Src = Dest->Buffer;
564 Dest->Buffer = NULL;
565 Dest->MaximumLength = 0;
566
567 if(Dest->Length > 0 && Src)
568 {
569 Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
570 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
571 if(!Dest->Buffer)
572 {
573 return STATUS_NO_MEMORY;
574 }
575
576 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
577 if(!NT_SUCCESS(Status))
578 {
579 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
580 Dest->Buffer = NULL;
581 return Status;
582 }
583
584 /* Make sure the string is null-terminated */
585 Src = (PWSTR)((PBYTE)Dest->Buffer + Dest->Length);
586 *Src = L'\0';
587
588 return STATUS_SUCCESS;
589 }
590
591 /* String is empty */
592 return STATUS_SUCCESS;
593 }
594
595 void UserDbgAssertThreadInfo(BOOL showCaller)
596 {
597 PTEB Teb;
598 PPROCESSINFO ppi;
599 PCLIENTINFO pci;
600 PTHREADINFO pti;
601
602 ppi = PsGetCurrentProcessWin32Process();
603 pti = PsGetCurrentThreadWin32Thread();
604 Teb = NtCurrentTeb();
605 pci = GetWin32ClientInfo();
606
607 ASSERT(Teb);
608 ASSERT(pti);
609 ASSERT(pti->ppi == ppi);
610 ASSERT(pti->pClientInfo == pci);
611 ASSERT(Teb->Win32ThreadInfo == pti);
612 ASSERT(pci->ppi == ppi);
613 ASSERT(pci->fsHooks == pti->fsHooks);
614 ASSERT(pci->ulClientDelta == DesktopHeapGetUserDelta());
615 if (pti->pcti && pci->pDeskInfo)
616 ASSERT(pci->pClientThreadInfo == (PVOID)((ULONG_PTR)pti->pcti - pci->ulClientDelta));
617 if (pti->KeyboardLayout)
618 ASSERT(pci->hKL == pti->KeyboardLayout->hkl);
619 if(pti->rpdesk != NULL)
620 ASSERT(pti->pDeskInfo == pti->rpdesk->pDeskInfo);
621
622 /*too bad we still get this assertion*/
623 /* ASSERT(pci->dwTIFlags == pti->TIF_flags); */
624 if(pci->dwTIFlags != pti->TIF_flags)
625 {
626 ERR("pci->dwTIFlags(0x%x) doesn't match pti->TIF_flags(0x%x)\n", pci->dwTIFlags, pti->TIF_flags);
627 if(showCaller)
628 {
629 DbgPrint("Caller:\n");
630 KeRosDumpStackFrames(NULL, 10);
631 }
632 pci->dwTIFlags = pti->TIF_flags;
633 }
634 }
635
636 void
637 NTAPI
638 UserDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
639 {
640 UserDbgAssertThreadInfo(FALSE);
641 }
642
643 ULONG_PTR
644 NTAPI
645 UserDbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
646 {
647 /* Make sure that the first syscall is NtUserInitialize */
648 /* too bad this fails */
649 //ASSERT(gbInitialized);
650
651 UserDbgAssertThreadInfo(TRUE);
652
653 return ulResult;
654 }
655
656
657 PPROCESSINFO
658 GetW32ProcessInfo(VOID)
659 {
660 return (PPROCESSINFO)PsGetCurrentProcessWin32Process();
661 }
662
663 PTHREADINFO
664 GetW32ThreadInfo(VOID)
665 {
666 UserDbgAssertThreadInfo(TRUE);
667 return (PTHREADINFO)PsGetCurrentThreadWin32Thread();
668 }
669
670 /* EOF */