- Add flags for NtCreateProcessEx for upcoming patch.
[reactos.git] / reactos / subsys / win32k / main / dllmain.c
index 71e8a49..94eb7a8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ReactOS W32 Subsystem
- *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 ReactOS Team
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: dllmain.c,v 1.56 2003/12/03 21:50:50 gvg Exp $
+/* $Id$
  *
  *  Entry Point for win32k.sys
  */
 
-#undef WIN32_LEAN_AND_MEAN
-#define WIN32_NO_STATUS
-#include <windows.h>
-#define NTOS_MODE_KERNEL
-#include <ntos.h>
-#include <ddk/winddi.h>
-
-#include <win32k/win32k.h>
-
-#include <include/winsta.h>
-#include <include/class.h>
-#include <include/window.h>
-#include <include/menu.h>
-#include <include/object.h>
-#include <include/input.h>
-#include <include/timer.h>
-#include <include/text.h>
-#include <include/caret.h>
-#include <include/hotkey.h>
-#include <include/guicheck.h>
+#include <w32k.h>
+#include <win32k/ntddraw.h>
+#include <include/napi.h>
 
 #define NDEBUG
-#include <win32k/debug1.h>
+#include <debug.h>
 
-extern SSDT Win32kSSDT[];
-extern SSPT Win32kSSPT[];
+BOOL INTERNAL_CALL GDI_CleanupForProcess (struct _EPROCESS *Process);
+
+extern ULONG_PTR Win32kSSDT[];
+extern UCHAR Win32kSSPT[];
 extern ULONG Win32kNumberOfSysCalls;
 
-NTSTATUS STDCALL
-Win32kProcessCallback (struct _EPROCESS *Process,
-                    BOOLEAN Create)
+PSHARED_SECTION_POOL SessionSharedSectionPool = NULL;
+
+NTSTATUS 
+STDCALL
+Win32kProcessCallback(struct _EPROCESS *Process,
+                      BOOLEAN Create)
 {
-  PW32PROCESS Win32Process;
-  NTSTATUS Status;
+    PW32PROCESS Win32Process;
+    DECLARE_RETURN(NTSTATUS);
+    
+    DPRINT("Enter Win32kProcessCallback\n");
+    UserEnterExclusive();
+    
+    /* Get the Win32 Process */
+    Win32Process = PsGetProcessWin32Process(Process);
+    
+    /* Allocate one if needed */
+    if (!Win32Process)
+    {
+        /* FIXME - lock the process */
+        Win32Process = ExAllocatePoolWithTag(NonPagedPool,
+                                             sizeof(W32PROCESS),
+                                             TAG('W', '3', '2', 'p'));
 
-#if 0
-  DbgPrint ("Win32kProcessCallback() called\n");
-#endif
+        if (Win32Process == NULL) RETURN( STATUS_NO_MEMORY);
+
+        RtlZeroMemory(Win32Process, sizeof(W32PROCESS));
+        
+        PsSetProcessWin32Process(Process, Win32Process);
+        /* FIXME - unlock the process */
+    }
 
-  Win32Process = Process->Win32Process;
   if (Create)
     {
-#if 0
-      DbgPrint ("  Create process\n");
-#endif
+      DPRINT("Creating W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
+
+      InitializeListHead(&Win32Process->ClassList);
 
-      InitializeListHead(&Win32Process->ClassListHead);
-      ExInitializeFastMutex(&Win32Process->ClassListLock);
-      
       InitializeListHead(&Win32Process->MenuListHead);
-      ExInitializeFastMutex(&Win32Process->MenuListLock);      
+
+      InitializeListHead(&Win32Process->PrivateFontListHead);
+      ExInitializeFastMutex(&Win32Process->PrivateFontListLock);
+
+      InitializeListHead(&Win32Process->DriverObjListHead);
+      ExInitializeFastMutex(&Win32Process->DriverObjListLock);
 
       Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout();
-      Win32Process->WindowStation = NULL;
-      if (Process->Win32WindowStation != NULL)
-       {
-         Status = 
-           IntValidateWindowStationHandle(Process->Win32WindowStation,
-                                          UserMode,
-                                          GENERIC_ALL,
-                                          &Win32Process->WindowStation);
-         if (!NT_SUCCESS(Status))
-           {
-             DbgPrint("Win32K: Failed to reference a window station for "
-                      "process.\n");
-           }
-       }
-
-      Win32Process->CreatedWindowOrDC = FALSE;
+
+      if(Process->Peb != NULL)
+      {
+        /* map the gdi handle table to user land */
+        Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process);
+      }
+
+      /* setup process flags */
+      Win32Process->Flags = 0;
     }
   else
     {
-#if 0
-      DbgPrint ("  Destroy process\n");
-      DbgPrint ("  IRQ level: %lu\n", KeGetCurrentIrql ());
-#endif
-         IntRemoveProcessWndProcHandles((HANDLE)Process->UniqueProcessId);
+      DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
+      IntRemoveProcessWndProcHandles((HANDLE)Process->UniqueProcessId);
       IntCleanupMenus(Process, Win32Process);
+      IntCleanupCurIcons(Process, Win32Process);
+      IntEngCleanupDriverObjs(Process, Win32Process);
+      CleanupMonitorImpl();
+      
+      /* no process windows should exist at this point, or the function will assert! */
+      DestroyProcessClasses(Win32Process);
 
-      CleanupForProcess(Process, Process->UniqueProcessId);
+      GDI_CleanupForProcess(Process);
 
-      IntGraphicsCheck(FALSE);
+      co_IntGraphicsCheck(FALSE);
+
+      /*
+       * Deregister logon application automatically
+       */
+      if(LogonProcess == Win32Process)
+      {
+        LogonProcess = NULL;
+      }
     }
 
-  return STATUS_SUCCESS;
+  RETURN( STATUS_SUCCESS);
+  
+CLEANUP:
+  UserLeave();
+  DPRINT("Leave Win32kProcessCallback, ret=%i\n",_ret_);
+  END_CLEANUP;
 }
 
 
