2 * Server-side USER handles
4 * Copyright (C) 2001 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 /* INCLUDES ******************************************************************/
31 PUSER_HANDLE_TABLE gHandleTable
= NULL
;
34 PUSER_HANDLE_ENTRY
handle_to_entry(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
36 unsigned short generation
;
37 int index
= (((unsigned int)handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
38 if (index
< 0 || index
>= ht
->nb_handles
)
40 if (!ht
->handles
[index
].type
)
42 generation
= (unsigned int)handle
>> 16;
43 if (generation
== ht
->handles
[index
].generation
|| !generation
|| generation
== 0xffff)
44 return &ht
->handles
[index
];
48 __inline
static HANDLE
entry_to_handle(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY ptr
)
50 int index
= ptr
- ht
->handles
;
51 return (HANDLE
)(((index
<< 1) + FIRST_USER_HANDLE
) + (ptr
->generation
<< 16));
54 __inline
static PUSER_HANDLE_ENTRY
alloc_user_entry(PUSER_HANDLE_TABLE ht
)
56 PUSER_HANDLE_ENTRY entry
;
58 DPRINT("handles used %i\n",gpsi
->cHandleEntries
);
63 ht
->freelist
= entry
->ptr
;
65 gpsi
->cHandleEntries
++;
69 if (ht
->nb_handles
>= ht
->allocated_handles
) /* need to grow the array */
72 int i
, iFree
= 0, iWindow
= 0, iMenu
= 0, iCursorIcon
= 0,
73 iHook
= 0, iCallProc
= 0, iAccel
= 0, iMonitor
= 0, iTimer
= 0;
75 DPRINT1("Out of user handles! Used -> %i, NM_Handle -> %d\n", gpsi
->cHandleEntries
, ht
->nb_handles
);
77 for(i
= 0; i
< ht
->nb_handles
; i
++)
79 switch (ht
->handles
[i
].type
)
81 case otFree
: // Should be zero.
112 DPRINT1("Handle Count by Type:\n Free = %d Window = %d Menu = %d CursorIcon = %d Hook = %d\n CallProc = %d Accel = %d Monitor = %d Timer = %d\n",
113 iFree
, iWindow
, iMenu
, iCursorIcon
, iHook
, iCallProc
, iAccel
, iMonitor
, iTimer
);
117 PUSER_HANDLE_ENTRY new_handles
;
118 /* grow array by 50% (but at minimum 32 entries) */
119 int growth
= max( 32, ht
->allocated_handles
/ 2 );
120 int new_size
= min( ht
->allocated_handles
+ growth
, (LAST_USER_HANDLE
-FIRST_USER_HANDLE
+1) >> 1 );
121 if (new_size
<= ht
->allocated_handles
)
123 if (!(new_handles
= UserHeapReAlloc( ht
->handles
, new_size
* sizeof(*ht
->handles
) )))
125 ht
->handles
= new_handles
;
126 ht
->allocated_handles
= new_size
;
130 entry
= &ht
->handles
[ht
->nb_handles
++];
132 entry
->generation
= 1;
134 gpsi
->cHandleEntries
++;
139 VOID
UserInitHandleTable(PUSER_HANDLE_TABLE ht
, PVOID mem
, ULONG bytes
)
145 ht
->allocated_handles
= bytes
/ sizeof(USER_HANDLE_ENTRY
);
148 __inline
static void *free_user_entry(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY entry
)
152 entry
->ptr
= ht
->freelist
;
156 ht
->freelist
= entry
;
158 gpsi
->cHandleEntries
--;
163 static __inline PVOID
164 UserHandleOwnerByType(USER_OBJECT_TYPE type
)
172 pi
= GetW32ThreadInfo();
180 pi
= GetW32ProcessInfo();
184 pi
= NULL
; /* System */
195 /* allocate a user handle for a given object */
196 HANDLE
UserAllocHandle(PUSER_HANDLE_TABLE ht
, PVOID object
, USER_OBJECT_TYPE type
)
198 PUSER_HANDLE_ENTRY entry
= alloc_user_entry(ht
);
204 entry
->pi
= UserHandleOwnerByType(type
);
205 if (++entry
->generation
>= 0xffff)
206 entry
->generation
= 1;
208 /* We have created a handle, which is a reference! */
209 UserReferenceObject(object
);
211 return entry_to_handle(ht
, entry
);
214 /* return a pointer to a user object from its handle */
215 PVOID
UserGetObject(PUSER_HANDLE_TABLE ht
, HANDLE handle
, USER_OBJECT_TYPE type
)
217 PUSER_HANDLE_ENTRY entry
;
221 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
223 SetLastWin32Error(ERROR_INVALID_HANDLE
);
230 /* get the full handle (32bit) for a possibly truncated (16bit) handle */
231 HANDLE
get_user_full_handle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
233 PUSER_HANDLE_ENTRY entry
;
235 if ((unsigned int)handle
>> 16)
237 if (!(entry
= handle_to_entry(ht
, handle
)))
239 return entry_to_handle( ht
, entry
);
243 /* same as get_user_object plus set the handle to the full 32-bit value */
244 void *get_user_object_handle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
246 PUSER_HANDLE_ENTRY entry
;
248 if (!(entry
= handle_to_entry(ht
, *handle
)) || entry
->type
!= type
)
250 *handle
= entry_to_handle( ht
, entry
);
254 /* return the next user handle after 'handle' that is of a given type */
255 PVOID
UserGetNextHandle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
257 PUSER_HANDLE_ENTRY entry
;
263 int index
= (((unsigned int)*handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
264 if (index
< 0 || index
>= ht
->nb_handles
)
266 entry
= ht
->handles
+ index
+ 1; /* start from the next one */
268 while (entry
< ht
->handles
+ ht
->nb_handles
)
270 if (!type
|| entry
->type
== type
)
272 *handle
= entry_to_handle(ht
, entry
);
280 BOOL FASTCALL
UserCreateHandleTable(VOID
)
285 //FIXME: dont alloc all at once! must be mapped into umode also...
286 //mem = ExAllocatePool(PagedPool, sizeof(USER_HANDLE_ENTRY) * 1024*2);
287 mem
= UserHeapAlloc(sizeof(USER_HANDLE_ENTRY
) * 1024*2);
290 DPRINT1("Failed creating handle table\n");
294 gHandleTable
= UserHeapAlloc(sizeof(USER_HANDLE_TABLE
));
295 if (gHandleTable
== NULL
)
298 DPRINT1("Failed creating handle table\n");
302 //FIXME: make auto growable
303 UserInitHandleTable(gHandleTable
, mem
, sizeof(USER_HANDLE_ENTRY
) * 1024*2);
313 UserCreateObject( PUSER_HANDLE_TABLE ht
,
316 USER_OBJECT_TYPE type
,
324 PDESKTOP rpdesk
= pDesktop
;
326 pti
= GetW32ThreadInfo();
328 if (!pDesktop
) rpdesk
= pti
->rpdesk
;
337 Object
= DesktopHeapAlloc(rpdesk
, size
);
342 Object
= UserHeapAlloc(size
);
351 hi
= UserAllocHandle(ht
, Object
, type
);
355 DesktopHeapFree(rpdesk
, Object
);
357 UserHeapFree(Object
);
361 RtlZeroMemory(Object
, size
);
368 ((PTHRDESKHEAD
)Object
)->rpdesk
= rpdesk
;
369 ((PTHRDESKHEAD
)Object
)->pSelf
= Object
;
371 ((PTHROBJHEAD
)Object
)->pti
= pti
;
376 ((PPROCDESKHEAD
)Object
)->rpdesk
= rpdesk
;
377 ((PPROCDESKHEAD
)Object
)->pSelf
= Object
;
381 ((PPROCMARKHEAD
)Object
)->ppi
= ppi
;
387 /* Now set default headers. */
388 ((PHEAD
)Object
)->h
= hi
;
389 ((PHEAD
)Object
)->cLockObj
= 2; // we need this, because we create 2 refs: handle and pointer!
399 UserDereferenceObject(PVOID object
)
401 PUSER_HANDLE_ENTRY entry
;
402 USER_OBJECT_TYPE type
;
404 ASSERT(((PHEAD
)object
)->cLockObj
>= 1);
406 if ((INT
)--((PHEAD
)object
)->cLockObj
<= 0)
408 entry
= handle_to_entry(gHandleTable
, ((PHEAD
)object
)->h
);
410 DPRINT("warning! Dereference to zero! Obj -> 0x%x\n", object
);
412 ((PHEAD
)object
)->cLockObj
= 0;
414 if (!(entry
->flags
& HANDLEENTRY_INDESTROY
))
418 free_user_entry(gHandleTable
, entry
);
427 return DesktopHeapFree(((PTHRDESKHEAD
)object
)->rpdesk
, object
);
430 return UserHeapFree(object
);
438 UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
440 PUSER_HANDLE_ENTRY entry
;
442 if (!(entry
= handle_to_entry( ht
, handle
)))
444 SetLastNtError( STATUS_INVALID_HANDLE
);
448 entry
->flags
= HANDLEENTRY_INDESTROY
;
450 return UserDereferenceObject(entry
->ptr
);
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
);