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
[TYPE_CTYPES
];
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
< TYPE_CTYPES
; 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
< TYPE_CTYPES
; 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
< TYPE_CTYPES
; 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(HANDLE_TYPE type
)
184 case TYPE_INPUTCONTEXT
:
185 pi
= GetW32ThreadInfo();
192 case TYPE_ACCELTABLE
:
193 case TYPE_SETWINDOWPOS
:
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
, HANDLE_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
, HANDLE_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
, HANDLE_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
, HANDLE_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
,
327 PDESKTOP rpdesk
= pDesktop
;
329 /* We could get the desktop for the new object from the pti however this is
330 * not always the case for example when creating a new desktop window for
331 * the desktop thread*/
333 if (!pti
) pti
= GetW32ThreadInfo();
334 if (!pDesktop
) rpdesk
= pti
->rpdesk
;
343 case TYPE_INPUTCONTEXT
:
344 Object
= DesktopHeapAlloc(rpdesk
, size
);
349 Object
= UserHeapAlloc(size
);
358 hi
= UserAllocHandle(ht
, Object
, type
);
362 DesktopHeapFree(rpdesk
, Object
);
364 UserHeapFree(Object
);
369 ppi
->DbgHandleCount
[type
]++;
372 RtlZeroMemory(Object
, size
);
378 case TYPE_INPUTCONTEXT
:
379 ((PTHRDESKHEAD
)Object
)->rpdesk
= rpdesk
;
380 ((PTHRDESKHEAD
)Object
)->pSelf
= Object
;
381 case TYPE_WINEVENTHOOK
:
382 ((PTHROBJHEAD
)Object
)->pti
= pti
;
387 ((PPROCDESKHEAD
)Object
)->rpdesk
= rpdesk
;
388 ((PPROCDESKHEAD
)Object
)->pSelf
= Object
;
392 ((PPROCMARKHEAD
)Object
)->ppi
= ppi
;
398 /* Now set default headers. */
399 ((PHEAD
)Object
)->h
= hi
;
400 ((PHEAD
)Object
)->cLockObj
= 2; // We need this, because we create 2 refs: handle and pointer!
410 UserDereferenceObject(PVOID object
)
412 PUSER_HANDLE_ENTRY entry
;
415 ASSERT(((PHEAD
)object
)->cLockObj
>= 1);
417 if ((INT
)--((PHEAD
)object
)->cLockObj
<= 0)
419 entry
= handle_to_entry(gHandleTable
, ((PHEAD
)object
)->h
);
423 ERR("Warning! Dereference Object without ENTRY! Obj -> 0x%x\n", object
);
426 TRACE("Warning! Dereference to zero! Obj -> 0x%x\n", object
);
428 ((PHEAD
)object
)->cLockObj
= 0;
430 if (!(entry
->flags
& HANDLEENTRY_INDESTROY
))
434 free_user_entry(gHandleTable
, entry
);
442 case TYPE_INPUTCONTEXT
:
443 return DesktopHeapFree(((PTHRDESKHEAD
)object
)->rpdesk
, object
);
446 return UserHeapFree(object
);
454 UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
456 PUSER_HANDLE_ENTRY entry
;
458 if (!(entry
= handle_to_entry( ht
, handle
)))
460 SetLastNtError( STATUS_INVALID_HANDLE
);
464 entry
->flags
= HANDLEENTRY_INDESTROY
;
466 return UserDereferenceObject(entry
->ptr
);
471 UserObjectInDestroy(HANDLE h
)
473 PUSER_HANDLE_ENTRY entry
;
475 if (!(entry
= handle_to_entry( gHandleTable
, h
)))
477 SetLastNtError( STATUS_INVALID_HANDLE
);
480 return (entry
->flags
& HANDLEENTRY_INDESTROY
);
485 UserDeleteObject(HANDLE h
, HANDLE_TYPE type
)
487 PVOID body
= UserGetObject(gHandleTable
, h
, type
);
489 if (!body
) return FALSE
;
491 ASSERT( ((PHEAD
)body
)->cLockObj
>= 1);
493 return UserFreeHandle(gHandleTable
, h
);
498 UserReferenceObject(PVOID obj
)
500 ASSERT(((PHEAD
)obj
)->cLockObj
>= 0);
502 ((PHEAD
)obj
)->cLockObj
++;
507 UserReferenceObjectByHandle(HANDLE handle
, HANDLE_TYPE type
)
511 object
= UserGetObject(gHandleTable
, handle
, type
);
514 UserReferenceObject(object
);
521 UserSetObjectOwner(PVOID obj
, HANDLE_TYPE type
, PVOID owner
)
523 PUSER_HANDLE_ENTRY entry
= handle_to_entry(gHandleTable
, ((PHEAD
)obj
)->h
);
524 PPROCESSINFO ppi
, oldppi
;
526 /* This must be called with a valid object */
529 /* For now, only supported for CursorIcon object */
533 ppi
= (PPROCESSINFO
)owner
;
535 oldppi
= ((PPROCMARKHEAD
)obj
)->ppi
;
536 ((PPROCMARKHEAD
)obj
)->ppi
= ppi
;
543 oldppi
->UserHandleCount
--;
544 ppi
->UserHandleCount
++;
546 oldppi
->DbgHandleCount
[type
]--;
547 ppi
->DbgHandleCount
[type
]++;
552 * NtUserValidateHandleSecure
560 NtUserValidateHandleSecure(
568 PUSER_HANDLE_ENTRY entry
;
569 if (!(entry
= handle_to_entry(gHandleTable
, handle
)))
571 EngSetLastError(ERROR_INVALID_HANDLE
);
580 if (UserGetWindowObject((HWND
) handle
)) return TRUE
;
585 if (UserGetMenuObject((HMENU
) handle
)) return TRUE
;
588 case TYPE_ACCELTABLE
:
590 if (UserGetAccelObject((HACCEL
) handle
)) return TRUE
;
595 if (UserGetCurIconObject((HCURSOR
) handle
)) return TRUE
;
600 if (IntGetHookObject((HHOOK
) handle
)) return TRUE
;
605 if (UserGetMonitorObject((HMONITOR
) handle
)) return TRUE
;
611 return UserGetCallProcInfo( handle
, &Proc
);
614 EngSetLastError(ERROR_INVALID_HANDLE
);
618 { /* Is handle entry restricted? */