-NTSTATUS STDCALL
-Win32kThreadCallback (struct _ETHREAD *Thread,
-                   BOOLEAN Create)
+NTSTATUS 
+STDCALL
+Win32kThreadCallback(struct _ETHREAD *Thread,
+                     BOOLEAN Create)
 {
-  struct _EPROCESS *Process;
-  PW32THREAD Win32Thread;
-  NTSTATUS Status;
+    struct _EPROCESS *Process;
+    PW32THREAD Win32Thread;
+    DECLARE_RETURN(NTSTATUS);
+    
+    DPRINT("Enter Win32kThreadCallback\n");
+    UserEnterExclusive();
+
+    Process = Thread->ThreadsProcess;
+    
+    /* Get the Win32 Thread */
+    Win32Thread = PsGetThreadWin32Thread(Thread);
+    
+    /* Allocate one if needed */
+    if (!Win32Thread)
+    {
+        /* FIXME - lock the process */
+        Win32Thread = ExAllocatePoolWithTag(NonPagedPool,
+                                            sizeof(W32THREAD),
+                                            TAG('W', '3', '2', 't'));
 
-#if 0
-  DbgPrint ("Win32kThreadCallback() called\n");
-#endif
+        if (Win32Thread == NULL) RETURN( STATUS_NO_MEMORY);
 
-  Process = Thread->ThreadsProcess;
-  Win32Thread = Thread->Win32Thread;
+        RtlZeroMemory(Win32Thread, sizeof(W32THREAD));
+        
+        PsSetThreadWin32Thread(Thread, Win32Thread);
+        /* FIXME - unlock the process */
+    }
   if (Create)
     {
-#if 0
-      DbgPrint ("  Create thread\n");
-#endif
-
-      IntDestroyCaret(Win32Thread);
+      HWINSTA hWinSta = NULL;
+      HDESK hDesk = NULL;
+      NTSTATUS Status;
+      PUNICODE_STRING DesktopPath;
+      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());
+
+      /*
+       * 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(hWinSta != NULL)
+        {
+          if(Process != CsrProcess)
+          {
+            HWINSTA hProcessWinSta = (HWINSTA)InterlockedCompareExchangePointer((PVOID)&Process->Win32WindowStation, (PVOID)hWinSta, NULL);
+            if(hProcessWinSta != NULL)
+            {
+              /* our process is already assigned to a different window station, we don't need the handle anymore */
+              NtClose(hWinSta);
+            }
+          }
+          else
+          {
+            NtClose(hWinSta);
+          }
+        }
+
+        if (hDesk != NULL)
+        {
+          Status = ObReferenceObjectByHandle(hDesk,
+                                             0,
+                                             ExDesktopObjectType,
+                                             KernelMode,
+                                             (PVOID*)&Win32Thread->Desktop,
+                                             NULL);
+          NtClose(hDesk);
+          if(!NT_SUCCESS(Status))
+          {
+            DPRINT1("Unable to reference thread desktop handle 0x%x\n", hDesk);
+            Win32Thread->Desktop = NULL;
+          }
+        }
+      }
+      Win32Thread->IsExiting = FALSE;
+      co_IntDestroyCaret(Win32Thread);
       Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
       Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
       Win32Thread->MessagePumpHookValue = 0;
       InitializeListHead(&Win32Thread->WindowListHead);
