[Win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / object.c
index 5ea4c1e..4df5c8f 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 
 
 /* INCLUDES ******************************************************************/
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
 
-int usedHandles=0;
+//int usedHandles=0;
 PUSER_HANDLE_TABLE gHandleTable = NULL;
 
 
@@ -55,20 +55,63 @@ __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
 {
    PUSER_HANDLE_ENTRY entry;
 
-   DPRINT("handles used %i\n",usedHandles);
+   DPRINT("handles used %i\n",gpsi->cHandleEntries);
 
    if (ht->freelist)
    {
       entry = ht->freelist;
       ht->freelist = entry->ptr;
 
-      usedHandles++;
+      gpsi->cHandleEntries++;
       return entry;
    }
 
    if (ht->nb_handles >= ht->allocated_handles)  /* need to grow the array */
    {
-      DPRINT1("Out of user handles!\n");
+/**/
+      int i, iFree = 0, iWindow = 0, iMenu = 0, iCursorIcon = 0,
+          iHook = 0, iCallProc = 0, iAccel = 0, iMonitor = 0, iTimer = 0;
+ /**/
+      DPRINT1("Out of user handles! Used -> %i, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
+//#if 0
+      for(i = 0; i < ht->nb_handles; i++)
+      {
+         switch (ht->handles[i].type)
+         {
+           case otFree: // Should be zero.
+            iFree++;
+            break;
+           case otWindow:
+            iWindow++;
+            break;
+           case otMenu:
+            iMenu++;
+            break;
+           case otCursorIcon:
+            iCursorIcon++;
+            break;
+           case otHook:
+            iHook++;
+            break;
+           case otCallProc:
+            iCallProc++;
+            break;
+           case otAccel:
+            iAccel++;
+            break;
+           case otMonitor:
+            iMonitor++;
+            break;
+           case otTimer:
+            iTimer++;
+            break;
+           default:
+            break;
+         }
+      }
+      DPRINT1("Handle Count by Type:\n Free = %d Window = %d Menu = %d CursorIcon = %d Hook = %d\n CallProc = %d Accel = %d Monitor = %d Timer = %d\n",
+      iFree, iWindow, iMenu, iCursorIcon, iHook, iCallProc, iAccel, iMonitor, iTimer );
+//#endif
       return NULL;
 #if 0
       PUSER_HANDLE_ENTRY new_handles;
@@ -88,7 +131,7 @@ __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
 
    entry->generation = 1;
 
-   usedHandles++;
+   gpsi->cHandleEntries++;
 
    return entry;
 }
@@ -108,14 +151,48 @@ __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY
    ret = entry->ptr;
    entry->ptr  = ht->freelist;
    entry->type = 0;
-   entry->pti = 0;
+   entry->flags = 0;
+   entry->pi = NULL;
    ht->freelist  = entry;
 
-   usedHandles--;
+   gpsi->cHandleEntries--;
 
    return ret;
 }
 
+static __inline PVOID
+UserHandleOwnerByType(USER_OBJECT_TYPE type)
+{
+    PVOID pi;
+
+    switch (type)
+    {
+        case otWindow:
+        case otInputContext:
+            pi = GetW32ThreadInfo();
+            break;
+
+        case otMenu:
+        case otCursorIcon:
+        case otHook:
+        case otCallProc:
+        case otAccel:
+        case otSMWP:
+            pi = GetW32ProcessInfo();
+            break;
+
+        case otMonitor:
+            pi = NULL; /* System */
+            break;
+
+        default:
+            pi = NULL;
+            break;
+    }
+
+    return pi;
+}
+
 /* allocate a user handle for a given object */
 HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE type )
 {
@@ -124,10 +201,14 @@ HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE typ
       return 0;
    entry->ptr  = object;
    entry->type = type;
-   entry->pti = GetW32ThreadInfo();
-   if (entry->pti->pi->UserHandleTable == NULL) GetW32ProcessInfo();
+   entry->flags = 0;
+   entry->pi = UserHandleOwnerByType(type);
    if (++entry->generation >= 0xffff)
       entry->generation = 1;
+
+   /* We have created a handle, which is a reference! */
+   UserReferenceObject(object);
+
    return entry_to_handle(ht, entry );
 }
 
@@ -140,7 +221,7 @@ PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type
 
    if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
    {
-      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      EngSetLastError(ERROR_INVALID_HANDLE);
       return NULL;
    }
    return entry->ptr;
@@ -171,20 +252,6 @@ void *get_user_object_handle(PUSER_HANDLE_TABLE ht,  HANDLE* handle, USER_OBJECT
    return entry->ptr;
 }
 
-/* free a user handle and return a pointer to the object */
-PVOID UserFreeHandle(PUSER_HANDLE_TABLE ht,  HANDLE handle )
-{
-   PUSER_HANDLE_ENTRY entry;
-
-   if (!(entry = handle_to_entry( ht, handle )))
-   {
-      SetLastNtError( STATUS_INVALID_HANDLE );
-      return NULL;
-   }
-
-   return free_user_entry(ht, entry );
-}
-
 /* return the next user handle after 'handle' that is of a given type */
 PVOID UserGetNextHandle(PUSER_HANDLE_TABLE ht, HANDLE* handle, USER_OBJECT_TYPE type )
 {
@@ -211,133 +278,210 @@ PVOID UserGetNextHandle(PUSER_HANDLE_TABLE ht, HANDLE* handle, USER_OBJECT_TYPE
    return NULL;
 }
 
-
-
-PVOID FASTCALL
-ObmCreateObject(PUSER_HANDLE_TABLE ht, HANDLE* h,USER_OBJECT_TYPE type , ULONG size)
+BOOL FASTCALL UserCreateHandleTable(VOID)
 {
 
-   HANDLE hi;
-   PUSER_OBJECT_HEADER hdr = UserHeapAlloc(size + sizeof(USER_OBJECT_HEADER));//ExAllocatePool(PagedPool, size + sizeof(USER_OBJECT_HEADER));
-   if (!hdr)
-      return NULL;
+   PVOID mem;
 
+   //FIXME: dont alloc all at once! must be mapped into umode also...
+   mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * 1024*2);
+   if (!mem)
+   {
+      DPRINT1("Failed creating handle table\n");
+      return FALSE;
+   }
 
-   hi = UserAllocHandle(ht, USER_HEADER_TO_BODY(hdr), type );
-   if (!hi)
+   gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
+   if (gHandleTable == NULL)
    {
-      //ExFreePool(hdr);
-       UserHeapFree(hdr);
-      return NULL;
+       UserHeapFree(mem);
+       DPRINT1("Failed creating handle table\n");
+       return FALSE;
    }
 
-   RtlZeroMemory(hdr, size + sizeof(USER_OBJECT_HEADER));
-   hdr->hSelf = hi;
-   hdr->RefCount++; //temp hack!
+   //FIXME: make auto growable
+   UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * 1024*2);
 
-   if (h)
-      *h = hi;
-   return USER_HEADER_TO_BODY(hdr);
+   return TRUE;
 }
 
