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
10 DBG_DEFAULT_CHANNEL(UserObj
);
13 PUSER_HANDLE_TABLE gHandleTable
= NULL
;
16 PUSER_HANDLE_ENTRY
handle_to_entry(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
18 unsigned short generation
;
19 int index
= (((unsigned int)handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
20 if (index
< 0 || index
>= ht
->nb_handles
)
22 if (!ht
->handles
[index
].type
)
24 generation
= (unsigned int)handle
>> 16;
25 if (generation
== ht
->handles
[index
].generation
|| !generation
|| generation
== 0xffff)
26 return &ht
->handles
[index
];
30 __inline
static HANDLE
entry_to_handle(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY ptr
)
32 int index
= ptr
- ht
->handles
;
33 return (HANDLE
)(((index
<< 1) + FIRST_USER_HANDLE
) + (ptr
->generation
<< 16));
36 __inline
static PUSER_HANDLE_ENTRY
alloc_user_entry(PUSER_HANDLE_TABLE ht
)
38 PUSER_HANDLE_ENTRY entry
;
39 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
40 TRACE("handles used %i\n",gpsi
->cHandleEntries
);
45 ht
->freelist
= entry
->ptr
;
47 gpsi
->cHandleEntries
++;
48 ppi
->UserHandleCount
++;
52 if (ht
->nb_handles
>= ht
->allocated_handles
) /* Need to grow the array */
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;
58 ERR("Out of user handles! Used -> %i, NM_Handle -> %d\n", gpsi
->cHandleEntries
, ht
->nb_handles
);
60 for(i
= 0; i
< ht
->nb_handles
; i
++)
62 switch (ht
->handles
[i
].type
)
64 case otFree
: // Should be zero.
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
);
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
)
111 if (!(new_handles
= UserHeapReAlloc( ht
->handles
, new_size
* sizeof(*ht
->handles
) )))
113 ht
->handles
= new_handles
;
114 ht
->allocated_handles
= new_size
;
118 entry
= &ht
->handles
[ht
->nb_handles
++];
120 entry
->generation
= 1;
122 gpsi
->cHandleEntries
++;
123 ppi
->UserHandleCount
++;
128 VOID
UserInitHandleTable(PUSER_HANDLE_TABLE ht
, PVOID mem
, ULONG bytes
)
134 ht
->allocated_handles
= bytes
/ sizeof(USER_HANDLE_ENTRY
);
137 __inline
static void *free_user_entry(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY entry
)
139 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
142 entry
->ptr
= ht
->freelist
;
146 ht
->freelist
= entry
;
148 gpsi
->cHandleEntries
--;
149 ppi
->UserHandleCount
--;
154 static __inline PVOID
155 UserHandleOwnerByType(USER_OBJECT_TYPE type
)
163 pi
= GetW32ThreadInfo();
172 pi
= GetW32ProcessInfo();
176 pi
= NULL
; /* System */
187 /* allocate a user handle for a given object */
188 HANDLE
UserAllocHandle(PUSER_HANDLE_TABLE ht
, PVOID object
, USER_OBJECT_TYPE type
)
190 PUSER_HANDLE_ENTRY entry
= alloc_user_entry(ht
);
196 entry
->pi
= UserHandleOwnerByType(type
);
197 if (++entry
->generation
>= 0xffff)
198 entry
->generation
= 1;
200 /* We have created a handle, which is a reference! */
201 UserReferenceObject(object
);
203 return entry_to_handle(ht
, entry
);
206 /* return a pointer to a user object from its handle */
207 PVOID
UserGetObject(PUSER_HANDLE_TABLE ht
, HANDLE handle
, USER_OBJECT_TYPE type
)
209 PUSER_HANDLE_ENTRY entry
;
213 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
215 EngSetLastError(ERROR_INVALID_HANDLE
);
222 /* Get the full handle (32bit) for a possibly truncated (16bit) handle */
223 HANDLE
get_user_full_handle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
225 PUSER_HANDLE_ENTRY entry
;
227 if ((unsigned int)handle
>> 16)
229 if (!(entry
= handle_to_entry(ht
, handle
)))
231 return entry_to_handle( ht
, entry
);
235 /* Same as get_user_object plus set the handle to the full 32-bit value */
236 void *get_user_object_handle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
238 PUSER_HANDLE_ENTRY entry
;
240 if (!(entry
= handle_to_entry(ht
, *handle
)) || entry
->type
!= type
)
242 *handle
= entry_to_handle( ht
, entry
);
248 BOOL FASTCALL
UserCreateHandleTable(VOID
)
253 // FIXME: Don't alloc all at once! Must be mapped into umode also...
254 mem
= UserHeapAlloc(sizeof(USER_HANDLE_ENTRY
) * 1024*2);
257 ERR("Failed creating handle table\n");
261 gHandleTable
= UserHeapAlloc(sizeof(USER_HANDLE_TABLE
));
262 if (gHandleTable
== NULL
)
265 ERR("Failed creating handle table\n");
269 // FIXME: Make auto growable
270 UserInitHandleTable(gHandleTable
, mem
, sizeof(USER_HANDLE_ENTRY
) * 1024*2);
280 UserCreateObject( PUSER_HANDLE_TABLE ht
,
283 USER_OBJECT_TYPE type
,
291 PDESKTOP rpdesk
= pDesktop
;
293 pti
= GetW32ThreadInfo();
295 if (!pDesktop
) rpdesk
= pti
->rpdesk
;
304 Object
= DesktopHeapAlloc(rpdesk
, size
);
309 Object
= UserHeapAlloc(size
);
318 hi
= UserAllocHandle(ht
, Object
, type
);
322 DesktopHeapFree(rpdesk
, Object
);
324 UserHeapFree(Object
);
328 RtlZeroMemory(Object
, size
);
335 ((PTHRDESKHEAD
)Object
)->rpdesk
= rpdesk
;
336 ((PTHRDESKHEAD
)Object
)->pSelf
= Object
;
338 ((PTHROBJHEAD
)Object
)->pti
= pti
;
343 ((PPROCDESKHEAD
)Object
)->rpdesk
= rpdesk
;
344 ((PPROCDESKHEAD
)Object
)->pSelf
= Object
;
348 ((PPROCMARKHEAD
)Object
)->ppi
= ppi
;
354 /* Now set default headers. */
355 ((PHEAD
)Object
)->h
= hi
;
356 ((PHEAD
)Object
)->cLockObj
= 2; // We need this, because we create 2 refs: handle and pointer!
366 UserDereferenceObject(PVOID object
)
368 PUSER_HANDLE_ENTRY entry
;
369 USER_OBJECT_TYPE type
;
371 ASSERT(((PHEAD
)object
)->cLockObj
>= 1);
373 if ((INT
)--((PHEAD
)object
)->cLockObj
<= 0)
375 entry
= handle_to_entry(gHandleTable
, ((PHEAD
)object
)->h
);
379 ERR("Warning! Dereference Object without ENTRY! Obj -> 0x%x\n", object
);
382 TRACE("Warning! Dereference to zero! Obj -> 0x%x\n", object
);
384 ((PHEAD
)object
)->cLockObj
= 0;
386 if (!(entry
->flags
& HANDLEENTRY_INDESTROY
))
390 free_user_entry(gHandleTable
, entry
);
399 return DesktopHeapFree(((PTHRDESKHEAD
)object
)->rpdesk
, object
);
402 return UserHeapFree(object
);
410 UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
412 PUSER_HANDLE_ENTRY entry
;
414 if (!(entry
= handle_to_entry( ht
, handle
)))
416 SetLastNtError( STATUS_INVALID_HANDLE
);
420 entry
->flags
= HANDLEENTRY_INDESTROY
;
422 return UserDereferenceObject(entry
->ptr
);
427 UserDeleteObject(HANDLE h
, USER_OBJECT_TYPE type
)
429 PVOID body
= UserGetObject(gHandleTable
, h
, type
);
431 if (!body
) return FALSE
;
433 ASSERT( ((PHEAD
)body
)->cLockObj
>= 1);
435 return UserFreeHandle(gHandleTable
, h
);
440 UserReferenceObject(PVOID obj
)
442 ASSERT(((PHEAD
)obj
)->cLockObj
>= 0);
444 ((PHEAD
)obj
)->cLockObj
++;
449 UserReferenceObjectByHandle(HANDLE handle
, USER_OBJECT_TYPE type
)
453 object
= UserGetObject(gHandleTable
, handle
, type
);
456 UserReferenceObject(object
);
462 * NtUserValidateHandleSecure
470 NtUserValidateHandleSecure(
478 PUSER_HANDLE_ENTRY entry
;
479 if (!(entry
= handle_to_entry(gHandleTable
, handle
)))
481 EngSetLastError(ERROR_INVALID_HANDLE
);
491 if ((Window
= UserGetWindowObject((HWND
) handle
))) return TRUE
;
497 if ((Menu
= UserGetMenuObject((HMENU
) handle
))) return TRUE
;
502 PACCELERATOR_TABLE Accel
;
503 if ((Accel
= UserGetAccelObject((HACCEL
) handle
))) return TRUE
;
508 PCURICON_OBJECT Cursor
;
509 if ((Cursor
= UserGetCurIconObject((HCURSOR
) handle
))) return TRUE
;
515 if ((Hook
= IntGetHookObject((HHOOK
) handle
))) return TRUE
;
521 if ((Monitor
= UserGetMonitorObject((HMONITOR
) handle
))) return TRUE
;
527 return UserGetCallProcInfo( handle
, &Proc
);
530 EngSetLastError(ERROR_INVALID_HANDLE
);
534 { /* Is handle entry restricted? */