-      ExInitializeFastMutex(&Win32Thread->WindowListLock);
-
-      /* By default threads get assigned their process's desktop. */
-      Win32Thread->Desktop = NULL;
-      if (Process->Win32Desktop != NULL)
-       {
-         Status = ObReferenceObjectByHandle(Process->Win32Desktop,
-                                            GENERIC_ALL,
-                                            ExDesktopObjectType,
-                                            UserMode,
-                                            (PVOID*)&Win32Thread->Desktop,
-                                            NULL);
-         if (!NT_SUCCESS(Status))
-           {
-             DbgPrint("Win32K: Failed to reference a desktop for thread.\n");
-           }
-       }
+      InitializeListHead(&Win32Thread->W32CallbackListHead);
     }
   else
     {
-#if 0
-      DbgPrint ("  Destroy thread\n");
-#endif
+      PSINGLE_LIST_ENTRY e;
+      
+      DPRINT("Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
 
-      RemoveTimersThread(Thread->Cid.UniqueThread);
+      Win32Thread->IsExiting = TRUE;
+      HOOK_DestroyThreadHooks(Thread);
       UnregisterThreadHotKeys(Thread);
-      DestroyThreadWindows(Thread);
+      /* what if this co_ func crash in umode? what will clean us up then? */
+      co_DestroyThreadWindows(Thread);
+      IntBlockInput(Win32Thread, FALSE);
+      MsqDestroyMessageQueue(Win32Thread->MessageQueue);
+      IntCleanupThreadCallbacks(Win32Thread);
+      if(Win32Thread->Desktop != NULL)
+      {
+        ObDereferenceObject(Win32Thread->Desktop);
+      }
+      
+      /* cleanup user object references stack */
+      e = PopEntryList(&Win32Thread->ReferencesList);
+      while (e)
+      {
+         PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(e, USER_REFERENCE_ENTRY, Entry);
+         DPRINT1("thread clean: remove reference obj 0x%x\n",ref->obj);
+         ObmDereferenceObject(ref->obj);
+         
+         e = PopEntryList(&Win32Thread->ReferencesList);
+      }
+      PsSetThreadWin32Thread(Thread, NULL);
     }
 
-  return STATUS_SUCCESS;
+  RETURN( STATUS_SUCCESS);
+  
+CLEANUP:
+  UserLeave();
+  DPRINT("Leave Win32kThreadCallback, ret=%i\n",_ret_);
+  END_CLEANUP;
+}
+
+/* Only used in ntuser/input.c KeyboardThreadMain(). If it's
+   not called there anymore, please delete */
+NTSTATUS
+Win32kInitWin32Thread(PETHREAD Thread)
+{
+  PEPROCESS Process;
+
+  Process = Thread->ThreadsProcess;
+
+  if (Process->Win32Process == NULL)
+    {
+      /* FIXME - lock the process */
+      Process->Win32Process = ExAllocatePool(NonPagedPool, sizeof(W32PROCESS));
+
+      if (Process->Win32Process == NULL)
+       return STATUS_NO_MEMORY;
+
+      RtlZeroMemory(Process->Win32Process, sizeof(W32PROCESS));
+      /* FIXME - unlock the process */
+
+      Win32kProcessCallback(Process, TRUE);
+    }
+
+  if (Thread->Tcb.Win32Thread == NULL)
+    {
+      Thread->Tcb.Win32Thread = ExAllocatePool (NonPagedPool, sizeof(W32THREAD));
+      if (Thread->Tcb.Win32Thread == NULL)
+       return STATUS_NO_MEMORY;
+
+      RtlZeroMemory(Thread->Tcb.Win32Thread, sizeof(W32THREAD));
+
+      Win32kThreadCallback(Thread, TRUE);
+    }
+
+  return(STATUS_SUCCESS);
 }
 
 
 /*
  * This definition doesn't work
  */
-// WINBOOL STDCALL DllMain(VOID)
 NTSTATUS STDCALL
