diff --git a/win32ss/gdi/eng/stubs.c b/win32ss/gdi/eng/stubs.c
index 8a91c86ff5..d76ddf5d64 100644
--- a/win32ss/gdi/eng/stubs.c
+++ b/win32ss/gdi/eng/stubs.c
@@ -889,34 +889,6 @@ NtGdiDeleteColorTransform(
     return FALSE;
 }
 
-/*
- * @unimplemented
- */
-ULONG
-APIENTRY
-NtGdiGetPerBandInfo(
-    IN HDC hdc,
-    IN OUT PERBANDINFO *ppbi)
-{
-    UNIMPLEMENTED;
-    return 0;
-}
-
-/*
- * @unimplemented
- */
-BOOL
-APIENTRY
-NtGdiDoBanding(
-    IN HDC hdc,
-    IN BOOL bStart,
-    OUT POINTL *pptl,
-    OUT PSIZE pSize)
-{
-    UNIMPLEMENTED;
-    return FALSE;
-}
-
 /*
  * @unimplemented
  */
diff --git a/win32ss/gdi/ntgdi/dc.h b/win32ss/gdi/ntgdi/dc.h
index b72ea21439..5fad510289 100644
--- a/win32ss/gdi/ntgdi/dc.h
+++ b/win32ss/gdi/ntgdi/dc.h
@@ -53,7 +53,7 @@ typedef struct _DCLEVEL
   PVOID             pColorSpace; /* COLORSPACE* */
   LONG              lIcmMode;
   LONG              lSaveDepth;
-  DWORD             unk1_00000000;
+  LONG              lSaveDepthStartDoc;
   HGDIOBJ           hdcSave;
   POINTL            ptlBrushOrigin;
   PBRUSH            pbrFill;
diff --git a/win32ss/gdi/ntgdi/print.c b/win32ss/gdi/ntgdi/print.c
index 582bfcac1c..b5b9652a66 100644
--- a/win32ss/gdi/ntgdi/print.c
+++ b/win32ss/gdi/ntgdi/print.c
@@ -11,278 +11,566 @@
 #define NDEBUG
 #include <debug.h>
 
