Fix a typo.
[reactos.git] / reactos / subsys / win32k / objects / dc.c
index 07f7f1c..e44b5df 100644 (file)
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: dc.c,v 1.153 2004/12/13 05:23:59 royce Exp $
+/* $Id$
  *
  * DC.C - Device context functions
  *
  */
+
 #include <w32k.h>
 
+#define NDEBUG
+#include <debug.h>
+
 #ifndef OBJ_COLORSPACE
 #define OBJ_COLORSPACE (14)
 #endif
@@ -47,7 +51,7 @@ func_type STDCALL  func_name( HDC hdc ) \
     return 0;                       \
   }                                 \
   ft = dc->dc_field;                \
-  DC_UnlockDc( hdc );                          \
+  DC_UnlockDc(dc);                             \
   return ft;                        \
 }
 
@@ -65,7 +69,7 @@ VOID FASTCALL Int##FuncName ( PDC dc, LP##type pt) \
 } \
 BOOL STDCALL NtGdi##FuncName ( HDC hdc, LP##type pt ) \
 { \
-  NTSTATUS Status; \
+  NTSTATUS Status = STATUS_SUCCESS; \
   type Safept; \
   PDC dc; \
   if(!pt) \
@@ -79,8 +83,19 @@ BOOL STDCALL NtGdi##FuncName ( HDC hdc, LP##type pt ) \
     return FALSE; \
   } \
   Int##FuncName( dc, &Safept); \
-  DC_UnlockDc(hdc); \
-  Status = MmCopyToCaller(pt, &Safept, sizeof( type )); \
+  DC_UnlockDc(dc); \
+  _SEH_TRY \
+  { \
+    ProbeForWrite(pt, \
+                  sizeof( type ), \
+                  1); \
+    *pt = Safept; \
+  } \
+  _SEH_HANDLE \
+  { \
+    Status = _SEH_GetExceptionCode(); \
+  } \
+  _SEH_END; \
   if(!NT_SUCCESS(Status)) \
   { \
     SetLastNtError(Status); \
@@ -107,7 +122,7 @@ INT STDCALL  func_name( HDC hdc, INT mode ) \
   } \
   prevMode = dc->dc_field;                  \
   dc->dc_field = mode;                      \
-  DC_UnlockDc ( hdc );                    \
+  DC_UnlockDc ( dc );                    \
   return prevMode;                          \
 }
 
@@ -124,7 +139,7 @@ NtGdiCancelDC(HDC  hDC)
 }
 
 HDC STDCALL