-DllMain (
+DriverEntry (
   IN   PDRIVER_OBJECT  DriverObject,
   IN   PUNICODE_STRING RegistryPath)
 {
   NTSTATUS Status;
   BOOLEAN Result;
-
-  IntInitializeWinLock();
+  W32_CALLOUT_DATA CalloutData;
 
   /*
    * Register user mode call interface
@@ -192,82 +320,129 @@ DllMain (
                                    1);
   if (Result == FALSE)
     {
-      DbgPrint("Adding system services failed!\n");
+      DPRINT1("Adding system services failed!\n");
       return STATUS_UNSUCCESSFUL;
     }
 
-  /*
-   * Register our per-process and per-thread structures.
-   */
-  PsEstablishWin32Callouts (Win32kProcessCallback,
-                           Win32kThreadCallback,
-                           0,
-                           0,
-                           sizeof(W32THREAD) + sizeof(THRDCARETINFO),
-                           sizeof(W32PROCESS));
+    /*
+     * Register Object Manager Callbacks
+     */
+    CalloutData.WinStaCreate = IntWinStaObjectOpen;
+    CalloutData.WinStaParse = IntWinStaObjectParse;
+    CalloutData.WinStaDelete = IntWinStaObjectDelete;
+    CalloutData.WinStaFind = IntWinStaObjectFind;
+    CalloutData.DesktopCreate = IntDesktopObjectCreate;
+    CalloutData.DesktopDelete = IntDesktopObjectDelete;
+    CalloutData.W32ProcessCallout = Win32kProcessCallback;
+    CalloutData.W32ThreadCallout = Win32kThreadCallback;
+    
+    /*
+     * Register our per-process and per-thread structures.
+     */
+    PsEstablishWin32Callouts(&CalloutData);
+
+  Status = IntUserCreateSharedSectionPool(48 * 1024 * 1024, /* 48 MB by default */
+                                          &SessionSharedSectionPool);
+  if (!NT_SUCCESS(Status))
+  {
+    DPRINT1("Failed to initialize the shared section pool: Status 0x%x\n", Status);
+  }
 
-  WinPosSetupInternalPos();
+  Status = InitUserImpl();
+  if (!NT_SUCCESS(Status))
+  {
+    DPRINT1("Failed to initialize user implementation!\n");
+    return STATUS_UNSUCCESSFUL;
+  }
+
+  Status = InitHotkeyImpl();
+  if (!NT_SUCCESS(Status))
+  {
+    DPRINT1("Failed to initialize hotkey implementation!\n");
+    return STATUS_UNSUCCESSFUL;
+  }
 
   Status = InitWindowStationImpl();
   if (!NT_SUCCESS(Status))
   {
-    DbgPrint("Failed to initialize window station implementation!\n");
+    DPRINT1("Failed to initialize window station implementation!\n");
     return STATUS_UNSUCCESSFUL;
   }
 
   Status = InitClassImpl();
   if (!NT_SUCCESS(Status))
   {
-    DbgPrint("Failed to initialize window class implementation!\n");
+    DPRINT1("Failed to initialize window class implementation!\n");
     return STATUS_UNSUCCESSFUL;
   }
 
   Status = InitDesktopImpl();
   if (!NT_SUCCESS(Status))
   {
-    DbgPrint("Failed to initialize window station implementation!\n");
+    DPRINT1("Failed to initialize desktop implementation!\n");
     return STATUS_UNSUCCESSFUL;
   }
 
   Status = InitWindowImpl();
   if (!NT_SUCCESS(Status))
   {
-    DbgPrint("Failed to initialize window implementation!\n");
+    DPRINT1("Failed to initialize window implementation!\n");
     return STATUS_UNSUCCESSFUL;
   }
 
   Status = InitMenuImpl();
   if (!NT_SUCCESS(Status))
   {
-    DbgPrint("Failed to initialize menu implementation!\n");
+    DPRINT1("Failed to initialize menu implementation!\n");
     return STATUS_UNSUCCESSFUL;
   }
 
   Status = InitInputImpl();
   if (!NT_SUCCESS(Status))
     {
-      DbgPrint("Failed to initialize input implementation.\n");
+      DPRINT1("Failed to initialize input implementation.\n");
       return(Status);
     }
 
   Status = InitKeyboardImpl();
   if (!NT_SUCCESS(Status))
     {
-      DbgPrint("Failed to initialize keyboard implementation.\n");
+      DPRINT1("Failed to initialize keyboard implementation.\n");
       return(Status);
     }
 
+  Status = InitMonitorImpl();
+  if (!NT_SUCCESS(Status))
+    {
+      DbgPrint("Failed to initialize monitor implementation!\n");
+      return STATUS_UNSUCCESSFUL;
+    }
+
   Status = MsqInitializeImpl();
   if (!NT_SUCCESS(Status))
     {
-      DbgPrint("Failed to initialize message queue implementation.\n");
+      DPRINT1("Failed to initialize message queue implementation.\n");
       return(Status);
     }
 
   Status = InitTimerImpl();
   if (!NT_SUCCESS(Status))
     {
-      DbgPrint("Failed to initialize timer implementation.\n");
+      DPRINT1("Failed to initialize timer implementation.\n");
+      return(Status);
+    }
+
+  Status = InitAcceleratorImpl();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to initialize accelerator implementation.\n");
+      return(Status);
+    }
+
+  Status = InitGuiCheckImpl();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to initialize GUI check implementation.\n");
       return(Status);
     }
 
@@ -283,6 +458,7 @@ DllMain (
   /* Create stock objects, ie. precreated objects commonly
      used by win32 applications */
   CreateStockObjects();
+  CreateSysColorObjects();
 
   return STATUS_SUCCESS;
 }