-BOOL FASTCALL
-ObmDeleteObject(HANDLE h, USER_OBJECT_TYPE type )
+//
+// New
+//
+PVOID
+FASTCALL
+UserCreateObject( PUSER_HANDLE_TABLE ht,
+                  PDESKTOP pDesktop,
+                  HANDLE* h,
+                  USER_OBJECT_TYPE type,
+                  ULONG size)
 {
-   PUSER_OBJECT_HEADER hdr;
-   PVOID body = UserGetObject(gHandleTable, h, type);
-   if (!body)
-      return FALSE;
+   HANDLE hi;
+   PVOID Object;
+   PTHREADINFO pti;
+   PPROCESSINFO ppi;
+   BOOL dt;
+   PDESKTOP rpdesk = pDesktop;
 
-   hdr = USER_BODY_TO_HEADER(body);
-   ASSERT(hdr->RefCount >= 0);
+   pti = GetW32ThreadInfo();
+   ppi = pti->ppi;
+   if (!pDesktop) rpdesk = pti->rpdesk;
 
-   hdr->destroyed = TRUE;
-   if (hdr->RefCount == 0)
+   switch (type)
    {
-      UserFreeHandle(gHandleTable, h);
-
-      memset(hdr, 0x55, sizeof(USER_OBJECT_HEADER));
-
-      UserHeapFree(hdr);
-      //ExFreePool(hdr);
-      return TRUE;
+      case otWindow:
+//      case otMenu:
+      case otHook:
+      case otCallProc:
+      case otInputContext:
+         Object = DesktopHeapAlloc(rpdesk, size);
+         dt = TRUE;
+         break;
+
+      default:
+         Object = UserHeapAlloc(size);
+         dt = FALSE;
+         break;
    }
 
-//   DPRINT1("info: something not destroyed bcause refs still left, inuse %i\n",usedHandles);
-   return FALSE;
-}
+   if (!Object)
+      return NULL;
 
 
-VOID FASTCALL ObmReferenceObject(PVOID obj)
-{
-   PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
+   hi = UserAllocHandle(ht, Object, type );
+   if (!hi)
+   {
+      if (dt)
+         DesktopHeapFree(rpdesk, Object);
+      else
+         UserHeapFree(Object);
+      return NULL;
+   }
 
-   ASSERT(hdr->RefCount >= 0);
+   RtlZeroMemory(Object, size);
 
-   hdr->RefCount++;
-}
+   switch (type)
+   {
+        case otWindow:
+        case otHook:
+        case otInputContext:
+            ((PTHRDESKHEAD)Object)->rpdesk = rpdesk;
+            ((PTHRDESKHEAD)Object)->pSelf = Object;
+        case otEvent:
+            ((PTHROBJHEAD)Object)->pti = pti;
+            break;
+
+        case otMenu:
+        case otCallProc:
+            ((PPROCDESKHEAD)Object)->rpdesk = rpdesk;
+            ((PPROCDESKHEAD)Object)->pSelf = Object;            
+            break;
+
+        case otCursorIcon:
+            ((PPROCMARKHEAD)Object)->ppi = ppi;
+            break;
+
+        default:
+            break;
+   }
+   /* Now set default headers. */
+   ((PHEAD)Object)->h = hi;
+   ((PHEAD)Object)->cLockObj = 2; // we need this, because we create 2 refs: handle and pointer!
 