-NtGdiCreateCompatableDC(HDC hDC)
+NtGdiCreateCompatibleDC(HDC hDC)
 {
   PDC  NewDC, OrigDC;
   HBITMAP  hBitmap;
@@ -136,7 +151,7 @@ NtGdiCreateCompatableDC(HDC hDC)
   if (hDC == NULL)
     {
       RtlInitUnicodeString(&DriverName, L"DISPLAY");
-      DisplayDC = IntGdiCreateDC(&DriverName, NULL, NULL, NULL);
+      DisplayDC = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, TRUE);
       if (NULL == DisplayDC)
         {
           return NULL;
@@ -158,7 +173,7 @@ NtGdiCreateCompatableDC(HDC hDC)
 
   if (NULL == hNewDC)
     {
-      DC_UnlockDc(hDC);
+      DC_UnlockDc(OrigDC);
       if (NULL != DisplayDC)
         {
           NtGdiDeleteDC(DisplayDC);
@@ -169,9 +184,9 @@ NtGdiCreateCompatableDC(HDC hDC)
 
   /* Copy information from original DC to new DC  */
   NewDC->hSelf = hNewDC;
+  NewDC->IsIC = FALSE;
 
   NewDC->PDev = OrigDC->PDev;
-  NewDC->DMW = OrigDC->DMW;
   memcpy(NewDC->FillPatternSurfaces,
          OrigDC->FillPatternSurfaces,
          sizeof OrigDC->FillPatternSurfaces);
@@ -193,8 +208,8 @@ NtGdiCreateCompatableDC(HDC hDC)
   /* Create default bitmap */
   if (!(hBitmap = NtGdiCreateBitmap( 1, 1, 1, NewDC->w.bitsPerPixel, NULL )))
     {
-      DC_UnlockDc( hDC );
-      DC_UnlockDc( hNewDC );
+      DC_UnlockDc( OrigDC );
+      DC_UnlockDc( NewDC );
       DC_FreeDC( hNewDC );
       if (NULL != DisplayDC)
         {
@@ -212,12 +227,13 @@ NtGdiCreateCompatableDC(HDC hDC)
   NewDC->w.textAlign = OrigDC->w.textAlign;
   NewDC->w.backgroundColor = OrigDC->w.backgroundColor;
   NewDC->w.backgroundMode = OrigDC->w.backgroundMode;
-  DC_UnlockDc( hDC );
+  NewDC->w.ROPmode = OrigDC->w.ROPmode;
+  DC_UnlockDc(NewDC);
+  DC_UnlockDc(OrigDC);
   if (NULL != DisplayDC)
     {
       NtGdiDeleteDC(DisplayDC);
     }
-  DC_UnlockDc(hNewDC);
 
   hVisRgn = NtGdiCreateRectRgn(0, 0, 1, 1);
   NtGdiSelectVisRgn(hNewDC, hVisRgn);
@@ -389,7 +405,7 @@ SetupDevMode(PDEVMODEW DevMode, ULONG DisplayNumber)
   if (Valid)
     {
       ProfilePath = ExAllocatePoolWithTag(PagedPool,
-                                          (wcslen(RegistryPath.Buffer) + 
+                                          (wcslen(RegistryPath.Buffer) +
                                            wcslen(Insert) + 1) * sizeof(WCHAR),
                                           TAG_DC);
       if (NULL != ProfilePath)
@@ -453,19 +469,16 @@ SetupDevMode(PDEVMODEW DevMode, ULONG DisplayNumber)
   return Valid;
 }
 
-BOOL FASTCALL
-IntCreatePrimarySurface()
+static BOOL FASTCALL
+IntPrepareDriver()
 {
    PGD_ENABLEDRIVER GDEnableDriver;
    DRVENABLEDATA DED;
-   SURFOBJ *SurfObj;
-   SIZEL SurfSize;
    UNICODE_STRING DriverFileNames;
    PWSTR CurrentName;
    BOOL GotDriver;
    BOOL DoDefault;
    ULONG DisplayNumber;
-   RECTL SurfaceRect;
 
    for (DisplayNumber = 0; ; DisplayNumber++)
    {
@@ -487,7 +500,6 @@ IntCreatePrimarySurface()
       if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
       {
          DPRINT1("FindDriverFileNames failed\n");
-         /* return FALSE; */
          continue;
       }
 
@@ -542,7 +554,6 @@ IntCreatePrimarySurface()
       {
          ObDereferenceObject(PrimarySurface.VideoFileObject);
          DPRINT1("No suitable DDI driver found\n");
-         /* return FALSE; */
          continue;
       }
 
@@ -607,7 +618,6 @@ IntCreatePrimarySurface()
             ObDereferenceObject(PrimarySurface.VideoFileObject);
             DPRINT1("DrvEnablePDEV with default parameters failed\n");
             DPRINT1("Perhaps DDI driver doesn't match miniport driver?\n");
-            /* return FALSE; */
             continue;
          }
       }
@@ -622,7 +632,7 @@ IntCreatePrimarySurface()
          DPRINT("Adjusting GDIInfo.ulLogPixelsY\n");
          PrimarySurface.GDIInfo.ulLogPixelsY = 96;
       }
-      
+
       PrimarySurface.Pointer.Exclude.right = -1;
 
       DPRINT("calling completePDev\n");
@@ -636,36 +646,135 @@ IntCreatePrimarySurface()
 
       DRIVER_ReferenceDriver(L"DISPLAY");
 
-      DPRINT("calling EnableSurface\n");
+      PrimarySurface.PreparedDriver = TRUE;
+      PrimarySurface.DisplayNumber = DisplayNumber;
 
-      /* Enable the drawing surface */
-      PrimarySurface.Handle =
-         PrimarySurface.DriverFunctions.EnableSurface(PrimarySurface.PDev);
-      if (NULL == PrimarySurface.Handle)
-      {
-/*         PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.PDev, FALSE);*/
-         PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.PDev);
-         ObDereferenceObject(PrimarySurface.VideoFileObject);
-         DPRINT1("DrvEnableSurface failed\n");
-         /* return FALSE; */
-         continue;
-      }
+      return TRUE;
+   }
 
-      /* attach monitor */
-      IntAttachMonitor(&PrimarySurface, DisplayNumber);
-
-      SurfObj = EngLockSurface((HSURF)PrimarySurface.Handle);
-      SurfObj->dhpdev = PrimarySurface.PDev;
-      SurfSize = SurfObj->sizlBitmap;
-      SurfSize = SurfObj->sizlBitmap;
-      SurfaceRect.left = SurfaceRect.top = 0;
-      SurfaceRect.right = SurfObj->sizlBitmap.cx;
-      SurfaceRect.bottom = SurfObj->sizlBitmap.cy;
-      /* FIXME - why does EngEraseSurface() sometimes crash?
-        EngEraseSurface(SurfObj, &SurfaceRect, 0); */
-      EngUnlockSurface(SurfObj);
-      IntShowDesktop(IntGetActiveDesktop(), SurfSize.cx, SurfSize.cy);
-      break;
+   return FALSE;
+}
+
+static BOOL FASTCALL
+IntPrepareDriverIfNeeded()
+{
+   return (PrimarySurface.PreparedDriver ? TRUE : IntPrepareDriver());
+}
+
+static BOOL FASTCALL
+PrepareVideoPrt()
+{
+   PIRP Irp;
+   NTSTATUS Status;
+   IO_STATUS_BLOCK Iosb;
+   BOOL Prepare = TRUE;
+   ULONG Length = sizeof(BOOL);
+   PIO_STACK_LOCATION StackPtr;
+   LARGE_INTEGER StartOffset;
+   PFILE_OBJECT FileObject = PrimarySurface.VideoFileObject;
+   PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
+
+   DPRINT("PrepareVideoPrt() called\n");
+
+   KeClearEvent(&PrimarySurface.VideoFileObject->Event);
+
+   ObReferenceObjectByPointer(FileObject, 0, IoFileObjectType, KernelMode);
+
+   StartOffset.QuadPart = 0;
+   Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
+                                      DeviceObject,
+                                      (PVOID) &Prepare,
+                                      Length,
+                                      &StartOffset,
+                                      NULL,
+                                      &Iosb);
+   if (NULL == Irp)
+   {
+      return FALSE;
+   }
+
+   /* Set up IRP Data */
+   Irp->Tail.Overlay.OriginalFileObject = FileObject;
+   Irp->RequestorMode = KernelMode;
+   Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
+   Irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
+   Irp->Flags |= IRP_WRITE_OPERATION;
+
+   /* Setup Stack Data */
+   StackPtr = IoGetNextIrpStackLocation(Irp);
+   StackPtr->FileObject = PrimarySurface.VideoFileObject;
+   StackPtr->Parameters.Write.Key = 0;
+
+   Status = IoCallDriver(DeviceObject, Irp);
+
+   if (STATUS_PENDING == Status)
+   {
+      KeWaitForSingleObject(&FileObject->Event, Executive, KernelMode, TRUE, 0);
+      Status = Iosb.Status;
+   }
+
+   return NT_SUCCESS(Status);
+}
+
+BOOL FASTCALL
+IntCreatePrimarySurface()
+{
+   SIZEL SurfSize;
+   RECTL SurfaceRect;
+   SURFOBJ *SurfObj;
+   BOOL calledFromUser;
+   
+   if (! IntPrepareDriverIfNeeded())
+   {
+      return FALSE;
+   }
+
+   if (! PrepareVideoPrt())
+   {
+      return FALSE;
+   }
+
+   DPRINT("calling EnableSurface\n");
+   /* Enable the drawing surface */
+   PrimarySurface.Handle =
+      PrimarySurface.DriverFunctions.EnableSurface(PrimarySurface.PDev);
+   if (NULL == PrimarySurface.Handle)
+   {
+/*      PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.PDev, FALSE);*/
+      PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.PDev);
+      ObDereferenceObject(PrimarySurface.VideoFileObject);
+      DPRINT1("DrvEnableSurface failed\n");
+      return FALSE;
+   }
+
+   PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.PDev, TRUE);
+
+   calledFromUser = UserIsEntered(); //fixme: possibly upgrade a shared lock
+   if (!calledFromUser){
+      UserEnterExclusive();
+   }
+
+   /* attach monitor */
+   IntAttachMonitor(&PrimarySurface, PrimarySurface.DisplayNumber);
+
+   SurfObj = EngLockSurface((HSURF)PrimarySurface.Handle);
+   SurfObj->dhpdev = PrimarySurface.PDev;
+   SurfSize = SurfObj->sizlBitmap;
+   SurfaceRect.left = SurfaceRect.top = 0;
+   SurfaceRect.right = SurfObj->sizlBitmap.cx;
+   SurfaceRect.bottom = SurfObj->sizlBitmap.cy;
+   /* FIXME - why does EngEraseSurface() sometimes crash?
+     EngEraseSurface(SurfObj, &SurfaceRect, 0); */
+
+   /* Put the pointer in the center of the screen */
+   GDIDEV(SurfObj)->Pointer.Pos.x = (SurfaceRect.right - SurfaceRect.left) / 2;
+   GDIDEV(SurfObj)->Pointer.Pos.y = (SurfaceRect.bottom - SurfaceRect.top) / 2;
+
+   EngUnlockSurface(SurfObj);
+   co_IntShowDesktop(IntGetActiveDesktop(), SurfSize.cx, SurfSize.cy);
+
+   if (!calledFromUser){
+      UserLeave();
    }
 
    return TRUE;
@@ -674,11 +783,22 @@ IntCreatePrimarySurface()
 VOID FASTCALL
 IntDestroyPrimarySurface()
   {
+    BOOL calledFromUser; 
+     
     DRIVER_UnreferenceDriver(L"DISPLAY");
 
+    calledFromUser = UserIsEntered();
+    if (!calledFromUser){
+       UserEnterExclusive();
+    }
+
     /* detach monitor */
     IntDetachMonitor(&PrimarySurface);
 
+    if (!calledFromUser){
+       UserLeave();
+    }
+
     /*
      * FIXME: Hide a mouse pointer there. Also because we have to prevent
      * memory leaks with the Eng* mouse routines.
@@ -688,6 +808,7 @@ IntDestroyPrimarySurface()
     PrimarySurface.DriverFunctions.AssertMode(PrimarySurface.PDev, FALSE);
     PrimarySurface.DriverFunctions.DisableSurface(PrimarySurface.PDev);
     PrimarySurface.DriverFunctions.DisablePDEV(PrimarySurface.PDev);
+    PrimarySurface.PreparedDriver = FALSE;
 
     DceEmptyCache();
 
@@ -698,23 +819,48 @@ HDC FASTCALL
 IntGdiCreateDC(PUNICODE_STRING Driver,
                PUNICODE_STRING Device,
                PUNICODE_STRING Output,
-               CONST PDEVMODEW InitData)
+               CONST PDEVMODEW InitData,
+               BOOL CreateAsIC)
 {
   HDC      hNewDC;
   PDC      NewDC;
   HDC      hDC = NULL;
-  SURFOBJ *SurfObj;
   HRGN     hVisRgn;
   UNICODE_STRING StdDriver;
+  BOOL calledFromUser;
   
   RtlInitUnicodeString(&StdDriver, L"DISPLAY");
-  
+
   if (NULL == Driver || 0 == RtlCompareUnicodeString(Driver, &StdDriver, TRUE))
     {
-      if (! IntGraphicsCheck(TRUE))
+      if (CreateAsIC)
         {
-          DPRINT1("Unable to initialize graphics, returning NULL dc\n");
-          return NULL;
+          if (! IntPrepareDriverIfNeeded())
+            {
+              DPRINT1("Unable to prepare graphics driver, returning NULL ic\n");
+              return NULL;
+            }
+        }
+      else
+        {
+          calledFromUser = UserIsEntered();
+          if (!calledFromUser){
+             UserEnterExclusive();
+          }
+          
+          if (! co_IntGraphicsCheck(TRUE))
+          {
+            if (!calledFromUser){
+               UserLeave();
+            } 
+            DPRINT1("Unable to initialize graphics, returning NULL dc\n");
+            return NULL;
+          }
+          
+          if (!calledFromUser){
+            UserLeave();
+          } 
+          
         }
     }
 
@@ -722,12 +868,12 @@ IntGdiCreateDC(PUNICODE_STRING Driver,
   if ((hNewDC = DC_FindOpenDC(Driver)) != NULL)
   {
     hDC = hNewDC;
-    return  NtGdiCreateCompatableDC(hDC);
+    return  NtGdiCreateCompatibleDC(hDC);
   }
 
   if (Driver != NULL && Driver->Buffer != NULL)
   {
-    DPRINT("NAME: %S\n", Driver->Buffer); // FIXME: Should not crash if NULL
+    DPRINT("NAME: %wZ\n", Driver); // FIXME: Should not crash if NULL
   }
 
   /*  Allocate a DC object  */
@@ -744,7 +890,7 @@ IntGdiCreateDC(PUNICODE_STRING Driver,
     return NULL;
   }
 
-  NewDC->DMW = PrimarySurface.DMW;
+  NewDC->IsIC = CreateAsIC;
   NewDC->DevInfo = &PrimarySurface.DevInfo;
   NewDC->GDIInfo = &PrimarySurface.GDIInfo;
   memcpy(NewDC->FillPatternSurfaces, PrimarySurface.FillPatterns,
@@ -754,47 +900,33 @@ IntGdiCreateDC(PUNICODE_STRING Driver,
   NewDC->DriverFunctions = PrimarySurface.DriverFunctions;
   NewDC->w.hBitmap = PrimarySurface.Handle;
 
-  NewDC->DMW.dmSize = sizeof(NewDC->DMW);
-  NewDC->DMW.dmFields = 0x000fc000;
-
-  /* FIXME: get mode selection information from somewhere  */
+  NewDC->w.bitsPerPixel = NewDC->GDIInfo->cBitsPixel * NewDC->GDIInfo->cPlanes;
+  DPRINT("Bits per pel: %u\n", NewDC->w.bitsPerPixel);
 
-  NewDC->DMW.dmLogPixels = 96;
-  SurfObj = EngLockSurface((HSURF)PrimarySurface.Handle);
-  if ( !SurfObj )
+  if (! CreateAsIC)
   {
-         DC_UnlockDc ( hNewDC );
-         DC_FreeDC ( hNewDC) ;
-         return NULL;
+    NewDC->w.hPalette = NewDC->DevInfo->hpalDefault;
+    NewDC->w.ROPmode = R2_COPYPEN;
+
+    DC_UnlockDc( NewDC );
+
+    hVisRgn = NtGdiCreateRectRgn(0, 0, NewDC->GDIInfo->ulHorzRes,
+                                 NewDC->GDIInfo->ulVertRes);
+    NtGdiSelectVisRgn(hNewDC, hVisRgn);
+    NtGdiDeleteObject(hVisRgn);
+
+    /*  Initialize the DC state  */
+    DC_InitDC(hNewDC);
+    NtGdiSetTextColor(hNewDC, RGB(0, 0, 0));
+    NtGdiSetTextAlign(hNewDC, TA_TOP);
+    NtGdiSetBkColor(hNewDC, RGB(255, 255, 255));
+    NtGdiSetBkMode(hNewDC, OPAQUE);
+  }
+  else
+  {
+    DC_UnlockDc( NewDC );
   }
-  NewDC->DMW.dmBitsPerPel = BitsPerFormat(SurfObj->iBitmapFormat);
-  NewDC->DMW.dmPelsWidth = SurfObj->sizlBitmap.cx;
-  NewDC->DMW.dmPelsHeight = SurfObj->sizlBitmap.cy;
-  NewDC->DMW.dmDisplayFlags = 0;
-  NewDC->DMW.dmDisplayFrequency = 0;
-
-  NewDC->w.bitsPerPixel = NewDC->DMW.dmBitsPerPel; // FIXME: set this here??
-
-  NewDC->w.hPalette = NewDC->DevInfo->hpalDefault;
-
-  DPRINT("Bits per pel: %u\n", NewDC->w.bitsPerPixel);
-  
-  DC_UnlockDc( hNewDC );
-
-  hVisRgn = NtGdiCreateRectRgn(0, 0, SurfObj->sizlBitmap.cx,
-                              SurfObj->sizlBitmap.cy);
-  NtGdiSelectVisRgn(hNewDC, hVisRgn);
-  NtGdiDeleteObject(hVisRgn);
-
-  /*  Initialize the DC state  */
-  DC_InitDC(hNewDC);
-  NtGdiSetTextColor(hNewDC, RGB(0, 0, 0));
-  NtGdiSetTextAlign(hNewDC, TA_TOP);
-  NtGdiSetBkColor(hNewDC, RGB(255, 255, 255));
-  NtGdiSetBkMode(hNewDC, OPAQUE);
 
-  EngUnlockSurface(SurfObj);
-  
   return hNewDC;
 }
 
@@ -807,11 +939,25 @@ NtGdiCreateDC(PUNICODE_STRING Driver,
   UNICODE_STRING SafeDriver, SafeDevice;
   DEVMODEW SafeInitData;
   HDC Ret;
-  NTSTATUS Status;
-  
+  NTSTATUS Status = STATUS_SUCCESS;
+
   if(InitData)
   {
-    Status = MmCopyFromCaller(&SafeInitData, InitData, sizeof(DEVMODEW));
+    _SEH_TRY
+    {
+      ProbeForRead(InitData,
+                   sizeof(DEVMODEW),
+                   1);
+      RtlCopyMemory(&SafeInitData,
+                    InitData,
+                    sizeof(DEVMODEW));
+    }
+    _SEH_HANDLE
+    {
+      Status = _SEH_GetExceptionCode();
+    }
+    _SEH_END;
+
     if(!NT_SUCCESS(Status))
     {
       SetLastNtError(Status);
@@ -819,7 +965,7 @@ NtGdiCreateDC(PUNICODE_STRING Driver,
     }
     /* FIXME - InitData can have some more bytes! */
   }
-  
+
   if(Driver)
   {
     Status = IntSafeCopyUnicodeString(&SafeDriver, Driver);
@@ -829,7 +975,7 @@ NtGdiCreateDC(PUNICODE_STRING Driver,
       return NULL;
     }
   }
-  
+
   if(Device)
   {
     Status = IntSafeCopyUnicodeString(&SafeDevice, Device);
@@ -840,9 +986,11 @@ NtGdiCreateDC(PUNICODE_STRING Driver,
       return NULL;
     }
   }
-  
-  Ret = IntGdiCreateDC(&SafeDriver, &SafeDevice, NULL, &SafeInitData);
-  
+
+  Ret = IntGdiCreateDC(NULL == Driver ? NULL : &SafeDriver,
+                       NULL == Device ? NULL : &SafeDevice, NULL,
+                       NULL == InitData ? NULL : &SafeInitData, FALSE);
+
   return Ret;
 }
 
@@ -850,10 +998,63 @@ HDC STDCALL
 NtGdiCreateIC(PUNICODE_STRING Driver,
               PUNICODE_STRING Device,
               PUNICODE_STRING Output,
-              CONST PDEVMODEW DevMode)
+              CONST PDEVMODEW InitData)
 {
-  /* FIXME: this should probably do something else...  */
-  return  NtGdiCreateDC(Driver, Device, Output, DevMode);
+  UNICODE_STRING SafeDriver, SafeDevice;
+  DEVMODEW SafeInitData;
+  HDC Ret;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  if(InitData)
+  {
+    _SEH_TRY
+    {
+      ProbeForRead(InitData,
+                   sizeof(DEVMODEW),
+                   1);
+      RtlCopyMemory(&SafeInitData,
+                    InitData,
+                    sizeof(DEVMODEW));
+    }
+    _SEH_HANDLE
+    {
+      Status = _SEH_GetExceptionCode();
+    }
+    _SEH_END;
+    if(!NT_SUCCESS(Status))
+    {
+      SetLastNtError(Status);
+      return NULL;
+    }
+    /* FIXME - InitData can have some more bytes! */
+  }
+
+  if(Driver)
+  {
+    Status = IntSafeCopyUnicodeString(&SafeDriver, Driver);
+    if(!NT_SUCCESS(Status))
+    {
+      SetLastNtError(Status);
+      return NULL;
+    }
+  }
+
+  if(Device)
+  {
+    Status = IntSafeCopyUnicodeString(&SafeDevice, Device);
+    if(!NT_SUCCESS(Status))
+    {
+      RtlFreeUnicodeString(&SafeDriver);
+      SetLastNtError(Status);
+      return NULL;
+    }
+  }
+
+  Ret = IntGdiCreateDC(NULL == Driver ? NULL : &SafeDriver,
+                       NULL == Device ? NULL : &SafeDevice, NULL,
+                       NULL == InitData ? NULL : &SafeInitData, TRUE);
+
+  return Ret;
 }
 
 BOOL STDCALL
@@ -861,10 +1062,17 @@ NtGdiDeleteDC(HDC  DCHandle)
 {
   PDC  DCToDelete;
 
+  if (!GDIOBJ_OwnedByCurrentProcess(DCHandle))
+    {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
+    }
+  
   DCToDelete = DC_LockDc(DCHandle);
   if (DCToDelete == NULL)
     {
-      return  FALSE;
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
     }
 
   /*  First delete all saved DCs  */
@@ -881,7 +1089,7 @@ NtGdiDeleteDC(HDC  DCHandle)
     }
     DC_SetNextDC (DCToDelete, DC_GetNextDC (savedDC));
     DCToDelete->saveLevel--;
-    DC_UnlockDc( savedHDC );
+    DC_UnlockDc( savedDC );
     NtGdiDeleteDC (savedHDC);
   }
 
@@ -921,7 +1129,7 @@ NtGdiDeleteDC(HDC  DCHandle)
 #if 0 /* FIXME */
   PATH_DestroyGdiPath (&DCToDelete->w.path);
 #endif
-  DC_UnlockDc( DCHandle );
+  DC_UnlockDc( DCToDelete );
   DC_FreeDC ( DCHandle );
 
   return TRUE;
@@ -957,13 +1165,13 @@ NtGdiGetCurrentObject(HDC  hDC, UINT  ObjectType)
 {
   HGDIOBJ SelObject;
   DC *dc;
-  
+
   if(!(dc = DC_LockDc(hDC)))
   {
     SetLastWin32Error(ERROR_INVALID_HANDLE);
     return NULL;
   }
-  
+
   switch(ObjectType)
   {
     case OBJ_PEN:
@@ -991,8 +1199,8 @@ NtGdiGetCurrentObject(HDC  hDC, UINT  ObjectType)
       SetLastWin32Error(ERROR_INVALID_PARAMETER);
       break;
   }
-  
-  DC_UnlockDc(hDC);
+
+  DC_UnlockDc(dc);
   return SelObject;
 }
 
@@ -1003,7 +1211,7 @@ IntGdiGetDCOrgEx(DC *dc, LPPOINT  Point)
 {
   Point->x = dc->w.DCOrgX;
   Point->y = dc->w.DCOrgY;
-  
+
   return  TRUE;
 }
 
@@ -1013,32 +1221,44 @@ NtGdiGetDCOrgEx(HDC  hDC, LPPOINT  Point)
   BOOL Ret;
   DC *dc;
   POINT SafePoint;
-  NTSTATUS Status;
-  
+  NTSTATUS Status = STATUS_SUCCESS;
+
   if(!Point)
   {
     SetLastWin32Error(ERROR_INVALID_PARAMETER);
     return FALSE;
   }
-  
+
   dc = DC_LockDc(hDC);
   if(!dc)
   {
     SetLastWin32Error(ERROR_INVALID_HANDLE);
     return FALSE;
   }
-  
+
   Ret = IntGdiGetDCOrgEx(dc, &SafePoint);
-  
-  Status = MmCopyToCaller(Point, &SafePoint, sizeof(POINT));
+
+  _SEH_TRY
+  {
+    ProbeForWrite(Point,
+                  sizeof(POINT),
+                  1);
+    *Point = SafePoint;
+  }
+  _SEH_HANDLE
+  {
+    Status = _SEH_GetExceptionCode();
+  }
+  _SEH_END;
+
   if(!NT_SUCCESS(Status))
   {
     SetLastNtError(Status);
-    DC_UnlockDc(hDC);
+    DC_UnlockDc(dc);
     return FALSE;
   }
-  
-  DC_UnlockDc(hDC);
+
+  DC_UnlockDc(dc);
   return Ret;
 }
 
@@ -1058,7 +1278,7 @@ NtGdiSetBkColor(HDC hDC, COLORREF color)
   oldColor = dc->w.backgroundColor;
   dc->w.backgroundColor = color;
   hBrush = dc->w.hBrush;
-  DC_UnlockDc ( hDC );
+  DC_UnlockDc(dc);
   NtGdiSelectObject(hDC, hBrush);
   return oldColor;
 }
