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