xref: /reactos/win32ss/user/ntuser/object.c (revision 02e84521)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          User handle manager
5  * FILE:             win32ss/user/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 /* Forward declarations */
16 _Success_(return!=NULL)
17 static PVOID AllocThreadObject(
18     _In_ PDESKTOP pDesk,
19     _In_ PTHREADINFO pti,
20     _In_ SIZE_T Size,
21     _Out_ PVOID* HandleOwner)
22 {
23     PTHROBJHEAD ObjHead;
24 
25     UNREFERENCED_PARAMETER(pDesk);
26 
27     ASSERT(Size > sizeof(*ObjHead));
28     ASSERT(pti != NULL);
29 
30     ObjHead = UserHeapAlloc(Size);
31     if (!ObjHead)
32         return NULL;
33 
34     RtlZeroMemory(ObjHead, Size);
35 
36     ObjHead->pti = pti;
37     IntReferenceThreadInfo(pti);
38     *HandleOwner = pti;
39     /* It's a thread object, but it still count as one for the process */
40     pti->ppi->UserHandleCount++;
41 
42     return ObjHead;
43 }
44 
45 static void FreeThreadObject(
46     _In_ PVOID Object)
47 {
48     PTHROBJHEAD ObjHead = (PTHROBJHEAD)Object;
49     PTHREADINFO pti = ObjHead->pti;
50 
51     UserHeapFree(ObjHead);
52 
53     pti->ppi->UserHandleCount--;
54     IntDereferenceThreadInfo(pti);
55 }
56 
57 _Success_(return!=NULL)
58 static PVOID AllocDeskThreadObject(
59     _In_ PDESKTOP pDesk,
60     _In_ PTHREADINFO pti,
61     _In_ SIZE_T Size,
62     _Out_ PVOID* HandleOwner)
63 {
64     PTHRDESKHEAD ObjHead;
65 
66     ASSERT(Size > sizeof(*ObjHead));
67     ASSERT(pti != NULL);
68 
69     if (!pDesk)
70         pDesk = pti->rpdesk;
71 
72     ObjHead = DesktopHeapAlloc(pDesk, Size);
73     if (!ObjHead)
74         return NULL;
75 
76     RtlZeroMemory(ObjHead, Size);
77 
78     ObjHead->pSelf = ObjHead;
79     ObjHead->rpdesk = pDesk;
80     ObjHead->pti = pti;
81     IntReferenceThreadInfo(pti);
82     *HandleOwner = pti;
83     /* It's a thread object, but it still count as one for the process */
84     pti->ppi->UserHandleCount++;
85 
86     return ObjHead;
87 }
88 
89 static void FreeDeskThreadObject(
90     _In_ PVOID Object)
91 {
92     PTHRDESKHEAD ObjHead = (PTHRDESKHEAD)Object;
93     PDESKTOP pDesk = ObjHead->rpdesk;
94     PTHREADINFO pti = ObjHead->pti;
95 
96     DesktopHeapFree(pDesk, Object);
97 
98     pti->ppi->UserHandleCount--;
99     IntDereferenceThreadInfo(pti);
100 }
101 
102 _Success_(return!=NULL)
103 static PVOID AllocDeskProcObject(
104     _In_ PDESKTOP pDesk,
105     _In_ PTHREADINFO pti,
106     _In_ SIZE_T Size,
107     _Out_ PVOID* HandleOwner)
108 {
109     PPROCDESKHEAD ObjHead;
110     PPROCESSINFO ppi;
111 
112     ASSERT(Size > sizeof(*ObjHead));
113     ASSERT(pDesk != NULL);
114     ASSERT(pti != NULL);
115 
116     ObjHead = DesktopHeapAlloc(pDesk, Size);
117     if (!ObjHead)
118         return NULL;
119 
120     RtlZeroMemory(ObjHead, Size);
121 
122     ppi = pti->ppi;
123 
124     ObjHead->pSelf = ObjHead;
125     ObjHead->rpdesk = pDesk;
126     ObjHead->hTaskWow = (DWORD_PTR)ppi;
127     ppi->UserHandleCount++;
128     IntReferenceProcessInfo(ppi);
129     *HandleOwner = ppi;
130 
131     return ObjHead;
132 }
133 
134 static void FreeDeskProcObject(
135     _In_ PVOID Object)
136 {
137     PPROCDESKHEAD ObjHead = (PPROCDESKHEAD)Object;
138     PDESKTOP pDesk = ObjHead->rpdesk;
139     PPROCESSINFO ppi = (PPROCESSINFO)ObjHead->hTaskWow;
140 
141     ppi->UserHandleCount--;
142     IntDereferenceProcessInfo(ppi);
143 
144     DesktopHeapFree(pDesk, Object);
145 }
146 
147 _Success_(return!=NULL)
148 static PVOID AllocProcMarkObject(
149     _In_ PDESKTOP pDesk,
150     _In_ PTHREADINFO pti,
151     _In_ SIZE_T Size,
152     _Out_ PVOID* HandleOwner)
153 {
154     PPROCMARKHEAD ObjHead;
155     PPROCESSINFO ppi = pti->ppi;
156 
157     UNREFERENCED_PARAMETER(pDesk);
158 
159     ASSERT(Size > sizeof(*ObjHead));
160 
161     ObjHead = UserHeapAlloc(Size);
162     if (!ObjHead)
163         return NULL;
164 
165     RtlZeroMemory(ObjHead, Size);
166 
167     ObjHead->ppi = ppi;
168     IntReferenceProcessInfo(ppi);
169     *HandleOwner = ppi;
170     ppi->UserHandleCount++;
171 
172     return ObjHead;
173 }
174 
175 void FreeProcMarkObject(
176     _In_ PVOID Object)
177 {
178     PPROCESSINFO ppi = ((PPROCMARKHEAD)Object)->ppi;
179 
180     UserHeapFree(Object);
181 
182     ppi->UserHandleCount--;
183     IntDereferenceProcessInfo(ppi);
184 }
185 
186 _Success_(return!=NULL)
187 static PVOID AllocSysObject(
188     _In_ PDESKTOP pDesk,
189     _In_ PTHREADINFO pti,
190     _In_ SIZE_T Size,
191     _Out_ PVOID* ObjectOwner)
192 {
193     PVOID Object;
194 
195     UNREFERENCED_PARAMETER(pDesk);
196     UNREFERENCED_PARAMETER(pti);
197 
198     ASSERT(Size > sizeof(HEAD));
199 
200     Object = UserHeapAlloc(Size);
201     if (!Object)
202         return NULL;
203 
204     *ObjectOwner = NULL;
205 
206     RtlZeroMemory(Object, Size);
207     return Object;
208 }
209 
210 static void FreeSysObject(
211     _In_ PVOID Object)
212 {
213     UserHeapFree(Object);
214 }
215 
216 static const struct
217 {
218     PVOID   (*ObjectAlloc)(PDESKTOP, PTHREADINFO, SIZE_T, PVOID*);
219     BOOLEAN (*ObjectDestroy)(PVOID);
220     void    (*ObjectFree)(PVOID);
221 } ObjectCallbacks[TYPE_CTYPES] =
222 {
223     { NULL,                     NULL,                       NULL },                 /* TYPE_FREE */
224     { AllocDeskThreadObject,    co_UserDestroyWindow,       FreeDeskThreadObject }, /* TYPE_WINDOW */
225     { AllocDeskProcObject,      UserDestroyMenuObject,      FreeDeskProcObject },   /* TYPE_MENU */
226     { AllocProcMarkObject,      IntDestroyCurIconObject,    FreeCurIconObject },    /* TYPE_CURSOR */
227     { AllocSysObject,           /*UserSetWindowPosCleanup*/NULL, FreeSysObject },   /* TYPE_SETWINDOWPOS */
228     { AllocDeskThreadObject,    IntRemoveHook,              FreeDeskThreadObject }, /* TYPE_HOOK */
229     { AllocSysObject,           /*UserClipDataCleanup*/NULL,FreeSysObject },        /* TYPE_CLIPDATA */
230     { AllocDeskProcObject,      DestroyCallProc,            FreeDeskProcObject },   /* TYPE_CALLPROC */
231     { AllocProcMarkObject,      UserDestroyAccelTable,      FreeProcMarkObject },   /* TYPE_ACCELTABLE */
232     { NULL,                     NULL,                       NULL },                 /* TYPE_DDEACCESS */
233     { NULL,                     NULL,                       NULL },                 /* TYPE_DDECONV */
234     { NULL,                     NULL,                       NULL },                 /* TYPE_DDEXACT */
235     { AllocSysObject,           /*UserMonitorCleanup*/NULL, FreeSysObject },        /* TYPE_MONITOR */
236     { AllocSysObject,           /*UserKbdLayoutCleanup*/NULL,FreeSysObject },       /* TYPE_KBDLAYOUT */
237     { AllocSysObject,           /*UserKbdFileCleanup*/NULL, FreeSysObject },        /* TYPE_KBDFILE */
238     { AllocThreadObject,        IntRemoveEvent,             FreeThreadObject },     /* TYPE_WINEVENTHOOK */
239     { AllocSysObject,           /*UserTimerCleanup*/NULL,   FreeSysObject },        /* TYPE_TIMER */
240     { NULL,                     NULL,                       NULL },                 /* TYPE_INPUTCONTEXT */
241     { NULL,                     NULL,                       NULL },                 /* TYPE_HIDDATA */
242     { NULL,                     NULL,                       NULL },                 /* TYPE_DEVICEINFO */
243     { NULL,                     NULL,                       NULL },                 /* TYPE_TOUCHINPUTINFO */
244     { NULL,                     NULL,                       NULL },                 /* TYPE_GESTUREINFOOBJ */
245 };
246 
247 #if DBG
248 
249 void DbgUserDumpHandleTable(VOID)
250 {
251     int HandleCounts[TYPE_CTYPES];
252     PPROCESSINFO ppiList;
253     int i;
254     PWCHAR TypeNames[] = {L"Free",L"Window",L"Menu", L"CursorIcon", L"SMWP", L"Hook", L"ClipBoardData", L"CallProc",
255                           L"Accel", L"DDEaccess", L"DDEconv", L"DDExact", L"Monitor", L"KBDlayout", L"KBDfile",
256                           L"Event", L"Timer", L"InputContext", L"HidData", L"DeviceInfo", L"TouchInput",L"GestureInfo"};
257 
258     ERR("Total handles count: %lu\n", gpsi->cHandleEntries);
259 
260     memset(HandleCounts, 0, sizeof(HandleCounts));
261 
262     /* First of all count the number of handles per type */
263     ppiList = gppiList;
264     while (ppiList)
265     {
266         ERR("Process %s (%p) handles count: %d\n\t", ppiList->peProcess->ImageFileName, ppiList->peProcess->UniqueProcessId, ppiList->UserHandleCount);
267 
268         for (i = 1 ;i < TYPE_CTYPES; i++)
269         {
270             HandleCounts[i] += ppiList->DbgHandleCount[i];
271 
272             DbgPrint("%S: %lu, ", TypeNames[i], ppiList->DbgHandleCount[i]);
273             if (i % 6 == 0)
274                 DbgPrint("\n\t");
275         }
276         DbgPrint("\n");
277 
278         ppiList = ppiList->ppiNext;
279     }
280 
281     /* Print total type counts */
282     ERR("Total handles of the running processes: \n\t");
283     for (i = 1 ;i < TYPE_CTYPES; i++)
284     {
285         DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
286         if (i % 6 == 0)
287             DbgPrint("\n\t");
288     }
289     DbgPrint("\n");
290 
291     /* Now count the handle counts that are allocated from the handle table */
292     memset(HandleCounts, 0, sizeof(HandleCounts));
293     for (i = 0; i < gHandleTable->nb_handles; i++)
294          HandleCounts[gHandleTable->handles[i].type]++;
295 
296     ERR("Total handles count allocated: \n\t");
297     for (i = 1 ;i < TYPE_CTYPES; i++)
298     {
299         DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
300         if (i % 6 == 0)
301             DbgPrint("\n\t");
302     }
303     DbgPrint("\n");
304 }
305 
306 #endif
307 
308 PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
309 {
310    unsigned short generation;
311    int index = (LOWORD(handle) - FIRST_USER_HANDLE) >> 1;
312    if (index < 0 || index >= ht->nb_handles)
313       return NULL;
314    if (!ht->handles[index].type)
315       return NULL;
316    generation = HIWORD(handle);
317    if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
318       return &ht->handles[index];
319    return NULL;
320 }
321 
322 __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
323 {
324    int index = ptr - ht->handles;
325    return (HANDLE)((((INT_PTR)index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
326 }
327 
328 __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
329 {
330    PUSER_HANDLE_ENTRY entry;
331    TRACE("handles used %lu\n", gpsi->cHandleEntries);
332 
333    if (ht->freelist)
334    {
335       entry = ht->freelist;
336       ht->freelist = entry->ptr;
337 
338       gpsi->cHandleEntries++;
339       return entry;
340    }
341 
342    if (ht->nb_handles >= ht->allocated_handles)  /* Need to grow the array */
343    {
344        ERR("Out of user handles! Used -> %lu, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
345 
346 #if DBG
347        DbgUserDumpHandleTable();
348 #endif
349 
350       return NULL;
351 #if 0
352       PUSER_HANDLE_ENTRY new_handles;
353       /* Grow array by 50% (but at minimum 32 entries) */
354       int growth = max( 32, ht->allocated_handles / 2 );
355       int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
356       if (new_size <= ht->allocated_handles)
357          return NULL;
358       if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
359          return NULL;
360       ht->handles = new_handles;
361       ht->allocated_handles = new_size;
362 #endif
363    }
364 
365    entry = &ht->handles[ht->nb_handles++];
366 
367    entry->generation = 1;
368 
369    gpsi->cHandleEntries++;
370 
371    return entry;
372 }
373 
374 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
375 {
376    ht->freelist = NULL;
377    ht->handles = mem;
378 
379    ht->nb_handles = 0;
380    ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
381 }
382 
383 
384 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
385 {
386    void *ret;
387 
388 #if DBG
389    {
390        PPROCESSINFO ppi;
391        switch (entry->type)
392        {
393            case TYPE_WINDOW:
394            case TYPE_HOOK:
395            case TYPE_WINEVENTHOOK:
396                ppi = ((PTHREADINFO)entry->pi)->ppi;
397                break;
398            case TYPE_MENU:
399            case TYPE_CURSOR:
400            case TYPE_CALLPROC:
401            case TYPE_ACCELTABLE:
402                ppi = entry->pi;
403                break;
404            default:
405                ppi = NULL;
406        }
407        if (ppi)
408            ppi->DbgHandleCount[entry->type]--;
409    }
410 #endif
411 
412    ret = entry->ptr;
413    entry->ptr  = ht->freelist;
414    entry->type = 0;
415    entry->flags = 0;
416    entry->pi = NULL;
417    ht->freelist  = entry;
418 
419    gpsi->cHandleEntries--;
420 
421    return ret;
422 }
423 
424 /* allocate a user handle for a given object */
425 HANDLE UserAllocHandle(
426     _Inout_ PUSER_HANDLE_TABLE ht,
427     _In_ PVOID object,
428     _In_ HANDLE_TYPE type,
429     _In_ PVOID HandleOwner)
430 {
431    PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
432    if (!entry)
433       return 0;
434    entry->ptr  = object;
435    entry->type = type;
436    entry->flags = 0;
437    entry->pi = HandleOwner;
438    if (++entry->generation >= 0xffff)
439       entry->generation = 1;
440 
441    /* We have created a handle, which is a reference! */
442    UserReferenceObject(object);
443 
444    return entry_to_handle(ht, entry );
445 }
446 
447 /* return a pointer to a user object from its handle without setting an error */
448 PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type )
449 {
450    PUSER_HANDLE_ENTRY entry;
451 
452    ASSERT(ht);
453 
454    if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
455    {
456       return NULL;
457    }
458    return entry->ptr;
459 }
460 
461 /* return a pointer to a user object from its handle */
462 PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type )
463 {
464    PUSER_HANDLE_ENTRY entry;
465 
466    ASSERT(ht);
467 
468    if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
469    {
470       EngSetLastError(ERROR_INVALID_HANDLE);
471       return NULL;
472    }
473    return entry->ptr;
474 }
475 
476 
477 /* Get the full handle (32bit) for a possibly truncated (16bit) handle */
478 HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht,  HANDLE handle )
479 {
480    PUSER_HANDLE_ENTRY entry;
481 
482    if ((ULONG_PTR)handle >> 16)
483       return handle;
484    if (!(entry = handle_to_entry(ht, handle )))
485       return handle;
486    return entry_to_handle( ht, entry );
487 }
488 
489 
490 /* Same as get_user_object plus set the handle to the full 32-bit value */
491 void *get_user_object_handle(PUSER_HANDLE_TABLE ht,  HANDLE* handle, HANDLE_TYPE type )
492 {
493    PUSER_HANDLE_ENTRY entry;
494 
495    if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
496       return NULL;
497    *handle = entry_to_handle( ht, entry );
498    return entry->ptr;
499 }
500 
501 
502 
503 BOOL FASTCALL UserCreateHandleTable(VOID)
504 {
505    PVOID mem;
506    INT HandleCount = 1024 * 4;
507 
508    // FIXME: Don't alloc all at once! Must be mapped into umode also...
509    mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * HandleCount);
510    if (!mem)
511    {
512       ERR("Failed creating handle table\n");
513       return FALSE;
514    }
515 
516    gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
517    if (gHandleTable == NULL)
518    {
519        UserHeapFree(mem);
520        ERR("Failed creating handle table\n");
521        return FALSE;
522    }
523 
524    // FIXME: Make auto growable
525    UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * HandleCount);
526 
527    return TRUE;
528 }
529 
530 //
531 // New
532 //
533 PVOID
534 FASTCALL
535 UserCreateObject( PUSER_HANDLE_TABLE ht,
536                   PDESKTOP pDesktop,
537                   PTHREADINFO pti,
538                   HANDLE* h,
539                   HANDLE_TYPE type,
540                   ULONG size)
541 {
542    HANDLE hi;
543    PVOID Object;
544    PVOID ObjectOwner;
545 
546    /* Some sanity checks. Other checks will be made in the allocator */
547    ASSERT(type < TYPE_CTYPES);
548    ASSERT(type != TYPE_FREE);
549    ASSERT(ht != NULL);
550 
551    /* Allocate the object */
552    ASSERT(ObjectCallbacks[type].ObjectAlloc != NULL);
553    Object = ObjectCallbacks[type].ObjectAlloc(pDesktop, pti, size, &ObjectOwner);
554    if (!Object)
555    {
556        ERR("User object allocation failed. Out of memory!\n");
557        return NULL;
558    }
559 
560    hi = UserAllocHandle(ht, Object, type, ObjectOwner);
561    if (hi == NULL)
562    {
563        ERR("Out of user handles!\n");
564        ObjectCallbacks[type].ObjectFree(Object);
565        return NULL;
566    }
567 
568 #if DBG
569    if (pti)
570        pti->ppi->DbgHandleCount[type]++;
571 #endif
572 
573    /* Give this object its identity. */
574    ((PHEAD)Object)->h = hi;
575 
576    /* The caller will get a locked object.
577     * Note: with the reference from the handle, that makes two */
578    UserReferenceObject(Object);
579 
580    if (h)
581       *h = hi;
582    return Object;
583 }
584 
585 BOOL
586 FASTCALL
587 UserMarkObjectDestroy(PVOID Object)
588 {
589     PUSER_HANDLE_ENTRY entry;
590     PHEAD ObjHead = Object;
591 
592     entry = handle_to_entry(gHandleTable, ObjHead->h);
593 
594     ASSERT(entry != NULL);
595 
596     entry->flags |= HANDLEENTRY_DESTROY;
597 
598     if (ObjHead->cLockObj > 1)
599     {
600         entry->flags &= ~HANDLEENTRY_INDESTROY;
601         TRACE("Count %d\n",ObjHead->cLockObj);
602         return FALSE;
603     }
604 
605     return TRUE;
606 }
607 
608 BOOL
609 FASTCALL
610 UserDereferenceObject(PVOID Object)
611 {
612     PHEAD ObjHead = Object;
613 
614     ASSERT(ObjHead->cLockObj >= 1);
615     ASSERT(ObjHead->cLockObj < 0x10000);
616 
617     if (--ObjHead->cLockObj == 0)
618     {
619         PUSER_HANDLE_ENTRY entry;
620         HANDLE_TYPE type;
621 
622         entry = handle_to_entry(gHandleTable, ObjHead->h);
623 
624         ASSERT(entry != NULL);
625         /* The entry should be marked as in deletion */
626         ASSERT(entry->flags & HANDLEENTRY_INDESTROY);
627 
628         type = entry->type;
629         ASSERT(type != TYPE_FREE);
630         ASSERT(type < TYPE_CTYPES);
631 
632         /* We can now get rid of everything */
633         free_user_entry(gHandleTable, entry );
634 
635 #if 0
636         /* Call the object destructor */
637         ASSERT(ObjectCallbacks[type].ObjectCleanup != NULL);
638         ObjectCallbacks[type].ObjectCleanup(Object);
639 #endif
640 
641         /* And free it */
642         ASSERT(ObjectCallbacks[type].ObjectFree != NULL);
643         ObjectCallbacks[type].ObjectFree(Object);
644 
645         return TRUE;
646     }
647     return FALSE;
648 }
649 
650 BOOL
651 FASTCALL
652 UserFreeHandle(PUSER_HANDLE_TABLE ht,  HANDLE handle )
653 {
654   PUSER_HANDLE_ENTRY entry;
655 
656   if (!(entry = handle_to_entry( ht, handle )))
657   {
658      SetLastNtError( STATUS_INVALID_HANDLE );
659      return FALSE;
660   }
661 
662   entry->flags = HANDLEENTRY_INDESTROY;
663 
664   return UserDereferenceObject(entry->ptr);
665 }
666 
667 BOOL
668 FASTCALL
669 UserObjectInDestroy(HANDLE h)
670 {
671   PUSER_HANDLE_ENTRY entry;
672 
673   if (!(entry = handle_to_entry( gHandleTable, h )))
674   {
675      SetLastNtError( STATUS_INVALID_HANDLE );
676      return TRUE;
677   }
678   return (entry->flags & HANDLEENTRY_INDESTROY);
679 }
680 
681 BOOL
682 FASTCALL
683 UserDeleteObject(HANDLE h, HANDLE_TYPE type )
684 {
685    PVOID body = UserGetObject(gHandleTable, h, type);
686 
687    if (!body) return FALSE;
688 
689    ASSERT( ((PHEAD)body)->cLockObj >= 1);
690    ASSERT( ((PHEAD)body)->cLockObj < 0x10000);
691 
692    return UserFreeHandle(gHandleTable, h);
693 }
694 
695 VOID
696 FASTCALL
697 UserReferenceObject(PVOID obj)
698 {
699    PHEAD ObjHead = obj;
700    ASSERT(ObjHead->cLockObj < 0x10000);
701 
702    ObjHead->cLockObj++;
703 }
704 
705 PVOID
706 FASTCALL
707 UserReferenceObjectByHandle(HANDLE handle, HANDLE_TYPE type)
708 {
709     PVOID object;
710 
711     object = UserGetObject(gHandleTable, handle, type);
712     if (object)
713     {
714        UserReferenceObject(object);
715     }
716     return object;
717 }
718 
719 BOOLEAN
720 UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner)
721 {
722     int i;
723     PUSER_HANDLE_ENTRY Entry;
724     BOOLEAN Ret = TRUE;
725 
726     /* Sweep the whole handle table */
727     for (i = 0; i < Table->allocated_handles; i++)
728     {
729         Entry = &Table->handles[i];
730 
731         if (Entry->pi != Owner)
732             continue;
733 
734         /* Do not destroy if it's already been done */
735         if (Entry->flags & HANDLEENTRY_INDESTROY)
736             continue;
737 
738         /* Call destructor */
739         if (!ObjectCallbacks[Entry->type].ObjectDestroy(Entry->ptr))
740         {
741             ERR("Failed destructing object %p, type %u.\n", Entry->ptr, Entry->type);
742             /* Don't return immediately, we must continue destroying the other objects */
743             Ret = FALSE;
744         }
745     }
746 
747     return Ret;
748 }
749 
750 /*
751  *
752  * Status
753  *    @implemented
754  */
755 
756 BOOL
757 APIENTRY
758 NtUserValidateHandleSecure(
759    HANDLE handle)
760 {
761    UINT uType;
762    PPROCESSINFO ppi;
763    PUSER_HANDLE_ENTRY entry;
764 
765    DECLARE_RETURN(BOOL);
766    UserEnterExclusive();
767 
768    if (!(entry = handle_to_entry(gHandleTable, handle )))
769    {
770       EngSetLastError(ERROR_INVALID_HANDLE);
771       RETURN( FALSE);
772    }
773    uType = entry->type;
774    switch (uType)
775    {
776        case TYPE_WINDOW:
777        case TYPE_INPUTCONTEXT:
778           ppi = ((PTHREADINFO)entry->pi)->ppi;
779           break;
780        case TYPE_MENU:
781        case TYPE_ACCELTABLE:
782        case TYPE_CURSOR:
783        case TYPE_HOOK:
784        case TYPE_CALLPROC:
785        case TYPE_SETWINDOWPOS:
786           ppi = entry->pi;
787           break;
788        default:
789           ppi = NULL;
790           break;
791    }
792 
793    if (!ppi) RETURN( FALSE);
794 
795    // Same process job returns TRUE.
796    if (gptiCurrent->ppi->pW32Job == ppi->pW32Job) RETURN( TRUE);
797 
798    RETURN( FALSE);
799 
800 CLEANUP:
801    UserLeave();
802    END_CLEANUP;
803 }
804