375e3bfbaa2b143e9bc3050bc802cc8ad7e32434
[reactos.git] / reactos / win32ss / user / ntuser / object.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: User handle manager
5 * FILE: subsystems/win32/win32k/ntuser/object.c
6 * PROGRAMER: Copyright (C) 2001 Alexandre Julliard
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserObj);
11
12 //int usedHandles=0;
13 PUSER_HANDLE_TABLE gHandleTable = NULL;
14
15 #if DBG
16
17 void DbgUserDumpHandleTable()
18 {
19 int HandleCounts[USER_HANDLE_TYPE_COUNT];
20 PPROCESSINFO ppiList;
21 int i;
22 PWCHAR TypeNames[] = {L"Free",L"Window",L"Menu", L"CursorIcon", L"SMWP", L"Hook", L"ClipBoardData", L"CallProc",
23 L"Accel", L"DDEaccess", L"DDEconv", L"DDExact", L"Monitor", L"KBDlayout", L"KBDfile",
24 L"Event", L"Timer", L"InputContext", L"HidData", L"DeviceInfo", L"TouchInput",L"GestureInfo"};
25
26 ERR("Total handles count: %d\n", gpsi->cHandleEntries);
27
28 memset(HandleCounts, 0, sizeof(HandleCounts));
29
30 /* First of all count the number of handles per tpe */
31 ppiList = gppiList;
32 while (ppiList)
33 {
34 ERR("Process %s (%d) handles count: %d\n\t", ppiList->peProcess->ImageFileName, ppiList->peProcess->UniqueProcessId, ppiList->UserHandleCount);
35
36 for (i = 1 ;i < USER_HANDLE_TYPE_COUNT; i++)
37 {
38 HandleCounts[i] += ppiList->DbgHandleCount[i];
39
40 DbgPrint("%S: %d, ", TypeNames[i], ppiList->DbgHandleCount[i]);
41 if (i % 6 == 0)
42 DbgPrint("\n\t");
43 }
44 DbgPrint("\n");
45
46 ppiList = ppiList->ppiNext;
47 }
48
49 /* Print total type counts */
50 ERR("Total handles of the running processes: \n\t");
51 for (i = 1 ;i < USER_HANDLE_TYPE_COUNT; i++)
52 {
53 DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
54 if (i % 6 == 0)
55 DbgPrint("\n\t");
56 }
57 DbgPrint("\n");
58
59 /* Now count the handle counts that are allocated from the handle table */
60 memset(HandleCounts, 0, sizeof(HandleCounts));
61 for (i = 0; i < gHandleTable->nb_handles; i++)
62 HandleCounts[gHandleTable->handles[i].type]++;
63
64 ERR("Total handles count allocated: \n\t");
65 for (i = 1 ;i < USER_HANDLE_TYPE_COUNT; i++)
66 {
67 DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
68 if (i % 6 == 0)
69 DbgPrint("\n\t");
70 }
71 DbgPrint("\n");
72 }
73
74 #endif
75
76 PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
77 {
78 unsigned short generation;
79 int index = (((unsigned int)handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
80 if (index < 0 || index >= ht->nb_handles)
81 return NULL;
82 if (!ht->handles[index].type)
83 return NULL;
84 generation = (unsigned int)handle >> 16;
85 if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
86 return &ht->handles[index];
87 return NULL;
88 }
89
90 __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
91 {
92 int index = ptr - ht->handles;
93 return (HANDLE)(((index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
94 }
95
96 __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
97 {
98 PUSER_HANDLE_ENTRY entry;
99 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
100 TRACE("handles used %i\n",gpsi->cHandleEntries);
101
102 if (ht->freelist)
103 {
104 entry = ht->freelist;
105 ht->freelist = entry->ptr;
106
107 gpsi->cHandleEntries++;
108 ppi->UserHandleCount++;
109 return entry;
110 }
111
112 if (ht->nb_handles >= ht->allocated_handles) /* Need to grow the array */
113 {
114 ERR("Out of user handles! Used -> %i, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
115
116 #if DBG
117 DbgUserDumpHandleTable();
118 #endif
119
120 return NULL;
121 #if 0
122 PUSER_HANDLE_ENTRY new_handles;
123 /* Grow array by 50% (but at minimum 32 entries) */
124 int growth = max( 32, ht->allocated_handles / 2 );
125 int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
126 if (new_size <= ht->allocated_handles)
127 return NULL;
128 if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
129 return NULL;
130 ht->handles = new_handles;
131 ht->allocated_handles = new_size;
132 #endif
133 }
134
135 entry = &ht->handles[ht->nb_handles++];
136
137 entry->generation = 1;
138
139 gpsi->cHandleEntries++;
140 ppi->UserHandleCount++;
141
142 return entry;
143 }
144
145 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
146 {
147 ht->freelist = NULL;
148 ht->handles = mem;
149
150 ht->nb_handles = 0;
151 ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
152 }
153
154 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
155 {
156 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
157 void *ret;
158
159 #if DBG
160 ppi->DbgHandleCount[entry->type]--;
161 #endif
162
163 ret = entry->ptr;
164 entry->ptr = ht->freelist;
165 entry->type = 0;
166 entry->flags = 0;
167 entry->pi = NULL;
168 ht->freelist = entry;
169
170 gpsi->cHandleEntries--;
171 ppi->UserHandleCount--;
172
173 return ret;
174 }
175
176 static __inline PVOID
177 UserHandleOwnerByType(USER_OBJECT_TYPE type)
178 {
179 PVOID pi;
180
181 switch (type)
182 {
183 case otWindow:
184 case otInputContext:
185 pi = GetW32ThreadInfo();
186 break;
187
188 case otMenu:
189 case otCursorIcon:
190 case otHook:
191 case otCallProc:
192 case otAccel:
193 case otSMWP:
194 pi = GetW32ProcessInfo();
195 break;
196
197 case otMonitor:
198 pi = NULL; /* System */
199 break;
200
201 default:
202 pi = NULL;
203 break;
204 }
205
206 return pi;
207 }
208
209 /* allocate a user handle for a given object */
210 HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE type )
211 {
212 PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
213 if (!entry)
214 return 0;
215 entry->ptr = object;
216 entry->type = type;
217 entry->flags = 0;
218 entry->pi = UserHandleOwnerByType(type);
219 if (++entry->generation >= 0xffff)
220 entry->generation = 1;
221
222 /* We have created a handle, which is a reference! */
223 UserReferenceObject(object);
224
225 return entry_to_handle(ht, entry );
226 }
227
228 /* return a pointer to a user object from its handle without setting an error */
229 PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type )
230 {
231 PUSER_HANDLE_ENTRY entry;
232
233 ASSERT(ht);
234
235 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
236 {
237 return NULL;
238 }
239 return entry->ptr;
240 }
241
242 /* return a pointer to a user object from its handle */
243 PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type )
244 {
245 PUSER_HANDLE_ENTRY entry;
246
247 ASSERT(ht);
248
249 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
250 {
251 EngSetLastError(ERROR_INVALID_HANDLE);
252 return NULL;
253 }
254 return entry->ptr;
255 }
256
257
258 /* Get the full handle (32bit) for a possibly truncated (16bit) handle */
259 HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht, HANDLE handle )
260 {
261 PUSER_HANDLE_ENTRY entry;
262
263 if ((unsigned int)handle >> 16)
264 return handle;
265 if (!(entry = handle_to_entry(ht, handle )))
266 return handle;
267 return entry_to_handle( ht, entry );
268 }
269
270
271 /* Same as get_user_object plus set the handle to the full 32-bit value */
272 void *get_user_object_handle(PUSER_HANDLE_TABLE ht, HANDLE* handle, USER_OBJECT_TYPE type )
273 {
274 PUSER_HANDLE_ENTRY entry;
275
276 if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
277 return NULL;
278 *handle = entry_to_handle( ht, entry );
279 return entry->ptr;
280 }
281
282
283
284 BOOL FASTCALL UserCreateHandleTable(VOID)
285 {
286 PVOID mem;
287 INT HandleCount = 1024 * 4;
288
289 // FIXME: Don't alloc all at once! Must be mapped into umode also...
290 mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * HandleCount);
291 if (!mem)
292 {
293 ERR("Failed creating handle table\n");
294 return FALSE;
295 }
296
297 gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
298 if (gHandleTable == NULL)
299 {
300 UserHeapFree(mem);
301 ERR("Failed creating handle table\n");
302 return FALSE;
303 }
304
305 // FIXME: Make auto growable
306 UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * HandleCount);
307
308 return TRUE;
309 }
310
311 //
312 // New
313 //
314 PVOID
315 FASTCALL
316 UserCreateObject( PUSER_HANDLE_TABLE ht,
317 PDESKTOP pDesktop,
318 HANDLE* h,
319 USER_OBJECT_TYPE type,
320 ULONG size)
321 {
322 HANDLE hi;
323 PVOID Object;
324 PTHREADINFO pti;
325 PPROCESSINFO ppi;
326 BOOL dt;
327 PDESKTOP rpdesk = pDesktop;
328
329 pti = GetW32ThreadInfo();
330 ppi = pti->ppi;
331 if (!pDesktop) rpdesk = pti->rpdesk;
332
333 switch (type)
334 {
335 case otWindow:
336 // case otMenu:
337 case otHook:
338 case otCallProc:
339 case otInputContext:
340 Object = DesktopHeapAlloc(rpdesk, size);
341 dt = TRUE;
342 break;
343
344 default:
345 Object = UserHeapAlloc(size);
346 dt = FALSE;
347 break;
348 }
349
350 if (!Object)
351 return NULL;
352
353
354 hi = UserAllocHandle(ht, Object, type );
355 if (!hi)
356 {
357 if (dt)
358 DesktopHeapFree(rpdesk, Object);
359 else
360 UserHeapFree(Object);
361 return NULL;
362 }
363
364 #if DBG
365 ppi->DbgHandleCount[type]++;
366 #endif
367
368 RtlZeroMemory(Object, size);
369
370 switch (type)
371 {
372 case otWindow:
373 case otHook:
374 case otInputContext:
375 ((PTHRDESKHEAD)Object)->rpdesk = rpdesk;
376 ((PTHRDESKHEAD)Object)->pSelf = Object;
377 case otEvent:
378 ((PTHROBJHEAD)Object)->pti = pti;
379 break;
380
381 case otMenu:
382 case otCallProc:
383 ((PPROCDESKHEAD)Object)->rpdesk = rpdesk;
384 ((PPROCDESKHEAD)Object)->pSelf = Object;
385 break;
386
387 case otCursorIcon:
388 ((PPROCMARKHEAD)Object)->ppi = ppi;
389 break;
390
391 default:
392 break;
393 }
394 /* Now set default headers. */
395 ((PHEAD)Object)->h = hi;
396 ((PHEAD)Object)->cLockObj = 2; // We need this, because we create 2 refs: handle and pointer!
397
398 if (h)
399 *h = hi;
400 return Object;
401 }
402
403
404 BOOL
405 FASTCALL
406 UserDereferenceObject(PVOID object)
407 {
408 PUSER_HANDLE_ENTRY entry;
409 USER_OBJECT_TYPE type;
410
411 ASSERT(((PHEAD)object)->cLockObj >= 1);
412
413 if ((INT)--((PHEAD)object)->cLockObj <= 0)
414 {
415 entry = handle_to_entry(gHandleTable, ((PHEAD)object)->h );
416
417 if (!entry)
418 {
419 ERR("Warning! Dereference Object without ENTRY! Obj -> 0x%x\n", object);
420 return FALSE;
421 }
422 TRACE("Warning! Dereference to zero! Obj -> 0x%x\n", object);
423
424 ((PHEAD)object)->cLockObj = 0;
425
426 if (!(entry->flags & HANDLEENTRY_INDESTROY))
427 return TRUE;
428
429 type = entry->type;
430 free_user_entry(gHandleTable, entry );
431
432 switch (type)
433 {
434 case otWindow:
435 // case otMenu:
436 case otHook:
437 case otCallProc:
438 case otInputContext:
439 return DesktopHeapFree(((PTHRDESKHEAD)object)->rpdesk, object);
440
441 default:
442 return UserHeapFree(object);
443 }
444 }
445 return FALSE;
446 }
447
448 BOOL
449 FASTCALL
450 UserFreeHandle(PUSER_HANDLE_TABLE ht, HANDLE handle )
451 {
452 PUSER_HANDLE_ENTRY entry;
453
454 if (!(entry = handle_to_entry( ht, handle )))
455 {
456 SetLastNtError( STATUS_INVALID_HANDLE );
457 return FALSE;
458 }
459
460 entry->flags = HANDLEENTRY_INDESTROY;
461
462 return UserDereferenceObject(entry->ptr);
463 }
464
465 BOOL
466 FASTCALL
467 UserObjectInDestroy(HANDLE h)
468 {
469 PUSER_HANDLE_ENTRY entry;
470
471 if (!(entry = handle_to_entry( gHandleTable, h )))
472 {
473 SetLastNtError( STATUS_INVALID_HANDLE );
474 return FALSE;
475 }
476 return (entry->flags & HANDLEENTRY_INDESTROY);
477 }
478
479 BOOL
480 FASTCALL
481 UserDeleteObject(HANDLE h, USER_OBJECT_TYPE type )
482 {
483 PVOID body = UserGetObject(gHandleTable, h, type);
484
485 if (!body) return FALSE;
486
487 ASSERT( ((PHEAD)body)->cLockObj >= 1);
488
489 return UserFreeHandle(gHandleTable, h);
490 }
491
492 VOID
493 FASTCALL
494 UserReferenceObject(PVOID obj)
495 {
496 ASSERT(((PHEAD)obj)->cLockObj >= 0);
497
498 ((PHEAD)obj)->cLockObj++;
499 }
500
501 PVOID
502 FASTCALL
503 UserReferenceObjectByHandle(HANDLE handle, USER_OBJECT_TYPE type)
504 {
505 PVOID object;
506
507 object = UserGetObject(gHandleTable, handle, type);
508 if (object)
509 {
510 UserReferenceObject(object);
511 }
512 return object;
513 }
514
515 /*
516 * NtUserValidateHandleSecure
517 *
518 * Status
519 * @implemented
520 */
521
522 BOOL
523 APIENTRY
524 NtUserValidateHandleSecure(
525 HANDLE handle,
526 BOOL Restricted)
527 {
528 if(!Restricted)
529 {
530 UINT uType;
531 {
532 PUSER_HANDLE_ENTRY entry;
533 if (!(entry = handle_to_entry(gHandleTable, handle )))
534 {
535 EngSetLastError(ERROR_INVALID_HANDLE);
536 return FALSE;
537 }
538 uType = entry->type;
539 }
540 switch (uType)
541 {
542 case otWindow:
543 {
544 if (UserGetWindowObject((HWND) handle)) return TRUE;
545 return FALSE;
546 }
547 case otMenu:
548 {
549 if (UserGetMenuObject((HMENU) handle)) return TRUE;
550 return FALSE;
551 }
552 case otAccel:
553 {
554 if (UserGetAccelObject((HACCEL) handle)) return TRUE;
555 return FALSE;
556 }
557 case otCursorIcon:
558 {
559 if (UserGetCurIconObject((HCURSOR) handle)) return TRUE;
560 return FALSE;
561 }
562 case otHook:
563 {
564 if (IntGetHookObject((HHOOK) handle)) return TRUE;
565 return FALSE;
566 }
567 case otMonitor:
568 {
569 if (UserGetMonitorObject((HMONITOR) handle)) return TRUE;
570 return FALSE;
571 }
572 case otCallProc:
573 {
574 WNDPROC_INFO Proc;
575 return UserGetCallProcInfo( handle, &Proc );
576 }
577 default:
578 EngSetLastError(ERROR_INVALID_HANDLE);
579 }
580 }
581 else
582 { /* Is handle entry restricted? */
583 STUB
584 }
585 return FALSE;
586 }