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