Sync to trunk head(r38096)
[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 DPRINT1("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()->Desktop->hProgmanWindow;
96 break;
97 case THREADSTATE_TASKMANWINDOW:
98 ret = (DWORD_PTR)GetW32ThreadInfo()->Desktop->hTaskManWindow;
99 break;
100 case THREADSTATE_ACTIVEWINDOW:
101 ret = (DWORD_PTR)UserGetActiveWindow();
102 break;
103 }
104
105 DPRINT("Leave NtUserGetThreadState, ret=%i\n", ret);
106 UserLeave();
107
108 return ret;
109 }
110
111
112 UINT
113 APIENTRY
114 NtUserGetDoubleClickTime(VOID)
115 {
116 UINT Result;
117 NTSTATUS Status;
118 PWINSTATION_OBJECT WinStaObject;
119 PSYSTEM_CURSORINFO CurInfo;
120 DECLARE_RETURN(UINT);
121
122 DPRINT("Enter NtUserGetDoubleClickTime\n");
123 UserEnterShared();
124
125 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
126 KernelMode,
127 0,
128 &WinStaObject);
129 if (!NT_SUCCESS(Status))
130 RETURN( (DWORD)FALSE);
131
132 CurInfo = IntGetSysCursorInfo(WinStaObject);
133 Result = CurInfo->DblClickSpeed;
134
135 ObDereferenceObject(WinStaObject);
136 RETURN( Result);
137
138 CLEANUP:
139 DPRINT("Leave NtUserGetDoubleClickTime, ret=%i\n",_ret_);
140 UserLeave();
141 END_CLEANUP;
142 }
143
144 BOOL
145 APIENTRY
146 NtUserGetGUIThreadInfo(
147 DWORD idThread, /* if NULL use foreground thread */
148 LPGUITHREADINFO lpgui)
149 {
150 NTSTATUS Status;
151 PTHRDCARETINFO CaretInfo;
152 GUITHREADINFO SafeGui;
153 PDESKTOP Desktop;
154 PUSER_MESSAGE_QUEUE MsgQueue;
155 PETHREAD Thread = NULL;
156 DECLARE_RETURN(BOOLEAN);
157
158 DPRINT("Enter NtUserGetGUIThreadInfo\n");
159 UserEnterShared();
160
161 Status = MmCopyFromCaller(&SafeGui, lpgui, sizeof(DWORD));
162 if(!NT_SUCCESS(Status))
163 {
164 SetLastNtError(Status);
165 RETURN( FALSE);
166 }
167
168 if(SafeGui.cbSize != sizeof(GUITHREADINFO))
169 {
170 SetLastWin32Error(ERROR_INVALID_PARAMETER);
171 RETURN( FALSE);
172 }
173
174 if(idThread)
175 {
176 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
177 if(!NT_SUCCESS(Status))
178 {
179 SetLastWin32Error(ERROR_ACCESS_DENIED);
180 RETURN( FALSE);
181 }
182 Desktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->Desktop;
183 }
184 else
185 {
186 /* get the foreground thread */
187 PTHREADINFO W32Thread = (PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread;
188 Desktop = W32Thread->Desktop;
189 if(Desktop)
190 {
191 MsgQueue = Desktop->ActiveMessageQueue;
192 if(MsgQueue)
193 {
194 Thread = MsgQueue->Thread;
195 }
196 }
197 }
198
199 if(!Thread || !Desktop)
200 {
201 if(idThread && Thread)
202 ObDereferenceObject(Thread);
203 SetLastWin32Error(ERROR_ACCESS_DENIED);
204 RETURN( FALSE);
205 }
206
207 MsgQueue = (PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue;
208 CaretInfo = MsgQueue->CaretInfo;
209
210 SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0);
211 if(MsgQueue->MenuOwner)
212 SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState;
213 if(MsgQueue->MoveSize)
214 SafeGui.flags |= GUI_INMOVESIZE;
215
216 /* FIXME add flag GUI_16BITTASK */
217
218 SafeGui.hwndActive = MsgQueue->ActiveWindow;
219 SafeGui.hwndFocus = MsgQueue->FocusWindow;
220 SafeGui.hwndCapture = MsgQueue->CaptureWindow;
221 SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
222 SafeGui.hwndMoveSize = MsgQueue->MoveSize;
223 SafeGui.hwndCaret = CaretInfo->hWnd;
224
225 SafeGui.rcCaret.left = CaretInfo->Pos.x;
226 SafeGui.rcCaret.top = CaretInfo->Pos.y;
227 SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx;
228 SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy;
229
230 if(idThread)
231 ObDereferenceObject(Thread);
232
233 Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO));
234 if(!NT_SUCCESS(Status))
235 {
236 SetLastNtError(Status);
237 RETURN( FALSE);
238 }
239
240 RETURN( TRUE);
241
242 CLEANUP:
243 DPRINT("Leave NtUserGetGUIThreadInfo, ret=%i\n",_ret_);
244 UserLeave();
245 END_CLEANUP;
246 }
247
248
249 DWORD
250 APIENTRY
251 NtUserGetGuiResources(
252 HANDLE hProcess,
253 DWORD uiFlags)
254 {
255 PEPROCESS Process;
256 PW32PROCESS W32Process;
257 NTSTATUS Status;
258 DWORD Ret = 0;
259 DECLARE_RETURN(DWORD);
260
261 DPRINT("Enter NtUserGetGuiResources\n");
262 UserEnterShared();
263
264 Status = ObReferenceObjectByHandle(hProcess,
265 PROCESS_QUERY_INFORMATION,
266 PsProcessType,
267 ExGetPreviousMode(),
268 (PVOID*)&Process,
269 NULL);
270
271 if(!NT_SUCCESS(Status))
272 {
273 SetLastNtError(Status);
274 RETURN( 0);
275 }
276
277 W32Process = (PW32PROCESS)Process->Win32Process;
278 if(!W32Process)
279 {
280 ObDereferenceObject(Process);
281 SetLastWin32Error(ERROR_INVALID_PARAMETER);
282 RETURN( 0);
283 }
284
285 switch(uiFlags)
286 {
287 case GR_GDIOBJECTS:
288 {
289 Ret = (DWORD)W32Process->GDIObjects;
290 break;
291 }
292 case GR_USEROBJECTS:
293 {
294 Ret = (DWORD)W32Process->UserObjects;
295 break;
296 }
297 default:
298 {
299 SetLastWin32Error(ERROR_INVALID_PARAMETER);
300 break;
301 }
302 }
303
304 ObDereferenceObject(Process);
305
306 RETURN( Ret);
307
308 CLEANUP:
309 DPRINT("Leave NtUserGetGuiResources, ret=%i\n",_ret_);
310 UserLeave();
311 END_CLEANUP;
312 }
313
314 NTSTATUS FASTCALL
315 IntSafeCopyUnicodeString(PUNICODE_STRING Dest,
316 PUNICODE_STRING Source)
317 {
318 NTSTATUS Status;
319 PWSTR Src;
320
321 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
322 if(!NT_SUCCESS(Status))
323 {
324 return Status;
325 }
326
327 if(Dest->Length > 0x4000)
328 {
329 return STATUS_UNSUCCESSFUL;
330 }
331
332 Src = Dest->Buffer;
333 Dest->Buffer = NULL;
334 Dest->MaximumLength = Dest->Length;
335
336 if(Dest->Length > 0 && Src)
337 {
338 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
339 if(!Dest->Buffer)
340 {
341 return STATUS_NO_MEMORY;
342 }
343
344 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
345 if(!NT_SUCCESS(Status))
346 {
347 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
348 Dest->Buffer = NULL;
349 return Status;
350 }
351
352
353 return STATUS_SUCCESS;
354 }
355
356 /* string is empty */
357 return STATUS_SUCCESS;
358 }
359
360 NTSTATUS FASTCALL
361 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest,
362 PUNICODE_STRING Source)
363 {
364 NTSTATUS Status;
365 PWSTR Src;
366
367 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
368 if(!NT_SUCCESS(Status))
369 {
370 return Status;
371 }
372
373 if(Dest->Length > 0x4000)
374 {
375 return STATUS_UNSUCCESSFUL;
376 }
377
378 Src = Dest->Buffer;
379 Dest->Buffer = NULL;
380 Dest->MaximumLength = 0;
381
382 if(Dest->Length > 0 && Src)
383 {
384 Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
385 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
386 if(!Dest->Buffer)
387 {
388 return STATUS_NO_MEMORY;
389 }
390
391 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
392 if(!NT_SUCCESS(Status))
393 {
394 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
395 Dest->Buffer = NULL;
396 return Status;
397 }
398
399 /* make sure the string is null-terminated */
400 Src = (PWSTR)((PBYTE)Dest->Buffer + Dest->Length);
401 *Src = L'\0';
402
403 return STATUS_SUCCESS;
404 }
405
406 /* string is empty */
407 return STATUS_SUCCESS;
408 }
409
410 NTSTATUS FASTCALL
411 IntUnicodeStringToNULLTerminated(PWSTR *Dest, PUNICODE_STRING Src)
412 {
413 if (Src->Length + sizeof(WCHAR) <= Src->MaximumLength
414 && L'\0' == Src->Buffer[Src->Length / sizeof(WCHAR)])
415 {
416 /* The unicode_string is already nul terminated. Just reuse it. */
417 *Dest = Src->Buffer;
418 return STATUS_SUCCESS;
419 }
420
421 *Dest = ExAllocatePoolWithTag(PagedPool, Src->Length + sizeof(WCHAR), TAG_STRING);
422 if (NULL == *Dest)
423 {
424 return STATUS_NO_MEMORY;
425 }
426 RtlCopyMemory(*Dest, Src->Buffer, Src->Length);
427 (*Dest)[Src->Length / 2] = L'\0';
428
429 return STATUS_SUCCESS;
430 }
431
432 void FASTCALL
433 IntFreeNULLTerminatedFromUnicodeString(PWSTR NullTerminated, PUNICODE_STRING UnicodeString)
434 {
435 if (NullTerminated != UnicodeString->Buffer)
436 {
437 ExFreePool(NullTerminated);
438 }
439 }
440
441 PW32PROCESSINFO
442 GetW32ProcessInfo(VOID)
443 {
444 PW32PROCESSINFO pi;
445 PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
446
447 if (W32Process == NULL)
448 {
449 /* FIXME - temporary hack for system threads... */
450 return NULL;
451 }
452
453 if (W32Process->ProcessInfo == NULL)
454 {
455 pi = UserHeapAlloc(sizeof(W32PROCESSINFO));
456 if (pi != NULL)
457 {
458 RtlZeroMemory(pi,
459 sizeof(W32PROCESSINFO));
460
461 /* initialize it */
462 pi->UserHandleTable = gHandleTable;
463 pi->hUserHeap = W32Process->HeapMappings.KernelMapping;
464 pi->UserHeapDelta = (ULONG_PTR)W32Process->HeapMappings.KernelMapping -
465 (ULONG_PTR)W32Process->HeapMappings.UserMapping;
466 pi->psi = gpsi;
467
468 if (InterlockedCompareExchangePointer((PVOID*)&W32Process->ProcessInfo,
469 pi,
470 NULL) != NULL)
471 {
472 UserHeapFree(pi);
473 }
474 }
475 else
476 {
477 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
478 }
479 }
480
481 return W32Process->ProcessInfo;
482 }
483
484 PW32THREADINFO
485 GetW32ThreadInfo(VOID)
486 {
487 PTEB Teb;
488 PW32THREADINFO ti;
489 PCLIENTINFO ci;
490 PTHREADINFO W32Thread = PsGetCurrentThreadWin32Thread();
491
492 if (W32Thread == NULL)
493 {
494 /* FIXME - temporary hack for system threads... */
495 return NULL;
496 }
497
498 /* allocate a THREADINFO structure if neccessary */
499 if (W32Thread->ThreadInfo == NULL)
500 {
501 ti = UserHeapAlloc(sizeof(W32THREADINFO));
502 if (ti != NULL)
503 {
504 RtlZeroMemory(ti,
505 sizeof(W32THREADINFO));
506
507 /* initialize it */
508 ti->kpi = GetW32ProcessInfo();
509 ti->pi = UserHeapAddressToUser(ti->kpi);
510 ti->Hooks = W32Thread->Hooks;
511 if (W32Thread->Desktop != NULL)
512 {
513 ti->Desktop = W32Thread->Desktop->DesktopInfo;
514 }
515 else
516 {
517 ti->Desktop = NULL;
518 }
519
520 W32Thread->ThreadInfo = ti;
521 /* update the TEB */
522 Teb = NtCurrentTeb();
523 ci = GetWin32ClientInfo();
524 _SEH2_TRY
525 {
526 ProbeForWrite(Teb,
527 sizeof(TEB),
528 sizeof(ULONG));
529
530 Teb->Win32ThreadInfo = UserHeapAddressToUser(W32Thread->ThreadInfo);
531 ci->pClientThreadInfo = &ti->ClientThreadInfo;
532 }
533 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
534 {
535 SetLastNtError(_SEH2_GetExceptionCode());
536 }
537 _SEH2_END;
538 }
539 else
540 {
541 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
542 }
543 }
544
545 return W32Thread->ThreadInfo;
546 }
547
548
549 /* EOF */