-HANDLE FASTCALL ObmObjectToHandle(PVOID obj)
-{
-    PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
-    return hdr->hSelf;
+   if (h)
+      *h = hi;
+   return Object;
 }
 
 
-BOOL FASTCALL ObmDereferenceObject2(PVOID obj)
+BOOL
+FASTCALL
+UserDereferenceObject(PVOID object)
 {
-   PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
+  PUSER_HANDLE_ENTRY entry;
+  USER_OBJECT_TYPE type;
 
-   ASSERT(hdr->RefCount >= 1);
+  ASSERT(((PHEAD)object)->cLockObj >= 1);
 
-   hdr->RefCount--;
+  if ((INT)--((PHEAD)object)->cLockObj <= 0)
+  {
+     entry = handle_to_entry(gHandleTable, ((PHEAD)object)->h );
 
-   // You can not have a zero here!
-   if (!hdr->destroyed && hdr->RefCount == 0) hdr->RefCount++; // BOUNCE!!!!!
+     DPRINT("warning! Dereference to zero! Obj -> 0x%x\n", object);
 
-   if (hdr->RefCount == 0 && hdr->destroyed)
-   {
-//      DPRINT1("info: something destroyed bcaise of deref, in use=%i\n",usedHandles);
-
-      UserFreeHandle(gHandleTable, hdr->hSelf);
+     ((PHEAD)object)->cLockObj = 0;
 
-      memset(hdr, 0x55, sizeof(USER_OBJECT_HEADER));
+     if (!(entry->flags & HANDLEENTRY_INDESTROY))
+        return TRUE;
 
-      UserHeapFree(hdr);
-      //ExFreePool(hdr);
+     type = entry->type;
+     free_user_entry(gHandleTable, entry );
 
-      return TRUE;
-   }
+     switch (type)
+     {
+        case otWindow:
+//        case otMenu:
+        case otHook:
+        case otCallProc:
+        case otInputContext:
+           return DesktopHeapFree(((PTHRDESKHEAD)object)->rpdesk, object);
 
-   return FALSE;
+        default:
+           return UserHeapFree(object);
+     }
+  }
+  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;
 
-BOOL FASTCALL ObmCreateHandleTable()
+  return UserDereferenceObject(entry->ptr);
+}
+
+BOOL
+FASTCALL
+UserDeleteObject(HANDLE h, USER_OBJECT_TYPE type )
 {
+   PVOID body = UserGetObject(gHandleTable, h, type);
+   
+   if (!body) return FALSE;
 
-   PVOID mem;
+   ASSERT( ((PHEAD)body)->cLockObj >= 1);
 
-   //FIXME: dont alloc all at once! must be mapped into umode also...
-   //mem = ExAllocatePool(PagedPool, sizeof(USER_HANDLE_ENTRY) * 1024*2);
-   mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * 1024*2);
-   if (!mem)
-   {
-      DPRINT1("Failed creating handle table\n");
-      return FALSE;
-   }
+   return UserFreeHandle(gHandleTable, h);
+}
 
-   gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
-   if (gHandleTable == NULL)
-   {
-       UserHeapFree(mem);
-       DPRINT1("Failed creating handle table\n");
-       return FALSE;
-   }
+VOID
+FASTCALL
+UserReferenceObject(PVOID obj)
+{
+   ASSERT(((PHEAD)obj)->cLockObj >= 0);
 
-   //FIXME: make auto growable
-   UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * 1024*2);
+   ((PHEAD)obj)->cLockObj++;
+}
 
-   return TRUE;
+PVOID
+FASTCALL
+UserReferenceObjectByHandle(HANDLE handle, USER_OBJECT_TYPE type)
+{
+    PVOID object;
+
+    object = UserGetObject(gHandleTable, handle, type);
+    if (object)
+    {
+       UserReferenceObject(object);
+    }
+    return object;
 }