Sync trunk head (r41026)
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / misc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Misc User funcs
5 * FILE: subsystem/win32/win32k/ntuser/misc.c
6 * PROGRAMER: Ge van Geldorp (ge@gse.nl)
7 * REVISION HISTORY:
8 * 2003/05/22 Created
9 */
10
11 #include <w32k.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16
17 SHORT
18 FASTCALL
19 IntGdiGetLanguageID()
20 {
21 HANDLE KeyHandle;
22 ULONG Size = sizeof(WCHAR) * (MAX_PATH + 12);
23 OBJECT_ATTRIBUTES ObAttr;
24 // http://support.microsoft.com/kb/324097
25 ULONG Ret = 0x409; // English
26 PVOID KeyInfo;
27 UNICODE_STRING Language;
28
29 RtlInitUnicodeString( &Language,
30 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language");
31
32 InitializeObjectAttributes( &ObAttr,
33 &Language,
34 OBJ_CASE_INSENSITIVE,
35 NULL,
36 NULL);
37
38 if ( NT_SUCCESS(ZwOpenKey(&KeyHandle, KEY_READ, &ObAttr)))
39 {
40 KeyInfo = ExAllocatePoolWithTag(PagedPool, Size, TAG_STRING);
41 if ( KeyInfo )
42 {
43 RtlInitUnicodeString(&Language, L"Default");
44
45 if ( NT_SUCCESS(ZwQueryValueKey( KeyHandle,
46 &Language,
47 KeyValuePartialInformation,
48 KeyInfo,
49 Size,
50 &Size)) )
51 {
52 RtlInitUnicodeString(&Language, (PVOID)((char *)KeyInfo + 12));
53 RtlUnicodeStringToInteger(&Language, 16, &Ret);
54 }
55 ExFreePoolWithTag(KeyInfo, TAG_STRING);
56 }
57 ZwClose(KeyHandle);
58 }
59 DPRINT("Language ID = %x\n",Ret);
60 return (SHORT) Ret;
61 }
62
63 /*
64 * @unimplemented
65 */
66 DWORD_PTR APIENTRY
67 NtUserGetThreadState(
68 DWORD Routine)
69 {
70 DWORD_PTR ret = 0;
71
72 DPRINT("Enter NtUserGetThreadState\n");
73 if (Routine != THREADSTATE_GETTHREADINFO)
74 {
75 UserEnterShared();
76 }
77 else
78 {
79 UserEnterExclusive();
80 }
81
82 switch (Routine)
83 {
84 case THREADSTATE_GETTHREADINFO:
85 GetW32ThreadInfo();
86 break;
87 case THREADSTATE_FOCUSWINDOW:
88 ret = (DWORD_PTR)IntGetThreadFocusWindow();
89 break;
90 case THREADSTATE_CAPTUREWINDOW:
91 /* FIXME should use UserEnterShared */
92 ret = (DWORD_PTR)IntGetCapture();
93 break;
94 case THREADSTATE_PROGMANWINDOW:
95 ret = (DWORD_PTR)GetW32ThreadInfo()->pDeskInfo->hProgmanWindow;
96 break;
97 case THREADSTATE_TASKMANWINDOW:
98 ret = (DWORD_PTR)GetW32ThreadInfo()->pDeskInfo->hTaskManWindow;
99 break;
100 case THREADSTATE_ACTIVEWINDOW:
101 ret = (DWORD_PTR)UserGetActiveWindow();
102 break;
103 case THREADSTATE_INSENDMESSAGE:
104 {
105 DWORD Ret = ISMEX_NOSEND;
106 PUSER_MESSAGE_QUEUE MessageQueue =
107 ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->MessageQueue;
108 DPRINT1("THREADSTATE_INSENDMESSAGE\n");
109
110 if (!IsListEmpty(&MessageQueue->SentMessagesListHead))
111 {
112 Ret = ISMEX_SEND;
113 }
114 else if (!IsListEmpty(&MessageQueue->NotifyMessagesListHead))
115 {
116 /* FIXME Need to set message flag when in callback mode with notify */
117 Ret = ISMEX_NOTIFY;
118 }
119 /* FIXME Need to set message flag if replied to or ReplyMessage */
120 RETURN( Ret);
121 }
122 case THREADSTATE_GETMESSAGETIME:
123 /* FIXME Needs more work! */
124 RETURN( ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->timeLast);
125
126 case THREADSTATE_GETINPUTSTATE:
127 RETURN( HIWORD(IntGetQueueStatus(FALSE)) & (QS_KEY | QS_MOUSEBUTTON));
128 }
129
130 DPRINT("Leave NtUserGetThreadState, ret=%i\n", ret);
131 UserLeave();
132
133 return ret;
134 }
135
136
137 UINT
138 APIENTRY
139 NtUserGetDoubleClickTime(VOID)
140 {
141 UINT Result;
142 NTSTATUS Status;
143 PWINSTATION_OBJECT WinStaObject;
144 PSYSTEM_CURSORINFO CurInfo;
145 DECLARE_RETURN(UINT);
146
147 DPRINT("Enter NtUserGetDoubleClickTime\n");
148 UserEnterShared();
149
150 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
151 KernelMode,
152 0,
153 &WinStaObject);
154 if (!NT_SUCCESS(Status))
155 RETURN( (DWORD)FALSE);
156
157 CurInfo = IntGetSysCursorInfo(WinStaObject);
158 Result = CurInfo->DblClickSpeed;
159
160 ObDereferenceObject(WinStaObject);
161 RETURN( Result);
162
163 CLEANUP:
164 DPRINT("Leave NtUserGetDoubleClickTime, ret=%i\n",_ret_);
165 UserLeave();
166 END_CLEANUP;
167 }
168
169 BOOL
170 APIENTRY
171 NtUserGetGUIThreadInfo(
172 DWORD idThread, /* if NULL use foreground thread */
173 LPGUITHREADINFO lpgui)
174 {
175 NTSTATUS Status;
176 PTHRDCARETINFO CaretInfo;
177 GUITHREADINFO SafeGui;
178 PDESKTOP Desktop;
179 PUSER_MESSAGE_QUEUE MsgQueue;
180 PETHREAD Thread = NULL;
181 DECLARE_RETURN(BOOLEAN);
182
183 DPRINT("Enter NtUserGetGUIThreadInfo\n");
184 UserEnterShared();
185
186 Status = MmCopyFromCaller(&SafeGui, lpgui, sizeof(DWORD));
187 if(!NT_SUCCESS(Status))
188 {
189 SetLastNtError(Status);
190 RETURN( FALSE);
191 }
192
193 if(SafeGui.cbSize != sizeof(GUITHREADINFO))
194 {
195 SetLastWin32Error(ERROR_INVALID_PARAMETER);
196 RETURN( FALSE);
197 }
198
199 if(idThread)
200 {
201 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
202 if(!NT_SUCCESS(Status))
203 {
204 SetLastWin32Error(ERROR_ACCESS_DENIED);
205 RETURN( FALSE);
206 }
207 Desktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->Desktop;
208 }
209 else
210 {
211 /* get the foreground thread */
212 PTHREADINFO W32Thread = (PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread;
213 Desktop = W32Thread->Desktop;
214 if(Desktop)
215 {
216 MsgQueue = Desktop->ActiveMessageQueue;
217 if(MsgQueue)
218 {
219 Thread = MsgQueue->Thread;
220 }
221 }
222 }
223
224 if(!Thread || !Desktop)
225 {
226 if(idThread && Thread)
227 ObDereferenceObject(Thread);
228 SetLastWin32Error(ERROR_ACCESS_DENIED);
229 RETURN( FALSE);
230 }
231
232 MsgQueue = (PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue;
233 CaretInfo = MsgQueue->CaretInfo;
234
235 SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0);
236 if(MsgQueue->MenuOwner)
237 SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState;
238 if(MsgQueue->MoveSize)
239 SafeGui.flags |= GUI_INMOVESIZE;
240
241 /* FIXME add flag GUI_16BITTASK */
242
243 SafeGui.hwndActive = MsgQueue->ActiveWindow;
244 SafeGui.hwndFocus = MsgQueue->FocusWindow;
245 SafeGui.hwndCapture = MsgQueue->CaptureWindow;
246 SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
247 SafeGui.hwndMoveSize = MsgQueue->MoveSize;
248 SafeGui.hwndCaret = CaretInfo->hWnd;
249
250 SafeGui.rcCaret.left = CaretInfo->Pos.x;
251 SafeGui.rcCaret.top = CaretInfo->Pos.y;
252 SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx;
253 SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy;
254
255 if(idThread)
256 ObDereferenceObject(Thread);
257
258 Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO));
259 if(!NT_SUCCESS(Status))
260 {
261 SetLastNtError(Status);
262 RETURN( FALSE);
263 }
264
265 RETURN( TRUE);
266
267 CLEANUP:
268 DPRINT("Leave NtUserGetGUIThreadInfo, ret=%i\n",_ret_);
269 UserLeave();
270 END_CLEANUP;
271 }
272
273
274 DWORD
275 APIENTRY
276 NtUserGetGuiResources(
277 HANDLE hProcess,
278 DWORD uiFlags)
279 {
280 PEPROCESS Process;
281 PW32PROCESS W32Process;
282 NTSTATUS Status;
283 DWORD Ret = 0;
284 DECLARE_RETURN(DWORD);
285
286 DPRINT("Enter NtUserGetGuiResources\n");
287 UserEnterShared();
288
289 Status = ObReferenceObjectByHandle(hProcess,
290 PROCESS_QUERY_INFORMATION,
291 PsProcessType,
292 ExGetPreviousMode(),
293 (PVOID*)&Process,
294 NULL);
295
296 if(!NT_SUCCESS(Status))
297 {
298 SetLastNtError(Status);
299 RETURN( 0);
300 }
301
302 W32Process = (PW32PROCESS)Process->Win32Process;
303 if(!W32Process)
304 {
305 ObDereferenceObject(Process);
306 SetLastWin32Error(ERROR_INVALID_PARAMETER);
307 RETURN( 0);
308 }
309
310 switch(uiFlags)
311 {
312 case GR_GDIOBJECTS:
313 {
314 Ret = (DWORD)W32Process->GDIHandleCount;
315 break;
316 }
317 case GR_USEROBJECTS:
318 {
319 Ret = (DWORD)W32Process->UserHandleCount;
320 break;
321 }
322 default:
323 {
324 SetLastWin32Error(ERROR_INVALID_PARAMETER);
325 break;
326 }
327 }
328
329 ObDereferenceObject(Process);
330
331 RETURN( Ret);
332
333 CLEANUP:
334 DPRINT("Leave NtUserGetGuiResources, ret=%i\n",_ret_);
335 UserLeave();
336 END_CLEANUP;
337 }
338
339 NTSTATUS FASTCALL
340 IntSafeCopyUnicodeString(PUNICODE_STRING Dest,
341 PUNICODE_STRING Source)
342 {
343 NTSTATUS Status;
344 PWSTR Src;
345
346 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
347 if(!NT_SUCCESS(Status))
348 {
349 return Status;
350 }
351
352 if(Dest->Length > 0x4000)
353 {
354 return STATUS_UNSUCCESSFUL;
355 }
356
357 Src = Dest->Buffer;
358 Dest->Buffer = NULL;
359 Dest->MaximumLength = Dest->Length;
360
361 if(Dest->Length > 0 && Src)
362 {
363 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
364 if(!Dest->Buffer)
365 {
366 return STATUS_NO_MEMORY;
367 }
368
369 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
370 if(!NT_SUCCESS(Status))
371 {
372 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
373 Dest->Buffer = NULL;
374 return Status;
375 }
376
377
378 return STATUS_SUCCESS;
379 }
380
381 /* string is empty */
382 return STATUS_SUCCESS;
383 }
384
385 NTSTATUS FASTCALL
386 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest,
387 PUNICODE_STRING Source)
388 {
389 NTSTATUS Status;
390 PWSTR Src;
391
392 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
393 if(!NT_SUCCESS(Status))
394 {
395 return Status;
396 }
397
398 if(Dest->Length > 0x4000)
399 {
400 return STATUS_UNSUCCESSFUL;
401 }
402
403 Src = Dest->Buffer;
404 Dest->Buffer = NULL;
405 Dest->MaximumLength = 0;
406
407 if(Dest->Length > 0 && Src)
408 {
409 Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
410 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
411 if(!Dest->Buffer)
412 {
413 return STATUS_NO_MEMORY;
414 }
415
416 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
417 if(!NT_SUCCESS(Status))
418 {
419 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
420 Dest->Buffer = NULL;
421 return Status;
422 }
423
424 /* make sure the string is null-terminated */
425 Src = (PWSTR)((PBYTE)Dest->Buffer + Dest->Length);
426 *Src = L'\0';
427
428 return STATUS_SUCCESS;
429 }
430
431 /* string is empty */
432 return STATUS_SUCCESS;
433 }
434
435 NTSTATUS FASTCALL
436 IntUnicodeStringToNULLTerminated(PWSTR *Dest, PUNICODE_STRING Src)
437 {
438 if (Src->Length + sizeof(WCHAR) <= Src->MaximumLength
439 && L'\0' == Src->Buffer[Src->Length / sizeof(WCHAR)])
440 {
441 /* The unicode_string is already nul terminated. Just reuse it. */
442 *Dest = Src->Buffer;
443 return STATUS_SUCCESS;
444 }
445
446 *Dest = ExAllocatePoolWithTag(PagedPool, Src->Length + sizeof(WCHAR), TAG_STRING);
447 if (NULL == *Dest)
448 {
449 return STATUS_NO_MEMORY;
450 }
451 RtlCopyMemory(*Dest, Src->Buffer, Src->Length);
452 (*Dest)[Src->Length / 2] = L'\0';
453
454 return STATUS_SUCCESS;
455 }
456
457 void FASTCALL
458 IntFreeNULLTerminatedFromUnicodeString(PWSTR NullTerminated, PUNICODE_STRING UnicodeString)
459 {
460 if (NullTerminated != UnicodeString->Buffer)
461 {
462 ExFreePool(NullTerminated);
463 }
464 }
465
466 PPROCESSINFO
467 GetW32ProcessInfo(VOID)
468 {
469 PPROCESSINFO pi;
470 PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
471
472 if (W32Process == NULL)
473 {
474 /* FIXME - temporary hack for system threads... */
475 return NULL;
476 }
477
478 if (W32Process->ProcessInfo == NULL)
479 {
480 pi = UserHeapAlloc(sizeof(PROCESSINFO));
481 if (pi != NULL)
482 {
483 RtlZeroMemory(pi,
484 sizeof(PROCESSINFO));
485
486 /* initialize it */
487 pi->UserHandleTable = gHandleTable;
488 pi->hUserHeap = W32Process->HeapMappings.KernelMapping;
489 pi->UserHeapDelta = (ULONG_PTR)W32Process->HeapMappings.KernelMapping -
490 (ULONG_PTR)W32Process->HeapMappings.UserMapping;
491
492 if (InterlockedCompareExchangePointer((PVOID*)&W32Process->ProcessInfo,
493 pi,
494 NULL) != NULL)
495 {
496 UserHeapFree(pi);
497 }
498 }
499 else
500 {
501 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
502 }
503 }
504
505 return W32Process->ProcessInfo;
506 }
507
508 PW32THREADINFO
509 GetW32ThreadInfo(VOID)
510 {
511 PTEB Teb;
512 PW32THREADINFO ti;
513 PPROCESSINFO ppi;
514 PCLIENTINFO pci;
515 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
516
517 if (pti == NULL)
518 {
519 /* FIXME - temporary hack for system threads... */
520 return NULL;
521 }
522
523 /* allocate a THREADINFO structure if neccessary */
524 if (pti->ThreadInfo == NULL)
525 {
526 ti = UserHeapAlloc(sizeof(W32THREADINFO));
527 if (ti != NULL)
528 {
529 RtlZeroMemory(ti,
530 sizeof(W32THREADINFO));
531
532 /* initialize it */
533 ti->ppi = ppi = GetW32ProcessInfo();
534 ti->fsHooks = pti->fsHooks;
535 pti->pcti = &pti->cti; // FIXME Need to set it in desktop.c!
536 if (pti->Desktop != NULL)
537 {
538 pti->pDeskInfo = ti->pDeskInfo = pti->Desktop->DesktopInfo;
539 }
540 else
541 {
542 pti->pDeskInfo = ti->pDeskInfo = NULL;
543 }
544
545 pti->ThreadInfo = ti;
546 /* update the TEB */
547 Teb = NtCurrentTeb();
548 pci = GetWin32ClientInfo();
549 pti->pClientInfo = pci;
550 _SEH2_TRY
551 {
552 ProbeForWrite(Teb,
553 sizeof(TEB),
554 sizeof(ULONG));
555
556 Teb->Win32ThreadInfo = UserHeapAddressToUser(pti->ThreadInfo);
557
558 pci->pClientThreadInfo = NULL; // FIXME Need to set it in desktop.c!
559 pci->ppi = ppi;
560 pci->fsHooks = pti->fsHooks;
561 /* CI may not have been initialized. */
562 if (!pci->pDeskInfo && pti->pDeskInfo)
563 {
564 if (!pci->ulClientDelta) pci->ulClientDelta = DesktopHeapGetUserDelta();
565
566 pci->pDeskInfo =
567 (PVOID)((ULONG_PTR)pti->pDeskInfo - pci->ulClientDelta);
568 }
569 }
570 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
571 {
572 SetLastNtError(_SEH2_GetExceptionCode());
573 }
574 _SEH2_END;
575 }
576 else
577 {
578 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
579 }
580 }
581
582 return pti->ThreadInfo;
583 }
584
585
586 /* EOF */