Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / win32ss / user / ntuser / object.c
diff --git a/win32ss/user/ntuser/object.c b/win32ss/user/ntuser/object.c
new file mode 100644 (file)
index 0000000..8fac269
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+ * COPYRIGHT:        See COPYING in the top level directory
+ * PROJECT:          ReactOS kernel
+ * PURPOSE:          User handle manager
+ * FILE:             win32ss/user/ntuser/object.c
+ * PROGRAMER:        Copyright (C) 2001 Alexandre Julliard
+ */
+
+#include <win32k.h>
+DBG_DEFAULT_CHANNEL(UserObj);
+
+//int usedHandles=0;
+PUSER_HANDLE_TABLE gHandleTable = NULL;
+
+/* Forward declarations */
+_Success_(return!=NULL)
+static PVOID AllocThreadObject(
+    _In_ PDESKTOP pDesk,
+    _In_ PTHREADINFO pti,
+    _In_ SIZE_T Size,
+    _Out_ PVOID* HandleOwner)
+{
+    PTHROBJHEAD ObjHead;
+
+    UNREFERENCED_PARAMETER(pDesk);
+
+    ASSERT(Size > sizeof(*ObjHead));
+    ASSERT(pti != NULL);
+
+    ObjHead = UserHeapAlloc(Size);
+    if (!ObjHead)
+        return NULL;
+
+    RtlZeroMemory(ObjHead, Size);
+
+    ObjHead->pti = pti;
+    IntReferenceThreadInfo(pti);
+    *HandleOwner = pti;
+    /* It's a thread object, but it still count as one for the process */
+    pti->ppi->UserHandleCount++;
+
+    return ObjHead;
+}
+
+static void FreeThreadObject(
+    _In_ PVOID Object)
+{
+    PTHROBJHEAD ObjHead = (PTHROBJHEAD)Object;
+    PTHREADINFO pti = ObjHead->pti;
+
+    UserHeapFree(ObjHead);
+
+    pti->ppi->UserHandleCount--;
+    IntDereferenceThreadInfo(pti);
+}
+
+_Success_(return!=NULL)
+static PVOID AllocDeskThreadObject(
+    _In_ PDESKTOP pDesk,
+    _In_ PTHREADINFO pti,
+    _In_ SIZE_T Size,
+    _Out_ PVOID* HandleOwner)
+{
+    PTHRDESKHEAD ObjHead;
+
+    ASSERT(Size > sizeof(*ObjHead));
+    ASSERT(pti != NULL);
+
+    if (!pDesk)
+        pDesk = pti->rpdesk;
+
+    ObjHead = DesktopHeapAlloc(pDesk, Size);
+    if (!ObjHead)
+        return NULL;
+
+    RtlZeroMemory(ObjHead, Size);
+
+    ObjHead->pSelf = ObjHead;
+    ObjHead->rpdesk = pDesk;
+    ObjHead->pti = pti;
+    IntReferenceThreadInfo(pti);
+    *HandleOwner = pti;
+    /* It's a thread object, but it still count as one for the process */
+    pti->ppi->UserHandleCount++;
+
+    return ObjHead;
+}
+
+static void FreeDeskThreadObject(
+    _In_ PVOID Object)
+{
+    PTHRDESKHEAD ObjHead = (PTHRDESKHEAD)Object;
+    PDESKTOP pDesk = ObjHead->rpdesk;
+    PTHREADINFO pti = ObjHead->pti;
+
+    DesktopHeapFree(pDesk, Object);
+
+    pti->ppi->UserHandleCount--;
+    IntDereferenceThreadInfo(pti);
+}
+
+_Success_(return!=NULL)
+static PVOID AllocDeskProcObject(
+    _In_ PDESKTOP pDesk,
+    _In_ PTHREADINFO pti,
+    _In_ SIZE_T Size,
+    _Out_ PVOID* HandleOwner)
+{
+    PPROCDESKHEAD ObjHead;
+    PPROCESSINFO ppi;
+
+    ASSERT(Size > sizeof(*ObjHead));
+    ASSERT(pDesk != NULL);
+    ASSERT(pti != NULL);
+
+    ObjHead = DesktopHeapAlloc(pDesk, Size);
+    if (!ObjHead)
+        return NULL;
+
+    RtlZeroMemory(ObjHead, Size);
+
+    ppi = pti->ppi;
+
+    ObjHead->pSelf = ObjHead;
+    ObjHead->rpdesk = pDesk;
+    ObjHead->hTaskWow = (DWORD_PTR)ppi;
+    ppi->UserHandleCount++;
+    IntReferenceProcessInfo(ppi);
+    *HandleOwner = ppi;
+
+    return ObjHead;
+}
+
+static void FreeDeskProcObject(
+    _In_ PVOID Object)
+{
+    PPROCDESKHEAD ObjHead = (PPROCDESKHEAD)Object;
+    PDESKTOP pDesk = ObjHead->rpdesk;
+    PPROCESSINFO ppi = (PPROCESSINFO)ObjHead->hTaskWow;
+
+    ppi->UserHandleCount--;
+    IntDereferenceProcessInfo(ppi);
+
+    DesktopHeapFree(pDesk, Object);
+}
+
+_Success_(return!=NULL)
+static PVOID AllocProcMarkObject(
+    _In_ PDESKTOP pDesk,
+    _In_ PTHREADINFO pti,
+    _In_ SIZE_T Size,
+    _Out_ PVOID* HandleOwner)
+{
+    PPROCMARKHEAD ObjHead;
+    PPROCESSINFO ppi = pti->ppi;
+
+    UNREFERENCED_PARAMETER(pDesk);
+
+    ASSERT(Size > sizeof(*ObjHead));
+
+    ObjHead = UserHeapAlloc(Size);
+    if (!ObjHead)
+        return NULL;
+
+    RtlZeroMemory(ObjHead, Size);
+
+    ObjHead->ppi = ppi;
+    IntReferenceProcessInfo(ppi);
+    *HandleOwner = ppi;
+    ppi->UserHandleCount++;
+
+    return ObjHead;
+}
+
+void FreeProcMarkObject(
+    _In_ PVOID Object)
+{
+    PPROCESSINFO ppi = ((PPROCMARKHEAD)Object)->ppi;
+
+    UserHeapFree(Object);
+
+    ppi->UserHandleCount--;
+    IntDereferenceProcessInfo(ppi);
+}
+
+_Success_(return!=NULL)
+static PVOID AllocSysObject(
+    _In_ PDESKTOP pDesk,
+    _In_ PTHREADINFO pti,
+    _In_ SIZE_T Size,
+    _Out_ PVOID* ObjectOwner)
+{
+    PVOID Object;
+
+    UNREFERENCED_PARAMETER(pDesk);
+    UNREFERENCED_PARAMETER(pti);
+
+    ASSERT(Size > sizeof(HEAD));
+
+    Object = UserHeapAlloc(Size);
+    if (!Object)
+        return NULL;
+
+    *ObjectOwner = NULL;
+
+    RtlZeroMemory(Object, Size);
+    return Object;
+}
+
+static void FreeSysObject(
+    _In_ PVOID Object)
+{
+    UserHeapFree(Object);
+}
+
+static const struct
+{
+    PVOID   (*ObjectAlloc)(PDESKTOP, PTHREADINFO, SIZE_T, PVOID*);
+    BOOLEAN (*ObjectDestroy)(PVOID);
+    void    (*ObjectFree)(PVOID);
+} ObjectCallbacks[TYPE_CTYPES] =
+{
+    { NULL,                     NULL,                       NULL },                 /* TYPE_FREE */
+    { AllocDeskThreadObject,    co_UserDestroyWindow,       FreeDeskThreadObject }, /* TYPE_WINDOW */
+    { AllocDeskProcObject,      UserDestroyMenuObject,      FreeDeskProcObject },   /* TYPE_MENU */
+    { AllocProcMarkObject,      IntDestroyCurIconObject,    FreeCurIconObject },    /* TYPE_CURSOR */
+    { AllocSysObject,           /*UserSetWindowPosCleanup*/NULL, FreeSysObject },   /* TYPE_SETWINDOWPOS */
+    { AllocDeskThreadObject,    IntRemoveHook,              FreeDeskThreadObject }, /* TYPE_HOOK */
+    { AllocSysObject,           /*UserClipDataCleanup*/NULL,FreeSysObject },        /* TYPE_CLIPDATA */
+    { AllocDeskProcObject,      DestroyCallProc,            FreeDeskProcObject },   /* TYPE_CALLPROC */
+    { AllocProcMarkObject,      UserDestroyAccelTable,      FreeProcMarkObject },   /* TYPE_ACCELTABLE */
+    { NULL,                     NULL,                       NULL },                 /* TYPE_DDEACCESS */
+    { NULL,                     NULL,                       NULL },                 /* TYPE_DDECONV */
+    { NULL,                     NULL,                       NULL },                 /* TYPE_DDEXACT */
+    { AllocSysObject,           /*UserMonitorCleanup*/NULL, FreeSysObject },        /* TYPE_MONITOR */
+    { AllocSysObject,           /*UserKbdLayoutCleanup*/NULL,FreeSysObject },       /* TYPE_KBDLAYOUT */
+    { AllocSysObject,           /*UserKbdFileCleanup*/NULL, FreeSysObject },        /* TYPE_KBDFILE */
+    { AllocThreadObject,        IntRemoveEvent,             FreeThreadObject },     /* TYPE_WINEVENTHOOK */
+    { AllocSysObject,           /*UserTimerCleanup*/NULL,   FreeSysObject },        /* TYPE_TIMER */
+    { NULL,                     NULL,                       NULL },                 /* TYPE_INPUTCONTEXT */
+    { NULL,                     NULL,                       NULL },                 /* TYPE_HIDDATA */
+    { NULL,                     NULL,                       NULL },                 /* TYPE_DEVICEINFO */
+    { NULL,                     NULL,                       NULL },                 /* TYPE_TOUCHINPUTINFO */
+    { NULL,                     NULL,                       NULL },                 /* TYPE_GESTUREINFOOBJ */
+};
+
+#if DBG
+
+void DbgUserDumpHandleTable(VOID)
+{
+    int HandleCounts[TYPE_CTYPES];
+    PPROCESSINFO ppiList;
+    int i;
+    PWCHAR TypeNames[] = {L"Free",L"Window",L"Menu", L"CursorIcon", L"SMWP", L"Hook", L"ClipBoardData", L"CallProc",
+                          L"Accel", L"DDEaccess", L"DDEconv", L"DDExact", L"Monitor", L"KBDlayout", L"KBDfile",
+                          L"Event", L"Timer", L"InputContext", L"HidData", L"DeviceInfo", L"TouchInput",L"GestureInfo"};
+
+    ERR("Total handles count: %lu\n", gpsi->cHandleEntries);
+
+    memset(HandleCounts, 0, sizeof(HandleCounts));
+
+    /* First of all count the number of handles per type */
+    ppiList = gppiList;
+    while (ppiList)
+    {
+        ERR("Process %s (%p) handles count: %d\n\t", ppiList->peProcess->ImageFileName, ppiList->peProcess->UniqueProcessId, ppiList->UserHandleCount);
+
+        for (i = 1 ;i < TYPE_CTYPES; i++)
+        {
+            HandleCounts[i] += ppiList->DbgHandleCount[i];
+
+            DbgPrint("%S: %lu, ", TypeNames[i], ppiList->DbgHandleCount[i]);
+            if (i % 6 == 0)
+                DbgPrint("\n\t");
+        }
+        DbgPrint("\n");
+
+        ppiList = ppiList->ppiNext;
+    }
+
+    /* Print total type counts */
+    ERR("Total handles of the running processes: \n\t");
+    for (i = 1 ;i < TYPE_CTYPES; i++)
+    {
+        DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
+        if (i % 6 == 0)
+            DbgPrint("\n\t");
+    }
+    DbgPrint("\n");
+
+    /* Now count the handle counts that are allocated from the handle table */
+    memset(HandleCounts, 0, sizeof(HandleCounts));
+    for (i = 0; i < gHandleTable->nb_handles; i++)
+         HandleCounts[gHandleTable->handles[i].type]++;
+
+    ERR("Total handles count allocated: \n\t");
+    for (i = 1 ;i < TYPE_CTYPES; i++)
+    {
+        DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
+        if (i % 6 == 0)
+            DbgPrint("\n\t");
+    }
+    DbgPrint("\n");
+}
+
+#endif
+
+PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
+{
+   unsigned short generation;
+   int index = (((unsigned int)handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
+   if (index < 0 || index >= ht->nb_handles)
+      return NULL;
+   if (!ht->handles[index].type)
+      return NULL;
+   generation = (unsigned int)handle >> 16;
+   if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
+      return &ht->handles[index];
+   return NULL;
+}
+
+__inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
+{
+   int index = ptr - ht->handles;
+   return (HANDLE)(((index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
+}
+
+__inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
+{
+   PUSER_HANDLE_ENTRY entry;
+   TRACE("handles used %lu\n", gpsi->cHandleEntries);
+
+   if (ht->freelist)
+   {
+      entry = ht->freelist;
+      ht->freelist = entry->ptr;
+
+      gpsi->cHandleEntries++;
+      return entry;
+   }
+
+   if (ht->nb_handles >= ht->allocated_handles)  /* Need to grow the array */
+   {
+       ERR("Out of user handles! Used -> %lu, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
+
+#if DBG
+       DbgUserDumpHandleTable();
+#endif
+
+      return NULL;
+#if 0
+      PUSER_HANDLE_ENTRY new_handles;
+      /* Grow array by 50% (but at minimum 32 entries) */
+      int growth = max( 32, ht->allocated_handles / 2 );
+      int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
+      if (new_size <= ht->allocated_handles)
+         return NULL;
+      if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
+         return NULL;
+      ht->handles = new_handles;
+      ht->allocated_handles = new_size;
+#endif
+   }
+
+   entry = &ht->handles[ht->nb_handles++];
+
+   entry->generation = 1;
+
+   gpsi->cHandleEntries++;
+
+   return entry;
+}
+
+VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
+{
+   ht->freelist = NULL;
+   ht->handles = mem;
+
+   ht->nb_handles = 0;
+   ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
+}
+
+
+__inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
+{
+   void *ret;
+
+#if DBG
+   {
+       PPROCESSINFO ppi;
+       switch (entry->type)
+       {
+           case TYPE_WINDOW:
+           case TYPE_HOOK:
+           case TYPE_WINEVENTHOOK:
+               ppi = ((PTHREADINFO)entry->pi)->ppi;
+               break;
+           case TYPE_MENU:
+           case TYPE_CURSOR:
+           case TYPE_CALLPROC:
+           case TYPE_ACCELTABLE:
+               ppi = entry->pi;
+               break;
+           default:
+               ppi = NULL;
+       }
+       if (ppi)
+           ppi->DbgHandleCount[entry->type]--;
+   }
+#endif
+
+   ret = entry->ptr;
+   entry->ptr  = ht->freelist;
+   entry->type = 0;
+   entry->flags = 0;
+   entry->pi = NULL;
+   ht->freelist  = entry;
+
+   gpsi->cHandleEntries--;
+
+   return ret;
+}
+
+/* allocate a user handle for a given object */
+HANDLE UserAllocHandle(
+    _Inout_ PUSER_HANDLE_TABLE ht,
+    _In_ PVOID object,
+    _In_ HANDLE_TYPE type,
+    _In_ PVOID HandleOwner)
+{
+   PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
+   if (!entry)
+      return 0;
+   entry->ptr  = object;
+   entry->type = type;
+   entry->flags = 0;
+   entry->pi = HandleOwner;
+   if (++entry->generation >= 0xffff)
+      entry->generation = 1;
+
+   /* We have created a handle, which is a reference! */
+   UserReferenceObject(object);
+
+   return entry_to_handle(ht, entry );
+}
+
+/* return a pointer to a user object from its handle without setting an error */
+PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type )
+{
+   PUSER_HANDLE_ENTRY entry;
+
+   ASSERT(ht);
+
+   if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
+   {
+      return NULL;
+   }
+   return entry->ptr;
+}
+
+/* return a pointer to a user object from its handle */
+PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type )
+{
+   PUSER_HANDLE_ENTRY entry;
+
+   ASSERT(ht);
+
+   if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
+   {
+      EngSetLastError(ERROR_INVALID_HANDLE);
+      return NULL;
+   }
+   return entry->ptr;
+}
+
+
+/* Get the full handle (32bit) for a possibly truncated (16bit) handle */
+HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht,  HANDLE handle )
+{
+   PUSER_HANDLE_ENTRY entry;
+
+   if ((unsigned int)handle >> 16)
+      return handle;
+   if (!(entry = handle_to_entry(ht, handle )))
+      return handle;
+   return entry_to_handle( ht, entry );
+}
+
+
+/* Same as get_user_object plus set the handle to the full 32-bit value */
+void *get_user_object_handle(PUSER_HANDLE_TABLE ht,  HANDLE* handle, HANDLE_TYPE type )
+{
+   PUSER_HANDLE_ENTRY entry;
+
+   if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
+      return NULL;
+   *handle = entry_to_handle( ht, entry );
+   return entry->ptr;
+}
+
+
+
+BOOL FASTCALL UserCreateHandleTable(VOID)
+{
+   PVOID mem;
+   INT HandleCount = 1024 * 4;
+
+   // FIXME: Don't alloc all at once! Must be mapped into umode also...
+   mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * HandleCount);
+   if (!mem)
+   {
+      ERR("Failed creating handle table\n");
+      return FALSE;
+   }
+
+   gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
+   if (gHandleTable == NULL)
+   {
+       UserHeapFree(mem);
+       ERR("Failed creating handle table\n");
+       return FALSE;
+   }
+
+   // FIXME: Make auto growable
+   UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * HandleCount);
+
+   return TRUE;
+}
+
+//
+// New
+//
+PVOID
+FASTCALL
+UserCreateObject( PUSER_HANDLE_TABLE ht,
+                  PDESKTOP pDesktop,
+                  PTHREADINFO pti,
+                  HANDLE* h,
+                  HANDLE_TYPE type,
+                  ULONG size)
+{
+   HANDLE hi;
+   PVOID Object;
+   PVOID ObjectOwner;
+
+   /* Some sanity checks. Other checks will be made in the allocator */
+   ASSERT(type < TYPE_CTYPES);
+   ASSERT(type != TYPE_FREE);
+   ASSERT(ht != NULL);
+
+   /* Allocate the object */
+   ASSERT(ObjectCallbacks[type].ObjectAlloc != NULL);
+   Object = ObjectCallbacks[type].ObjectAlloc(pDesktop, pti, size, &ObjectOwner);
+   if (!Object)
+   {
+       ERR("User object allocation failed. Out of memory!\n");
+       return NULL;
+   }
+
+   hi = UserAllocHandle(ht, Object, type, ObjectOwner);
+   if (hi == NULL)
+   {
+       ERR("Out of user handles!\n");
+       ObjectCallbacks[type].ObjectFree(Object);
+       return NULL;
+   }
+
+#if DBG
+   if (pti)
+       pti->ppi->DbgHandleCount[type]++;
+#endif
+
+   /* Give this object its identity. */
+   ((PHEAD)Object)->h = hi;
+
+   /* The caller will get a locked object.
+    * Note: with the reference from the handle, that makes two */
+   UserReferenceObject(Object);
+
+   if (h)
+      *h = hi;
+   return Object;
+}
+
+BOOL
+FASTCALL
+UserMarkObjectDestroy(PVOID Object)
+{
+    PUSER_HANDLE_ENTRY entry;
+    PHEAD ObjHead = Object;
+
+    entry = handle_to_entry(gHandleTable, ObjHead->h);
+
+    ASSERT(entry != NULL);
+
+    entry->flags |= HANDLEENTRY_DESTROY;
+
+    if (ObjHead->cLockObj > 1)
+    {
+        entry->flags &= ~HANDLEENTRY_INDESTROY;
+        TRACE("Count %d\n",ObjHead->cLockObj);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+BOOL
+FASTCALL
+UserDereferenceObject(PVOID Object)
+{
+    PHEAD ObjHead = Object;
+
+    ASSERT(ObjHead->cLockObj >= 1);
+    ASSERT(ObjHead->cLockObj < 0x10000);
+
+    if (--ObjHead->cLockObj == 0)
+    {
+        PUSER_HANDLE_ENTRY entry;
+        HANDLE_TYPE type;
+
+        entry = handle_to_entry(gHandleTable, ObjHead->h);
+
+        ASSERT(entry != NULL);
+        /* The entry should be marked as in deletion */
+        ASSERT(entry->flags & HANDLEENTRY_INDESTROY);
+
+        type = entry->type;
+        ASSERT(type != TYPE_FREE);
+        ASSERT(type < TYPE_CTYPES);
+
+        /* We can now get rid of everything */
+        free_user_entry(gHandleTable, entry );
+
+#if 0
+        /* Call the object destructor */
+        ASSERT(ObjectCallbacks[type].ObjectCleanup != NULL);
+        ObjectCallbacks[type].ObjectCleanup(Object);
+#endif
+
+        /* And free it */
+        ASSERT(ObjectCallbacks[type].ObjectFree != NULL);
+        ObjectCallbacks[type].ObjectFree(Object);
+
+        return TRUE;
+    }
+    return FALSE;
+}
+
+BOOL
+FASTCALL
+UserFreeHandle(PUSER_HANDLE_TABLE ht,  HANDLE handle )
+{
+  PUSER_HANDLE_ENTRY entry;
+
+  if (!(entry = handle_to_entry( ht, handle )))
+  {
+     SetLastNtError( STATUS_INVALID_HANDLE );
+     return FALSE;
+  }
+
+  entry->flags = HANDLEENTRY_INDESTROY;
+
+  return UserDereferenceObject(entry->ptr);
+}
+
+BOOL
+FASTCALL
+UserObjectInDestroy(HANDLE h)
+{
+  PUSER_HANDLE_ENTRY entry;
+
+  if (!(entry = handle_to_entry( gHandleTable, h )))
+  {
+     SetLastNtError( STATUS_INVALID_HANDLE );
+     return TRUE;
+  }
+  return (entry->flags & HANDLEENTRY_INDESTROY);
+}
+
+BOOL
+FASTCALL
+UserDeleteObject(HANDLE h, HANDLE_TYPE type )
+{
+   PVOID body = UserGetObject(gHandleTable, h, type);
+
+   if (!body) return FALSE;
+
+   ASSERT( ((PHEAD)body)->cLockObj >= 1);
+   ASSERT( ((PHEAD)body)->cLockObj < 0x10000);
+
+   return UserFreeHandle(gHandleTable, h);
+}
+
+VOID
+FASTCALL
+UserReferenceObject(PVOID obj)
+{
+   PHEAD ObjHead = obj;
+   ASSERT(ObjHead->cLockObj < 0x10000);
+
+   ObjHead->cLockObj++;
+}
+
+PVOID
+FASTCALL
+UserReferenceObjectByHandle(HANDLE handle, HANDLE_TYPE type)
+{
+    PVOID object;
+
+    object = UserGetObject(gHandleTable, handle, type);
+    if (object)
+    {
+       UserReferenceObject(object);
+    }
+    return object;
+}
+
+BOOLEAN
+UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner)
+{
+    int i;
+    PUSER_HANDLE_ENTRY Entry;
+    BOOLEAN Ret = TRUE;
+
+    /* Sweep the whole handle table */
+    for (i = 0; i < Table->allocated_handles; i++)
+    {
+        Entry = &Table->handles[i];
+
+        if (Entry->pi != Owner)
+            continue;
+
+        /* Do not destroy if it's already been done */
+        if (Entry->flags & HANDLEENTRY_INDESTROY)
+            continue;
+
+        /* Call destructor */
+        if (!ObjectCallbacks[Entry->type].ObjectDestroy(Entry->ptr))
+        {
+            ERR("Failed destructing object %p, type %u.\n", Entry->ptr, Entry->type);
+            /* Don't return immediately, we must continue destroying the other objects */
+            Ret = FALSE;
+        }
+    }
+
+    return Ret;
+}
+
+/*
+ *
+ * Status
+ *    @implemented
+ */
+
+BOOL
+APIENTRY
+NtUserValidateHandleSecure(
+   HANDLE handle)
+{
+   UINT uType;
+   PPROCESSINFO ppi;
+   PUSER_HANDLE_ENTRY entry;
+
+   DECLARE_RETURN(BOOL);
+   UserEnterExclusive();
+
+   if (!(entry = handle_to_entry(gHandleTable, handle )))
+   {
+      EngSetLastError(ERROR_INVALID_HANDLE);
+      RETURN( FALSE);
+   }
+   uType = entry->type;
+   switch (uType)
+   {
+       case TYPE_WINDOW:
+       case TYPE_INPUTCONTEXT:
+          ppi = ((PTHREADINFO)entry->pi)->ppi;
+          break;
+       case TYPE_MENU:
+       case TYPE_ACCELTABLE:
+       case TYPE_CURSOR:
+       case TYPE_HOOK:
+       case TYPE_CALLPROC:
+       case TYPE_SETWINDOWPOS:
+          ppi = entry->pi;
+          break;
+       default:
+          ppi = NULL;
+          break;
+   }
+
+   if (!ppi) RETURN( FALSE);
+
+   // Same process job returns TRUE.
+   if (gptiCurrent->ppi->pW32Job == ppi->pW32Job) RETURN( TRUE);
+
+   RETURN( FALSE);
+
+CLEANUP:
+   UserLeave();
+   END_CLEANUP;
+}