xref: /reactos/win32ss/user/ntuser/object.c (revision 84344399)
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 _Success_(return!=NULL)
211 static PVOID AllocSysObjectCB(
212     _In_ PDESKTOP pDesk,
213     _In_ PTHREADINFO pti,
214     _In_ SIZE_T Size,
215     _Out_ PVOID* ObjectOwner)
216 {
217     PVOID Object;
218 
219     UNREFERENCED_PARAMETER(pDesk);
220     UNREFERENCED_PARAMETER(pti);
221     ASSERT(Size > sizeof(HEAD));
222 
223     /* Allocate the clipboard data */
224     // FIXME: This allocation should be done on the current session pool;
225     // however ReactOS' MM doesn't support session pool yet.
226     Object = ExAllocatePoolZero(/* SESSION_POOL_MASK | */ PagedPool, Size, USERTAG_CLIPBOARD);
227     if (!Object)
228     {
229         ERR("ExAllocatePoolZero failed. No object created.\n");
230         return NULL;
231     }
232 
233     *ObjectOwner = NULL;
234     return Object;
235 }
236 
237 static void FreeSysObject(
238     _In_ PVOID Object)
239 {
240     UserHeapFree(Object);
241 }
242 
243 static void FreeSysObjectCB(
244     _In_ PVOID Object)
245 {
246     ExFreePoolWithTag(Object, USERTAG_CLIPBOARD);
247 }
248 
249 static const struct
250 {
251     PVOID   (*ObjectAlloc)(PDESKTOP, PTHREADINFO, SIZE_T, PVOID*);
252     BOOLEAN (*ObjectDestroy)(PVOID);
253     void    (*ObjectFree)(PVOID);
254 } ObjectCallbacks[TYPE_CTYPES] =
255 {
256     { NULL,                     NULL,                       NULL },                 /* TYPE_FREE */
257     { AllocDeskThreadObject,    co_UserDestroyWindow,       FreeDeskThreadObject }, /* TYPE_WINDOW */
258     { AllocDeskProcObject,      UserDestroyMenuObject,      FreeDeskProcObject },   /* TYPE_MENU */
259     { AllocProcMarkObject,      IntDestroyCurIconObject,    FreeCurIconObject },    /* TYPE_CURSOR */
260     { AllocSysObject,           /*UserSetWindowPosCleanup*/NULL, FreeSysObject },   /* TYPE_SETWINDOWPOS */
261     { AllocDeskThreadObject,    IntRemoveHook,              FreeDeskThreadObject }, /* TYPE_HOOK */
262     { AllocSysObjectCB,         /*UserClipDataCleanup*/NULL,FreeSysObjectCB },      /* TYPE_CLIPDATA */
263     { AllocDeskProcObject,      DestroyCallProc,            FreeDeskProcObject },   /* TYPE_CALLPROC */
264     { AllocProcMarkObject,      UserDestroyAccelTable,      FreeProcMarkObject },   /* TYPE_ACCELTABLE */
265     { NULL,                     NULL,                       NULL },                 /* TYPE_DDEACCESS */
266     { NULL,                     NULL,                       NULL },                 /* TYPE_DDECONV */
267     { NULL,                     NULL,                       NULL },                 /* TYPE_DDEXACT */
268     { AllocSysObject,           /*UserMonitorCleanup*/NULL, FreeSysObject },        /* TYPE_MONITOR */
269     { AllocSysObject,           /*UserKbdLayoutCleanup*/NULL,FreeSysObject },       /* TYPE_KBDLAYOUT */
270     { AllocSysObject,           /*UserKbdFileCleanup*/NULL, FreeSysObject },        /* TYPE_KBDFILE */
271     { AllocThreadObject,        IntRemoveEvent,             FreeThreadObject },     /* TYPE_WINEVENTHOOK */
272     { AllocSysObject,           /*UserTimerCleanup*/NULL,   FreeSysObject },        /* TYPE_TIMER */
273     { AllocInputContextObject,  UserDestroyInputContext,    UserFreeInputContext }, /* TYPE_INPUTCONTEXT */
274     { NULL,                     NULL,                       NULL },                 /* TYPE_HIDDATA */
275     { NULL,                     NULL,                       NULL },                 /* TYPE_DEVICEINFO */
276     { NULL,                     NULL,                       NULL },                 /* TYPE_TOUCHINPUTINFO */
277     { NULL,                     NULL,                       NULL },                 /* TYPE_GESTUREINFOOBJ */
278 };
279 
280 #if DBG
281 
282 void DbgUserDumpHandleTable(VOID)
283 {
284     int HandleCounts[TYPE_CTYPES];
285     PPROCESSINFO ppiList;
286     int i;
287     PWCHAR TypeNames[] = {L"Free",L"Window",L"Menu", L"CursorIcon", L"SMWP", L"Hook", L"ClipBoardData", L"CallProc",
288                           L"Accel", L"DDEaccess", L"DDEconv", L"DDExact", L"Monitor", L"KBDlayout", L"KBDfile",
289                           L"Event", L"Timer", L"InputContext", L"HidData", L"DeviceInfo", L"TouchInput",L"GestureInfo"};
290 
291     ERR("Total handles count: %lu\n", gpsi->cHandleEntries);
292 
293     memset(HandleCounts, 0, sizeof(HandleCounts));
294 
295     /* First of all count the number of handles per type */
296     ppiList = gppiList;
297     while (ppiList)
298     {
299         ERR("Process %s (%p) handles count: %d\n\t", ppiList->peProcess->ImageFileName, ppiList->peProcess->UniqueProcessId, ppiList->UserHandleCount);
300 
301         for (i = 1 ;i < TYPE_CTYPES; i++)
302         {
303             HandleCounts[i] += ppiList->DbgHandleCount[i];
304 
305             DbgPrint("%S: %lu, ", TypeNames[i], ppiList->DbgHandleCount[i]);
306             if (i % 6 == 0)
307                 DbgPrint("\n\t");
308         }
309         DbgPrint("\n");
310 
311         ppiList = ppiList->ppiNext;
312     }
313 
314     /* Print total type counts */
315     ERR("Total handles of the running processes: \n\t");
316     for (i = 1 ;i < TYPE_CTYPES; i++)
317     {
318         DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
319         if (i % 6 == 0)
320             DbgPrint("\n\t");
321     }
322     DbgPrint("\n");
323 
324     /* Now count the handle counts that are allocated from the handle table */
325     memset(HandleCounts, 0, sizeof(HandleCounts));
326     for (i = 0; i < gHandleTable->nb_handles; i++)
327          HandleCounts[gHandleTable->handles[i].type]++;
328 
329     ERR("Total handles count allocated: \n\t");
330     for (i = 1 ;i < TYPE_CTYPES; i++)
331     {
332         DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
333         if (i % 6 == 0)
334             DbgPrint("\n\t");
335     }
336     DbgPrint("\n");
337 }
338 
339 #endif
340 
341 PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
342 {
343    unsigned short generation;
344    int index = (LOWORD(handle) - FIRST_USER_HANDLE) >> 1;
345    if (index < 0 || index >= ht->nb_handles)
346       return NULL;
347    if (!ht->handles[index].type)
348       return NULL;
349    generation = HIWORD(handle);
350    if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
351       return &ht->handles[index];
352    return NULL;
353 }
354 
355 __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
356 {
357    int index = ptr - ht->handles;
358    return (HANDLE)((((INT_PTR)index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
359 }
360 
361 __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
362 {
363    PUSER_HANDLE_ENTRY entry;
364    TRACE("handles used %lu\n", gpsi->cHandleEntries);
365 
366    if (ht->freelist)
367    {
368       entry = ht->freelist;
369       ht->freelist = entry->ptr;
370 
371       gpsi->cHandleEntries++;
372       return entry;
373    }
374 
375    if (ht->nb_handles >= ht->allocated_handles)  /* Need to grow the array */
376    {
377        ERR("Out of user handles! Used -> %lu, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
378 
379 #if DBG
380        DbgUserDumpHandleTable();
381 #endif
382 
383       return NULL;
384 #if 0
385       PUSER_HANDLE_ENTRY new_handles;
386       /* Grow array by 50% (but at minimum 32 entries) */
387       int growth = max( 32, ht->allocated_handles / 2 );
388       int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
389       if (new_size <= ht->allocated_handles)
390          return NULL;
391       if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
392          return NULL;
393       ht->handles = new_handles;
394       ht->allocated_handles = new_size;
395 #endif
396    }
397 
398    entry = &ht->handles[ht->nb_handles++];
399 
400    entry->generation = 1;
401 
402    gpsi->cHandleEntries++;
403 
404    return entry;
405 }
406 
407 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
408 {
409    ht->freelist = NULL;
410    ht->handles = mem;
411 
412    ht->nb_handles = 0;
413    ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
414 }
415 
416 
417 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
418 {
419    void *ret;
420 
421 #if DBG
422    {
423        PPROCESSINFO ppi;
424        switch (entry->type)
425        {
426            case TYPE_WINDOW:
427            case TYPE_HOOK:
428            case TYPE_WINEVENTHOOK:
429                ppi = ((PTHREADINFO)entry->pi)->ppi;
430                break;
431            case TYPE_MENU:
432            case TYPE_CURSOR:
433            case TYPE_CALLPROC:
434            case TYPE_ACCELTABLE:
435                ppi = entry->pi;
436                break;
437            default:
438                ppi = NULL;
439        }
440        if (ppi)
441            ppi->DbgHandleCount[entry->type]--;
442    }
443 #endif
444 
445    ret = entry->ptr;
446    entry->ptr  = ht->freelist;
447    entry->type = 0;
448    entry->flags = 0;
449    entry->pi = NULL;
450    ht->freelist  = entry;
451 
452    gpsi->cHandleEntries--;
453 
454    return ret;
455 }
456 
457 /* allocate a user handle for a given object */
458 HANDLE UserAllocHandle(
459     _Inout_ PUSER_HANDLE_TABLE ht,
460     _In_ PVOID object,
461     _In_ HANDLE_TYPE type,
462     _In_ PVOID HandleOwner)
463 {
464    PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
465    if (!entry)
466       return 0;
467    entry->ptr  = object;
468    entry->type = type;
469    entry->flags = 0;
470    entry->pi = HandleOwner;
471    if (++entry->generation >= 0xffff)
472       entry->generation = 1;
473 
474    /* We have created a handle, which is a reference! */
475    UserReferenceObject(object);
476 
477    return entry_to_handle(ht, entry );
478 }
479 
480 /* return a pointer to a user object from its handle without setting an error */
481 PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type )
482 {
483    PUSER_HANDLE_ENTRY entry;
484 
485    ASSERT(ht);
486 
487    if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
488    {
489       return NULL;
490    }
491    return entry->ptr;
492 }
493 
494 /* return a pointer to a user object from its handle */
495 PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type )
496 {
497    PUSER_HANDLE_ENTRY entry;
498 
499    ASSERT(ht);
500 
501    if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
502    {
503       EngSetLastError(ERROR_INVALID_HANDLE);
504       return NULL;
505    }
506    return entry->ptr;
507 }
508 
509 
510 /* Get the full handle (32bit) for a possibly truncated (16bit) handle */
511 HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht,  HANDLE handle )
512 {
513    PUSER_HANDLE_ENTRY entry;
514 
515    if ((ULONG_PTR)handle >> 16)
516       return handle;
517    if (!(entry = handle_to_entry(ht, handle )))
518       return handle;
519    return entry_to_handle( ht, entry );
520 }
521 
522 
523 /* Same as get_user_object plus set the handle to the full 32-bit value */
524 void *get_user_object_handle(PUSER_HANDLE_TABLE ht,  HANDLE* handle, HANDLE_TYPE type )
525 {
526    PUSER_HANDLE_ENTRY entry;
527 
528    if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
529       return NULL;
530    *handle = entry_to_handle( ht, entry );
531    return entry->ptr;
532 }
533 
534 
535 
536 BOOL FASTCALL UserCreateHandleTable(VOID)
537 {
538    PVOID mem;
539    INT HandleCount = 1024 * 4;
540 
541    // FIXME: Don't alloc all at once! Must be mapped into umode also...
542    mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * HandleCount);
543    if (!mem)
544    {
545       ERR("Failed creating handle table\n");
546       return FALSE;
547    }
548 
549    gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
550    if (gHandleTable == NULL)
551    {
552        UserHeapFree(mem);
553        ERR("Failed creating handle table\n");
554        return FALSE;
555    }
556 
557    // FIXME: Make auto growable
558    UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * HandleCount);
559 
560    return TRUE;
561 }
562 
563 //
564 // New
565 //
566 PVOID
567 FASTCALL
568 UserCreateObject( PUSER_HANDLE_TABLE ht,
569                   PDESKTOP pDesktop,
570                   PTHREADINFO pti,
571                   HANDLE* h,
572                   HANDLE_TYPE type,
573                   ULONG size)
574 {
575    HANDLE hi;
576    PVOID Object;
577    PVOID ObjectOwner;
578 
579    /* Some sanity checks. Other checks will be made in the allocator */
580    ASSERT(type < TYPE_CTYPES);
581    ASSERT(type != TYPE_FREE);
582    ASSERT(ht != NULL);
583 
584    /* Allocate the object */
585    ASSERT(ObjectCallbacks[type].ObjectAlloc != NULL);
586    Object = ObjectCallbacks[type].ObjectAlloc(pDesktop, pti, size, &ObjectOwner);
587    if (!Object)
588    {
589        ERR("User object allocation failed. Out of memory!\n");
590        return NULL;
591    }
592 
593    hi = UserAllocHandle(ht, Object, type, ObjectOwner);
594    if (hi == NULL)
595    {
596        ERR("Out of user handles!\n");
597        ObjectCallbacks[type].ObjectFree(Object);
598        return NULL;
599    }
600 
601 #if DBG
602    if (pti)
603        pti->ppi->DbgHandleCount[type]++;
604 #endif
605 
606    /* Give this object its identity. */
607    ((PHEAD)Object)->h = hi;
608 
609    /* The caller will get a locked object.
610     * Note: with the reference from the handle, that makes two */
611    UserReferenceObject(Object);
612 
613    if (h)
614       *h = hi;
615    return Object;
616 }
617 
618 // Win: HMMarkObjectDestroy
619 BOOL
620 FASTCALL
621 UserMarkObjectDestroy(PVOID Object)
622 {
623     PUSER_HANDLE_ENTRY entry;
624     PHEAD ObjHead = Object;
625 
626     entry = handle_to_entry(gHandleTable, ObjHead->h);
627 
628     ASSERT(entry != NULL);
629 
630     entry->flags |= HANDLEENTRY_DESTROY;
631 
632     if (ObjHead->cLockObj > 1)
633     {
634         entry->flags &= ~HANDLEENTRY_INDESTROY;
635         TRACE("Count %d\n",ObjHead->cLockObj);
636         return FALSE;
637     }
638 
639     return TRUE;
640 }
641 
642 BOOL
643 FASTCALL
644 UserDereferenceObject(PVOID Object)
645 {
646     PHEAD ObjHead = Object;
647 
648     ASSERT(ObjHead->cLockObj >= 1);
649     ASSERT(ObjHead->cLockObj < 0x10000);
650 
651     if (--ObjHead->cLockObj == 0)
652     {
653         PUSER_HANDLE_ENTRY entry;
654         HANDLE_TYPE type;
655 
656         entry = handle_to_entry(gHandleTable, ObjHead->h);
657 
658         ASSERT(entry != NULL);
659         /* The entry should be marked as in deletion */
660         ASSERT(entry->flags & HANDLEENTRY_INDESTROY);
661 
662         type = entry->type;
663         ASSERT(type != TYPE_FREE);
664         ASSERT(type < TYPE_CTYPES);
665 
666         /* We can now get rid of everything */
667         free_user_entry(gHandleTable, entry );
668 
669 #if 0
670         /* Call the object destructor */
671         ASSERT(ObjectCallbacks[type].ObjectCleanup != NULL);
672         ObjectCallbacks[type].ObjectCleanup(Object);
673 #endif
674 
675         /* And free it */
676         ASSERT(ObjectCallbacks[type].ObjectFree != NULL);
677         ObjectCallbacks[type].ObjectFree(Object);
678 
679         return TRUE;
680     }
681     return FALSE;
682 }
683 
684 BOOL
685 FASTCALL
686 UserFreeHandle(PUSER_HANDLE_TABLE ht,  HANDLE handle )
687 {
688   PUSER_HANDLE_ENTRY entry;
689 
690   if (!(entry = handle_to_entry( ht, handle )))
691   {
692      SetLastNtError( STATUS_INVALID_HANDLE );
693      return FALSE;
694   }
695 
696   entry->flags = HANDLEENTRY_INDESTROY;
697 
698   return UserDereferenceObject(entry->ptr);
699 }
700 
701 BOOL
702 FASTCALL
703 UserObjectInDestroy(HANDLE h)
704 {
705   PUSER_HANDLE_ENTRY entry;
706 
707   if (!(entry = handle_to_entry( gHandleTable, h )))
708   {
709      SetLastNtError( STATUS_INVALID_HANDLE );
710      return TRUE;
711   }
712   return (entry->flags & HANDLEENTRY_INDESTROY);
713 }
714 
715 BOOL
716 FASTCALL
717 UserDeleteObject(HANDLE h, HANDLE_TYPE type )
718 {
719    PVOID body = UserGetObject(gHandleTable, h, type);
720 
721    if (!body) return FALSE;
722 
723    ASSERT( ((PHEAD)body)->cLockObj >= 1);
724    ASSERT( ((PHEAD)body)->cLockObj < 0x10000);
725 
726    return UserFreeHandle(gHandleTable, h);
727 }
728 
729 VOID
730 FASTCALL
731 UserReferenceObject(PVOID obj)
732 {
733    PHEAD ObjHead = obj;
734    ASSERT(ObjHead->cLockObj < 0x10000);
735 
736    ObjHead->cLockObj++;
737 }
738 
739 PVOID
740 FASTCALL
741 UserReferenceObjectByHandle(HANDLE handle, HANDLE_TYPE type)
742 {
743     PVOID object;
744 
745     object = UserGetObject(gHandleTable, handle, type);
746     if (object)
747     {
748        UserReferenceObject(object);
749     }
750     return object;
751 }
752 
753 BOOLEAN
754 UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner)
755 {
756     int i;
757     PUSER_HANDLE_ENTRY Entry;
758     BOOLEAN Ret = TRUE;
759 
760     /* Sweep the whole handle table */
761     for (i = 0; i < Table->allocated_handles; i++)
762     {
763         Entry = &Table->handles[i];
764 
765         if (Entry->pi != Owner)
766             continue;
767 
768         /* Do not destroy if it's already been done */
769         if (Entry->flags & HANDLEENTRY_INDESTROY)
770             continue;
771 
772         /* Call destructor */
773         if (!ObjectCallbacks[Entry->type].ObjectDestroy(Entry->ptr))
774         {
775             ERR("Failed destructing object %p, type %u.\n", Entry->ptr, Entry->type);
776             /* Don't return immediately, we must continue destroying the other objects */
777             Ret = FALSE;
778         }
779     }
780 
781     return Ret;
782 }
783 
784 /*
785  *
786  * Status
787  *    @implemented
788  */
789 
790 BOOL
791 APIENTRY
792 NtUserValidateHandleSecure(
793    HANDLE handle)
794 {
795    UINT uType;
796    PPROCESSINFO ppi;
797    PUSER_HANDLE_ENTRY entry;
798    BOOL Ret = FALSE;
799 
800    UserEnterExclusive();
801 
802    if (!(entry = handle_to_entry(gHandleTable, handle )))
803    {
804       EngSetLastError(ERROR_INVALID_HANDLE);
805       goto Exit; // Return FALSE
806    }
807    uType = entry->type;
808    switch (uType)
809    {
810        case TYPE_WINDOW:
811        case TYPE_INPUTCONTEXT:
812           ppi = ((PTHREADINFO)entry->pi)->ppi;
813           break;
814        case TYPE_MENU:
815        case TYPE_ACCELTABLE:
816        case TYPE_CURSOR:
817        case TYPE_HOOK:
818        case TYPE_CALLPROC:
819        case TYPE_SETWINDOWPOS:
820           ppi = entry->pi;
821           break;
822        default:
823           ppi = NULL;
824           break;
825    }
826 
827    if (!ppi)
828        goto Exit; // Return FALSE
829 
830    // Same process job returns TRUE.
831    if (gptiCurrent->ppi->pW32Job == ppi->pW32Job) Ret = TRUE;
832 
833 Exit:
834    UserLeave();
835    return Ret;
836 }
837 
838 // Win: HMAssignmentLock
839 PVOID FASTCALL UserAssignmentLock(PVOID *ppvObj, PVOID pvNew)
840 {
841     PVOID pvOld = *ppvObj;
842     *ppvObj = pvNew;
843 
844     if (pvOld && pvOld == pvNew)
845         return pvOld;
846 
847     if (pvNew)
848         UserReferenceObject(pvNew);
849 
850     if (pvOld)
851     {
852         if (UserDereferenceObject(pvOld))
853             pvOld = NULL;
854     }
855 
856     return pvOld;
857 }
858 
859 // Win: HMAssignmentUnlock
860 PVOID FASTCALL UserAssignmentUnlock(PVOID *ppvObj)
861 {
862     PVOID pvOld = *ppvObj;
863     *ppvObj = NULL;
864 
865     if (pvOld)
866     {
867         if (UserDereferenceObject(pvOld))
868             pvOld = NULL;
869     }
870 
871     return pvOld;
872 }
873