@@ -1079,7 +1299,7 @@ NtGdiGetDCState(HDC  hDC)
   hnewdc = DC_AllocDC(NULL);
   if (hnewdc == NULL)
   {
-    DC_UnlockDc( hDC );
+    DC_UnlockDc(dc);
     return 0;
   }
   newdc = DC_LockDc( hnewdc );
@@ -1138,6 +1358,7 @@ NtGdiGetDCState(HDC  hDC)
 
   newdc->hSelf = hnewdc;
   newdc->saveLevel = 0;
+  newdc->IsIC = dc->IsIC;
 
 #if 0
   PATH_InitGdiPath( &newdc->w.path );
@@ -1151,8 +1372,8 @@ NtGdiGetDCState(HDC  hDC)
     newdc->w.hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
     NtGdiCombineRgn( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
   }
-  DC_UnlockDc( hnewdc );
-  DC_UnlockDc( hDC );
+  DC_UnlockDc( newdc );
+  DC_UnlockDc( dc );
   return  hnewdc;
 }
 
@@ -1248,9 +1469,9 @@ NtGdiSetDCState ( HDC hDC, HDC hDCSave )
                res = CLIPPING_UpdateGCRegion( dc );
                ASSERT ( res != ERROR );
        }
-       DC_UnlockDc ( hDC );
+       DC_UnlockDc ( dc );
 #else
