[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / main / dllmain.c
index 42efcf9..21b1802 100644 (file)
@@ -89,8 +89,6 @@ Win32kProcessCallback(struct _EPROCESS *Process,
         Win32Process->HeapMappings.UserMapping = UserBase;
         Win32Process->HeapMappings.Count = 1;
 
-        InitializeListHead(&Win32Process->ClassList);
-
         InitializeListHead(&Win32Process->MenuListHead);
 
         InitializeListHead(&Win32Process->GDIBrushAttrFreeList);
@@ -103,27 +101,46 @@ Win32kProcessCallback(struct _EPROCESS *Process,
         ExInitializeFastMutex(&Win32Process->DriverObjListLock);
 
         Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout();
+        EngCreateEvent((PEVENT *)&Win32Process->InputIdleEvent);
+        KeInitializeEvent(Win32Process->InputIdleEvent, NotificationEvent, FALSE);
 
         if(Process->Peb != NULL)
         {
             /* map the gdi handle table to user land */
-            Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(GdiTableSection, Process);
+            Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process);
             Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT;
         }
 
         Win32Process->peProcess = Process;
         /* setup process flags */
         Win32Process->W32PF_flags = 0;
+
+        /* Create pools for GDI object attributes */
+        Win32Process->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG');
+        Win32Process->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG');
+        Win32Process->pPoolRgnAttr = GdiPoolCreate(sizeof(RGN_ATTR), 'agrG');
+        ASSERT(Win32Process->pPoolDcAttr);
+        ASSERT(Win32Process->pPoolBrushAttr);
+        ASSERT(Win32Process->pPoolRgnAttr);
     }
     else
     {
         DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
+        Win32Process->W32PF_flags |= W32PF_TERMINATED;
+
+        if (Win32Process->InputIdleEvent)
+        {
+           EngFreeMem((PVOID)Win32Process->InputIdleEvent);
+           Win32Process->InputIdleEvent = NULL;
+        }
+
         IntCleanupMenus(Process, Win32Process);
         IntCleanupCurIcons(Process, Win32Process);
         CleanupMonitorImpl();
 
         /* no process windows should exist at this point, or the function will assert! */
         DestroyProcessClasses(Win32Process);
+        Win32Process->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
 
         GDI_CleanupForProcess(Process);
 
@@ -136,6 +153,20 @@ Win32kProcessCallback(struct _EPROCESS *Process,
         {
             LogonProcess = NULL;
         }
+
+        /* Close the startup desktop */
+        ASSERT(Win32Process->rpdeskStartup);
+        ASSERT(Win32Process->hdeskStartup);
+        ObDereferenceObject(Win32Process->rpdeskStartup);
+        ZwClose(Win32Process->hdeskStartup);
+
+        /* Close the current window station */
+        UserSetProcessWindowStation(NULL);
+
+        /* Destroy GDI pools */
+        GdiPoolDestroy(Win32Process->pPoolDcAttr);
+        GdiPoolDestroy(Win32Process->pPoolBrushAttr);
+        GdiPoolDestroy(Win32Process->pPoolRgnAttr);
     }
 
     RETURN( STATUS_SUCCESS);
@@ -187,6 +218,7 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
         HDESK hDesk = NULL;
         NTSTATUS Status;
         PUNICODE_STRING DesktopPath;
+        PDESKTOP pdesk;
         PRTL_USER_PROCESS_PARAMETERS ProcessParams = (Process->Peb ? Process->Peb->ProcessParameters : NULL);
 
         DPRINT("Creating W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
@@ -199,103 +231,127 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
             InitializeListHead(&Win32Thread->aphkStart[i]);
         }
 
-        /*
-         * inherit the thread desktop and process window station (if not yet inherited) from the process startup
-         * info structure. See documentation of CreateProcess()
-         */
-        DesktopPath = (ProcessParams ? ((ProcessParams->DesktopInfo.Length > 0) ? &ProcessParams->DesktopInfo : NULL) : NULL);
-        Status = IntParseDesktopPath(Process,
-                                     DesktopPath,
-                                     &hWinSta,
-                                     &hDesk);
-        if(NT_SUCCESS(Status))
+        Win32Thread->TIF_flags &= ~TIF_INCLEANUP;
+        co_IntDestroyCaret(Win32Thread);
+        Win32Thread->ppi = PsGetCurrentProcessWin32Process();
+        Win32Thread->ptiSibling = Win32Thread->ppi->ptiList;
+        Win32Thread->ppi->ptiList = Win32Thread;
+        Win32Thread->ppi->cThreads++;
+        if (Win32Thread->rpdesk && !Win32Thread->pDeskInfo)
         {
-            if(hWinSta != NULL)
+           Win32Thread->pDeskInfo = Win32Thread->rpdesk->pDeskInfo;
+        }
+        Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
+        Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
+
+        /* HAAAAAAAACK! This should go to Win32kProcessCallback */
+        if(Win32Thread->ppi->hdeskStartup == NULL)
+        {
+            /*
+             * inherit the thread desktop and process window station (if not yet inherited) from the process startup
+             * info structure. See documentation of CreateProcess()
+             */
+            DesktopPath = (ProcessParams ? ((ProcessParams->DesktopInfo.Length > 0) ? &ProcessParams->DesktopInfo : NULL) : NULL);
+            Status = IntParseDesktopPath(Process,
+                                         DesktopPath,
+                                         &hWinSta,
+                                         &hDesk);
+            if(NT_SUCCESS(Status))
             {
-                if(Process != CsrProcess)
+                if(hWinSta != NULL)
                 {
-                    HWINSTA hProcessWinSta = (HWINSTA)InterlockedCompareExchangePointer((PVOID)&Process->Win32WindowStation, (PVOID)hWinSta, NULL);
-                    if(hProcessWinSta != NULL)
+                    if(!UserSetProcessWindowStation(hWinSta))
                     {
-                        /* our process is already assigned to a different window station, we don't need the handle anymore */
-                        NtClose(hWinSta);
+                        DPRINT1("Failed to set process window station\n");
                     }
                 }
-                else
-                {
-                    NtClose(hWinSta);
-                }
-            }
 
-            if (hDesk != NULL)
-            {
-                PDESKTOP DesktopObject;
-                Win32Thread->rpdesk = NULL;
-                Status = ObReferenceObjectByHandle(hDesk,
-                                                   0,
-                                                   ExDesktopObjectType,
-                                                   KernelMode,
-                                                   (PVOID*)&DesktopObject,
-                                                   NULL);
-                NtClose(hDesk);
-                if(NT_SUCCESS(Status))
+                if (hDesk != NULL)
                 {
-                    if (!IntSetThreadDesktop(DesktopObject,
-                                             FALSE))
+                    /* Validate the new desktop. */
+                    Status = IntValidateDesktopHandle(hDesk,
+                                                      UserMode,
+                                                      0,
+                                                      &pdesk);
+
+                    if(NT_SUCCESS(Status))
                     {
-                        DPRINT1("Unable to set thread desktop\n");
+                        Win32Thread->ppi->hdeskStartup = hDesk;
+                        Win32Thread->ppi->rpdeskStartup = pdesk;
                     }
                 }
-                else
-                {
-                    DPRINT1("Unable to reference thread desktop handle 0x%x\n", hDesk);
-                }
+            }
+            else
+            {
+               DPRINT1("No Desktop handle for this Thread!\n");
             }
         }
-        else
-        {
-           DPRINT1("No Desktop handle for this Thread!\n");
-        }
-        Win32Thread->TIF_flags &= ~TIF_INCLEANUP;
-        co_IntDestroyCaret(Win32Thread);
-        Win32Thread->ppi = PsGetCurrentProcessWin32Process();
-        if (Win32Thread->rpdesk && !Win32Thread->pDeskInfo)
+
+        if (Win32Thread->ppi->hdeskStartup != NULL)
         {
-           Win32Thread->pDeskInfo = Win32Thread->rpdesk->pDeskInfo;
+            if (!IntSetThreadDesktop(Win32Thread->ppi->hdeskStartup, FALSE))
+            {
+                DPRINT1("Unable to set thread desktop\n");
+            }
         }
-        Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
-        Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
+
         pTeb = NtCurrentTeb();
         if (pTeb)
         { /* Attempt to startup client support which should have been initialized in IntSetThreadDesktop. */
            PCLIENTINFO pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
            Win32Thread->pClientInfo = pci;
-           pci->pClientThreadInfo = NULL;
            pci->ppi = Win32Thread->ppi;
            pci->fsHooks = Win32Thread->fsHooks;
            if (Win32Thread->KeyboardLayout) pci->hKL = Win32Thread->KeyboardLayout->hkl;
            pci->dwTIFlags = Win32Thread->TIF_flags;
            /* CI may not have been initialized. */
-           if (!pci->pDeskInfo && Win32Thread->pDeskInfo) 
+           if (!pci->pDeskInfo && Win32Thread->pDeskInfo)
            {
               if (!pci->ulClientDelta) pci->ulClientDelta = DesktopHeapGetUserDelta();
 
               pci->pDeskInfo = (PVOID)((ULONG_PTR)Win32Thread->pDeskInfo - pci->ulClientDelta);
            }
+           if (Win32Thread->pcti && pci->pDeskInfo)
+              pci->pClientThreadInfo = (PVOID)((ULONG_PTR)Win32Thread->pcti - pci->ulClientDelta);
+           else
+              pci->pClientThreadInfo = NULL;
         }
         else
         {
            DPRINT1("No TEB for this Thread!\n");
+           // System thread running! Now SendMessage should be okay.
+           Win32Thread->pcti = &Win32Thread->cti;
         }
         Win32Thread->pEThread = Thread;
     }
     else
     {
+        PTHREADINFO pti;
         PSINGLE_LIST_ENTRY e;
 
         DPRINT("Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
 
         Win32Thread->TIF_flags |= TIF_INCLEANUP;
+        pti = Win32Thread->ppi->ptiList;
+        if (pti == Win32Thread)
+        {
+           Win32Thread->ppi->ptiList = Win32Thread->ptiSibling;
+           Win32Thread->ppi->cThreads--;
+        }
+        else
+        {
+           do
+           {
+               if (pti->ptiSibling == Win32Thread)
+               {
+                  pti->ptiSibling = Win32Thread->ptiSibling;
+                  Win32Thread->ppi->cThreads--;
+                  break;
+               }
+               pti = pti->ptiSibling;
+           }
+           while (pti);
+        }
         DceFreeThreadDCE(Win32Thread);
         HOOK_DestroyThreadHooks(Thread);
         EVENT_DestroyThreadEvents(Thread);
@@ -320,8 +376,7 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
             e = PopEntryList(&Win32Thread->ReferencesList);
         }
 
-        IntSetThreadDesktop(NULL,
-                            TRUE);
+        IntSetThreadDesktop(NULL, TRUE);
 
         PsSetThreadWin32Thread(Thread, NULL);
     }
@@ -420,10 +475,18 @@ DriverEntry(
     CalloutData.ProcessCallout = Win32kProcessCallback;
     CalloutData.ThreadCallout = Win32kThreadCallback;
     CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
+    CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
+    CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
 
     /* Register our per-process and per-thread structures. */
     PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
 
+#if DBG_ENABLE_SERVICE_HOOKS
+    /* Register service hook callbacks */
+    KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
+    KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
+#endif
+
     /* Create the global USER heap */
     GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
                                     &GlobalUserHeapBase,