Sync with trunk head (part 1 of 2)
[reactos.git] / 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 <win32k.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16
17 SHORT
18 FASTCALL
19 IntGdiGetLanguageID(VOID)
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 PUSER_MESSAGE_QUEUE MessageQueue =
106 ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->MessageQueue;
107 DPRINT1("THREADSTATE_INSENDMESSAGE\n");
108
109 ret = ISMEX_NOSEND;
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 break;
121 }
122 case THREADSTATE_GETMESSAGETIME:
123 /* FIXME Needs more work! */
124 ret = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->timeLast;
125 break;
126
127 case THREADSTATE_GETINPUTSTATE:
128 ret = HIWORD(IntGetQueueStatus(FALSE)) & (QS_KEY | QS_MOUSEBUTTON);
129 break;
130 }
131
132 DPRINT("Leave NtUserGetThreadState, ret=%i\n", ret);
133 UserLeave();
134
135 return ret;
136 }
137
138
139 UINT
140 APIENTRY
141 NtUserGetDoubleClickTime(VOID)
142 {
143 UINT Result;
144
145 DPRINT("Enter NtUserGetDoubleClickTime\n");
146 UserEnterShared();
147
148 // FIXME: Check if this works on non-interactive winsta
149 Result = gspv.iDblClickTime;
150
151 DPRINT("Leave NtUserGetDoubleClickTime, ret=%i\n", Result);
152 UserLeave();
153 return Result;
154 }
155
156 BOOL
157 APIENTRY
158 NtUserGetGUIThreadInfo(
159 DWORD idThread, /* if NULL use foreground thread */
160 LPGUITHREADINFO lpgui)
161 {
162 NTSTATUS Status;
163 PTHRDCARETINFO CaretInfo;
164 GUITHREADINFO SafeGui;
165 PDESKTOP Desktop;
166 PUSER_MESSAGE_QUEUE MsgQueue;
167 PETHREAD Thread = NULL;
168 DECLARE_RETURN(BOOLEAN);
169
170 DPRINT("Enter NtUserGetGUIThreadInfo\n");
171 UserEnterShared();
172
173 Status = MmCopyFromCaller(&SafeGui, lpgui, sizeof(DWORD));
174 if(!NT_SUCCESS(Status))
175 {
176 SetLastNtError(Status);
177 RETURN( FALSE);
178 }
179
180 if(SafeGui.cbSize != sizeof(GUITHREADINFO))
181 {
182 SetLastWin32Error(ERROR_INVALID_PARAMETER);
183 RETURN( FALSE);
184 }
185
186 if(idThread)
187 {
188 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
189 if(!NT_SUCCESS(Status))
190 {
191 SetLastWin32Error(ERROR_ACCESS_DENIED);
192 RETURN( FALSE);
193 }
194 Desktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk;
195 }
196 else
197 {
198 /* get the foreground thread */
199 PTHREADINFO W32Thread = (PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread;
200 Desktop = W32Thread->rpdesk;
201 if(Desktop)
202 {
203 MsgQueue = Desktop->ActiveMessageQueue;
204 if(MsgQueue)
205 {
206 Thread = MsgQueue->Thread;
207 }
208 }
209 }
210
211 if(!Thread || !Desktop)
212 {
213 if(idThread && Thread)
214 ObDereferenceObject(Thread);
215 SetLastWin32Error(ERROR_ACCESS_DENIED);
216 RETURN( FALSE);
217 }
218
219 MsgQueue = (PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue;
220 CaretInfo = MsgQueue->CaretInfo;
221
222 SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0);
223 if(MsgQueue->MenuOwner)
224 SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState;
225 if(MsgQueue->MoveSize)
226 SafeGui.flags |= GUI_INMOVESIZE;
227
228 /* FIXME add flag GUI_16BITTASK */
229
230 SafeGui.hwndActive = MsgQueue->ActiveWindow;
231 SafeGui.hwndFocus = MsgQueue->FocusWindow;
232 SafeGui.hwndCapture = MsgQueue->CaptureWindow;
233 SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
234 SafeGui.hwndMoveSize = MsgQueue->MoveSize;
235 SafeGui.hwndCaret = CaretInfo->hWnd;
236
237 SafeGui.rcCaret.left = CaretInfo->Pos.x;
238 SafeGui.rcCaret.top = CaretInfo->Pos.y;
239 SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx;
240 SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy;
241
242 if(idThread)
243 ObDereferenceObject(Thread);
244
245 Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO));
246 if(!NT_SUCCESS(Status))
247 {
248 SetLastNtError(Status);
249 RETURN( FALSE);
250 }
251
252 RETURN( TRUE);
253
254 CLEANUP:
255 DPRINT("Leave NtUserGetGUIThreadInfo, ret=%i\n",_ret_);
256 UserLeave();
257 END_CLEANUP;
258 }
259
260
261 DWORD
262 APIENTRY
263 NtUserGetGuiResources(
264 HANDLE hProcess,
265 DWORD uiFlags)
266 {
267 PEPROCESS Process;
268 PPROCESSINFO W32Process;
269 NTSTATUS Status;
270 DWORD Ret = 0;
271 DECLARE_RETURN(DWORD);
272
273 DPRINT("Enter NtUserGetGuiResources\n");
274 UserEnterShared();
275
276 Status = ObReferenceObjectByHandle(hProcess,
277 PROCESS_QUERY_INFORMATION,
278 PsProcessType,
279 ExGetPreviousMode(),
280 (PVOID*)&Process,
281 NULL);
282
283 if(!NT_SUCCESS(Status))
284 {
285 SetLastNtError(Status);
286 RETURN( 0);
287 }
288
289 W32Process = (PPROCESSINFO)Process->Win32Process;
290 if(!W32Process)
291 {
292 ObDereferenceObject(Process);
293 SetLastWin32Error(ERROR_INVALID_PARAMETER);
294 RETURN( 0);
295 }
296
297 switch(uiFlags)
298 {
299 case GR_GDIOBJECTS:
300 {
301 Ret = (DWORD)W32Process->GDIHandleCount;
302 break;
303 }
304 case GR_USEROBJECTS:
305 {
306 Ret = (DWORD)W32Process->UserHandleCount;
307 break;
308 }
309 default:
310 {
311 SetLastWin32Error(ERROR_INVALID_PARAMETER);
312 break;
313 }
314 }
315
316 ObDereferenceObject(Process);
317
318 RETURN( Ret);
319
320 CLEANUP:
321 DPRINT("Leave NtUserGetGuiResources, ret=%i\n",_ret_);
322 UserLeave();
323 END_CLEANUP;
324 }
325
326 NTSTATUS FASTCALL
327 IntSafeCopyUnicodeString(PUNICODE_STRING Dest,
328 PUNICODE_STRING Source)
329 {
330 NTSTATUS Status;
331 PWSTR Src;
332
333 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
334 if(!NT_SUCCESS(Status))
335 {
336 return Status;
337 }
338
339 if(Dest->Length > 0x4000)
340 {
341 return STATUS_UNSUCCESSFUL;
342 }
343
344 Src = Dest->Buffer;
345 Dest->Buffer = NULL;
346 Dest->MaximumLength = Dest->Length;
347
348 if(Dest->Length > 0 && Src)
349 {
350 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
351 if(!Dest->Buffer)
352 {
353 return STATUS_NO_MEMORY;
354 }
355
356 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
357 if(!NT_SUCCESS(Status))
358 {
359 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
360 Dest->Buffer = NULL;
361 return Status;
362 }
363
364
365 return STATUS_SUCCESS;
366 }
367
368 /* string is empty */
369 return STATUS_SUCCESS;
370 }
371
372 NTSTATUS FASTCALL
373 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest,
374 PUNICODE_STRING Source)
375 {
376 NTSTATUS Status;
377 PWSTR Src;
378
379 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
380 if(!NT_SUCCESS(Status))
381 {
382 return Status;
383 }
384
385 if(Dest->Length > 0x4000)
386 {
387 return STATUS_UNSUCCESSFUL;
388 }
389
390 Src = Dest->Buffer;
391 Dest->Buffer = NULL;
392 Dest->MaximumLength = 0;
393
394 if(Dest->Length > 0 && Src)
395 {
396 Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
397 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
398 if(!Dest->Buffer)
399 {
400 return STATUS_NO_MEMORY;
401 }
402
403 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
404 if(!NT_SUCCESS(Status))
405 {
406 ExFreePoolWithTag(Dest->Buffer, TAG_STRING);
407 Dest->Buffer = NULL;
408 return Status;
409 }
410
411 /* make sure the string is null-terminated */
412 Src = (PWSTR)((PBYTE)Dest->Buffer + Dest->Length);
413 *Src = L'\0';
414
415 return STATUS_SUCCESS;
416 }
417
418 /* string is empty */
419 return STATUS_SUCCESS;
420 }
421
422 NTSTATUS FASTCALL
423 IntUnicodeStringToNULLTerminated(PWSTR *Dest, PUNICODE_STRING Src)
424 {
425 if (Src->Length + sizeof(WCHAR) <= Src->MaximumLength
426 && L'\0' == Src->Buffer[Src->Length / sizeof(WCHAR)])
427 {
428 /* The unicode_string is already nul terminated. Just reuse it. */
429 *Dest = Src->Buffer;
430 return STATUS_SUCCESS;
431 }
432
433 *Dest = ExAllocatePoolWithTag(PagedPool, Src->Length + sizeof(WCHAR), TAG_STRING);
434 if (NULL == *Dest)
435 {
436 return STATUS_NO_MEMORY;
437 }
438 RtlCopyMemory(*Dest, Src->Buffer, Src->Length);
439 (*Dest)[Src->Length / 2] = L'\0';
440
441 return STATUS_SUCCESS;
442 }
443
444 void FASTCALL
445 IntFreeNULLTerminatedFromUnicodeString(PWSTR NullTerminated, PUNICODE_STRING UnicodeString)
446 {
447 if (NullTerminated != UnicodeString->Buffer)
448 {
449 ExFreePool(NullTerminated);
450 }
451 }
452
453 PPROCESSINFO
454 GetW32ProcessInfo(VOID)
455 {
456 return (PPROCESSINFO)PsGetCurrentProcessWin32Process();
457 }
458
459 PTHREADINFO
460 GetW32ThreadInfo(VOID)
461 {
462 PTEB Teb;
463 PPROCESSINFO ppi;
464 PCLIENTINFO pci;
465 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
466
467 if (pti == NULL)
468 {
469 /* FIXME - temporary hack for system threads... */
470 return NULL;
471 }
472 /* initialize it */
473 pti->ppi = ppi = GetW32ProcessInfo();
474
475 pti->pcti = &pti->cti; // FIXME Need to set it in desktop.c!
476
477 if (pti->rpdesk != NULL)
478 {
479 pti->pDeskInfo = pti->rpdesk->pDeskInfo;
480 }
481 else
482 {
483 pti->pDeskInfo = NULL;
484 }
485 /* update the TEB */
486 Teb = NtCurrentTeb();
487 pci = GetWin32ClientInfo();
488 pti->pClientInfo = pci;
489 _SEH2_TRY
490 {
491 ProbeForWrite( Teb,
492 sizeof(TEB),
493 sizeof(ULONG));
494
495 Teb->Win32ThreadInfo = (PW32THREAD) pti;
496
497 pci->pClientThreadInfo = NULL; // FIXME Need to set it in desktop.c!
498 pci->ppi = ppi;
499 pci->fsHooks = pti->fsHooks;
500 if (pti->KeyboardLayout) pci->hKL = pti->KeyboardLayout->hkl;
501 pci->dwTIFlags = pti->TIF_flags;
502 /* CI may not have been initialized. */
503 if (!pci->pDeskInfo && pti->pDeskInfo)
504 {
505 if (!pci->ulClientDelta) pci->ulClientDelta = DesktopHeapGetUserDelta();
506
507 pci->pDeskInfo = (PVOID)((ULONG_PTR)pti->pDeskInfo - pci->ulClientDelta);
508 }
509 }
510 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
511 {
512 SetLastNtError(_SEH2_GetExceptionCode());
513 }
514 _SEH2_END;
515
516 return pti;
517 }
518
519
520 /* EOF */