- Fall back onto some of the previous win32k icon handling code, and fix user32 to...
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / object.c
1 /*
2 * Server-side USER handles
3 *
4 * Copyright (C) 2001 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21
22
23 /* INCLUDES ******************************************************************/
24
25 #include <w32k.h>
26
27 #define NDEBUG
28 #include <debug.h>
29
30 int usedHandles=0;
31 PUSER_HANDLE_TABLE gHandleTable = NULL;
32
33
34 PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
35 {
36 unsigned short generation;
37 int index = (((unsigned int)handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
38 if (index < 0 || index >= ht->nb_handles)
39 return NULL;
40 if (!ht->handles[index].type)
41 return NULL;
42 generation = (unsigned int)handle >> 16;
43 if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
44 return &ht->handles[index];
45 return NULL;
46 }
47
48 __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
49 {
50 int index = ptr - ht->handles;
51 return (HANDLE)(((index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
52 }
53
54 __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
55 {
56 PUSER_HANDLE_ENTRY entry;
57
58 DPRINT("handles used %i\n",usedHandles);
59
60 if (ht->freelist)
61 {
62 entry = ht->freelist;
63 ht->freelist = entry->ptr;
64
65 usedHandles++;
66 return entry;
67 }
68
69 if (ht->nb_handles >= ht->allocated_handles) /* need to grow the array */
70 {
71 /**/
72 int i, iFree = 0, iWindow = 0, iMenu = 0, iCursorIcon = 0,
73 iHook = 0, iCallProc = 0, iAccel = 0, iMonitor = 0;
74 /**/
75 DPRINT1("Out of user handles! Used -> %i, NM_Handle -> %d\n", usedHandles, ht->nb_handles);
76 //#if 0
77 for(i = 0; i < ht->nb_handles; i++)
78 {
79 switch (ht->handles[i].type)
80 {
81 case otFree: // Should be zero.
82 iFree++;
83 break;
84 case otWindow:
85 iWindow++;
86 break;
87 case otMenu:
88 iMenu++;
89 break;
90 case otCursorIcon:
91 iCursorIcon++;
92 break;
93 case otHook:
94 iHook++;
95 break;
96 case otCallProc:
97 iCallProc++;
98 break;
99 case otAccel:
100 iAccel++;
101 break;
102 case otMonitor:
103 iMonitor++;
104 break;
105 default:
106 break;
107 }
108 }
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 );
111
112 ASSERT(FALSE);
113 //#endif
114 return NULL;
115 #if 0
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)
121 return NULL;
122 if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
123 return NULL;
124 ht->handles = new_handles;
125 ht->allocated_handles = new_size;
126 #endif
127 }
128
129 entry = &ht->handles[ht->nb_handles++];
130
131 entry->generation = 1;
132
133 usedHandles++;
134
135 return entry;
136 }
137
138 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
139 {
140 ht->freelist = NULL;
141 ht->handles = mem;
142
143 ht->nb_handles = 0;
144 ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
145 }
146
147 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
148 {
149 void *ret;
150 ret = entry->ptr;
151 entry->ptr = ht->freelist;
152 entry->type = 0;
153 entry->pi = NULL;
154 ht->freelist = entry;
155
156 usedHandles--;
157
158 return ret;
159 }
160
161 static __inline PVOID
162 UserHandleOwnerByType(USER_OBJECT_TYPE type)
163 {
164 PVOID pi;
165
166 switch (type)
167 {
168 case otWindow:
169 pi = GetW32ThreadInfo();
170 break;
171
172 case otMenu:
173 case otCursorIcon:
174 case otHook:
175 case otCallProc:
176 case otAccel:
177 pi = GetW32ProcessInfo();
178 break;
179
180 case otMonitor:
181 pi = NULL; /* System */
182 break;
183
184 default:
185 pi = NULL;
186 break;
187 }
188
189 return pi;
190 }
191
192 /* allocate a user handle for a given object */
193 HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE type )
194 {
195 PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
196 if (!entry)
197 return 0;
198 entry->ptr = object;
199 entry->type = type;
200 entry->pi = UserHandleOwnerByType(type);
201 if (++entry->generation >= 0xffff)
202 entry->generation = 1;
203 return entry_to_handle(ht, entry );
204 }
205
206 /* return a pointer to a user object from its handle */
207 PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type )
208 {
209 PUSER_HANDLE_ENTRY entry;
210
211 ASSERT(ht);
212
213 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
214 {
215 SetLastWin32Error(ERROR_INVALID_HANDLE);
216 return NULL;
217 }
218 return entry->ptr;
219 }
220
221
222 /* get the full handle (32bit) for a possibly truncated (16bit) handle */
223 HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht, HANDLE handle )
224 {
225 PUSER_HANDLE_ENTRY entry;
226
227 if ((unsigned int)handle >> 16)
228 return handle;
229 if (!(entry = handle_to_entry(ht, handle )))
230 return handle;
231 return entry_to_handle( ht, entry );
232 }
233
234
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 )
237 {
238 PUSER_HANDLE_ENTRY entry;
239
240 if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
241 return NULL;
242 *handle = entry_to_handle( ht, entry );
243 return entry->ptr;
244 }
245
246 /* free a user handle and return a pointer to the object */
247 PVOID UserFreeHandle(PUSER_HANDLE_TABLE ht, HANDLE handle )
248 {
249 PUSER_HANDLE_ENTRY entry;
250
251 if (!(entry = handle_to_entry( ht, handle )))
252 {
253 SetLastNtError( STATUS_INVALID_HANDLE );
254 return NULL;
255 }
256
257 return free_user_entry(ht, entry );
258 }
259
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 )
262 {
263 PUSER_HANDLE_ENTRY entry;
264
265 if (!*handle)
266 entry = ht->handles;
267 else
268 {
269 int index = (((unsigned int)*handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
270 if (index < 0 || index >= ht->nb_handles)
271 return NULL;
272 entry = ht->handles + index + 1; /* start from the next one */
273 }
274 while (entry < ht->handles + ht->nb_handles)
275 {
276 if (!type || entry->type == type)
277 {
278 *handle = entry_to_handle(ht, entry );
279 return entry->ptr;
280 }
281 entry++;
282 }
283 return NULL;
284 }
285
286
287
288 PVOID FASTCALL
289 ObmCreateObject(PUSER_HANDLE_TABLE ht, HANDLE* h,USER_OBJECT_TYPE type , ULONG size)
290 {
291
292 HANDLE hi;
293 PUSER_OBJECT_HEADER hdr = UserHeapAlloc(size + sizeof(USER_OBJECT_HEADER));//ExAllocatePool(PagedPool, size + sizeof(USER_OBJECT_HEADER));
294 if (!hdr)
295 return NULL;
296
297
298 hi = UserAllocHandle(ht, USER_HEADER_TO_BODY(hdr), type );
299 if (!hi)
300 {
301 //ExFreePool(hdr);
302 UserHeapFree(hdr);
303 return NULL;
304 }
305
306 RtlZeroMemory(hdr, size + sizeof(USER_OBJECT_HEADER));
307 hdr->hSelf = hi;
308 hdr->RefCount++; //temp hack!
309
310 if (h)
311 *h = hi;
312 return USER_HEADER_TO_BODY(hdr);
313 }
314
315 BOOL FASTCALL
316 ObmDeleteObject(HANDLE h, USER_OBJECT_TYPE type )
317 {
318 PUSER_OBJECT_HEADER hdr;
319 PVOID body = UserGetObject(gHandleTable, h, type);
320 if (!body)
321 return FALSE;
322
323 hdr = USER_BODY_TO_HEADER(body);
324 ASSERT(hdr->RefCount >= 0);
325
326 hdr->destroyed = TRUE;
327 if (hdr->RefCount == 0)
328 {
329 UserFreeHandle(gHandleTable, h);
330
331 memset(hdr, 0x55, sizeof(USER_OBJECT_HEADER));
332
333 UserHeapFree(hdr);
334 //ExFreePool(hdr);
335 return TRUE;
336 }
337
338 // DPRINT1("info: something not destroyed bcause refs still left, inuse %i\n",usedHandles);
339 return FALSE;
340 }
341
342
343 VOID FASTCALL ObmReferenceObject(PVOID obj)
344 {
345 PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
346
347 ASSERT(hdr->RefCount >= 0);
348
349 hdr->RefCount++;
350 }
351
352 HANDLE FASTCALL ObmObjectToHandle(PVOID obj)
353 {
354 PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
355 return hdr->hSelf;
356 }
357
358
359 BOOL FASTCALL ObmDereferenceObject2(PVOID obj)
360 {
361 PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
362
363 ASSERT(hdr->RefCount >= 1);
364
365 hdr->RefCount--;
366
367 // You can not have a zero here!
368 if (!hdr->destroyed && hdr->RefCount == 0) hdr->RefCount++; // BOUNCE!!!!!
369
370 if (hdr->RefCount == 0 && hdr->destroyed)
371 {
372 // DPRINT1("info: something destroyed bcaise of deref, in use=%i\n",usedHandles);
373
374 UserFreeHandle(gHandleTable, hdr->hSelf);
375
376 memset(hdr, 0x55, sizeof(USER_OBJECT_HEADER));
377
378 UserHeapFree(hdr);
379 //ExFreePool(hdr);
380
381 return TRUE;
382 }
383
384 return FALSE;
385 }
386
387
388
389 BOOL FASTCALL ObmCreateHandleTable()
390 {
391
392 PVOID mem;
393
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);
397 if (!mem)
398 {
399 DPRINT1("Failed creating handle table\n");
400 return FALSE;
401 }
402
403 gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
404 if (gHandleTable == NULL)
405 {
406 UserHeapFree(mem);
407 DPRINT1("Failed creating handle table\n");
408 return FALSE;
409 }
410
411 //FIXME: make auto growable
412 UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * 1024*2);
413
414 return TRUE;
415 }