+
+static
+VOID
+DC_Pop_Locks(PDC pdc)
+{
+    PDEVOBJ_vReference(pdc->ppdev);
+    SURFACE_ShareLockByPointer(pdc->dclevel.pSurface);
+    /* Lock and update first DC */
+    if (pdc->dctype == DCTYPE_DIRECT)
+    {
+        EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
+    }
+    GDIOBJ_vUnlockObject(&pdc->BaseObject);
+}
+
+static
+VOID
+DC_Push_Locks(PDC pdc)
+{
+    GDIOBJ_LockObject(pdc->BaseObject.hHmgr, GDIObjType_DC_TYPE);
+    if (pdc->dctype == DCTYPE_DIRECT)
+    {
+        EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
+    }
+    SURFACE_ShareUnlockSurface(pdc->dclevel.pSurface);
+    PDEVOBJ_vRelease(pdc->ppdev);
+}
+
+BOOL
+APIENTRY
+IntEndDoc(
+    HDC  hDC,
+    DWORD doAbort
+)
+{
+    PPDEVOBJ ppdev;
+    PDC pdc;
+    INT Ret = FALSE;
+
+    pdc = DC_LockDc(hDC);
+    if (pdc == NULL)
+    {
+        EngSetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    if ( !pdc->dclevel.pSurface ||
+         !(ppdev = pdc->ppdev)  ||
+          ppdev->flFlags & PDEV_DISPLAY ||
+         !ppdev->hSpooler )
+    {
+        if (pdc) DC_UnlockDc( pdc );
+        EngSetLastError(ERROR_CAN_NOT_COMPLETE);
+        return FALSE;
+    }
+
+    if ( pdc->dclevel.lSaveDepth > pdc->dclevel.lSaveDepthStartDoc )
+    {
+        DC_vRestoreDC( pdc, pdc->dclevel.lSaveDepthStartDoc );
+    }
+
+    if (ppdev->DriverFunctions.EndDoc)
+    {
+        SURFOBJ *pSurfObj = &pdc->dclevel.pSurface->SurfObj;
+
+        Ret = ppdev->DriverFunctions.EndDoc(pSurfObj, doAbort);
+    }
+
+    pdc->dclevel.pSurface = NULL; // This DC has no surface (empty mem or info DC).
+    pdc->ipfdDevMax = -1;
+
+    PDEVOBJ_vRelease(ppdev);
+
+    DC_UnlockDc( pdc );
+    return Ret;
+
+}
+
 INT
 APIENTRY
 NtGdiAbortDoc(HDC  hDC)
 {
-  UNIMPLEMENTED;
-  return 0;
+    return IntEndDoc(hDC, ED_ABORTDOC);
 }
 
-INT
+/*
+ * @implemented
+ */
+BOOL
 APIENTRY
-NtGdiEndDoc(HDC  hDC)
+NtGdiDoBanding(
+    IN HDC hdc,
+    IN BOOL bStart,
+    OUT POINTL *pptl,
+    OUT PSIZE pSize)
 {
-  UNIMPLEMENTED;
-  return 0;
+    PPDEVOBJ ppdev;
+    PDC pdc;
+    SURFOBJ *pSurfObj;
+    POINTL ptlSafe;
+    SIZEL sizeSafe;
+    INT Ret = FALSE;
+
+    pdc = DC_LockDc(hdc);
+    if ( !pdc                   ||
+         !pdc->dclevel.pSurface ||
+         !(ppdev = pdc->ppdev)  ||
+         !ppdev->hSpooler       ||
+         !(pdc->dclevel.pSurface->flags & BANDING_SURFACE) )
+    {
+        if (pdc) DC_UnlockDc(pdc);
+        return FALSE;
+    }
+
+    pSurfObj = &pdc->dclevel.pSurface->SurfObj;
+
+    if (bStart)
+    {
+        Ret = ppdev->DriverFunctions.StartBanding( pSurfObj, &ptlSafe );
+        sizeSafe.cx = pSurfObj->sizlBitmap.cx;
+        sizeSafe.cy = pSurfObj->sizlBitmap.cy;
+        pdc->ptlDoBanding.x = ptlSafe.x;
+        pdc->ptlDoBanding.y = ptlSafe.y;
+    }
+    else
+    {
+        Ret = ppdev->DriverFunctions.NextBand( pSurfObj, &ptlSafe );
+        if (Ret)
+        {
+            if ( ptlSafe.x == -1 &&          // physical page's bands have been drawn.
+                 ppdev->flFlags & PDEV_UMPD )
+            {
+                pdc->fs &= ~DC_RESET;
+                if (pdc->dclevel.pSurface->pWinObj)
+                {
+                    EngDeleteWnd((WNDOBJ *)pdc->dclevel.pSurface->pWinObj); // See UserGethWnd.
+                    pdc->dclevel.pSurface->pWinObj = NULL;
+                }
+                pdc->ipfdDevMax = 0;
+            }
+            else
+            {
+                pdc->ptlDoBanding.x = ptlSafe.x;
+                pdc->ptlDoBanding.y = ptlSafe.y;
+            }
+        }
+    }
+    if (Ret)
+    {
+        _SEH2_TRY
+        {
+            ProbeForWrite(pptl, sizeof(POINT), 1);
+            *pptl = ptlSafe;
+
+            ProbeForWrite(pSize, sizeof(SIZE), 1);
+            *pSize = sizeSafe;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Ret = FALSE;
+        }
+        _SEH2_END;
+    }
+    DC_UnlockDc(pdc);
+    return Ret;
 }
 
 INT
 APIENTRY
-NtGdiEndPage(HDC  hDC)
+NtGdiEndDoc(HDC  hDC)
 {
-  UNIMPLEMENTED;
-  return 0;
+  return IntEndDoc(hDC, 0);
 }
 
 INT
-FASTCALL
-IntGdiEscape(PDC    dc,
-             INT    Escape,
-             INT    InSize,
-             LPCSTR InData,
-             LPVOID OutData)
+APIENTRY
+NtGdiEndPage(HDC  hDC)
 {
-  if (Escape == QUERYESCSUPPORT)
-    return FALSE;
-
-  UNIMPLEMENTED;
-  return SP_ERROR;
+    PPDEVOBJ ppdev;
+    PDC pdc;
+    INT Ret = 0;
+
+    pdc = DC_LockDc(hDC);
+    if (!pdc || !pdc->dclevel.pSurface)
+    {
+        if (pdc) DC_UnlockDc(pdc);
+        EngSetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+
+    if ( (ppdev = pdc->ppdev) && !(ppdev->flFlags & PDEV_DISPLAY) )
+    {
+        if ( ppdev->flFlags & PDEV_UMPD &&
+             ppdev->hSpooler &&
+             ppdev->DriverFunctions.SendPage)
+        {
+           SURFOBJ *pSurfObj = &pdc->dclevel.pSurface->SurfObj;
+
+           if (ppdev->DriverFunctions.SendPage(pSurfObj))
+           {
+               pdc->fs &= ~DC_RESET;
+               if (pdc->dclevel.pSurface->pWinObj)
+               {
+                  EngDeleteWnd((WNDOBJ *)pdc->dclevel.pSurface->pWinObj); // See UserGethWnd.
+                  pdc->dclevel.pSurface->pWinObj = NULL;
+               }
+               pdc->ipfdDevMax = -1;
+               Ret = 1;
+           }
+        }
+    }
+    DC_UnlockDc(pdc);
+    return Ret;
 }
 
 INT
 APIENTRY
-NtGdiEscape(HDC  hDC,
-            INT  Escape,
-            INT  InSize,
-            LPCSTR  InData,
-            LPVOID  OutData)
+IntExtEscape(
+    PDC    pdc,
+    INT    iEsc,
+    INT    cjIn,
+    LPSTR  pjIn,
+    INT    cjOut,
+    LPSTR  pjOut
+)
 {
-  PDC dc;
-  INT ret;
-
-  dc = DC_LockDc(hDC);
-  if (dc == NULL)
+    INT ret;
+    PPDEVOBJ ppdev;
+    BOOL bQOGLGI = FALSE;
   {
-    EngSetLastError(ERROR_INVALID_HANDLE);
-    return SP_ERROR;
+    SURFACE *psurf;
+    INT Result;
+
+    if ((pdc->ppdev->DriverFunctions.Escape == NULL) ||
+        (pdc->dclevel.pSurface == NULL))
+    {
+       Result = 0;
+    }
+    else
+    {
+       DC_vPrepareDCsForBlit(pdc, NULL, NULL, NULL);
+       psurf = pdc->dclevel.pSurface;
+
+       Result = pdc->ppdev->DriverFunctions.Escape(
+          &psurf->SurfObj,
+          iEsc,
+          cjIn,
+          pjIn,
+          cjOut,
+          pjOut );
+
+       DC_vFinishBlit(pdc, NULL);
+    }
+    return Result;
   }
 
-  /* TODO: FIXME: Don't pass umode buffer to an Int function */
-  ret = IntGdiEscape(dc, Escape, InSize, InData, OutData);
+    if ( iEsc == QUERYESCSUPPORT && cjIn < sizeof(ULONG) )
+        return 0;
+
+    if ( iEsc == QUERYESCSUPPORT )
+    {
+         DWORD dwIn = *(PDWORD)pjIn;
 
-  DC_UnlockDc( dc );
-  return ret;
+         if ( dwIn == OPENGL_GETINFO || dwIn == OPENGL_CMD )
+         {
+             DPRINT1("QUERYESCSUPPORT OPENGL_GETINFO or OPENGL_CMD\n");
+             bQOGLGI = TRUE;
+         }
+    } 
+
+    ppdev = pdc->ppdev;
+
+    if ( !ppdev || !ppdev->DriverFunctions.Escape )
+        return 0;
+
+    // Fix part of CORE-16465.
+    if ( bQOGLGI || iEsc == OPENGL_CMD || iEsc == OPENGL_GETINFO )
+    {
+        if ( pdc->dctype != DCTYPE_DIRECT /*|| ppdev->DxDd_Flags & */ ) // Not Direct or DxDD
+            return 0;
+
+        DPRINT1("OPENGL_GETINFO or OPENGL_CMD\n");
+        ret = ppdev->DriverFunctions.Escape( &pdc->dclevel.pSurface->SurfObj, iEsc, cjIn, pjIn, cjOut, pjOut );
+
+        return ret;
+    }
+
+    if ( iEsc == DCICOMMAND )
+    {
+        return 0;
+    }
+
+    if ( iEsc == WNDOBJ_SETUP )
+    {
+        if ( pdc->dctype != DCTYPE_DIRECT ) return 0;
+
+        ret = ppdev->DriverFunctions.Escape( &pdc->dclevel.pSurface->SurfObj, iEsc, cjIn, pjIn, cjOut, pjOut );
+        // FIXME: Do EWndObj stuff. See eng/engwindow.c.
+        /*if ( gbWndobjUpdate )
+        {
+            gbWndobjUpdate = 0;
+            //Force a Client Region Update
+        }*/
+        return ret;
+    }
+
+    if ( !pdc->dclevel.pSurface && cjIn > sizeof(WORD) )
+    {
+        SURFOBJ sTemp;
+
+        RtlZeroMemory( &sTemp, sizeof(SURFACE) );
+
+        sTemp.hdev = (HDEV)ppdev;
+        sTemp.dhpdev = pdc->dhpdev;
+        sTemp.iType = STYPE_DEVICE;
+
+        switch ( iEsc )
+        {
+            case SETCOPYCOUNT:
+            {
+                pdc->ulCopyCount = (*(PUSHORT)pjIn); // Save copy count in DC
+
+                return ppdev->DriverFunctions.Escape( &sTemp, iEsc, cjIn, pjIn, cjOut, pjOut );
+            }
+
+            case EPSPRINTING:
+            {
+                if ((*(PUSHORT)pjIn))
+                {
+                   pdc->fs |= DC_EPSPRINTINGESCAPE;
+                }
+                else
+                {
+                   pdc->fs &= ~DC_EPSPRINTINGESCAPE;
+                }
+                return 1;
+            }
+
+            default:
+                return 0; // Must have a surface!
+        }
+    }
+
+    if (!pdc->dclevel.pSurface)
+    {
+        return 0;
+    }
+
+    // Have a surface. So fall through.
+
+    DPRINT1("ExtEscape Code %d\n",iEsc);
+    DC_Pop_Locks(pdc);
+    ret = ppdev->DriverFunctions.Escape( &pdc->dclevel.pSurface->SurfObj, iEsc, cjIn, pjIn, cjOut, pjOut );
+    DC_Push_Locks(pdc);
+    return ret;
+}
+
+INT
+APIENTRY
+IntNameExtEscape(
+    PWCHAR pDriver,
+    INT    iEsc,
+    INT    cjIn,
+    LPSTR  pjIn,
+    INT    cjOut,
+    LPSTR  pjOut
+)
+{
+    PPDEVOBJ ppdev;
+    UNICODE_STRING usDriver;
+    WCHAR awcBuffer[MAX_PATH];
+    RtlInitEmptyUnicodeString(&usDriver, awcBuffer, sizeof(awcBuffer));
+    RtlAppendUnicodeToString(&usDriver, L"\\SystemRoot\\System32\\");
+    RtlAppendUnicodeToString(&usDriver, pDriver);
+
+    ppdev = EngpGetPDEV(&usDriver);
+    if ( ppdev && ppdev->DriverFunctions.Escape )
+    {
+       return ppdev->DriverFunctions.Escape( &ppdev->pSurface->SurfObj, iEsc, cjIn, pjIn, cjOut, pjOut );
+    }
+    return 0;
 }
 
 INT
 APIENTRY
 NtGdiExtEscape(
-   HDC    hDC,
-   IN OPTIONAL PWCHAR pDriver,
-   IN INT nDriver,
-   INT    Escape,
-   INT    InSize,
-   OPTIONAL LPSTR UnsafeInData,
-   INT    OutSize,
-   OPTIONAL LPSTR  UnsafeOutData)
+    _In_opt_ HDC hdc,
+    _In_reads_opt_(cwcDriver) PWCHAR pDriver,
+    _In_ INT cwcDriver,
+    _In_ INT iEsc,
+    _In_ INT cjIn,
+    _In_reads_bytes_opt_(cjIn) LPSTR pjIn,
+    _In_ INT cjOut,
+    _Out_writes_bytes_opt_(cjOut) LPSTR pjOut
+)
 {
-   LPVOID   SafeInData = NULL;
-   LPVOID   SafeOutData = NULL;
-   NTSTATUS Status = STATUS_SUCCESS;
-   INT      Result;
-   PPDEVOBJ ppdev;
-   PSURFACE psurf;
-
-   if (hDC == NULL)
+    PDC pdc;
+    LPSTR SafeInData = NULL;
+    LPSTR SafeOutData = NULL;
+    PWCHAR psafeDriver = NULL;
+    INT Ret = 0;
+
+    if ( pDriver )
+    {
+        psafeDriver = ExAllocatePoolWithTag( PagedPool, (cwcDriver + 1) * sizeof(WCHAR), GDITAG_TEMP );
+        RtlZeroMemory( psafeDriver, (cwcDriver + 1) * sizeof(WCHAR) );
+    }
+
+    if ( cjIn )
+    {
+       SafeInData = ExAllocatePoolWithTag( PagedPool, cjIn + 1, GDITAG_TEMP );
+    }
+
+    if ( cjOut )
+    {
+       SafeOutData = ExAllocatePoolWithTag( PagedPool, cjOut + 1, GDITAG_TEMP );
+    }
+
+    _SEH2_TRY
+    {
+        if ( psafeDriver )
+        {
+            ProbeForRead(pDriver, cwcDriver * sizeof(WCHAR), 1);
+            RtlCopyMemory(psafeDriver, pDriver, cwcDriver * sizeof(WCHAR));
+        }
+        if ( SafeInData )
+        {
+            ProbeForRead(pjIn, cjIn, 1);
+            RtlCopyMemory(SafeInData, pjIn, cjIn);
+        }
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        SetLastNtError(_SEH2_GetExceptionCode());
+        _SEH2_YIELD(goto Exit);
+    }
+    _SEH2_END;
+
+
+   if ( pDriver )
    {
-      if (pDriver)
-      {
-         /* FIXME : Get the pdev from its name */
-         UNIMPLEMENTED;
-         return -1;
-      }
-
-      ppdev = EngpGetPDEV(NULL);
-      if (!ppdev)
-      {
-         EngSetLastError(ERROR_BAD_DEVICE);
-         return -1;
-      }
-
-      /* We're using the primary surface of the pdev. Lock it */
-      EngAcquireSemaphore(ppdev->hsemDevLock);
-
-      psurf = ppdev->pSurface;
-      if (!psurf)
-      {
-         EngReleaseSemaphore(ppdev->hsemDevLock);
-         PDEVOBJ_vRelease(ppdev);
-         return 0;
-      }
-      SURFACE_ShareLockByPointer(psurf);
+       Ret = IntNameExtEscape( psafeDriver, iEsc, cjIn, SafeInData, cjOut, SafeOutData );
    }
    else
    {
-      PDC pDC = DC_LockDc(hDC);
-      if ( pDC == NULL )
-      {
-         EngSetLastError(ERROR_INVALID_HANDLE);
-         return -1;
-      }
-
-      /* Get the PDEV from the DC */
-      ppdev = pDC->ppdev;
-      PDEVOBJ_vReference(ppdev);
-
-      /* Check if we have a surface */
-      psurf = pDC->dclevel.pSurface;
-      if (!psurf)
-      {
-         DC_UnlockDc(pDC);
-         PDEVOBJ_vRelease(ppdev);
-         return 0;
-      }
-      SURFACE_ShareLockByPointer(psurf);
-
-      /* We're done with the DC */
-      DC_UnlockDc(pDC);
-   }
-
-   /* See if we actually have a driver function to call */
-   if (ppdev->DriverFunctions.Escape == NULL)
-   {
-      Result = 0;
-      goto Exit;
-   }
-
-   if ( InSize && UnsafeInData )
-   {
-      _SEH2_TRY
-      {
-        ProbeForRead(UnsafeInData,
-                     InSize,
-                     1);
-      }
-      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-      {
-        Status = _SEH2_GetExceptionCode();
-      }
-      _SEH2_END;
-
-      if (!NT_SUCCESS(Status))
-      {
-         Result = -1;
-         goto Exit;
-      }
-
-      SafeInData = ExAllocatePoolWithTag ( PagedPool, InSize, GDITAG_TEMP );
-      if ( !SafeInData )
-      {
-         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-         Result = -1;
-         goto Exit;
-      }
-
-      _SEH2_TRY
-      {
-        /* Pointers were already probed! */
-        RtlCopyMemory(SafeInData,
-                      UnsafeInData,
-                      InSize);
-      }
-      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-      {
-        Status = _SEH2_GetExceptionCode();
-      }
-      _SEH2_END;
-
-      if ( !NT_SUCCESS(Status) )
-      {
-         SetLastNtError(Status);
-         Result = -1;
-         goto Exit;
-      }
-   }
-
-   if ( OutSize && UnsafeOutData )
-   {
-      _SEH2_TRY
-      {
-        ProbeForWrite(UnsafeOutData,
-                      OutSize,
-                      1);
-      }
-      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-      {
-        Status = _SEH2_GetExceptionCode();
-      }
-      _SEH2_END;
-
-      if (!NT_SUCCESS(Status))
-      {
-         SetLastNtError(Status);
-         Result = -1;
-         goto Exit;
-      }
-
-      SafeOutData = ExAllocatePoolWithTag ( PagedPool, OutSize, GDITAG_TEMP );
-      if ( !SafeOutData )
-      {
-         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-         Result = -1;
-         goto Exit;
-      }
-   }
-
-   /* Finally call the driver */
-   Result = ppdev->DriverFunctions.Escape(
-         &psurf->SurfObj,
-         Escape,
-         InSize,
-         SafeInData,
-         OutSize,
-         SafeOutData );
-
-Exit:
-   if (hDC == NULL)
-   {
-      EngReleaseSemaphore(ppdev->hsemDevLock);
-   }
-   SURFACE_ShareUnlockSurface(psurf);
-   PDEVOBJ_vRelease(ppdev);
+       pdc = DC_LockDc(hdc);
+       if ( pdc )
+       {
+           Ret = IntExtEscape( pdc, iEsc, cjIn, SafeInData, cjOut, SafeOutData );
 
-   if ( SafeInData )
-   {
-      ExFreePoolWithTag ( SafeInData ,GDITAG_TEMP );
+           DC_UnlockDc(pdc);
+       }
    }
 
-   if ( SafeOutData )
+   if ( Ret )
    {
-      if (Result > 0)
+      if ( SafeOutData )
       {
          _SEH2_TRY
          {
-            /* Pointers were already probed! */
-            RtlCopyMemory(UnsafeOutData, SafeOutData, OutSize);
+            ProbeForWrite(pjOut, cjOut, 1);
+            RtlCopyMemory(pjOut, SafeOutData, cjOut);
          }
          _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
          {
-            Status = _SEH2_GetExceptionCode();
+            SetLastNtError(_SEH2_GetExceptionCode());
+            Ret = 0;
          }
          _SEH2_END;
-
-         if ( !NT_SUCCESS(Status) )
-         {
-            SetLastNtError(Status);
-            Result = -1;
-         }
       }
-
-      ExFreePoolWithTag ( SafeOutData, GDITAG_TEMP );
    }
+Exit:
+   if ( psafeDriver ) ExFreePoolWithTag ( psafeDriver, GDITAG_TEMP );
+   if ( SafeInData ) ExFreePoolWithTag ( SafeInData, GDITAG_TEMP );
+   if ( SafeOutData ) ExFreePoolWithTag ( SafeOutData, GDITAG_TEMP );
 
-   return Result;
+   return Ret;
+}
+
+
+INT
+APIENTRY
+IntStartDoc(
+    IN HDC hdc,
+    IN DOCINFOW *pdi,
+    OUT BOOL *pbBanding,
+    IN INT iJob)
+{
+    PPDEVOBJ ppdev;
+    PDC pdc;
+    SURFOBJ *pSurfObj;
+    INT Ret = 0;
+
+    pdc = DC_LockDc(hdc);
+    if ( !pdc                   ||
+          pdc->dclevel.pSurface ||
+          pdc->dctype           ||
+         !(ppdev = pdc->ppdev)  ||
+         !ppdev->hSpooler       ||
+          (ppdev->flFlags & PDEV_DISPLAY) ||
+         !(ppdev->flFlags & PDEV_UMPD) )
+    {
+        if (pdc) DC_UnlockDc(pdc);
+        return FALSE;
+    }
+
+    if ( !(pdc->dclevel.pSurface = PDEVOBJ_pSurface( ppdev )) )
+    {
+        DC_UnlockDc(pdc);
+        return FALSE;
+    }
+
+    if ( pdc->dclevel.pSurface )
+    {
+        pdc->dclevel.sizl.cx = ppdev->pSurface->SurfObj.sizlBitmap.cx;
+        pdc->dclevel.sizl.cy = ppdev->pSurface->SurfObj.sizlBitmap.cy;
+        IntSetDefaultRegion(pdc);
+    }
+
+    pSurfObj = &pdc->dclevel.pSurface->SurfObj;
+
+    *pbBanding = !!(pdc->dclevel.pSurface->flags & BANDING_SURFACE);
+
+    Ret = ppdev->pfn.StartDoc(pSurfObj, (LPWSTR)pdi->lpszDocName, iJob );
+
+    if (  pdc->ulCopyCount != -1 )
+    {
+        ULONG ulCopyCount = pdc->ulCopyCount;
+
+        IntExtEscape( pdc,
+                      SETCOPYCOUNT,
+                      sizeof(ULONG),
+                      (LPSTR)&ulCopyCount,
+                      0,
+                      NULL );
+
+        pdc->ulCopyCount = -1;
+    }
+
+    if ( pdc->fs & DC_EPSPRINTINGESCAPE )
+    {
+        WORD Temp = 1;
+
+        IntExtEscape( pdc,
+                      EPSPRINTING,
+                      sizeof(WORD),
+                      (LPSTR)&Temp,
+                      0,
+                      NULL );
+
+        pdc->fs &= ~DC_EPSPRINTINGESCAPE;
+    }
+
+    if ( Ret )
+    {
+        pdc->dclevel.lSaveDepthStartDoc = pdc->dclevel.lSaveDepth;
+    }
+
+    DC_UnlockDc(pdc);
+    return Ret;
 }
 
 INT
@@ -293,15 +581,199 @@ NtGdiStartDoc(
     OUT BOOL *pbBanding,
     IN INT iJob)
 {
-  UNIMPLEMENTED;
-  return 0;
+   DOCINFOW diSafe;
+   BOOL bBanding;
+   INT size, Ret = 0;
+
+   diSafe.cbSize = 0;
+   diSafe.lpszDocName = NULL;
+   diSafe.lpszOutput = NULL; 
+   diSafe.lpszDatatype = NULL;
+   diSafe.fwType = 0;
+
+   if ( pdi )
+   {
+       _SEH2_TRY
+       {
+           ProbeForRead(pdi, sizeof(DOCINFOW), 1);
+           diSafe.cbSize = pdi->cbSize;
+           diSafe.fwType = pdi->fwType;
+
+           if ( pdi->lpszDocName )
+           {
+               size = (wcslen(pdi->lpszDocName) + 1) * sizeof(WCHAR);
+
+               diSafe.lpszDocName = (LPCWSTR)ExAllocatePoolWithTag(PagedPool, size, GDITAG_TEMP);
+
+               RtlCopyMemory((PVOID)diSafe.lpszDocName, (PVOID)pdi->lpszDocName, size);
+           }
+           if ( pdi->lpszOutput )
+           {
+               size = (wcslen(pdi->lpszOutput) + 1) * sizeof(WCHAR);
+
+               diSafe.lpszOutput = (LPCWSTR)ExAllocatePoolWithTag(PagedPool, size, GDITAG_TEMP);
+
+               RtlCopyMemory((PVOID)diSafe.lpszOutput, (PVOID)pdi->lpszOutput, size);
+           }
+           if ( pdi->lpszDatatype )
+           {
+               size = (wcslen(pdi->lpszDatatype) + 1) * sizeof(WCHAR);
+
+               diSafe.lpszDatatype = (LPCWSTR)ExAllocatePoolWithTag(PagedPool, size, GDITAG_TEMP);
+
+               RtlCopyMemory((PVOID)diSafe.lpszDatatype, (PVOID)pdi->lpszDatatype, size);
+           }
+       }
+       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+       {
+           SetLastNtError(_SEH2_GetExceptionCode());
+           _SEH2_YIELD(goto Exit);
+       }
+       _SEH2_END;
+   }
+
+   Ret = IntStartDoc( hdc, &diSafe, &bBanding, iJob );
+
+   if (Ret)
+   {
+       _SEH2_TRY
+       {
+           ProbeForWrite(pbBanding, sizeof(BOOL), 1);
+           *pbBanding = bBanding;
+       }
+       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+       {
+           SetLastNtError(_SEH2_GetExceptionCode());
+           Ret = FALSE;
+       }
+       _SEH2_END;
+  }
+Exit:
+  if ( diSafe.lpszDocName ) ExFreePoolWithTag((PVOID)diSafe.lpszDocName, GDITAG_TEMP);
+
+  if ( diSafe.lpszOutput ) ExFreePoolWithTag((PVOID)diSafe.lpszOutput, GDITAG_TEMP);
+
+  if ( diSafe.lpszDatatype ) ExFreePoolWithTag((PVOID)diSafe.lpszDatatype, GDITAG_TEMP);
+
+  return Ret;
 }
 
 INT
 APIENTRY
-NtGdiStartPage(HDC  hDC)
+NtGdiStartPage(
+    HDC  hDC
+)
+{
+    PPDEVOBJ ppdev;
+    PDC pdc;
+    INT Ret = 0;
+
+    pdc = DC_LockDc(hDC);
+    if (!pdc || !pdc->dclevel.pSurface)
+    {
+        if (pdc) DC_UnlockDc(pdc);
+        EngSetLastError(ERROR_INVALID_HANDLE);
+        return 0;
+    }
+
+    if ( (ppdev = pdc->ppdev) )
+    {
+        if ( ppdev->flFlags & PDEV_UMPD &&
+             ppdev->hSpooler &&
+             ppdev->DriverFunctions.StartPage )
+        {
+           SURFOBJ *pSurfObj = &pdc->dclevel.pSurface->SurfObj;
+
+           if (ppdev->DriverFunctions.StartPage(pSurfObj))
+           {
+               pdc->fs |= DC_RESET;
+               pdc->ptlDoBanding.x = pdc->ptlDoBanding.y = 0;
+               Ret = 1;
+           }
+           else
+           {
+               DC_UnlockDc(pdc);
+               IntEndDoc(hDC, ED_ABORTDOC);
+               return Ret;
+           }
+        }
+    }
+    DC_UnlockDc(pdc);
+    return Ret;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+APIENTRY
+NtGdiGetPerBandInfo(
+    IN HDC hdc,
+    IN OUT PERBANDINFO *ppbi)
 {
-  UNIMPLEMENTED;
-  return 0;
+    PPDEVOBJ ppdev;
+    PDC pdc;
+    PERBANDINFO pbi;
+    INT Ret = DDI_ERROR;
+
+    _SEH2_TRY
+    {
+        ProbeForRead( ppbi, sizeof(PERBANDINFO), 1 );
+        RtlCopyMemory( &pbi, ppbi, sizeof(PERBANDINFO) );
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        SetLastNtError(_SEH2_GetExceptionCode());
+        _SEH2_YIELD(return Ret);
+    }
+    _SEH2_END;
+
+    pbi.bRepeatThisBand = FALSE;
+
+    pdc = DC_LockDc(hdc);
+    if (!pdc )
+    {
+        EngSetLastError(ERROR_INVALID_HANDLE);
+        return Ret;
+    }
+
+    if ( pdc->dclevel.pSurface && 
+         (ppdev = pdc->ppdev) )
+    {
+        if ( ppdev->hSpooler &&
+             pdc->dclevel.pSurface->flags & BANDING_SURFACE )
+        {
+            if ( ppdev->DriverFunctions.QueryPerBandInfo )
+            {
+                SURFOBJ *pSurfObj = &pdc->dclevel.pSurface->SurfObj;
+
+                Ret = ppdev->DriverFunctions.QueryPerBandInfo(pSurfObj, &pbi);
+            }
+            else
+            {
+                Ret = 0;
+            }
+        }
+    }
+
+    if ( Ret != DDI_ERROR )
+    {
+        _SEH2_TRY
+        {
+            ProbeForWrite( ppbi, sizeof(PERBANDINFO), 1 );
+            RtlCopyMemory( ppbi, &pbi, sizeof(PERBANDINFO) );
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            SetLastNtError(_SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
+    DC_UnlockDc(pdc);
+    return Ret;
 }
+
 /* EOF */
+
+
