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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
;
155 ht
->freelist
= entry
;
157 gpsi
->cHandleEntries
--;
162 static __inline PVOID
163 UserHandleOwnerByType(USER_OBJECT_TYPE type
)
170 pi
= GetW32ThreadInfo();
178 pi
= GetW32ProcessInfo();
182 pi
= NULL
; /* System */
193 /* allocate a user handle for a given object */
194 HANDLE
UserAllocHandle(PUSER_HANDLE_TABLE ht
, PVOID object
, USER_OBJECT_TYPE type
)
196 PUSER_HANDLE_ENTRY entry
= alloc_user_entry(ht
);
201 entry
->pi
= UserHandleOwnerByType(type
);
202 if (++entry
->generation
>= 0xffff)
203 entry
->generation
= 1;
205 /* We have created a handle, which is a reference! */
206 UserReferenceObject(object
);
208 return entry_to_handle(ht
, entry
);
211 /* return a pointer to a user object from its handle */
212 PVOID
UserGetObject(PUSER_HANDLE_TABLE ht
, HANDLE handle
, USER_OBJECT_TYPE type
)
214 PUSER_HANDLE_ENTRY entry
;
218 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
220 SetLastWin32Error(ERROR_INVALID_HANDLE
);
227 /* get the full handle (32bit) for a possibly truncated (16bit) handle */
228 HANDLE
get_user_full_handle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
230 PUSER_HANDLE_ENTRY entry
;
232 if ((unsigned int)handle
>> 16)
234 if (!(entry
= handle_to_entry(ht
, handle
)))
236 return entry_to_handle( ht
, entry
);
240 /* same as get_user_object plus set the handle to the full 32-bit value */
241 void *get_user_object_handle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
243 PUSER_HANDLE_ENTRY entry
;
245 if (!(entry
= handle_to_entry(ht
, *handle
)) || entry
->type
!= type
)
247 *handle
= entry_to_handle( ht
, entry
);
251 /* free a user handle */
252 BOOL
UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
254 PUSER_HANDLE_ENTRY entry
;
257 if (!(entry
= handle_to_entry( ht
, handle
)))
259 SetLastNtError( STATUS_INVALID_HANDLE
);
263 object
= free_user_entry(ht
, entry
);
265 /* We removed the handle, which was a reference! */
266 return UserDereferenceObject(object
);
271 /* return the next user handle after 'handle' that is of a given type */
272 PVOID
UserGetNextHandle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
274 PUSER_HANDLE_ENTRY entry
;
280 int index
= (((unsigned int)*handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
281 if (index
< 0 || index
>= ht
->nb_handles
)
283 entry
= ht
->handles
+ index
+ 1; /* start from the next one */
285 while (entry
< ht
->handles
+ ht
->nb_handles
)
287 if (!type
|| entry
->type
== type
)
289 *handle
= entry_to_handle(ht
, entry
);
300 UserCreateObject(PUSER_HANDLE_TABLE ht
, HANDLE
* h
,USER_OBJECT_TYPE type
, ULONG size
)
304 PUSER_OBJECT_HEADER hdr
= UserHeapAlloc(size
+ sizeof(USER_OBJECT_HEADER
));//ExAllocatePool(PagedPool, size + sizeof(USER_OBJECT_HEADER));
309 hi
= UserAllocHandle(ht
, USER_HEADER_TO_BODY(hdr
), type
);
317 RtlZeroMemory(hdr
, size
+ sizeof(USER_OBJECT_HEADER
));
319 hdr
->RefCount
= 2; // we need this, because we create 2 refs: handle and pointer!
323 return USER_HEADER_TO_BODY(hdr
);
327 UserDeleteObject(HANDLE h
, USER_OBJECT_TYPE type
)
329 PUSER_OBJECT_HEADER hdr
;
330 PVOID body
= UserGetObject(gHandleTable
, h
, type
);
334 hdr
= USER_BODY_TO_HEADER(body
);
335 ASSERT(hdr
->RefCount
>= 1);
337 hdr
->destroyed
= TRUE
;
338 return UserFreeHandle(gHandleTable
, h
);
342 VOID FASTCALL
UserReferenceObject(PVOID obj
)
344 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
346 ASSERT(hdr
->RefCount
>= 0);
352 PVOID FASTCALL
UserReferenceObjectByHandle(HANDLE handle
, USER_OBJECT_TYPE type
)
356 object
= UserGetObject(gHandleTable
, handle
, type
);
359 UserReferenceObject(object
);
366 HANDLE FASTCALL
UserObjectToHandle(PVOID obj
)
368 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
373 BOOL FASTCALL
UserDereferenceObject(PVOID obj
)
375 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
377 ASSERT(hdr
->RefCount
>= 1);
381 // You can not have a zero here!
382 if (!hdr
->destroyed
&& hdr
->RefCount
== 0)
384 hdr
->RefCount
++; // BOUNCE!!!!!
385 DPRINT1("warning! Dereference to zero without deleting! Obj -> 0x%x\n", obj
);
388 if (hdr
->RefCount
== 0 && hdr
->destroyed
)
390 // DPRINT1("info: something destroyed bcaise of deref, in use=%i\n",gpsi->cHandleEntries);
392 memset(hdr
, 0x55, sizeof(USER_OBJECT_HEADER
));
394 return UserHeapFree(hdr
);
405 BOOL FASTCALL
UserCreateHandleTable(VOID
)
410 //FIXME: dont alloc all at once! must be mapped into umode also...
411 //mem = ExAllocatePool(PagedPool, sizeof(USER_HANDLE_ENTRY) * 1024*2);
412 mem
= UserHeapAlloc(sizeof(USER_HANDLE_ENTRY
) * 1024*2);
415 DPRINT1("Failed creating handle table\n");
419 gHandleTable
= UserHeapAlloc(sizeof(USER_HANDLE_TABLE
));
420 if (gHandleTable
== NULL
)
423 DPRINT1("Failed creating handle table\n");
427 //FIXME: make auto growable
428 UserInitHandleTable(gHandleTable
, mem
, sizeof(USER_HANDLE_ENTRY
) * 1024*2);