-       DC_UnlockDc ( hDC );
+       DC_UnlockDc ( dc );
        NtGdiSelectClipRgn(hDC, dcs->w.hClipRgn);
 #endif
 
@@ -1267,11 +1488,11 @@ NtGdiSetDCState ( HDC hDC, HDC hDCSave )
        GDISelectPalette16( hDC, dcs->w.hPalette, FALSE );
 #endif
       } else {
-       DC_UnlockDc(hDC);
+       DC_UnlockDc(dc);
       }
-      DC_UnlockDc ( hDCSave );
+      DC_UnlockDc ( dcs );
     } else {
-      DC_UnlockDc ( hDC );
+      DC_UnlockDc ( dc );
       SetLastWin32Error(ERROR_INVALID_HANDLE);
     }
   }
@@ -1282,7 +1503,7 @@ NtGdiSetDCState ( HDC hDC, HDC hDCSave )
 INT FASTCALL
 IntGdiGetDeviceCaps(PDC dc, INT Index)
 {
-  INT ret;
+  INT ret = 0;
   POINT  pt;
 
   /* Retrieve capability */
@@ -1492,7 +1713,7 @@ NtGdiGetDeviceCaps(HDC  hDC,
 
   DPRINT("(%04x,%d): returning %d\n", hDC, Index, ret);
 
-  DC_UnlockDc( hDC );
+  DC_UnlockDc( dc );
   return ret;
 }
 
@@ -1512,7 +1733,7 @@ IntGdiGetObject(HANDLE Handle, INT Count, LPVOID Buffer)
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return 0;
     }
