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