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 without setting an error */
207 PVOID
UserGetObjectNoErr(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
)
220 /* return a pointer to a user object from its handle */
221 PVOID
UserGetObject(PUSER_HANDLE_TABLE ht
, HANDLE handle
, USER_OBJECT_TYPE type
)
223 PUSER_HANDLE_ENTRY entry
;
227 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
229 EngSetLastError(ERROR_INVALID_HANDLE
);
236 /* Get the full handle (32bit) for a possibly truncated (16bit) handle */
237 HANDLE
get_user_full_handle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
239 PUSER_HANDLE_ENTRY entry
;
241 if ((unsigned int)handle
>> 16)
243 if (!(entry
= handle_to_entry(ht
, handle
)))
245 return entry_to_handle( ht
, entry
);
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
)
252 PUSER_HANDLE_ENTRY entry
;
254 if (!(entry
= handle_to_entry(ht
, *handle
)) || entry
->type
!= type
)
256 *handle
= entry_to_handle( ht
, entry
);
262 BOOL FASTCALL
UserCreateHandleTable(VOID
)
267 // FIXME: Don't alloc all at once! Must be mapped into umode also...
268 mem
= UserHeapAlloc(sizeof(USER_HANDLE_ENTRY
) * 1024*2);
271 ERR("Failed creating handle table\n");
275 gHandleTable
= UserHeapAlloc(sizeof(USER_HANDLE_TABLE
));
276 if (gHandleTable
== NULL
)
279 ERR("Failed creating handle table\n");
283 // FIXME: Make auto growable
284 UserInitHandleTable(gHandleTable
, mem
, sizeof(USER_HANDLE_ENTRY
) * 1024*2);
294 UserCreateObject( PUSER_HANDLE_TABLE ht
,
297 USER_OBJECT_TYPE type
,
305 PDESKTOP rpdesk
= pDesktop
;
307 pti
= GetW32ThreadInfo();
309 if (!pDesktop
) rpdesk
= pti
->rpdesk
;
318 Object
= DesktopHeapAlloc(rpdesk
, size
);
323 Object
= UserHeapAlloc(size
);
332 hi
= UserAllocHandle(ht
, Object
, type
);
336 DesktopHeapFree(rpdesk
, Object
);
338 UserHeapFree(Object
);
342 RtlZeroMemory(Object
, size
);
349 ((PTHRDESKHEAD
)Object
)->rpdesk
= rpdesk
;
350 ((PTHRDESKHEAD
)Object
)->pSelf
= Object
;
352 ((PTHROBJHEAD
)Object
)->pti
= pti
;
357 ((PPROCDESKHEAD
)Object
)->rpdesk
= rpdesk
;
358 ((PPROCDESKHEAD
)Object
)->pSelf
= Object
;
362 ((PPROCMARKHEAD
)Object
)->ppi
= ppi
;
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!
380 UserDereferenceObject(PVOID object
)
382 PUSER_HANDLE_ENTRY entry
;
383 USER_OBJECT_TYPE type
;
385 ASSERT(((PHEAD
)object
)->cLockObj
>= 1);
387 if ((INT
)--((PHEAD
)object
)->cLockObj
<= 0)
389 entry
= handle_to_entry(gHandleTable
, ((PHEAD
)object
)->h
);
393 ERR("Warning! Dereference Object without ENTRY! Obj -> 0x%x\n", object
);
396 TRACE("Warning! Dereference to zero! Obj -> 0x%x\n", object
);
398 ((PHEAD
)object
)->cLockObj
= 0;
400 if (!(entry
->flags
& HANDLEENTRY_INDESTROY
))
404 free_user_entry(gHandleTable
, entry
);
413 return DesktopHeapFree(((PTHRDESKHEAD
)object
)->rpdesk
, object
);
416 return UserHeapFree(object
);
424 UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
426 PUSER_HANDLE_ENTRY entry
;
428 if (!(entry
= handle_to_entry( ht
, handle
)))
430 SetLastNtError( STATUS_INVALID_HANDLE
);
434 entry
->flags
= HANDLEENTRY_INDESTROY
;
436 return UserDereferenceObject(entry
->ptr
);
441 UserObjectInDestroy(HANDLE h
)
443 PUSER_HANDLE_ENTRY entry
;
445 if (!(entry
= handle_to_entry( gHandleTable
, h
)))
447 SetLastNtError( STATUS_INVALID_HANDLE
);
450 return (entry
->flags
& HANDLEENTRY_INDESTROY
);
455 UserDeleteObject(HANDLE h
, USER_OBJECT_TYPE type
)
457 PVOID body
= UserGetObject(gHandleTable
, h
, type
);
459 if (!body
) return FALSE
;
461 ASSERT( ((PHEAD
)body
)->cLockObj
>= 1);
463 return UserFreeHandle(gHandleTable
, h
);
468 UserReferenceObject(PVOID obj
)
470 ASSERT(((PHEAD
)obj
)->cLockObj
>= 0);
472 ((PHEAD
)obj
)->cLockObj
++;
477 UserReferenceObjectByHandle(HANDLE handle
, USER_OBJECT_TYPE type
)
481 object
= UserGetObject(gHandleTable
, handle
, type
);
484 UserReferenceObject(object
);
490 * NtUserValidateHandleSecure
498 NtUserValidateHandleSecure(
506 PUSER_HANDLE_ENTRY entry
;
507 if (!(entry
= handle_to_entry(gHandleTable
, handle
)))
509 EngSetLastError(ERROR_INVALID_HANDLE
);
518 if (UserGetWindowObject((HWND
) handle
)) return TRUE
;
523 if (UserGetMenuObject((HMENU
) handle
)) return TRUE
;
528 if (UserGetAccelObject((HACCEL
) handle
)) return TRUE
;
533 if (UserGetCurIconObject((HCURSOR
) handle
)) return TRUE
;
538 if (IntGetHookObject((HHOOK
) handle
)) return TRUE
;
543 if (UserGetMonitorObject((HMONITOR
) handle
)) return TRUE
;
549 return UserGetCallProcInfo( handle
, &Proc
);
552 EngSetLastError(ERROR_INVALID_HANDLE
);
556 { /* Is handle entry restricted? */