-  
+
   ObjectType = GDIOBJ_GetObjectType(Handle);
   switch (ObjectType)
     {
@@ -1547,7 +1768,7 @@ IntGdiGetObject(HANDLE Handle, INT Count, LPVOID Buffer)
         break;
     }
 
-  GDIOBJ_UnlockObj(Handle);
+  GDIOBJ_UnlockObjByPtr(GdiObject);
 
   return Result;
 }
@@ -1557,23 +1778,53 @@ NtGdiGetObject(HANDLE handle, INT count, LPVOID buffer)
 {
   INT Ret;
   LPVOID SafeBuf;
-  NTSTATUS Status;
+  NTSTATUS Status = STATUS_SUCCESS;
 
   if (count <= 0)
   {
     return 0;
   }
   
+  _SEH_TRY
+  {
+    ProbeForWrite(buffer,
+                  count,
+                  1);
+  }
+  _SEH_HANDLE
+  {
+    Status = _SEH_GetExceptionCode();
+  }
+  _SEH_END;
+  
+  if(!NT_SUCCESS(Status))
+  {
+    SetLastNtError(Status);
+    return 0;
+  }
+
   SafeBuf = ExAllocatePoolWithTag(PagedPool, count, TAG_GDIOBJ);
   if(!SafeBuf)
   {
     SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
     return 0;
   }
-  
+
   Ret = IntGdiGetObject(handle, count, SafeBuf);
-  
-  Status = MmCopyToCaller(buffer, SafeBuf, count);
+
+  _SEH_TRY
+  {
+    /* pointer already probed! */
+    RtlCopyMemory(buffer,
+                  SafeBuf,
+                  count);
+  }
+  _SEH_HANDLE
+  {
+    Status = _SEH_GetExceptionCode();
+  }
+  _SEH_END;
+
   ExFreePool(SafeBuf);
   if(!NT_SUCCESS(Status))
   {
@@ -1646,7 +1897,7 @@ NtGdiGetObjectType(HANDLE handle)
       result = 0;
       break;
   }
-  GDIOBJ_UnlockObj(handle);
+  GDIOBJ_UnlockObjByPtr(ptr);
   return result;
 }
 
@@ -1687,7 +1938,7 @@ NtGdiRestoreDC(HDC  hDC, INT  SaveLevel)
 
   if ((SaveLevel < 1) || (SaveLevel > dc->saveLevel))
   {
-    DC_UnlockDc(hDC);
+    DC_UnlockDc(dc);
     return FALSE;
   }
 
@@ -1699,14 +1950,14 @@ NtGdiRestoreDC(HDC  hDC, INT  SaveLevel)
     dcs = DC_LockDc (hdcs);
     if (dcs == NULL)
     {
-      DC_UnlockDc(hDC);
+      DC_UnlockDc(dc);
       return FALSE;
     }
     DC_SetNextDC (dcs, DC_GetNextDC (dcs));
     if (--dc->saveLevel < SaveLevel)
       {
-       DC_UnlockDc( hDC );
-        DC_UnlockDc( hdcs );
+       DC_UnlockDc( dc );
+        DC_UnlockDc( dcs );
         NtGdiSetDCState(hDC, hdcs);
 #if 0
         if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
@@ -1724,11 +1975,11 @@ NtGdiRestoreDC(HDC  hDC, INT  SaveLevel)
       }
     else
       {
-      DC_UnlockDc( hdcs );
+      DC_UnlockDc( dcs );
       }
     NtGdiDeleteDC (hdcs);
   }
-  DC_UnlockDc( hDC );
+  DC_UnlockDc( dc );
   return  success;
 }
 
@@ -1755,7 +2006,7 @@ NtGdiSaveDC(HDC  hDC)
   dc = DC_LockDc (hDC);
   if (dc == NULL)
   {
-    DC_UnlockDc(hdcs);
+    DC_UnlockDc(dcs);
     SetLastWin32Error(ERROR_INVALID_HANDLE);
     return 0;
   }
@@ -1777,8 +2028,8 @@ NtGdiSaveDC(HDC  hDC)
   DC_SetNextDC (dcs, DC_GetNextDC (dc));
   DC_SetNextDC (dc, hdcs);
   ret = ++dc->saveLevel;
-  DC_UnlockDc( hdcs );
-  DC_UnlockDc( hDC );
+  DC_UnlockDc( dcs );
+  DC_UnlockDc( dc );
 
   return  ret;
 }
@@ -1794,12 +2045,11 @@ NtGdiSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
   PGDIBRUSHOBJ brush;
   XLATEOBJ *XlateObj;
   DWORD objectType;
