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