[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / object.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: User handle manager
5 * FILE: subsystems/win32/win32k/ntuser/object.c
6 * PROGRAMER: Copyright (C) 2001 Alexandre Julliard
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserObj);
11
12 //int usedHandles=0;
13 PUSER_HANDLE_TABLE gHandleTable = NULL;
14
15
16 PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
17 {
18 unsigned short generation;
19 int index = (((unsigned int)handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
20 if (index < 0 || index >= ht->nb_handles)
21 return NULL;
22 if (!ht->handles[index].type)
23 return NULL;
24 generation = (unsigned int)handle >> 16;
25 if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
26 return &ht->handles[index];
27 return NULL;
28 }
29
30 __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
31 {
32 int index = ptr - ht->handles;
33 return (HANDLE)(((index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
34 }
35
36 __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
37 {
38 PUSER_HANDLE_ENTRY entry;
39 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
40 TRACE("handles used %i\n",gpsi->cHandleEntries);
41
42 if (ht->freelist)
43 {
44 entry = ht->freelist;
45 ht->freelist = entry->ptr;
46
47 gpsi->cHandleEntries++;
48 ppi->UserHandleCount++;
49 return entry;
50 }
51
52 if (ht->nb_handles >= ht->allocated_handles) /* Need to grow the array */
53 {
54 /**/
55 int i, iFree = 0, iWindow = 0, iMenu = 0, iCursorIcon = 0,
56 iHook = 0, iCallProc = 0, iAccel = 0, iMonitor = 0, iTimer = 0, iEvent = 0, iSMWP = 0;
57 /**/
58 ERR("Out of user handles! Used -> %i, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
59 //#if 0
60 for(i = 0; i < ht->nb_handles; i++)
61 {
62 switch (ht->handles[i].type)
63 {
64 case otFree: // Should be zero.
65 iFree++;
66 break;
67 case otWindow:
68 iWindow++;
69 break;
70 case otMenu:
71 iMenu++;
72 break;
73 case otCursorIcon:
74 iCursorIcon++;
75 break;
76 case otHook:
77 iHook++;
78 break;
79 case otCallProc:
80 iCallProc++;
81 break;
82 case otAccel:
83 iAccel++;
84 break;
85 case otMonitor:
86 iMonitor++;
87 break;
88 case otTimer:
89 iTimer++;
90 break;
91 case otEvent:
92 iEvent++;
93 break;
94 case otSMWP:
95 iSMWP++;
96 default:
97 break;
98 }
99 }
100 ERR("Handle Count by Type:\n Free = %d Window = %d Menu = %d CursorIcon = %d Hook = %d\n CallProc = %d Accel = %d Monitor = %d Timer = %d Event = %d SMWP = %d\n",
101 iFree, iWindow, iMenu, iCursorIcon, iHook, iCallProc, iAccel, iMonitor, iTimer, iEvent, iSMWP );
102 //#endif
103 return NULL;
104 #if 0
105 PUSER_HANDLE_ENTRY new_handles;
106 /* Grow array by 50% (but at minimum 32 entries) */
107 int growth = max( 32, ht->allocated_handles / 2 );
108 int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
109 if (new_size <= ht->allocated_handles)
110 return NULL;
111 if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
112 return NULL;
113 ht->handles = new_handles;
114 ht->allocated_handles = new_size;
115 #endif
116 }
117
118 entry = &ht->handles[ht->nb_handles++];
119
120 entry->generation = 1;
121
122 gpsi->cHandleEntries++;
123 ppi->UserHandleCount++;
124
125 return entry;
126 }
127
128 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
129 {
130 ht->freelist = NULL;
131 ht->handles = mem;
132
133 ht->nb_handles = 0;
134 ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
135 }
136
137 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
138 {
139 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
140 void *ret;
141 ret = entry->ptr;
142 entry->ptr = ht->freelist;
143 entry->type = 0;
144 entry->flags = 0;
145 entry->pi = NULL;
146 ht->freelist = entry;
147
148 gpsi->cHandleEntries--;
149 ppi->UserHandleCount--;
150
151 return ret;
152 }
153
154 static __inline PVOID
155 UserHandleOwnerByType(USER_OBJECT_TYPE type)
156 {
157 PVOID pi;
158
159 switch (type)
160 {
161 case otWindow:
162 case otInputContext:
163 pi = GetW32ThreadInfo();
164 break;
165
166 case otMenu:
167 case otCursorIcon:
168 case otHook:
169 case otCallProc:
170 case otAccel:
171 case otSMWP:
172 pi = GetW32ProcessInfo();
173 break;
174
175 case otMonitor:
176 pi = NULL; /* System */
177 break;
178
179 default:
180 pi = NULL;
181 break;
182 }
183
184 return pi;
185 }
186
187 /* allocate a user handle for a given object */
188 HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE type )
189 {
190 PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
191 if (!entry)
192 return 0;
193 entry->ptr = object;
194 entry->type = type;
195 entry->flags = 0;
196 entry->pi = UserHandleOwnerByType(type);
197 if (++entry->generation >= 0xffff)
198 entry->generation = 1;
199
200 /* We have created a handle, which is a reference! */
201 UserReferenceObject(object);
202
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 EngSetLastError(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
247
248 BOOL FASTCALL UserCreateHandleTable(VOID)
249 {
250
251 PVOID mem;
252
253 // FIXME: Don't alloc all at once! Must be mapped into umode also...
254 mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * 1024*2);
255 if (!mem)
256 {
257 ERR("Failed creating handle table\n");
258 return FALSE;
259 }
260
261 gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
262 if (gHandleTable == NULL)
263 {
264 UserHeapFree(mem);
265 ERR("Failed creating handle table\n");
266 return FALSE;
267 }
268
269 // FIXME: Make auto growable
270 UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * 1024*2);
271
272 return TRUE;
273 }
274
275 //
276 // New
277 //
278 PVOID
279 FASTCALL
280 UserCreateObject( PUSER_HANDLE_TABLE ht,
281 PDESKTOP pDesktop,
282 HANDLE* h,
283 USER_OBJECT_TYPE type,
284 ULONG size)
285 {
286 HANDLE hi;
287 PVOID Object;
288 PTHREADINFO pti;
289 PPROCESSINFO ppi;
290 BOOL dt;
291 PDESKTOP rpdesk = pDesktop;
292
293 pti = GetW32ThreadInfo();
294 ppi = pti->ppi;
295 if (!pDesktop) rpdesk = pti->rpdesk;
296
297 switch (type)
298 {
299 case otWindow:
300 // case otMenu:
301 case otHook:
302 case otCallProc:
303 case otInputContext:
304 Object = DesktopHeapAlloc(rpdesk, size);
305 dt = TRUE;
306 break;
307
308 default:
309 Object = UserHeapAlloc(size);
310 dt = FALSE;
311 break;
312 }
313
314 if (!Object)
315 return NULL;
316
317
318 hi = UserAllocHandle(ht, Object, type );
319 if (!hi)
320 {
321 if (dt)
322 DesktopHeapFree(rpdesk, Object);
323 else
324 UserHeapFree(Object);
325 return NULL;
326 }
327
328 RtlZeroMemory(Object, size);
329
330 switch (type)
331 {
332 case otWindow:
333 case otHook:
334 case otInputContext:
335 ((PTHRDESKHEAD)Object)->rpdesk = rpdesk;
336 ((PTHRDESKHEAD)Object)->pSelf = Object;
337 case otEvent:
338 ((PTHROBJHEAD)Object)->pti = pti;
339 break;
340
341 case otMenu:
342 case otCallProc:
343 ((PPROCDESKHEAD)Object)->rpdesk = rpdesk;
344 ((PPROCDESKHEAD)Object)->pSelf = Object;
345 break;
346
347 case otCursorIcon:
348 ((PPROCMARKHEAD)Object)->ppi = ppi;
349 break;
350
351 default:
352 break;
353 }
354 /* Now set default headers. */
355 ((PHEAD)Object)->h = hi;
356 ((PHEAD)Object)->cLockObj = 2; // We need this, because we create 2 refs: handle and pointer!
357
358 if (h)
359 *h = hi;
360 return Object;
361 }
362
363
364 BOOL
365 FASTCALL
366 UserDereferenceObject(PVOID object)
367 {
368 PUSER_HANDLE_ENTRY entry;
369 USER_OBJECT_TYPE type;
370
371 ASSERT(((PHEAD)object)->cLockObj >= 1);
372
373 if ((INT)--((PHEAD)object)->cLockObj <= 0)
374 {
375 entry = handle_to_entry(gHandleTable, ((PHEAD)object)->h );
376
377 if (!entry)
378 {
379 ERR("Warning! Dereference Object without ENTRY! Obj -> 0x%x\n", object);
380 return FALSE;
381 }
382 TRACE("Warning! Dereference to zero! Obj -> 0x%x\n", object);
383
384 ((PHEAD)object)->cLockObj = 0;
385
386 if (!(entry->flags & HANDLEENTRY_INDESTROY))
387 return TRUE;
388
389 type = entry->type;
390 free_user_entry(gHandleTable, entry );
391
392 switch (type)
393 {
394 case otWindow:
395 // case otMenu:
396 case otHook:
397 case otCallProc:
398 case otInputContext:
399 return DesktopHeapFree(((PTHRDESKHEAD)object)->rpdesk, object);
400
401 default:
402 return UserHeapFree(object);
403 }
404 }
405 return FALSE;
406 }
407
408 BOOL
409 FASTCALL
410 UserFreeHandle(PUSER_HANDLE_TABLE ht, HANDLE handle )
411 {
412 PUSER_HANDLE_ENTRY entry;
413
414 if (!(entry = handle_to_entry( ht, handle )))
415 {
416 SetLastNtError( STATUS_INVALID_HANDLE );
417 return FALSE;
418 }
419
420 entry->flags = HANDLEENTRY_INDESTROY;
421
422 return UserDereferenceObject(entry->ptr);
423 }
424
425 BOOL
426 FASTCALL
427 UserDeleteObject(HANDLE h, USER_OBJECT_TYPE type )
428 {
429 PVOID body = UserGetObject(gHandleTable, h, type);
430
431 if (!body) return FALSE;
432
433 ASSERT( ((PHEAD)body)->cLockObj >= 1);
434
435 return UserFreeHandle(gHandleTable, h);
436 }
437
438 VOID
439 FASTCALL
440 UserReferenceObject(PVOID obj)
441 {
442 ASSERT(((PHEAD)obj)->cLockObj >= 0);
443
444 ((PHEAD)obj)->cLockObj++;
445 }
446
447 PVOID
448 FASTCALL
449 UserReferenceObjectByHandle(HANDLE handle, USER_OBJECT_TYPE type)
450 {
451 PVOID object;
452
453 object = UserGetObject(gHandleTable, handle, type);
454 if (object)
455 {
456 UserReferenceObject(object);
457 }
458 return object;
459 }
460
461 /*
462 * NtUserValidateHandleSecure
463 *
464 * Status
465 * @implemented
466 */
467
468 BOOL
469 APIENTRY
470 NtUserValidateHandleSecure(
471 HANDLE handle,
472 BOOL Restricted)
473 {
474 if(!Restricted)
475 {
476 UINT uType;
477 {
478 PUSER_HANDLE_ENTRY entry;
479 if (!(entry = handle_to_entry(gHandleTable, handle )))
480 {
481 EngSetLastError(ERROR_INVALID_HANDLE);
482 return FALSE;
483 }
484 uType = entry->type;
485 }
486 switch (uType)
487 {
488 case otWindow:
489 {
490 PWND Window;
491 if ((Window = UserGetWindowObject((HWND) handle))) return TRUE;
492 return FALSE;
493 }
494 case otMenu:
495 {
496 PMENU_OBJECT Menu;
497 if ((Menu = UserGetMenuObject((HMENU) handle))) return TRUE;
498 return FALSE;
499 }
500 case otAccel:
501 {
502 PACCELERATOR_TABLE Accel;
503 if ((Accel = UserGetAccelObject((HACCEL) handle))) return TRUE;
504 return FALSE;
505 }
506 case otCursorIcon:
507 {
508 PCURICON_OBJECT Cursor;
509 if ((Cursor = UserGetCurIconObject((HCURSOR) handle))) return TRUE;
510 return FALSE;
511 }
512 case otHook:
513 {
514 PHOOK Hook;
515 if ((Hook = IntGetHookObject((HHOOK) handle))) return TRUE;
516 return FALSE;
517 }
518 case otMonitor:
519 {
520 PMONITOR Monitor;
521 if ((Monitor = UserGetMonitorObject((HMONITOR) handle))) return TRUE;
522 return FALSE;
523 }
524 case otCallProc:
525 {
526 WNDPROC_INFO Proc;
527 return UserGetCallProcInfo( handle, &Proc );
528 }
529 default:
530 EngSetLastError(ERROR_INVALID_HANDLE);
531 }
532 }
533 else
534 { /* Is handle entry restricted? */
535 STUB
536 }
537 return FALSE;
538 }