-  ULONG NumColors = 0;
   HRGN hVisRgn;
   BOOLEAN Failed;
 
   if(!hDC || !hGDIObj) return NULL;
-  
+
   dc = DC_LockDc(hDC);
   if (NULL == dc)
     {
@@ -1820,7 +2070,7 @@ NtGdiSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
       }
 
       XlateObj = IntGdiCreateBrushXlate(dc, pen, &Failed);
-      PENOBJ_UnlockPen(hGDIObj);
+      PENOBJ_UnlockPen(pen);
       if (Failed)
       {
         SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
@@ -1843,7 +2093,7 @@ NtGdiSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
       }
 
       XlateObj = IntGdiCreateBrushXlate(dc, brush, &Failed);
-      BRUSHOBJ_UnlockBrush(hGDIObj);
+      BRUSHOBJ_UnlockBrush(brush);
       if (Failed)
       {
         SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
@@ -1869,14 +2119,14 @@ NtGdiSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
       // must be memory dc to select bitmap
       if (!(dc->w.flags & DC_MEMORY))
         {
-          DC_UnlockDc(hDC);
+          DC_UnlockDc(dc);
           return NULL;
         }
       pb = BITMAPOBJ_LockBitmap(hGDIObj);
       if (NULL == pb)
        {
          SetLastWin32Error(ERROR_INVALID_HANDLE);
-          DC_UnlockDc(hDC);
+          DC_UnlockDc(dc);
          return NULL;
        }
       objOrg = (HGDIOBJ)dc->w.hBitmap;
@@ -1888,21 +2138,7 @@ NtGdiSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
       if(pb->dib)
       {
         dc->w.bitsPerPixel = pb->dib->dsBmih.biBitCount;
-
-        if(pb->dib->dsBmih.biBitCount <= 8)
-        {
-          if(pb->dib->dsBmih.biBitCount == 1) { NumColors = 2; } else
-          if(pb->dib->dsBmih.biBitCount == 4) { NumColors = 16; } else
-          if(pb->dib->dsBmih.biBitCount == 8) { NumColors = 256; }
-          dc->w.hPalette = PALETTE_AllocPaletteIndexedRGB(NumColors, pb->ColorMap);
-        }
-        else
-        {
-          dc->w.hPalette = PALETTE_AllocPalette(PAL_BITFIELDS, 0, NULL,
-                                                pb->dib->dsBitfields[0],
-                                                pb->dib->dsBitfields[1],
-                                                pb->dib->dsBitfields[2]);
-        }
+        dc->w.hPalette = pb->hDIBPalette;
       }
       else
       {
@@ -1914,16 +2150,16 @@ NtGdiSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
       NtGdiSelectObject ( hDC, dc->w.hBrush );
       NtGdiSelectObject ( hDC, dc->w.hPen );
 
-      DC_UnlockDc ( hDC );
+      DC_UnlockDc ( dc );
       hVisRgn = NtGdiCreateRectRgn ( 0, 0, pb->SurfObj.sizlBitmap.cx, pb->SurfObj.sizlBitmap.cy );
-      BITMAPOBJ_UnlockBitmap( hGDIObj );
+      BITMAPOBJ_UnlockBitmap( pb );
       NtGdiSelectVisRgn ( hDC, hVisRgn );
       NtGdiDeleteObject ( hVisRgn );
 
       return objOrg;
 
     case GDI_OBJECT_TYPE_REGION:
-      DC_UnlockDc (hDC);
+      DC_UnlockDc (dc);
       /*
        * The return value is one of the following values:
        *  SIMPLEREGION
@@ -1935,7 +2171,7 @@ NtGdiSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
     default:
       break;
   }
-  DC_UnlockDc( hDC );
+  DC_UnlockDc( dc );
   return objOrg;
 }
 
@@ -1967,7 +2203,7 @@ NtGdiSetHookFlags(HDC hDC, WORD Flags)
       dc->w.flags &= ~DC_DIRTY;
     }
 
-  DC_UnlockDc(hDC);
+  DC_UnlockDc(dc);
 
   return wRet;
 }
@@ -1986,7 +2222,7 @@ DC_AllocDC(PUNICODE_STRING Driver)
   PDC  NewDC;
   HDC  hDC;
   PWSTR Buf = NULL;
-  
+
   if (Driver != NULL)
   {
     Buf = ExAllocatePoolWithTag(PagedPool, Driver->MaximumLength, TAG_DC);
@@ -2009,7 +2245,7 @@ DC_AllocDC(PUNICODE_STRING Driver)
 
   NewDC = DC_LockDc(hDC);
   /* FIXME - Handle NewDC == NULL! */
-  
+
   if (Driver != NULL)
   {
     RtlCopyMemory(&NewDC->DriverName, Driver, sizeof(UNICODE_STRING));
@@ -2038,7 +2274,7 @@ DC_AllocDC(PUNICODE_STRING Driver)
 
   NewDC->w.hPalette = NtGdiGetStockObject(DEFAULT_PALETTE);
 
-  DC_UnlockDc(hDC);
+  DC_UnlockDc(NewDC);
 
   return  hDC;
 }
@@ -2165,7 +2401,7 @@ DC_SetOwnership(HDC hDC, PEPROCESS Owner)
         {
           GDIOBJ_CopyOwnership(hDC, DC->w.hGCClipRgn);
         }
-      DC_UnlockDc(hDC);
+      DC_UnlockDc(DC);
     }
 }
 
