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
);
116 PUSER_HANDLE_ENTRY new_handles
;
117 /* grow array by 50% (but at minimum 32 entries) */
118 int growth
= max( 32, ht
->allocated_handles
/ 2 );
119 int new_size
= min( ht
->allocated_handles
+ growth
, (LAST_USER_HANDLE
-FIRST_USER_HANDLE
+1) >> 1 );
120 if (new_size
<= ht
->allocated_handles
)
122 if (!(new_handles
= UserHeapReAlloc( ht
->handles
, new_size
* sizeof(*ht
->handles
) )))
124 ht
->handles
= new_handles
;
125 ht
->allocated_handles
= new_size
;
129 entry
= &ht
->handles
[ht
->nb_handles
++];
131 entry
->generation
= 1;
138 VOID
UserInitHandleTable(PUSER_HANDLE_TABLE ht
, PVOID mem
, ULONG bytes
)
144 ht
->allocated_handles
= bytes
/ sizeof(USER_HANDLE_ENTRY
);
147 __inline
static void *free_user_entry(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY entry
)
151 entry
->ptr
= ht
->freelist
;
154 ht
->freelist
= entry
;
161 static __inline PVOID
162 UserHandleOwnerByType(USER_OBJECT_TYPE type
)
169 pi
= GetW32ThreadInfo();
177 pi
= GetW32ProcessInfo();
181 pi
= NULL
; /* System */
192 /* allocate a user handle for a given object */
193 HANDLE
UserAllocHandle(PUSER_HANDLE_TABLE ht
, PVOID object
, USER_OBJECT_TYPE type
)
195 PUSER_HANDLE_ENTRY entry
= alloc_user_entry(ht
);
200 entry
->pi
= UserHandleOwnerByType(type
);
201 if (++entry
->generation
>= 0xffff)
202 entry
->generation
= 1;
203 return entry_to_handle(ht
, entry
);
206 /* return a pointer to a user object from its handle */
207 PVOID
UserGetObject(PUSER_HANDLE_TABLE ht
, HANDLE handle
, USER_OBJECT_TYPE type
)
209 PUSER_HANDLE_ENTRY entry
;
213 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
215 SetLastWin32Error(ERROR_INVALID_HANDLE
);
222 /* get the full handle (32bit) for a possibly truncated (16bit) handle */
223 HANDLE
get_user_full_handle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
225 PUSER_HANDLE_ENTRY entry
;
227 if ((unsigned int)handle
>> 16)
229 if (!(entry
= handle_to_entry(ht
, handle
)))
231 return entry_to_handle( ht
, entry
);
235 /* same as get_user_object plus set the handle to the full 32-bit value */
236 void *get_user_object_handle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
238 PUSER_HANDLE_ENTRY entry
;
240 if (!(entry
= handle_to_entry(ht
, *handle
)) || entry
->type
!= type
)
242 *handle
= entry_to_handle( ht
, entry
);
246 /* free a user handle and return a pointer to the object */
247 PVOID
UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
249 PUSER_HANDLE_ENTRY entry
;
251 if (!(entry
= handle_to_entry( ht
, handle
)))
253 SetLastNtError( STATUS_INVALID_HANDLE
);
257 return free_user_entry(ht
, entry
);
260 /* return the next user handle after 'handle' that is of a given type */
261 PVOID
UserGetNextHandle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
263 PUSER_HANDLE_ENTRY entry
;
269 int index
= (((unsigned int)*handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
270 if (index
< 0 || index
>= ht
->nb_handles
)
272 entry
= ht
->handles
+ index
+ 1; /* start from the next one */
274 while (entry
< ht
->handles
+ ht
->nb_handles
)
276 if (!type
|| entry
->type
== type
)
278 *handle
= entry_to_handle(ht
, entry
);
289 ObmCreateObject(PUSER_HANDLE_TABLE ht
, HANDLE
* h
,USER_OBJECT_TYPE type
, ULONG size
)
293 PUSER_OBJECT_HEADER hdr
= UserHeapAlloc(size
+ sizeof(USER_OBJECT_HEADER
));//ExAllocatePool(PagedPool, size + sizeof(USER_OBJECT_HEADER));
298 hi
= UserAllocHandle(ht
, USER_HEADER_TO_BODY(hdr
), type
);
306 RtlZeroMemory(hdr
, size
+ sizeof(USER_OBJECT_HEADER
));
308 hdr
->RefCount
++; //temp hack!
312 return USER_HEADER_TO_BODY(hdr
);
316 ObmDeleteObject(HANDLE h
, USER_OBJECT_TYPE type
)
318 PUSER_OBJECT_HEADER hdr
;
319 PVOID body
= UserGetObject(gHandleTable
, h
, type
);
323 hdr
= USER_BODY_TO_HEADER(body
);
324 ASSERT(hdr
->RefCount
>= 0);
326 hdr
->destroyed
= TRUE
;
327 if (hdr
->RefCount
== 0)
329 UserFreeHandle(gHandleTable
, h
);
331 memset(hdr
, 0x55, sizeof(USER_OBJECT_HEADER
));
338 // DPRINT1("info: something not destroyed bcause refs still left, inuse %i\n",usedHandles);
343 VOID FASTCALL
ObmReferenceObject(PVOID obj
)
345 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
347 ASSERT(hdr
->RefCount
>= 0);
352 HANDLE FASTCALL
ObmObjectToHandle(PVOID obj
)
354 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
359 BOOL FASTCALL
ObmDereferenceObject2(PVOID obj
)
361 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
363 ASSERT(hdr
->RefCount
>= 1);
367 // You can not have a zero here!
368 if (!hdr
->destroyed
&& hdr
->RefCount
== 0) hdr
->RefCount
++; // BOUNCE!!!!!
370 if (hdr
->RefCount
== 0 && hdr
->destroyed
)
372 // DPRINT1("info: something destroyed bcaise of deref, in use=%i\n",usedHandles);
374 UserFreeHandle(gHandleTable
, hdr
->hSelf
);
376 memset(hdr
, 0x55, sizeof(USER_OBJECT_HEADER
));
389 BOOL FASTCALL
ObmCreateHandleTable()
394 //FIXME: dont alloc all at once! must be mapped into umode also...
395 //mem = ExAllocatePool(PagedPool, sizeof(USER_HANDLE_ENTRY) * 1024*2);
396 mem
= UserHeapAlloc(sizeof(USER_HANDLE_ENTRY
) * 1024*2);
399 DPRINT1("Failed creating handle table\n");
403 gHandleTable
= UserHeapAlloc(sizeof(USER_HANDLE_TABLE
));
404 if (gHandleTable
== NULL
)
407 DPRINT1("Failed creating handle table\n");
411 //FIXME: make auto growable
412 UserInitHandleTable(gHandleTable
, mem
, sizeof(USER_HANDLE_ENTRY
) * 1024*2);