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",usedHandles
);
63 ht
->freelist
= entry
->ptr
;
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;
75 DPRINT1("Out of user handles! Used -> %i, NM_Handle -> %d\n", usedHandles
, ht
->nb_handles
);
77 for(i
= 0; i
< ht
->nb_handles
; i
++)
79 switch (ht
->handles
[i
].type
)
81 case otFree
: // Should be zero.
109 DPRINT1("Handle Count by Type:\n Free = %d Window = %d Menu = %d CursorIcon = %d Hook = %d\n CallProc = %d Accel = %d Monitor = %d\n",
110 iFree
, iWindow
, iMenu
, iCursorIcon
, iHook
, iCallProc
, iAccel
, iMonitor
);
114 PUSER_HANDLE_ENTRY new_handles
;
115 /* grow array by 50% (but at minimum 32 entries) */
116 int growth
= max( 32, ht
->allocated_handles
/ 2 );
117 int new_size
= min( ht
->allocated_handles
+ growth
, (LAST_USER_HANDLE
-FIRST_USER_HANDLE
+1) >> 1 );
118 if (new_size
<= ht
->allocated_handles
)
120 if (!(new_handles
= UserHeapReAlloc( ht
->handles
, new_size
* sizeof(*ht
->handles
) )))
122 ht
->handles
= new_handles
;
123 ht
->allocated_handles
= new_size
;
127 entry
= &ht
->handles
[ht
->nb_handles
++];
129 entry
->generation
= 1;
136 VOID
UserInitHandleTable(PUSER_HANDLE_TABLE ht
, PVOID mem
, ULONG bytes
)
142 ht
->allocated_handles
= bytes
/ sizeof(USER_HANDLE_ENTRY
);
145 __inline
static void *free_user_entry(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY entry
)
149 entry
->ptr
= ht
->freelist
;
152 ht
->freelist
= entry
;
159 static __inline PVOID
160 UserHandleOwnerByType(USER_OBJECT_TYPE type
)
167 pi
= GetW32ThreadInfo();
175 pi
= GetW32ProcessInfo();
179 pi
= NULL
; /* System */
190 /* allocate a user handle for a given object */
191 HANDLE
UserAllocHandle(PUSER_HANDLE_TABLE ht
, PVOID object
, USER_OBJECT_TYPE type
)
193 PUSER_HANDLE_ENTRY entry
= alloc_user_entry(ht
);
198 entry
->pi
= UserHandleOwnerByType(type
);
199 if (++entry
->generation
>= 0xffff)
200 entry
->generation
= 1;
201 return entry_to_handle(ht
, entry
);
204 /* return a pointer to a user object from its handle */
205 PVOID
UserGetObject(PUSER_HANDLE_TABLE ht
, HANDLE handle
, USER_OBJECT_TYPE type
)
207 PUSER_HANDLE_ENTRY entry
;
211 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
213 SetLastWin32Error(ERROR_INVALID_HANDLE
);
220 /* get the full handle (32bit) for a possibly truncated (16bit) handle */
221 HANDLE
get_user_full_handle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
223 PUSER_HANDLE_ENTRY entry
;
225 if ((unsigned int)handle
>> 16)
227 if (!(entry
= handle_to_entry(ht
, handle
)))
229 return entry_to_handle( ht
, entry
);
233 /* same as get_user_object plus set the handle to the full 32-bit value */
234 void *get_user_object_handle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
236 PUSER_HANDLE_ENTRY entry
;
238 if (!(entry
= handle_to_entry(ht
, *handle
)) || entry
->type
!= type
)
240 *handle
= entry_to_handle( ht
, entry
);
244 /* free a user handle and return a pointer to the object */
245 PVOID
UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
247 PUSER_HANDLE_ENTRY entry
;
249 if (!(entry
= handle_to_entry( ht
, handle
)))
251 SetLastNtError( STATUS_INVALID_HANDLE
);
255 return free_user_entry(ht
, entry
);
258 /* return the next user handle after 'handle' that is of a given type */
259 PVOID
UserGetNextHandle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
261 PUSER_HANDLE_ENTRY entry
;
267 int index
= (((unsigned int)*handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
268 if (index
< 0 || index
>= ht
->nb_handles
)
270 entry
= ht
->handles
+ index
+ 1; /* start from the next one */
272 while (entry
< ht
->handles
+ ht
->nb_handles
)
274 if (!type
|| entry
->type
== type
)
276 *handle
= entry_to_handle(ht
, entry
);
287 ObmCreateObject(PUSER_HANDLE_TABLE ht
, HANDLE
* h
,USER_OBJECT_TYPE type
, ULONG size
)
291 PUSER_OBJECT_HEADER hdr
= UserHeapAlloc(size
+ sizeof(USER_OBJECT_HEADER
));//ExAllocatePool(PagedPool, size + sizeof(USER_OBJECT_HEADER));
296 hi
= UserAllocHandle(ht
, USER_HEADER_TO_BODY(hdr
), type
);
304 RtlZeroMemory(hdr
, size
+ sizeof(USER_OBJECT_HEADER
));
306 hdr
->RefCount
++; //temp hack!
310 return USER_HEADER_TO_BODY(hdr
);
314 ObmDeleteObject(HANDLE h
, USER_OBJECT_TYPE type
)
316 PUSER_OBJECT_HEADER hdr
;
317 PVOID body
= UserGetObject(gHandleTable
, h
, type
);
321 hdr
= USER_BODY_TO_HEADER(body
);
322 ASSERT(hdr
->RefCount
>= 0);
324 hdr
->destroyed
= TRUE
;
325 if (hdr
->RefCount
== 0)
327 UserFreeHandle(gHandleTable
, h
);
329 memset(hdr
, 0x55, sizeof(USER_OBJECT_HEADER
));
336 // DPRINT1("info: something not destroyed bcause refs still left, inuse %i\n",usedHandles);
341 VOID FASTCALL
ObmReferenceObject(PVOID obj
)
343 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
345 ASSERT(hdr
->RefCount
>= 0);
350 HANDLE FASTCALL
ObmObjectToHandle(PVOID obj
)
352 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
357 BOOL FASTCALL
ObmDereferenceObject2(PVOID obj
)
359 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
361 ASSERT(hdr
->RefCount
>= 1);
365 // You can not have a zero here!
366 if (!hdr
->destroyed
&& hdr
->RefCount
== 0) hdr
->RefCount
++; // BOUNCE!!!!!
368 if (hdr
->RefCount
== 0 && hdr
->destroyed
)
370 // DPRINT1("info: something destroyed bcaise of deref, in use=%i\n",usedHandles);
372 UserFreeHandle(gHandleTable
, hdr
->hSelf
);
374 memset(hdr
, 0x55, sizeof(USER_OBJECT_HEADER
));
387 BOOL FASTCALL
ObmCreateHandleTable()
392 //FIXME: dont alloc all at once! must be mapped into umode also...
393 //mem = ExAllocatePool(PagedPool, sizeof(USER_HANDLE_ENTRY) * 1024*2);
394 mem
= UserHeapAlloc(sizeof(USER_HANDLE_ENTRY
) * 1024*2);
397 DPRINT1("Failed creating handle table\n");
401 gHandleTable
= UserHeapAlloc(sizeof(USER_HANDLE_TABLE
));
402 if (gHandleTable
== NULL
)
405 DPRINT1("Failed creating handle table\n");
409 //FIXME: make auto growable
410 UserInitHandleTable(gHandleTable
, mem
, sizeof(USER_HANDLE_ENTRY
) * 1024*2);