@@ -2222,26 +2458,28 @@ IntSetDCColor(HDC hDC, ULONG Object, COLORREF Color)
 /*! \brief Enumerate possible display settings for the given display...
  *
  * \todo Make thread safe!?
- * \todo Don't ignore lpszDeviceName
+ * \todo Don't ignore pDeviceName
  * \todo Implement non-raw mode (only return settings valid for driver and monitor)
  */
 BOOL FASTCALL
 IntEnumDisplaySettings(
-  PUNICODE_STRING lpszDeviceName,
-  DWORD iModeNum,
-  LPDEVMODEW lpDevMode,
-  DWORD dwFlags)
+  IN PUNICODE_STRING pDeviceName  OPTIONAL,
+  IN DWORD iModeNum,
+  IN OUT LPDEVMODEW pDevMode,
+  IN DWORD dwFlags)
 {
   static DEVMODEW *CachedDevModes = NULL, *CachedDevModesEnd = NULL;
   static DWORD SizeOfCachedDevModes = 0;
-  LPDEVMODEW CachedMode = NULL;
+  PDEVMODEW CachedMode = NULL;
   DEVMODEW DevMode;
   INT Size, OldSize;
   ULONG DisplayNumber = 0; /* only default display supported */
-  
-  if (lpDevMode->dmSize != SIZEOF_DEVMODEW_300 &&
-      lpDevMode->dmSize != SIZEOF_DEVMODEW_400 &&
-      lpDevMode->dmSize != SIZEOF_DEVMODEW_500)
+
+  DPRINT("DevMode->dmSize = %d\n", pDevMode->dmSize);
+  DPRINT("DevMode->dmExtraSize = %d\n", pDevMode->dmDriverExtra);
+  if (pDevMode->dmSize != SIZEOF_DEVMODEW_300 &&
+      pDevMode->dmSize != SIZEOF_DEVMODEW_400 &&
+      pDevMode->dmSize != SIZEOF_DEVMODEW_500)
   {
     SetLastWin32Error(STATUS_INVALID_PARAMETER);
     return FALSE;
@@ -2249,8 +2487,8 @@ IntEnumDisplaySettings(
 
   if (iModeNum == ENUM_CURRENT_SETTINGS)
   {
-    CachedMode = &PrimarySurface.DMW;    
-    assert(CachedMode->dmSize > 0);
+    CachedMode = &PrimarySurface.DMW;
+    ASSERT(CachedMode->dmSize > 0);
   }
   else if (iModeNum == ENUM_REGISTRY_SETTINGS)
   {
@@ -2276,7 +2514,7 @@ IntEnumDisplaySettings(
       UNICODE_STRING DriverFileNames;
       LPWSTR CurrentName;
       DRVENABLEDATA DrvEnableData;
-  
+
       /* Retrieve DDI driver names from registry */
       RtlInitUnicodeString(&DriverFileNames, NULL);
       if (!FindDriverFileNames(&DriverFileNames, DisplayNumber))
@@ -2284,13 +2522,13 @@ IntEnumDisplaySettings(
         DPRINT1("FindDriverFileNames failed\n");
         return FALSE;
       }
-      
+
       if (!HalQueryDisplayOwnership())
       {
         IntCreatePrimarySurface();
         PrimarySurfaceCreated = TRUE;
       }
-  
+
       /*
        * DriverFileNames may be a list of drivers in REG_SZ_MULTI format,
        * scan all of them until a good one found.
@@ -2301,7 +2539,7 @@ IntEnumDisplaySettings(
       {
         INT i;
         PGD_ENABLEDRIVER GDEnableDriver;
-  
+
         /* Get the DDI driver's entry point */
         GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
         if (NULL == GDEnableDriver)
@@ -2309,30 +2547,30 @@ IntEnumDisplaySettings(
           DPRINT("FindDDIDriver failed for %S\n", CurrentName);
           continue;
         }
-  
+
         /*  Call DDI driver's EnableDriver function  */
         RtlZeroMemory(&DrvEnableData, sizeof (DrvEnableData));
-  
+
         if (!GDEnableDriver(DDI_DRIVER_VERSION_NT5_01, sizeof (DrvEnableData), &DrvEnableData))
         {
           DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
           continue;
         }
-        
+
         CachedDevModesEnd = CachedDevModes;
-        
+
         /* find DrvGetModes function */
         for (i = 0; i < DrvEnableData.c; i++)
         {
           PDRVFN DrvFn = DrvEnableData.pdrvfn + i;
           PGD_GETMODES GetModes;
           INT SizeNeeded, SizeUsed;
-  
+
           if (DrvFn->iFunc != INDEX_DrvGetModes)
             continue;
-  
+
           GetModes = (PGD_GETMODES)DrvFn->pfn;
-  
+
           /* make sure we have enough memory to hold the modes */
           SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject), 0, NULL);
           if (SizeNeeded <= 0)
@@ -2340,12 +2578,12 @@ IntEnumDisplaySettings(
             DPRINT("DrvGetModes failed for %S\n", CurrentName);
             break;
           }
-          
+
           SizeUsed = CachedDevModesEnd - CachedDevModes;
           if (SizeOfCachedDevModes - SizeUsed < SizeNeeded)
           {
             PVOID NewBuffer;
-            
+
             SizeOfCachedDevModes += SizeNeeded;
             NewBuffer = ExAllocatePool(PagedPool, SizeOfCachedDevModes);
             if (NewBuffer == NULL)
@@ -2370,7 +2608,7 @@ IntEnumDisplaySettings(
             CachedDevModes = NewBuffer;
             CachedDevModesEnd = (DEVMODEW *)((PCHAR)NewBuffer + SizeUsed);
           }
-  
+
           /* query modes */
           SizeNeeded = GetModes((HANDLE)(PrimarySurface.VideoFileObject->DeviceObject),
                                 SizeOfCachedDevModes - SizeUsed,
@@ -2386,12 +2624,12 @@ IntEnumDisplaySettings(
           break;
         }
       }
-      
+
       if (PrimarySurfaceCreated)
       {
         IntDestroyPrimarySurface();
       }
-  
+
       RtlFreeUnicodeString(&DriverFileNames);
     }
 
@@ -2414,24 +2652,239 @@ IntEnumDisplaySettings(
     }
   }
 
-  assert(CachedMode != NULL);
+  ASSERT(CachedMode != NULL);
 
-  Size = OldSize = lpDevMode->dmSize;
+  Size = OldSize = pDevMode->dmSize;
   if (Size > CachedMode->dmSize)
     Size = CachedMode->dmSize;
-  RtlCopyMemory(lpDevMode, CachedMode, Size);
-  RtlZeroMemory((PCHAR)lpDevMode + Size, OldSize - Size);
-  lpDevMode->dmSize = OldSize;
-  
-  Size = OldSize = lpDevMode->dmDriverExtra;
+  RtlCopyMemory(pDevMode, CachedMode, Size);
+  RtlZeroMemory((PCHAR)pDevMode + Size, OldSize - Size);
+  pDevMode->dmSize = OldSize;
+
+  Size = OldSize = pDevMode->dmDriverExtra;
   if (Size > CachedMode->dmDriverExtra)
     Size = CachedMode->dmDriverExtra;
-  RtlCopyMemory((PCHAR)lpDevMode + lpDevMode->dmSize,
+  RtlCopyMemory((PCHAR)pDevMode + pDevMode->dmSize,
                 (PCHAR)CachedMode + CachedMode->dmSize, Size);
-  RtlZeroMemory((PCHAR)lpDevMode + lpDevMode->dmSize + Size, OldSize - Size);
-  lpDevMode->dmDriverExtra = OldSize;
+  RtlZeroMemory((PCHAR)pDevMode + pDevMode->dmSize + Size, OldSize - Size);
+  pDevMode->dmDriverExtra = OldSize;
 
   return TRUE;
 }
+LONG
+FASTCALL
+IntChangeDisplaySettings(
+  IN PUNICODE_STRING pDeviceName  OPTIONAL,
+  IN LPDEVMODEW DevMode,
+  IN DWORD dwflags,
+  IN PVOID lParam  OPTIONAL)
+{
+  BOOLEAN Global = FALSE;
+  BOOLEAN NoReset = FALSE;
+  BOOLEAN Reset = FALSE;
+  BOOLEAN SetPrimary = FALSE;
+  LONG Ret=0;
+  NTSTATUS Status ;
+
+  DPRINT1("display flag : %x\n",dwflags);
+
+  if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
+  {
+    /* Check global, reset and noreset flags */
+    if ((dwflags & CDS_GLOBAL) == CDS_GLOBAL)
+      Global = TRUE;
+    if ((dwflags & CDS_NORESET) == CDS_NORESET)
+      NoReset = TRUE;
+    dwflags &= ~(CDS_GLOBAL | CDS_NORESET);
+  }
+  if ((dwflags & CDS_RESET) == CDS_RESET)
+    Reset = TRUE;
+  if ((dwflags & CDS_SET_PRIMARY) == CDS_SET_PRIMARY)
+    SetPrimary = TRUE;
+  dwflags &= ~(CDS_RESET | CDS_SET_PRIMARY);
+
+  if (Reset && NoReset)
+    return DISP_CHANGE_BADFLAGS;
+
+  if (dwflags == 0)
+  {
+   /* Dynamically change graphics mode */
+   DPRINT1("flag 0 UNIMPLEMENT \n");
+   return DISP_CHANGE_FAILED;
+  }
+
+  if ((dwflags & CDS_TEST) == CDS_TEST)
+  {
+   /* Test reslution */
+   dwflags &= ~CDS_TEST;
+   DPRINT1("flag CDS_TEST UNIMPLEMENT");
+   Ret = DISP_CHANGE_FAILED;
+  }
+  
+  if ((dwflags & CDS_FULLSCREEN) == CDS_FULLSCREEN)
+  {
+   DEVMODE lpDevMode;
+   /* Full Screen */
+   dwflags &= ~CDS_FULLSCREEN;
+   DPRINT1("flag CDS_FULLSCREEN partially implemented");
+   Ret = DISP_CHANGE_FAILED;
+
+   lpDevMode.dmBitsPerPel =0;
+   lpDevMode.dmPelsWidth  =0;
+   lpDevMode.dmPelsHeight =0;
+   lpDevMode.dmDriverExtra =0;
+
+   lpDevMode.dmSize = sizeof(DEVMODE);
+   Status = IntEnumDisplaySettings(pDeviceName,  ENUM_CURRENT_SETTINGS, &lpDevMode, 0);
+   if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED;
+
+   DPRINT1("Req Mode     : %d x %d x %d\n", DevMode->dmPelsWidth,DevMode->dmPelsHeight,DevMode->dmBitsPerPel);
+   DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode.dmPelsWidth,lpDevMode.dmPelsHeight, lpDevMode.dmBitsPerPel);
+
+
+   if ((lpDevMode.dmBitsPerPel == DevMode->dmBitsPerPel) &&
+       (lpDevMode.dmPelsWidth  == DevMode->dmPelsWidth) &&
+       (lpDevMode.dmPelsHeight == DevMode->dmPelsHeight))
+          Ret = DISP_CHANGE_SUCCESSFUL; 
+  }
+
+  if ((dwflags & CDS_VIDEOPARAMETERS) == CDS_VIDEOPARAMETERS)
+  {  
+    dwflags &= ~CDS_VIDEOPARAMETERS;
+    if (lParam == NULL) Ret=DISP_CHANGE_BADPARAM;
+       else
+       {
+               DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENT");
+               Ret = DISP_CHANGE_FAILED;
+       }
+
+  }    
+
+  if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY)
+  {  
+  
+               UNICODE_STRING ObjectName;
+               UNICODE_STRING KernelModeName;
+               WCHAR KernelModeNameBuffer[256];
+               UNICODE_STRING RegistryKey;
+               WCHAR RegistryKeyBuffer[512];
+               PDEVICE_OBJECT DeviceObject;            
+               ULONG LastSlash;
+               OBJECT_ATTRIBUTES ObjectAttributes;
+               HANDLE DevInstRegKey;
+               ULONG NewValue;
+               
+
+               DPRINT1("set CDS_UPDATEREGISTRY \n");
+               
+               dwflags &= ~CDS_UPDATEREGISTRY; 
+
+               /* Get device name (pDeviceName is "\.\xxx") */
+               for (LastSlash = pDeviceName->Length / sizeof(WCHAR); LastSlash > 0; LastSlash--)
+               {
+                       if (pDeviceName->Buffer[LastSlash - 1] == L'\\')
+                               break;
+               }
+               
+               if (LastSlash == 0) return DISP_CHANGE_RESTART;
+               ObjectName = *pDeviceName;
+               ObjectName.Length -= LastSlash * sizeof(WCHAR);
+               ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR);
+               ObjectName.Buffer += LastSlash;
+
+               KernelModeName.Length = 0;
+               KernelModeName.MaximumLength = sizeof(KernelModeNameBuffer);
+               KernelModeName.Buffer = KernelModeNameBuffer;
+
+               /* Open \??\xxx (ex: "\??\DISPLAY1") */
+               Status = RtlAppendUnicodeToString(&KernelModeName, L"\\??\\");
+               
+               if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED;
+               Status = RtlAppendUnicodeStringToString(&KernelModeName, &ObjectName);
+               
+               if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED;
+               Status = ObReferenceObjectByName(
+                       &KernelModeName,
+                       OBJ_CASE_INSENSITIVE,
+                       NULL,
+                       0,
+                       IoDeviceObjectType,
+                       KernelMode,
+                       NULL,
+                       (PVOID*)&DeviceObject);
+
+               if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED;
+               /* Get associated driver name (ex: "VBE") */
+               for (LastSlash = DeviceObject->DriverObject->DriverName.Length / sizeof(WCHAR); LastSlash > 0; LastSlash--)
+               {
+                       if (DeviceObject->DriverObject->DriverName.Buffer[LastSlash - 1] == L'\\')
+                               break;
+               }
+
+               if (LastSlash == 0) { ObDereferenceObject(DeviceObject); return DISP_CHANGE_FAILED; }
+               ObjectName = DeviceObject->DriverObject->DriverName;
+               ObjectName.Length -= LastSlash * sizeof(WCHAR);
+               ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR);
+               ObjectName.Buffer += LastSlash;
+
+               RegistryKey.Length = 0;
+               RegistryKey.MaximumLength = sizeof(RegistryKeyBuffer);
+               RegistryKey.Buffer = RegistryKeyBuffer;
+
+               /* Open registry key */
+               Status = RtlAppendUnicodeToString(&RegistryKey,
+                       L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\");
+               
+               if (!NT_SUCCESS(Status)) { ObDereferenceObject(DeviceObject); return DISP_CHANGE_FAILED; }
+               Status = RtlAppendUnicodeStringToString(&RegistryKey, &ObjectName);
+
+               if (!NT_SUCCESS(Status)) { ObDereferenceObject(DeviceObject); return DISP_CHANGE_FAILED; }
+               Status = RtlAppendUnicodeToString(&RegistryKey,
+                       L"\\Device0");
+
+               if (!NT_SUCCESS(Status)) { ObDereferenceObject(DeviceObject); return DISP_CHANGE_FAILED; }
+
+               InitializeObjectAttributes(&ObjectAttributes, &RegistryKey,
+                       OBJ_CASE_INSENSITIVE, NULL, NULL);
+               Status = ZwOpenKey(&DevInstRegKey, GENERIC_READ | GENERIC_WRITE, &ObjectAttributes);
+               ObDereferenceObject(DeviceObject);
+               if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED;
+
+               /* Update needed fields */
+               if (NT_SUCCESS(Status) && DevMode->dmFields & DM_BITSPERPEL)
+               {
+                       RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.BitsPerPel");
+                       NewValue = DevMode->dmBitsPerPel;
+                       Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));                 
+               }
+
+               if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSWIDTH)
+               {
+                       RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.XResolution");
+                       NewValue = DevMode->dmPelsWidth;                        
+                       Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));                 
+               }
+
+               if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSHEIGHT)
+               {
+                       RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.YResolution");
+                       NewValue = DevMode->dmPelsHeight;
+                       Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue));                 
+               }
+
+               ZwClose(DevInstRegKey);
+               if (NT_SUCCESS(Status))
+                       Ret = DISP_CHANGE_RESTART;
+               else
+                       /* return DISP_CHANGE_NOTUPDATED when we can save to reg only vaild for NT */ 
+                       Ret = DISP_CHANGE_NOTUPDATED;
+               
+    }
+ if (dwflags != 0)  
+    Ret = DISP_CHANGE_BADFLAGS;
+
+  return Ret;
+}
 
 /* EOF */