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
;
17 void DbgUserDumpHandleTable()
19 int HandleCounts
[USER_HANDLE_TYPE_COUNT
];
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"};
26 ERR("Total handles count: %d\n", gpsi
->cHandleEntries
);
28 memset(HandleCounts
, 0, sizeof(HandleCounts
));
30 /* First of all count the number of handles per tpe */
34 ERR("Process %s (%d) handles count: %d\n\t", ppiList
->peProcess
->ImageFileName
, ppiList
->peProcess
->UniqueProcessId
, ppiList
->UserHandleCount
);
36 for (i
= 1 ;i
< USER_HANDLE_TYPE_COUNT
; i
++)
38 HandleCounts
[i
] += ppiList
->DbgHandleCount
[i
];
40 DbgPrint("%S: %d, ", TypeNames
[i
], ppiList
->DbgHandleCount
[i
]);
46 ppiList
= ppiList
->ppiNext
;
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
++)
53 DbgPrint("%S: %d, ", TypeNames
[i
], HandleCounts
[i
]);
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
]++;
64 ERR("Total handles count allocated: \n\t");
65 for (i
= 1 ;i
< USER_HANDLE_TYPE_COUNT
; i
++)
67 DbgPrint("%S: %d, ", TypeNames
[i
], HandleCounts
[i
]);
76 PUSER_HANDLE_ENTRY
handle_to_entry(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
78 unsigned short generation
;
79 int index
= (((unsigned int)handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
80 if (index
< 0 || index
>= ht
->nb_handles
)
82 if (!ht
->handles
[index
].type
)
84 generation
= (unsigned int)handle
>> 16;
85 if (generation
== ht
->handles
[index
].generation
|| !generation
|| generation
== 0xffff)
86 return &ht
->handles
[index
];
90 __inline
static HANDLE
entry_to_handle(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY ptr
)
92 int index
= ptr
- ht
->handles
;
93 return (HANDLE
)(((index
<< 1) + FIRST_USER_HANDLE
) + (ptr
->generation
<< 16));
96 __inline
static PUSER_HANDLE_ENTRY
alloc_user_entry(PUSER_HANDLE_TABLE ht
)
98 PUSER_HANDLE_ENTRY entry
;
99 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
100 TRACE("handles used %i\n",gpsi
->cHandleEntries
);
104 entry
= ht
->freelist
;
105 ht
->freelist
= entry
->ptr
;
107 gpsi
->cHandleEntries
++;
108 ppi
->UserHandleCount
++;
112 if (ht
->nb_handles
>= ht
->allocated_handles
) /* Need to grow the array */
114 ERR("Out of user handles! Used -> %i, NM_Handle -> %d\n", gpsi
->cHandleEntries
, ht
->nb_handles
);
117 DbgUserDumpHandleTable();
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
)
128 if (!(new_handles
= UserHeapReAlloc( ht
->handles
, new_size
* sizeof(*ht
->handles
) )))
130 ht
->handles
= new_handles
;
131 ht
->allocated_handles
= new_size
;
135 entry
= &ht
->handles
[ht
->nb_handles
++];
137 entry
->generation
= 1;
139 gpsi
->cHandleEntries
++;
140 ppi
->UserHandleCount
++;
145 VOID
UserInitHandleTable(PUSER_HANDLE_TABLE ht
, PVOID mem
, ULONG bytes
)
151 ht
->allocated_handles
= bytes
/ sizeof(USER_HANDLE_ENTRY
);
154 __inline
static void *free_user_entry(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY entry
)
156 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
160 ppi
->DbgHandleCount
[entry
->type
]--;
164 entry
->ptr
= ht
->freelist
;
168 ht
->freelist
= entry
;
170 gpsi
->cHandleEntries
--;
171 ppi
->UserHandleCount
--;
176 static __inline PVOID
177 UserHandleOwnerByType(USER_OBJECT_TYPE type
)
185 pi
= GetW32ThreadInfo();
194 pi
= GetW32ProcessInfo();
198 pi
= NULL
; /* System */
209 /* allocate a user handle for a given object */
210 HANDLE
UserAllocHandle(PUSER_HANDLE_TABLE ht
, PVOID object
, USER_OBJECT_TYPE type
)
212 PUSER_HANDLE_ENTRY entry
= alloc_user_entry(ht
);
218 entry
->pi
= UserHandleOwnerByType(type
);
219 if (++entry
->generation
>= 0xffff)
220 entry
->generation
= 1;
222 /* We have created a handle, which is a reference! */
223 UserReferenceObject(object
);
225 return entry_to_handle(ht
, entry
);
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
)
231 PUSER_HANDLE_ENTRY entry
;
235 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
242 /* return a pointer to a user object from its handle */
243 PVOID
UserGetObject(PUSER_HANDLE_TABLE ht
, HANDLE handle
, USER_OBJECT_TYPE type
)
245 PUSER_HANDLE_ENTRY entry
;
249 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
251 EngSetLastError(ERROR_INVALID_HANDLE
);
258 /* Get the full handle (32bit) for a possibly truncated (16bit) handle */
259 HANDLE
get_user_full_handle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
261 PUSER_HANDLE_ENTRY entry
;
263 if ((unsigned int)handle
>> 16)
265 if (!(entry
= handle_to_entry(ht
, handle
)))
267 return entry_to_handle( ht
, entry
);
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
)
274 PUSER_HANDLE_ENTRY entry
;
276 if (!(entry
= handle_to_entry(ht
, *handle
)) || entry
->type
!= type
)
278 *handle
= entry_to_handle( ht
, entry
);
284 BOOL FASTCALL
UserCreateHandleTable(VOID
)
287 INT HandleCount
= 1024 * 4;
289 // FIXME: Don't alloc all at once! Must be mapped into umode also...
290 mem
= UserHeapAlloc(sizeof(USER_HANDLE_ENTRY
) * HandleCount
);
293 ERR("Failed creating handle table\n");
297 gHandleTable
= UserHeapAlloc(sizeof(USER_HANDLE_TABLE
));
298 if (gHandleTable
== NULL
)
301 ERR("Failed creating handle table\n");
305 // FIXME: Make auto growable
306 UserInitHandleTable(gHandleTable
, mem
, sizeof(USER_HANDLE_ENTRY
) * HandleCount
);
316 UserCreateObject( PUSER_HANDLE_TABLE ht
,
319 USER_OBJECT_TYPE type
,
327 PDESKTOP rpdesk
= pDesktop
;
329 pti
= GetW32ThreadInfo();
331 if (!pDesktop
) rpdesk
= pti
->rpdesk
;
340 Object
= DesktopHeapAlloc(rpdesk
, size
);
345 Object
= UserHeapAlloc(size
);
354 hi
= UserAllocHandle(ht
, Object
, type
);
358 DesktopHeapFree(rpdesk
, Object
);
360 UserHeapFree(Object
);
365 ppi
->DbgHandleCount
[type
]++;
368 RtlZeroMemory(Object
, size
);
375 ((PTHRDESKHEAD
)Object
)->rpdesk
= rpdesk
;
376 ((PTHRDESKHEAD
)Object
)->pSelf
= Object
;
378 ((PTHROBJHEAD
)Object
)->pti
= pti
;
383 ((PPROCDESKHEAD
)Object
)->rpdesk
= rpdesk
;
384 ((PPROCDESKHEAD
)Object
)->pSelf
= Object
;
388 ((PPROCMARKHEAD
)Object
)->ppi
= ppi
;
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!
406 UserDereferenceObject(PVOID object
)
408 PUSER_HANDLE_ENTRY entry
;
409 USER_OBJECT_TYPE type
;
411 ASSERT(((PHEAD
)object
)->cLockObj
>= 1);
413 if ((INT
)--((PHEAD
)object
)->cLockObj
<= 0)
415 entry
= handle_to_entry(gHandleTable
, ((PHEAD
)object
)->h
);
419 ERR("Warning! Dereference Object without ENTRY! Obj -> 0x%x\n", object
);
422 TRACE("Warning! Dereference to zero! Obj -> 0x%x\n", object
);
424 ((PHEAD
)object
)->cLockObj
= 0;
426 if (!(entry
->flags
& HANDLEENTRY_INDESTROY
))
430 free_user_entry(gHandleTable
, entry
);
439 return DesktopHeapFree(((PTHRDESKHEAD
)object
)->rpdesk
, object
);
442 return UserHeapFree(object
);
450 UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
452 PUSER_HANDLE_ENTRY entry
;
454 if (!(entry
= handle_to_entry( ht
, handle
)))
456 SetLastNtError( STATUS_INVALID_HANDLE
);
460 entry
->flags
= HANDLEENTRY_INDESTROY
;
462 return UserDereferenceObject(entry
->ptr
);
467 UserObjectInDestroy(HANDLE h
)
469 PUSER_HANDLE_ENTRY entry
;
471 if (!(entry
= handle_to_entry( gHandleTable
, h
)))
473 SetLastNtError( STATUS_INVALID_HANDLE
);
476 return (entry
->flags
& HANDLEENTRY_INDESTROY
);
481 UserDeleteObject(HANDLE h
, USER_OBJECT_TYPE type
)
483 PVOID body
= UserGetObject(gHandleTable
, h
, type
);
485 if (!body
) return FALSE
;
487 ASSERT( ((PHEAD
)body
)->cLockObj
>= 1);
489 return UserFreeHandle(gHandleTable
, h
);
494 UserReferenceObject(PVOID obj
)
496 ASSERT(((PHEAD
)obj
)->cLockObj
>= 0);
498 ((PHEAD
)obj
)->cLockObj
++;
503 UserReferenceObjectByHandle(HANDLE handle
, USER_OBJECT_TYPE type
)
507 object
= UserGetObject(gHandleTable
, handle
, type
);
510 UserReferenceObject(object
);
516 * NtUserValidateHandleSecure
524 NtUserValidateHandleSecure(
532 PUSER_HANDLE_ENTRY entry
;
533 if (!(entry
= handle_to_entry(gHandleTable
, handle
)))
535 EngSetLastError(ERROR_INVALID_HANDLE
);
544 if (UserGetWindowObject((HWND
) handle
)) return TRUE
;
549 if (UserGetMenuObject((HMENU
) handle
)) return TRUE
;
554 if (UserGetAccelObject((HACCEL
) handle
)) return TRUE
;
559 if (UserGetCurIconObject((HCURSOR
) handle
)) return TRUE
;
564 if (IntGetHookObject((HHOOK
) handle
)) return TRUE
;
569 if (UserGetMonitorObject((HMONITOR
) handle
)) return TRUE
;
575 return UserGetCallProcInfo( handle
, &Proc
);
578 EngSetLastError(ERROR_INVALID_HANDLE
);
582 { /* Is handle entry restricted? */