Sync with trunk head (r48654)
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Mon, 30 Aug 2010 19:55:47 +0000 (19:55 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Mon, 30 Aug 2010 19:55:47 +0000 (19:55 +0000)
svn path=/branches/reactos-yarotows/; revision=48660

87 files changed:
1  2 
base/applications/network/netstat/netstat.c
dll/ntdll/ldr/utils.c
dll/win32/faultrep/faultrep.rbuild
dll/win32/gdi32/objects/text.c
dll/win32/iphlpapi/iphlpapi_main.c
dll/win32/iphlpapi/iphlpapi_private.h
dll/win32/iphlpapi/registry.c
dll/win32/user32/windows/window.c
drivers/bus/acpi/busmgr/bus.c
drivers/bus/acpi/buspdo.c
drivers/bus/pcix/debug.c
drivers/bus/pcix/enum.c
drivers/bus/pcix/fdo.c
drivers/bus/pcix/pci.h
drivers/bus/pcix/pci/id.c
drivers/bus/pcix/pdo.c
drivers/bus/pcix/utils.c
drivers/filesystems/cdfs/cdfs.c
drivers/filesystems/cdfs/cdfs.h
drivers/filesystems/cdfs/cdfs.rbuild
drivers/filesystems/cdfs/common.c
drivers/filesystems/cdfs/devctrl.c
drivers/filesystems/cdfs/dirctl.c
drivers/filesystems/cdfs/fcb.c
drivers/filesystems/cdfs/fsctl.c
drivers/filesystems/fastfat/create.c
drivers/filesystems/fastfat/direntry.c
drivers/filesystems/fastfat/dirwr.c
drivers/filesystems/fastfat/fcb.c
drivers/filesystems/fastfat/iface.c
drivers/filesystems/fastfat/misc.c
drivers/filesystems/fastfat/pnp.c
drivers/filesystems/fastfat/vfat.h
drivers/filesystems/fastfat/vfatfs.rbuild
drivers/filesystems/fastfat/volume.c
drivers/input/i8042prt/mouse.c
drivers/network/tcpip/datalink/lan.c
drivers/network/tcpip/tcpip/fileobjs.c
drivers/network/tcpip/tcpip/ninfo.c
include/ddk/wdm.h
include/ndk/ldrfuncs.h
include/psdk/ntddvdeo.h
include/psdk/ntdef.h
include/psdk/wingdi.h
include/reactos/mc/bugcodes.mc
include/reactos/win32k/ntgdityp.h
include/xdk/iotypes.h
lib/drivers/ip/transport/tcp/tcp.c
lib/drivers/oskittcp/oskittcp/interface.c
lib/drivers/oskittcp/oskittcp/route.c
lib/drivers/oskittcp/oskittcp/tcp_input.c
lib/drivers/oskittcp/oskittcp/tcp_subr.c
lib/drivers/oskittcp/oskittcp/uipc_socket2.c
ntoskrnl/ex/init.c
ntoskrnl/include/internal/io.h
ntoskrnl/include/internal/mm.h
ntoskrnl/include/internal/po.h
ntoskrnl/io/iomgr/device.c
ntoskrnl/io/iomgr/deviface.c
ntoskrnl/io/iomgr/file.c
ntoskrnl/io/iomgr/iofunc.c
ntoskrnl/io/iomgr/irp.c
ntoskrnl/io/pnpmgr/pnpmgr.c
ntoskrnl/io/pnpmgr/pnpreport.c
ntoskrnl/kdbg/kdb.c
ntoskrnl/mm/ARM3/miarm.h
ntoskrnl/mm/ARM3/mminit.c
ntoskrnl/mm/ARM3/pagfault.c
ntoskrnl/mm/ARM3/pool.c
ntoskrnl/mm/ARM3/procsup.c
ntoskrnl/mm/ARM3/sysldr.c
ntoskrnl/mm/ARM3/vadnode.c
ntoskrnl/po/events.c
ntoskrnl/po/power.c
ntoskrnl/ps/kill.c
ntoskrnl/ps/process.c
subsystems/win32/win32k/eng/mouse.c
subsystems/win32/win32k/include/text.h
subsystems/win32/win32k/ntuser/message.c
subsystems/win32/win32k/ntuser/msgqueue.c
subsystems/win32/win32k/ntuser/timer.c
subsystems/win32/win32k/objects/cliprgn.c
subsystems/win32/win32k/objects/coord.c
subsystems/win32/win32k/objects/font.c
subsystems/win32/win32k/objects/freetype.c
subsystems/win32/win32k/objects/print.c
subsystems/win32/win32k/objects/text.c

Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,b77c04c..b77c04c
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 55e2f78,0000000..02bb965
mode 100644,000000..100644
--- /dev/null
@@@ -1,704 -1,0 +1,718 @@@
-     LONG lDelta;
-     HBITMAP hbmp;
-     RECTL rcl;
 +/*
 + * PROJECT:          ReactOS win32 subsystem
 + * PURPOSE:          Mouse pointer functions
 + * FILE:             subsystems/win32k/eng/mouse.c
 + * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
 + *                   Timo Kreuzer (timo.kreuzer@reactos.org)
 + * REVISION HISTORY:
 + *       06-06-2001  CSH  Created
 + */
 +/* INCLUDES ******************************************************************/
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +/* FUNCTIONS *****************************************************************/
 +
 +BOOL
 +APIENTRY
 +EngSetPointerTag(
 +      IN HDEV hdev,
 +      IN SURFOBJ *psoMask,
 +      IN SURFOBJ *psoColor,
 +      IN XLATEOBJ *pxlo,
 +      IN FLONG fl)
 +{
 +    // This function is obsolete for Windows 2000 and later.
 +    // This function is still supported, but always returns FALSE.
 +    // www.osr.com/ddk/graphics/gdifncs_4yav.htm
 +    return FALSE;
 +}
 +
 +/*
 + * FUNCTION: Notify the mouse driver that drawing is about to begin in
 + * a rectangle on a particular surface.
 + */
 +INT INTERNAL_CALL
 +MouseSafetyOnDrawStart(
 +    PPDEVOBJ ppdev,
 +    LONG HazardX1,
 +    LONG HazardY1,
 +    LONG HazardX2,
 +    LONG HazardY2)
 +{
 +    LONG tmp;
 +    GDIPOINTER *pgp;
 +
 +    ASSERT(ppdev != NULL);
 +    ASSERT(ppdev->pSurface != NULL);
 +
 +    pgp = &ppdev->Pointer;
 +
 +    if (pgp->Exclude.right == -1)
 +    {
 +        return FALSE;
 +    }
 +
 +    ppdev->SafetyRemoveCount++;
 +
 +    if (ppdev->SafetyRemoveLevel != 0)
 +    {
 +        return FALSE;
 +    }
 +
 +    if (HazardX1 > HazardX2)
 +    {
 +        tmp = HazardX2;
 +        HazardX2 = HazardX1;
 +        HazardX1 = tmp;
 +    }
 +    if (HazardY1 > HazardY2)
 +    {
 +        tmp = HazardY2;
 +        HazardY2 = HazardY1;
 +        HazardY1 = tmp;
 +    }
 +
 +    if (pgp->Exclude.right >= HazardX1
 +            && pgp->Exclude.left <= HazardX2
 +            && pgp->Exclude.bottom >= HazardY1
 +            && pgp->Exclude.top <= HazardY2)
 +    {
 +        ppdev->SafetyRemoveLevel = ppdev->SafetyRemoveCount;
 +        ppdev->pfnMovePointer(&ppdev->pSurface->SurfObj, -1, -1, NULL);
 +    }
 +
 +    return(TRUE);
 +}
 +
 +/*
 + * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
 + */
 +INT INTERNAL_CALL
 +MouseSafetyOnDrawEnd(
 +    PPDEVOBJ ppdev)
 +{
 +    GDIPOINTER *pgp;
 +
 +    ASSERT(ppdev != NULL);
 +    ASSERT(ppdev->pSurface != NULL);
 +
 +    pgp = &ppdev->Pointer;
 +
 +    if (pgp->Exclude.right == -1)
 +    {
 +        return FALSE;
 +    }
 +
 +    if (--ppdev->SafetyRemoveCount >= ppdev->SafetyRemoveLevel)
 +    {
 +        return FALSE;
 +    }
 +
 +    ppdev->pfnMovePointer(&ppdev->pSurface->SurfObj, gpsi->ptCursor.x, gpsi->ptCursor.y, &pgp->Exclude);
 +
 +    ppdev->SafetyRemoveLevel = 0;
 +
 +    return(TRUE);
 +}
 +
 +/* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
 +
 +VOID
 +INTERNAL_CALL
 +IntHideMousePointer(
 +    PDEVOBJ *ppdev,
 +    SURFOBJ *psoDest)
 +{
 +    GDIPOINTER *pgp;
 +    POINTL pt;
 +    RECTL rclDest;
 +    POINTL ptlSave;
 +
 +    ASSERT(ppdev);
 +    ASSERT(psoDest);
 +
 +    pgp = &ppdev->Pointer;
 +
 +    if (!pgp->Enabled)
 +    {
 +        return;
 +    }
 +
 +    pgp->Enabled = FALSE;
 +
 +    if (!pgp->psurfSave)
 +    {
 +        DPRINT1("No SaveSurface!\n");
 +        return;
 +    }
 +
 +    /* Calculate cursor coordinates */
 +    pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
 +    pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
 +
 +    rclDest.left = max(pt.x, 0);
 +    rclDest.top = max(pt.y, 0);
 +    rclDest.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
 +    rclDest.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
 +
 +    ptlSave.x = rclDest.left - pt.x;
 +    ptlSave.y = rclDest.top - pt.y;
 +
 +    IntEngBitBlt(psoDest,
 +                   &pgp->psurfSave->SurfObj,
 +                   NULL,
 +                   NULL,
 +                   NULL,
 +                   &rclDest,
 +                   &ptlSave,
 +                   &ptlSave,
 +                   NULL,
 +                   NULL,
 +                   ROP3_TO_ROP4(SRCCOPY));
 +}
 +
 +VOID
 +INTERNAL_CALL
 +IntShowMousePointer(PDEVOBJ *ppdev, SURFOBJ *psoDest)
 +{
 +    GDIPOINTER *pgp;
 +    POINTL pt;
 +    RECTL rclSurf, rclPointer;
 +
 +    ASSERT(ppdev);
 +    ASSERT(psoDest);
 +
 +    pgp = &ppdev->Pointer;
 +
 +    if (pgp->Enabled)
 +    {
 +        return;
 +    }
 +
 +    pgp->Enabled = TRUE;
 +
++    /* Check if we have any mouse pointer */
++    if (!pgp->psurfSave) return;
++
 +    /* Calculate pointer coordinates */
 +    pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
 +    pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
 +
 +    /* Calculate the rect on the surface */
 +    rclSurf.left = max(pt.x, 0);
 +    rclSurf.top = max(pt.y, 0);
 +    rclSurf.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
 +    rclSurf.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
 +
 +    /* Calculate the rect in the pointer bitmap */
 +    rclPointer.left = rclSurf.left - pt.x;
 +    rclPointer.top = rclSurf.top - pt.y;
 +    rclPointer.right = min(pgp->Size.cx, psoDest->sizlBitmap.cx - pt.x);
 +    rclPointer.bottom = min(pgp->Size.cy, psoDest->sizlBitmap.cy - pt.y);
 +
 +    /* Copy the pixels under the cursor to temporary surface. */
 +    IntEngBitBlt(&pgp->psurfSave->SurfObj,
 +                   psoDest,
 +                   NULL,
 +                   NULL,
 +                   NULL,
 +                   &rclPointer,
 +                   (POINTL*)&rclSurf,
 +                   NULL,
 +                   NULL,
 +                   NULL,
 +                   ROP3_TO_ROP4(SRCCOPY));
 +
 +    /* Blt the pointer on the screen. */
 +    if (pgp->psurfColor)
 +    {
 +        IntEngBitBlt(psoDest,
 +                       &pgp->psurfMask->SurfObj,
 +                       NULL,
 +                       NULL,
 +                       NULL,
 +                       &rclSurf,
 +                       (POINTL*)&rclPointer,
 +                       NULL,
 +                       NULL,
 +                       NULL,
 +                       ROP3_TO_ROP4(SRCAND));
 +
 +        IntEngBitBlt(psoDest,
 +                       &pgp->psurfColor->SurfObj,
 +                       NULL,
 +                       NULL,
 +                       NULL,
 +                       &rclSurf,
 +                       (POINTL*)&rclPointer,
 +                       NULL,
 +                       NULL,
 +                       NULL,
 +                       ROP3_TO_ROP4(SRCINVERT));
 +    }
 +    else
 +    {
 +        IntEngBitBlt(psoDest,
 +                       &pgp->psurfMask->SurfObj,
 +                       NULL,
 +                       NULL,
 +                       NULL,
 +                       &rclSurf,
 +                       (POINTL*)&rclPointer,
 +                       NULL,
 +                       NULL,
 +                       NULL,
 +                       ROP3_TO_ROP4(SRCAND));
 +
 +        rclPointer.top += pgp->Size.cy;
 +
 +        IntEngBitBlt(psoDest,
 +                       &pgp->psurfMask->SurfObj,
 +                       NULL,
 +                       NULL,
 +                       NULL,
 +                       &rclSurf,
 +                       (POINTL*)&rclPointer,
 +                       NULL,
 +                       NULL,
 +                       NULL,
 +                       ROP3_TO_ROP4(SRCINVERT));
 +    }
 +}
 +
 +/*
 + * @implemented
 + */
 +ULONG APIENTRY
 +EngSetPointerShape(
 +    IN SURFOBJ *pso,
 +    IN SURFOBJ *psoMask,
 +    IN SURFOBJ *psoColor,
 +    IN XLATEOBJ *pxlo,
 +    IN LONG xHot,
 +    IN LONG yHot,
 +    IN LONG x,
 +    IN LONG y,
 +    IN RECTL *prcl,
 +    IN FLONG fl)
 +{
 +    PDEVOBJ *ppdev;
 +    GDIPOINTER *pgp;
-         pgp->Size.cx = psoColor->sizlBitmap.cx;
-         pgp->Size.cy = psoColor->sizlBitmap.cy;
-         if (psoMask)
-         {
-             // CHECKME: Is this really required? if we have a color surface,
-             // we only need the AND part of the mask.
-             /* Check if the sizes match as they should */
-             if (psoMask->sizlBitmap.cx != psoColor->sizlBitmap.cx ||
-                 psoMask->sizlBitmap.cy != psoColor->sizlBitmap.cy * 2)
-             {
-                 DPRINT("Sizes of mask (%ld,%ld) and color (%ld,%ld) don't match\n",
-                        psoMask->sizlBitmap.cx, psoMask->sizlBitmap.cy,
-                        psoColor->sizlBitmap.cx, psoColor->sizlBitmap.cy);
- //                return SPS_ERROR;
++    LONG lDelta = 0;
++    HBITMAP hbmSave = NULL, hbmColor = NULL, hbmMask = NULL;
++    PSURFACE psurfSave = NULL, psurfColor = NULL, psurfMask = NULL;
++    RECTL rectl;
++    SIZEL sizel = {0, 0};
 +
 +    ASSERT(pso);
 +
 +    ppdev = GDIDEV(pso);
 +    pgp = &ppdev->Pointer;
 +
++    /* Do we have any bitmap at all? */
++    if (psoColor || psoMask)
++    {
++        /* Get the size of the new pointer */
 +    if (psoColor)
 +    {
-         }
-     }
-     else if (psoMask)
++            sizel.cx = psoColor->sizlBitmap.cx;
++            sizel.cy = psoColor->sizlBitmap.cy;
 +            }
-         pgp->Size.cx = psoMask->sizlBitmap.cx;
-         pgp->Size.cy = psoMask->sizlBitmap.cy / 2;
++        else// if (psoMask)
 +    {
-     IntHideMousePointer(ppdev, pso);
-     if (pgp->psurfColor)
-     {
-         EngDeleteSurface(pgp->psurfColor->BaseObject.hHmgr);
-         SURFACE_ShareUnlockSurface(pgp->psurfColor);
-         pgp->psurfColor = NULL;
-     }
-     if (pgp->psurfMask)
-     {
-         EngDeleteSurface(pgp->psurfMask->BaseObject.hHmgr);
-         SURFACE_ShareUnlockSurface(pgp->psurfMask);
-         pgp->psurfMask = NULL;
++            sizel.cx = psoMask->sizlBitmap.cx;
++            sizel.cy = psoMask->sizlBitmap.cy / 2;
 +    }
 +
-     if (pgp->psurfSave != NULL)
-     {
-         EngDeleteSurface(pgp->psurfSave->BaseObject.hHmgr);
-         SURFACE_ShareUnlockSurface(pgp->psurfSave);
-         pgp->psurfSave = NULL;
-     }
-     /* See if we are being asked to hide the pointer. */
-     if (psoMask == NULL && psoColor == NULL)
++        rectl.left = 0;
++        rectl.top = 0;
++        rectl.right = sizel.cx;
++        rectl.bottom = sizel.cy;
++
++        /* Calculate lDelta for our surfaces. */
++        lDelta = DIB_GetDIBWidthBytes(sizel.cx, 
++                                      BitsPerFormat(pso->iBitmapFormat));
++
++        /* Create a bitmap for saving the pixels under the cursor. */
++        hbmSave = EngCreateBitmap(sizel,
++                                  lDelta,
++                                  pso->iBitmapFormat,
++                                  BMF_TOPDOWN | BMF_NOZEROINIT,
++                                  NULL);
++        psurfSave = SURFACE_ShareLockSurface(hbmSave);
++        if (!psurfSave) goto failure;
 +    }
 +
-         return SPS_ACCEPT_NOEXCLUDE;
-     }
-     pgp->HotSpot.x = xHot;
-     pgp->HotSpot.y = yHot;
++    if (psoColor)
 +    {
-     /* Calculate lDelta for our surfaces. */
-     lDelta = DIB_GetDIBWidthBytes(pgp->Size.cx,
-                                   BitsPerFormat(pso->iBitmapFormat));
-     rcl.left = 0;
-     rcl.top = 0;
-     rcl.right = pgp->Size.cx;
-     rcl.bottom = pgp->Size.cy;
-     /* Create surface for saving the pixels under the cursor. */
-     hbmp = EngCreateBitmap(pgp->Size,
++        /* Color bitmap must have the same format as the dest surface */
++        if (psoColor->iBitmapFormat != pso->iBitmapFormat) goto failure;
 +
-     pgp->psurfSave = SURFACE_ShareLockSurface(hbmp);
++        /* Create a bitmap to copy the color bitmap to */
++        hbmColor = EngCreateBitmap(psoColor->sizlBitmap,
 +                           lDelta,
 +                           pso->iBitmapFormat,
 +                           BMF_TOPDOWN | BMF_NOZEROINIT,
 +                           NULL);
-         hbmp = EngCreateBitmap(psoMask->sizlBitmap,
++        psurfColor = SURFACE_ShareLockSurface(hbmColor);
++        if (!psurfColor) goto failure;
++
++        /* Now copy the given bitmap */
++        rectl.bottom = psoColor->sizlBitmap.cy;
++        IntEngCopyBits(&psurfColor->SurfObj,
++                       psoColor,
++                       NULL,
++                       pxlo,
++                       &rectl,
++                       (POINTL*)&rectl);
++    }
 +
 +    /* Create a mask surface */
 +    if (psoMask)
 +    {
 +        EXLATEOBJ exlo;
 +        PPALETTE ppal;
 +
-         pgp->psurfMask = SURFACE_ShareLockSurface(hbmp);
++        /* Create a bitmap for the mask */
++        hbmMask = EngCreateBitmap(psoMask->sizlBitmap,
 +                               lDelta,
 +                               pso->iBitmapFormat,
 +                               BMF_TOPDOWN | BMF_NOZEROINIT,
 +                               NULL);
-         if(pgp->psurfMask)
-         {
++        psurfMask = SURFACE_ShareLockSurface(hbmMask);
++        if (!psurfMask) goto failure;
 +
-             rcl.bottom = psoMask->sizlBitmap.cy;
-             IntEngCopyBits(&pgp->psurfMask->SurfObj,
++        /* Initialize an EXLATEOBJ */
 +            ppal = PALETTE_LockPalette(ppdev->devinfo.hpalDefault);
 +            EXLATEOBJ_vInitialize(&exlo,
 +                                  &gpalMono,
 +                                  ppal,
 +                                  0,
 +                                  RGB(0xff,0xff,0xff),
 +                                  RGB(0,0,0));
 +
-                            &rcl,
-                            (POINTL*)&rcl);
++        /* Copy the mask bitmap */
++        rectl.bottom = psoMask->sizlBitmap.cy;
++        IntEngCopyBits(&psurfMask->SurfObj,
 +                           psoMask,
 +                           NULL,
 +                           &exlo.xlo,
-             if (ppal)
-                 PALETTE_UnlockPalette(ppal);
++                       &rectl,
++                       (POINTL*)&rectl);
 +
++        /* Cleanup */
 +            EXLATEOBJ_vCleanup(&exlo);
-     else
++        if (ppal) PALETTE_UnlockPalette(ppal);
 +        }
++
++    /* Hide mouse pointer */
++    IntHideMousePointer(ppdev, pso);
++
++    /* Free old color bitmap */
++    if (pgp->psurfColor)
++    {
++        EngDeleteSurface(pgp->psurfColor->BaseObject.hHmgr);
++        SURFACE_ShareUnlockSurface(pgp->psurfColor);
++        pgp->psurfColor = NULL;
 +    }
-     /* Create a color surface */
-     if (psoColor)
++
++    /* Free old mask bitmap */
++    if (pgp->psurfMask)
 +    {
++        EngDeleteSurface(pgp->psurfMask->BaseObject.hHmgr);
++        SURFACE_ShareUnlockSurface(pgp->psurfMask);
 +        pgp->psurfMask = NULL;
 +    }
 +
-         hbmp = EngCreateBitmap(psoColor->sizlBitmap,
-                                lDelta,
-                                pso->iBitmapFormat,
-                                BMF_TOPDOWN | BMF_NOZEROINIT,
-                                NULL);
-         pgp->psurfColor = SURFACE_ShareLockSurface(hbmp);
-         if (pgp->psurfColor)
-         {
-             rcl.bottom = psoColor->sizlBitmap.cy;
-             IntEngCopyBits(&pgp->psurfColor->SurfObj,
-                            psoColor,
-                            NULL,
-                            pxlo,
-                            &rcl,
-                            (POINTL*)&rcl);
++    /* Free old save bitmap */
++    if (pgp->psurfSave)
 +    {
-     }
-     else
++        EngDeleteSurface(pgp->psurfSave->BaseObject.hHmgr);
++        SURFACE_ShareUnlockSurface(pgp->psurfSave);
++        pgp->psurfSave = NULL;
 +        }
-         pgp->psurfColor = NULL;
++
++    /* See if we are being asked to hide the pointer. */
++    if (psoMask == NULL && psoColor == NULL)
 +    {
++        /* We're done */
++        return SPS_ACCEPT_NOEXCLUDE;
 +    }
 +
++    /* Now set the new cursor */
++    pgp->psurfColor = psurfColor;
++    pgp->psurfMask = psurfMask;
++    pgp->psurfSave = psurfSave;
++    pgp->HotSpot.x = xHot;
++    pgp->HotSpot.y = yHot;
++    pgp->Size = sizel;
++
 +    if (x != -1)
 +    {
 +        ppdev->ptlPointer.x = x;
 +        ppdev->ptlPointer.y = y;
 +
 +        IntShowMousePointer(ppdev, pso);
 +
 +        if (prcl != NULL)
 +        {
 +            prcl->left = x - pgp->HotSpot.x;
 +            prcl->top = y - pgp->HotSpot.x;
 +            prcl->right = prcl->left + pgp->Size.cx;
 +            prcl->bottom = prcl->top + pgp->Size.cy;
 +        }
 +    }
 +    else if (prcl != NULL)
 +    {
 +        prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
 +    }
 +
 +    return SPS_ACCEPT_NOEXCLUDE;
++
++failure:
++    /* Cleanup surfaces */
++    if (hbmMask) EngDeleteSurface(hbmMask);
++    if (psurfMask) SURFACE_ShareUnlockSurface(psurfMask);
++    if (hbmColor) EngDeleteSurface(hbmColor);
++    if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
++    if (hbmSave) EngDeleteSurface(hbmSave);
++    if (psurfSave) SURFACE_ShareUnlockSurface(psurfSave);
++
++    return SPS_ERROR;
 +}
 +
 +/*
 + * @implemented
 + */
 +
 +VOID APIENTRY
 +EngMovePointer(
 +    IN SURFOBJ *pso,
 +    IN LONG x,
 +    IN LONG y,
 +    IN RECTL *prcl)
 +{
 +    PDEVOBJ *ppdev;
 +    GDIPOINTER *pgp;
 +
 +    ASSERT(pso);
 +
 +    ppdev = GDIDEV(pso);
 +    ASSERT(ppdev);
 +
 +    pgp = &ppdev->Pointer;
 +
 +    IntHideMousePointer(ppdev, pso);
 +
 +    ppdev->ptlPointer.x = x;
 +    ppdev->ptlPointer.y = y;
 +
 +    if (x != -1)
 +    {
 +        IntShowMousePointer(ppdev, pso);
 +        if (prcl != NULL)
 +        {
 +            prcl->left = x - pgp->HotSpot.x;
 +            prcl->top = y - pgp->HotSpot.y;
 +            prcl->right = prcl->left + pgp->Size.cx;
 +            prcl->bottom = prcl->top + pgp->Size.cy;
 +        }
 +    }
 +    else if (prcl != NULL)
 +    {
 +        prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
 +    }
 +}
 +
 +ULONG APIENTRY
 +IntEngSetPointerShape(
 +   IN SURFOBJ *pso,
 +   IN SURFOBJ *psoMask,
 +   IN SURFOBJ *psoColor,
 +   IN XLATEOBJ *pxlo,
 +   IN LONG xHot,
 +   IN LONG yHot,
 +   IN LONG x,
 +   IN LONG y,
 +   IN RECTL *prcl,
 +   IN FLONG fl)
 +{
 +    ULONG ulResult = SPS_DECLINE;
 +    PFN_DrvSetPointerShape pfnSetPointerShape;
 +    PPDEVOBJ ppdev = GDIDEV(pso);
 +
 +    pfnSetPointerShape = GDIDEVFUNCS(pso).SetPointerShape;
 +
 +    if (pfnSetPointerShape)
 +    {
 +        ulResult = pfnSetPointerShape(pso,
 +                                      psoMask,
 +                                      psoColor,
 +                                      pxlo,
 +                                      xHot,
 +                                      yHot,
 +                                      x,
 +                                      y,
 +                                      prcl,
 +                                      fl);
 +    }
 +
 +    /* Check if the driver accepted it */
 +    if (ulResult == SPS_ACCEPT_NOEXCLUDE)
 +    {
 +        /* Set MovePointer to the driver function */
 +        ppdev->pfnMovePointer = GDIDEVFUNCS(pso).MovePointer;
 +    }
 +    else
 +    {
 +        /* Set software pointer */
 +        ulResult = EngSetPointerShape(pso,
 +                                      psoMask,
 +                                      psoColor,
 +                                      pxlo,
 +                                      xHot,
 +                                      yHot,
 +                                      x,
 +                                      y,
 +                                      prcl,
 +                                      fl);
 +        /* Set MovePointer to the eng function */
 +        ppdev->pfnMovePointer = EngMovePointer;
 +    }
 +
 +    return ulResult;
 +}
 +
 +ULONG
 +NTAPI
 +GreSetPointerShape(
 +    HDC hdc,
 +    HBITMAP hbmMask,
 +    HBITMAP hbmColor,
 +    LONG xHot,
 +    LONG yHot,
 +    LONG x,
 +    LONG y)
 +{
 +    PDC pdc;
 +    PSURFACE psurf, psurfMask, psurfColor;
 +    EXLATEOBJ exlo;
 +    FLONG fl = 0;
 +    ULONG ulResult = 0;
 +
 +    pdc = DC_LockDc(hdc);
 +    if (!pdc)
 +    {
 +        DPRINT1("Failed to lock the DC.\n");
 +        return 0;
 +    }
 +
 +    ASSERT(pdc->dctype == DCTYPE_DIRECT);
 +    EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
 +    /* We're not sure DC surface is the good one */
 +    psurf = pdc->ppdev->pSurface;
 +    if (!psurf)
 +    {
 +        DPRINT1("DC has no surface.\n");
 +        EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
 +        DC_UnlockDc(pdc);
 +        return 0;
 +    }
 +
 +    /* Lock the mask bitmap */
 +    if (hbmMask)
 +        psurfMask = SURFACE_ShareLockSurface(hbmMask);
 +    else
 +        psurfMask = NULL;
 +
 +    /* Check for color bitmap */
 +    if (hbmColor)
 +    {
 +        /* We have one, lock it */
 +        psurfColor = SURFACE_ShareLockSurface(hbmColor);
 +
 +        if (psurfColor)
 +        {
 +            /* Create an XLATEOBJ, no mono support */
 +            EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurf->ppal, 0, 0, 0);
 +        }
 +    }
 +    else
 +        psurfColor = NULL;
 +
 +    /* Call the driver or eng function */
 +    ulResult = IntEngSetPointerShape(&psurf->SurfObj,
 +                                     psurfMask ? &psurfMask->SurfObj : NULL,
 +                                     psurfColor ? &psurfColor->SurfObj : NULL,
 +                                     psurfColor ? &exlo.xlo : NULL,
 +                                     xHot,
 +                                     yHot,
 +                                     x,
 +                                     y,
 +                                     &pdc->ppdev->Pointer.Exclude,
 +                                     fl | SPS_CHANGE);
 +
 +    /* Cleanup */
 +    if (psurfColor)
 +    {
 +        EXLATEOBJ_vCleanup(&exlo);
 +        SURFACE_ShareUnlockSurface(psurfColor);
 +    }
 +
 +    if (psurfMask)
 +        SURFACE_ShareUnlockSurface(psurfMask);
 +
 +    EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
 +
 +    /* Unlock the DC */
 +    DC_UnlockDc(pdc);
 +
 +    /* Return result */
 +    return ulResult;
 +}
 +
 +VOID
 +NTAPI
 +GreMovePointer(
 +    HDC hdc,
 +    LONG x,
 +    LONG y)
 +{
 +    PDC pdc;
 +    PRECTL prcl;
 +
 +    /* Lock the DC */
 +    pdc = DC_LockDc(hdc);
 +    if (!pdc)
 +    {
 +        DPRINT1("Failed to lock the DC.\n");
 +        return;
 +    }
 +    ASSERT(pdc->dctype == DCTYPE_DIRECT);
 +
 +    /* Acquire PDEV lock */
 +    EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
 +
 +    /* Check if we need to move it */
 +    if(pdc->ppdev->SafetyRemoveLevel == 0)
 +    {
 +        /* Store the cursor exclude position in the PDEV */
 +        prcl = &pdc->ppdev->Pointer.Exclude;
 +
 +        /* Call Eng/Drv function */
 +        pdc->ppdev->pfnMovePointer(&pdc->ppdev->pSurface->SurfObj, x, y, prcl);
 +    }
 +
 +    /* Release PDEV lock */
 +    EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
 +
 +    /* Unlock the DC */
 +    DC_UnlockDc(pdc);
 +}
 +
 +
 +/* EOF */
index c4006ed,0000000..87cce90
mode 100644,000000..100644
--- /dev/null
@@@ -1,2855 -1,0 +1,2859 @@@
-       *HitTest = co_IntSendMessage(Window->hSelf, WM_NCHITTEST, 0,
-                                    MAKELONG(Msg->pt.x, Msg->pt.y));
 +/*
 + * COPYRIGHT:        See COPYING in the top level directory
 + * PROJECT:          ReactOS kernel
 + * PURPOSE:          Messages
 + * FILE:             subsys/win32k/ntuser/message.c
 + * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
 + * REVISION HISTORY:
 + *       06-06-2001  CSH  Created
 + */
 +
 +/* INCLUDES ******************************************************************/
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +#define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
 +
 +typedef struct
 +{
 +   UINT uFlags;
 +   UINT uTimeout;
 +   ULONG_PTR Result;
 +}
 +DOSENDMESSAGE, *PDOSENDMESSAGE;
 +
 +/* FUNCTIONS *****************************************************************/
 +
 +NTSTATUS FASTCALL
 +IntInitMessageImpl(VOID)
 +{
 +   return STATUS_SUCCESS;
 +}
 +
 +NTSTATUS FASTCALL
 +IntCleanupMessageImpl(VOID)
 +{
 +   return STATUS_SUCCESS;
 +}
 +
 +#define MMS_SIZE_WPARAM      -1
 +#define MMS_SIZE_WPARAMWCHAR -2
 +#define MMS_SIZE_LPARAMSZ    -3
 +#define MMS_SIZE_SPECIAL     -4
 +#define MMS_FLAG_READ        0x01
 +#define MMS_FLAG_WRITE       0x02
 +#define MMS_FLAG_READWRITE   (MMS_FLAG_READ | MMS_FLAG_WRITE)
 +typedef struct tagMSGMEMORY
 +{
 +   UINT Message;
 +   UINT Size;
 +   INT Flags;
 +}
 +MSGMEMORY, *PMSGMEMORY;
 +
 +static MSGMEMORY MsgMemory[] =
 +   {
 +      { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
 +      { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
 +      { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
 +      { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
 +      { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
 +      { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
 +      { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
 +      { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
 +      { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
 +      { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
 +      { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
 +      { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
 +      { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
 +   };
 +
 +static PMSGMEMORY FASTCALL
 +FindMsgMemory(UINT Msg)
 +{
 +   PMSGMEMORY MsgMemoryEntry;
 +
 +   /* See if this message type is present in the table */
 +   for (MsgMemoryEntry = MsgMemory;
 +         MsgMemoryEntry < MsgMemory + sizeof(MsgMemory) / sizeof(MSGMEMORY);
 +         MsgMemoryEntry++)
 +   {
 +      if (Msg == MsgMemoryEntry->Message)
 +      {
 +         return MsgMemoryEntry;
 +      }
 +   }
 +
 +   return NULL;
 +}
 +
 +static UINT FASTCALL
 +MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
 +{
 +   CREATESTRUCTW *Cs;
 +   PUNICODE_STRING WindowName;
 +   PUNICODE_STRING ClassName;
 +   UINT Size = 0;
 +
 +   _SEH2_TRY
 +   {
 +      if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
 +      {
 +         Size = (UINT)wParam;
 +      }
 +      else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
 +      {
 +         Size = (UINT) (wParam * sizeof(WCHAR));
 +      }
 +      else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
 +      {
 +         Size = (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
 +      }
 +      else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
 +      {
 +         switch(MsgMemoryEntry->Message)
 +         {
 +            case WM_CREATE:
 +            case WM_NCCREATE:
 +               Cs = (CREATESTRUCTW *) lParam;
 +               WindowName = (PUNICODE_STRING) Cs->lpszName;
 +               ClassName = (PUNICODE_STRING) Cs->lpszClass;
 +               Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
 +               if (IS_ATOM(ClassName->Buffer))
 +               {
 +                  Size += sizeof(WCHAR) + sizeof(ATOM);
 +               }
 +               else
 +               {
 +                  Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
 +               }
 +               break;
 +
 +            case WM_NCCALCSIZE:
 +               Size = wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
 +               break;
 +
 +            case WM_COPYDATA:
 +               Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
 +               break;
 +
 +            case WM_COPYGLOBALDATA:
 +               Size = wParam;
 +               break;
 +
 +            default:
 +               ASSERT(FALSE);
 +               Size = 0;
 +               break;
 +         }
 +      }
 +      else
 +      {
 +         Size = MsgMemoryEntry->Size;
 +      }
 +   }
 +   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +   {
 +      DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
 +      Size = 0;
 +   }
 +   _SEH2_END;
 +   return Size;
 +}
 +
 +static NTSTATUS
 +PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolNeeded)
 +{
 +   NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
 +   NCCALCSIZE_PARAMS *PackedNcCalcsize;
 +   CREATESTRUCTW *UnpackedCs;
 +   CREATESTRUCTW *PackedCs;
 +   PLARGE_STRING WindowName;
 +   PUNICODE_STRING ClassName;
 +   POOL_TYPE PoolType;
 +   UINT Size;
 +   PCHAR CsData;
 +
 +   *lParamPacked = lParam;
 +
 +    if (NonPagedPoolNeeded)
 +       PoolType = NonPagedPool;
 +    else
 +       PoolType = PagedPool;
 +
 +   if (WM_NCCALCSIZE == Msg && wParam)
 +   {
 +
 +      UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
 +      PackedNcCalcsize = ExAllocatePoolWithTag(PoolType,
 +                         sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
 +                         TAG_MSG);
 +
 +      if (NULL == PackedNcCalcsize)
 +      {
 +         DPRINT1("Not enough memory to pack lParam\n");
 +         return STATUS_NO_MEMORY;
 +      }
 +      RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
 +      PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
 +      RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
 +      *lParamPacked = (LPARAM) PackedNcCalcsize;
 +   }
 +   else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
 +   {
 +      UnpackedCs = (CREATESTRUCTW *) lParam;
 +      WindowName = (PLARGE_STRING) UnpackedCs->lpszName;
 +      ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
 +      Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
 +      if (IS_ATOM(ClassName->Buffer))
 +      {
 +         Size += sizeof(WCHAR) + sizeof(ATOM);
 +      }
 +      else
 +      {
 +         Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
 +      }
 +      PackedCs = ExAllocatePoolWithTag(PoolType, Size, TAG_MSG);
 +      if (NULL == PackedCs)
 +      {
 +         DPRINT1("Not enough memory to pack lParam\n");
 +         return STATUS_NO_MEMORY;
 +      }
 +      RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW));
 +      CsData = (PCHAR) (PackedCs + 1);
 +      PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs);
 +      RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length);
 +      CsData += WindowName->Length;
 +      *((WCHAR *) CsData) = L'\0';
 +      CsData += sizeof(WCHAR);
 +      PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs);
 +      if (IS_ATOM(ClassName->Buffer))
 +      {
 +         *((WCHAR *) CsData) = L'A';
 +         CsData += sizeof(WCHAR);
 +         *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer;
 +         CsData += sizeof(ATOM);
 +      }
 +      else
 +      {
 +         *((WCHAR *) CsData) = L'S';
 +         CsData += sizeof(WCHAR);
 +         RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length);
 +         CsData += ClassName->Length;
 +         *((WCHAR *) CsData) = L'\0';
 +         CsData += sizeof(WCHAR);
 +      }
 +      ASSERT(CsData == (PCHAR) PackedCs + Size);
 +      *lParamPacked = (LPARAM) PackedCs;
 +   }
 +
 +   else if (PoolType == NonPagedPool)
 +   {
 +      PMSGMEMORY MsgMemoryEntry;
 +      PVOID PackedData;
 +
 +      MsgMemoryEntry = FindMsgMemory(Msg);
 +
 +      if ((!MsgMemoryEntry) || (MsgMemoryEntry->Size < 0))
 +      {
 +         /* Keep previous behavior */
 +         return STATUS_SUCCESS;
 +      }
 +      PackedData = ExAllocatePoolWithTag(NonPagedPool, MsgMemorySize(MsgMemoryEntry, wParam, lParam), TAG_MSG);
 +      RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam));
 +      *lParamPacked = (LPARAM)PackedData;
 +   }
 +
 +   return STATUS_SUCCESS;
 +}
 +
 +static NTSTATUS
 +UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolUsed)
 +{
 +   NCCALCSIZE_PARAMS *UnpackedParams;
 +   NCCALCSIZE_PARAMS *PackedParams;
 +   PWINDOWPOS UnpackedWindowPos;
 +
 +   if (lParamPacked == lParam)
 +   {
 +      return STATUS_SUCCESS;
 +   }
 +
 +   if (WM_NCCALCSIZE == Msg && wParam)
 +   {
 +      PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
 +      UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
 +      UnpackedWindowPos = UnpackedParams->lppos;
 +      RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
 +      UnpackedParams->lppos = UnpackedWindowPos;
 +      RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
 +      ExFreePool((PVOID) lParamPacked);
 +
 +      return STATUS_SUCCESS;
 +   }
 +   else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
 +   {
 +      ExFreePool((PVOID) lParamPacked);
 +
 +      return STATUS_SUCCESS;
 +   }
 +   else if (NonPagedPoolUsed)
 +   {
 +      PMSGMEMORY MsgMemoryEntry;
 +      MsgMemoryEntry = FindMsgMemory(Msg);
 +      if (MsgMemoryEntry->Size < 0)
 +      {
 +         /* Keep previous behavior */
 +         return STATUS_INVALID_PARAMETER;
 +      }
 +
 +      if (MsgMemory->Flags == MMS_FLAG_READWRITE)
 +      {
 +         //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemory->Size);
 +      }
 +      ExFreePool((PVOID) lParamPacked);
 +      return STATUS_SUCCESS;
 +   }
 +
 +   ASSERT(FALSE);
 +
 +   return STATUS_INVALID_PARAMETER;
 +}
 +
 +static
 +VOID
 +FASTCALL
 +IntCallWndProc
 +( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
 +{
 +   BOOL SameThread = FALSE;
 +
 +   if (Window->pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
 +      SameThread = TRUE;
 +
 +   if ((!SameThread && (Window->pti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROC))) ||
 +        (SameThread && ISITHOOKED(WH_CALLWNDPROC)) )
 +   {
 +      CWPSTRUCT CWP;
 +      CWP.hwnd    = hWnd;
 +      CWP.message = Msg;
 +      CWP.wParam  = wParam;
 +      CWP.lParam  = lParam;
 +      co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
 +   }
 +}
 +
 +static
 +VOID
 +FASTCALL
 +IntCallWndProcRet
 +( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
 +{
 +   BOOL SameThread = FALSE;
 +
 +   if (Window->pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
 +      SameThread = TRUE;
 +
 +   if ((!SameThread && (Window->pti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
 +        (SameThread && ISITHOOKED(WH_CALLWNDPROCRET)) )
 +   {
 +      CWPRETSTRUCT CWPR;
 +      CWPR.hwnd    = hWnd;
 +      CWPR.message = Msg;
 +      CWPR.wParam  = wParam;
 +      CWPR.lParam  = lParam;
 +      CWPR.lResult = *uResult;
 +      co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
 +   }
 +}
 +
 +LRESULT
 +FASTCALL
 +IntDispatchMessage(PMSG pMsg)
 +{
 +  LARGE_INTEGER TickCount;
 +  LONG Time;
 +  LRESULT retval;
 +  PMSGMEMORY MsgMemoryEntry;
 +  INT lParamBufferSize;
 +  LPARAM lParamPacked;
 +  PWINDOW_OBJECT Window = NULL;
 +
 +  if (pMsg->hwnd)
 +  {
 +     Window = UserGetWindowObject(pMsg->hwnd);
 +     if (!Window || !Window->Wnd) return 0;
 +  }
 +
 +  if (((pMsg->message == WM_SYSTIMER) ||
 +       (pMsg->message == WM_TIMER)) &&
 +      (pMsg->lParam) )
 +  {
 +     if (pMsg->message == WM_TIMER)
 +     {
 +        if (ValidateTimerCallback(PsGetCurrentThreadWin32Thread(),Window,pMsg->wParam,pMsg->lParam))
 +        {
 +           KeQueryTickCount(&TickCount);
 +           Time = MsqCalculateMessageTime(&TickCount);
 +           return co_IntCallWindowProc((WNDPROC)pMsg->lParam,
 +                                        TRUE,
 +                                        pMsg->hwnd,
 +                                        WM_TIMER,
 +                                        pMsg->wParam,
 +                                        (LPARAM)Time,
 +                                        sizeof(LPARAM));
 +        }
 +        return 0;
 +     }
 +     else
 +     {
 +        PTIMER pTimer = FindSystemTimer(pMsg);
 +        if (pTimer && pTimer->pfn)
 +        {
 +           KeQueryTickCount(&TickCount);
 +           Time = MsqCalculateMessageTime(&TickCount);
 +           pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
 +        }
 +        return 0;
 +     }
 +  }
 +  // Need a window!
 +  if ( !Window || !Window->Wnd ) return 0;
 +
 +  /* See if this message type is present in the table */
 +  MsgMemoryEntry = FindMsgMemory(pMsg->message);
 +  if ( !MsgMemoryEntry )
 +  {
 +     lParamBufferSize = -1;
 +  }
 +  else
 +  {
 +     lParamBufferSize = MsgMemorySize(MsgMemoryEntry, pMsg->wParam, pMsg->lParam);
 +  }
 +
 +  if (! NT_SUCCESS(PackParam(&lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
 +  {
 +     DPRINT1("Failed to pack message parameters\n");
 +     return 0;
 +  }
 +
 +  retval = co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
 +                                !Window->Wnd->Unicode,
 +                                 pMsg->hwnd,
 +                                 pMsg->message,
 +                                 pMsg->wParam,
 +                                 lParamPacked,
 +                                 lParamBufferSize);
 +
 +  if (! NT_SUCCESS(UnpackParam(lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
 +  {
 +     DPRINT1("Failed to unpack message parameters\n");
 +  }
 +
 +  if (pMsg->message == WM_PAINT)
 +  {
 +  /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
 +     HRGN hrgn = IntSysCreateRectRgn( 0, 0, 0, 0 );
 +     co_UserGetUpdateRgn( Window, hrgn, TRUE );
 +     REGION_FreeRgnByHandle( hrgn );
 +  }
 +  return retval;
 +}
 +
 +VOID FASTCALL
 +co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
 +{
 +   if(!Msg->hwnd || ThreadQueue->CaptureWindow)
 +   {
 +      return;
 +   }
 +
 +   switch(Msg->message)
 +   {
 +      case WM_MOUSEMOVE:
 +         {
 +            co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
 +            break;
 +         }
 +      case WM_NCMOUSEMOVE:
 +         {
 +            co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
 +            break;
 +         }
 +      case WM_LBUTTONDOWN:
 +      case WM_MBUTTONDOWN:
 +      case WM_RBUTTONDOWN:
 +      case WM_XBUTTONDOWN:
 +      case WM_LBUTTONDBLCLK:
 +      case WM_MBUTTONDBLCLK:
 +      case WM_RBUTTONDBLCLK:
 +      case WM_XBUTTONDBLCLK:
 +         {
 +            WPARAM wParam;
 +            PSYSTEM_CURSORINFO CurInfo;
 +                      CurInfo = IntGetSysCursorInfo();
 +
 +            wParam = (WPARAM)(CurInfo->ButtonsDown);
 +
 +            co_IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
 +            co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
 +            break;
 +         }
 +      case WM_NCLBUTTONDOWN:
 +      case WM_NCMBUTTONDOWN:
 +      case WM_NCRBUTTONDOWN:
 +      case WM_NCXBUTTONDOWN:
 +      case WM_NCLBUTTONDBLCLK:
 +      case WM_NCMBUTTONDBLCLK:
 +      case WM_NCRBUTTONDBLCLK:
 +      case WM_NCXBUTTONDBLCLK:
 +         {
 +            co_IntSendMessage(Msg->hwnd, WM_NCMOUSEMOVE, (WPARAM)Msg->wParam, Msg->lParam);
 +            co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
 +            break;
 +         }
 +   }
 +}
 +
 +BOOL FASTCALL
 +co_IntActivateWindowMouse(
 +   PUSER_MESSAGE_QUEUE ThreadQueue,
 +   LPMSG Msg,
 +   PWINDOW_OBJECT MsgWindow,
 +   USHORT *HitTest)
 +{
 +   ULONG Result;
 +   PWINDOW_OBJECT Parent;
 +
 +   ASSERT_REFS_CO(MsgWindow);
 +
 +   if(*HitTest == (USHORT)HTTRANSPARENT)
 +   {
 +      /* eat the message, search again! */
 +      return TRUE;
 +   }
 +
 +   Parent = IntGetParent(MsgWindow);//fixme: deref retval?
 +
 +   /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
 +   Result = co_IntSendMessage(MsgWindow->hSelf,
 +                              WM_MOUSEACTIVATE,
 +                              (WPARAM) (Parent ? Parent->hSelf : MsgWindow->hSelf),
 +                              (LPARAM)MAKELONG(*HitTest, Msg->message)
 +                             );
 +
 +   switch (Result)
 +   {
 +      case MA_NOACTIVATEANDEAT:
 +         return TRUE;
 +      case MA_NOACTIVATE:
 +         break;
 +      case MA_ACTIVATEANDEAT:
 +         co_IntMouseActivateWindow(MsgWindow);
 +         return TRUE;
 +      default:
 +         /* MA_ACTIVATE */
 +         co_IntMouseActivateWindow(MsgWindow);
 +         break;
 +   }
 +
 +   return FALSE;
 +}
 +
 +BOOL FASTCALL
 +co_IntTranslateMouseMessage(
 +   PUSER_MESSAGE_QUEUE ThreadQueue,
 +   LPMSG Msg,
 +   USHORT *HitTest,
 +   BOOL Remove)
 +{
 +   PWINDOW_OBJECT Window;
 +   USER_REFERENCE_ENTRY Ref, DesktopRef;
 +
 +   if(!(Window = UserGetWindowObject(Msg->hwnd)))
 +   {
 +      /* let's just eat the message?! */
 +      return TRUE;
 +   }
 +
++   *HitTest = HTCLIENT;
++
 +   UserRefObjectCo(Window, &Ref);
 +
 +   if ( ThreadQueue == Window->pti->MessageQueue &&
 +        ThreadQueue->CaptureWindow != Window->hSelf)
 +   {
 +      /* only send WM_NCHITTEST messages if we're not capturing the window! */
-    else
-    {
-       *HitTest = HTCLIENT;
-    }
++      if (Remove ) 
++      {
++         *HitTest = co_IntSendMessage(Window->hSelf, WM_NCHITTEST, 0,
++                                      MAKELONG(Msg->pt.x, Msg->pt.y));
++      } 
++      /* else we are going to see this message again, but then with Remove == TRUE */
 +
 +      if (*HitTest == (USHORT)HTTRANSPARENT)
 +      {
 +         PWINDOW_OBJECT DesktopWindow;
 +         HWND hDesktop = IntGetDesktopWindow();
 +
 +         if ((DesktopWindow = UserGetWindowObject(hDesktop)))
 +         {
 +            PWINDOW_OBJECT Wnd;
 +
 +            UserRefObjectCo(DesktopWindow, &DesktopRef);
 +
 +            co_WinPosWindowFromPoint(DesktopWindow, Window->pti->MessageQueue, &Msg->pt, &Wnd);
 +            if (Wnd)
 +            {
 +               if (Wnd != Window)
 +               {
 +                  /* post the message to the other window */
 +                  Msg->hwnd = Wnd->hSelf;
 +                  if(!(Wnd->state & WINDOWSTATUS_DESTROYING))
 +                  {
 +                     MsqPostMessage(Wnd->pti->MessageQueue, Msg, FALSE,
 +                                    Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
 +                                    QS_MOUSEBUTTON);
 +                  }
 +
 +                  /* eat the message */
 +                  UserDereferenceObject(Wnd);
 +                  UserDerefObjectCo(DesktopWindow);
 +                  UserDerefObjectCo(Window);
 +                  return TRUE;
 +               }
 +               UserDereferenceObject(Wnd);
 +            }
 +
 +            UserDerefObjectCo(DesktopWindow);
 +         }
 +      }
 +   }
 +
 +   if ( gspv.bMouseClickLock &&
 +        ( (Msg->message == WM_LBUTTONUP) ||
 +          (Msg->message == WM_LBUTTONDOWN) ) )
 +   {
 +      if (MsqIsClkLck(Msg, Remove))
 +      {
 +        // FIXME: drop the message, hack: use WM_NULL
 +        Msg->message = WM_NULL;
 +      }
 +   }
 +
 +   if (IS_BTN_MESSAGE(Msg->message, DOWN))
 +   {
 +      /* generate double click messages, if necessary */
 +      if ((((*HitTest) != HTCLIENT) ||
 +            (Window->Wnd->pcls->style & CS_DBLCLKS)) &&
 +            MsqIsDblClk(Msg, Remove))
 +      {
 +         Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
 +      }
 +   }
 +
 +   if(Msg->message != WM_MOUSEWHEEL)
 +   {
 +
 +      if ((*HitTest) != HTCLIENT)
 +      {
 +         Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
 +         if ( (Msg->message == WM_NCRBUTTONUP) &&
 +              (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)) )
 +         {
 +            Msg->message = WM_CONTEXTMENU;
 +            Msg->wParam = (WPARAM)Window->hSelf;
 +         }
 +         else
 +         {
 +            Msg->wParam = *HitTest;
 +         }
 +         Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
 +      }
 +      else if ( ThreadQueue->MoveSize == NULL &&
 +                ThreadQueue->MenuOwner == NULL )
 +      {
 +         /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
 +         Msg->lParam = MAKELONG(
 +                          Msg->pt.x - (WORD)Window->Wnd->rcClient.left,
 +                          Msg->pt.y - (WORD)Window->Wnd->rcClient.top);
 +      }
 +   }
 +
 +   UserDerefObjectCo(Window);
 +   return FALSE;
 +}
 +
 +BOOL ProcessMouseMessage(MSG* Msg, USHORT HitTest, UINT RemoveMsg)
 +{
 +    MOUSEHOOKSTRUCT MHook;
 +    EVENTMSG Event;
 +
 +    Event.message = Msg->message;
 +    Event.time    = Msg->time;
 +    Event.hwnd    = Msg->hwnd;
 +    Event.paramL  = Msg->pt.x;
 +    Event.paramH  = Msg->pt.y;
 +    co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
 +
 +
 +    MHook.pt           = Msg->pt;
 +    MHook.hwnd         = Msg->hwnd;
 +    MHook.wHitTestCode = HitTest;
 +    MHook.dwExtraInfo  = 0;
 +    if (co_HOOK_CallHooks( WH_MOUSE,
 +                           RemoveMsg ? HC_ACTION : HC_NOREMOVE,
 +                           Msg->message,
 +                           (LPARAM)&MHook ))
 +    {
 +        if (ISITHOOKED(WH_CBT))
 +        {
 +            MHook.pt           = Msg->pt;
 +            MHook.hwnd         = Msg->hwnd;
 +            MHook.wHitTestCode = HitTest;
 +            MHook.dwExtraInfo  = 0;
 +            co_HOOK_CallHooks( WH_CBT,
 +                               HCBT_CLICKSKIPPED,
 +                               Msg->message,
 +                               (LPARAM)&MHook);
 +        }
 +        return FALSE;
 +    }
 +
 +      return TRUE;
 +}
 +
 +BOOL ProcessKeyboardMessage(MSG* Msg, UINT RemoveMsg)
 +{
 +   EVENTMSG Event;
 +
 +   Event.message = Msg->message;
 +   Event.hwnd    = Msg->hwnd;
 +   Event.time    = Msg->time;
 +   Event.paramL  = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
 +   Event.paramH  = Msg->lParam & 0x7FFF;
 +   if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
 +   co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
 +
 +    if (co_HOOK_CallHooks( WH_KEYBOARD,
 +                           RemoveMsg ? HC_ACTION : HC_NOREMOVE,
 +                           LOWORD(Msg->wParam),
 +                           Msg->lParam))
 +    {
 +        if (ISITHOOKED(WH_CBT))
 +        {
 +            /* skip this message */
 +            co_HOOK_CallHooks( WH_CBT,
 +                               HCBT_KEYSKIPPED,
 +                               LOWORD(Msg->wParam),
 +                               Msg->lParam );
 +        }
 +        return FALSE;
 +    }
 +      return TRUE;
 +}
 +/*
 + * Internal version of PeekMessage() doing all the work
 + */
 +BOOL FASTCALL
 +co_IntPeekMessage( PUSER_MESSAGE Msg,
 +                   PWINDOW_OBJECT Window,
 +                   UINT MsgFilterMin,
 +                   UINT MsgFilterMax,
 +                   UINT RemoveMsg )
 +{
 +   PTHREADINFO pti;
 +   LARGE_INTEGER LargeTickCount;
 +   PUSER_MESSAGE_QUEUE ThreadQueue;
 +   PUSER_MESSAGE Message;
 +   BOOL Present, RemoveMessages;
 +   USER_REFERENCE_ENTRY Ref;
 +   USHORT HitTest;
 +
 +   /* The queues and order in which they are checked are documented in the MSDN
 +      article on GetMessage() */
 +
 +   pti = PsGetCurrentThreadWin32Thread();
 +   ThreadQueue = pti->MessageQueue;
 +
 +   /* Inspect RemoveMsg flags */
 +   /* Note:
 +       The only flag we process is PM_REMOVE.
 +       Processing (High word) PM_QS_Xx Is needed. This and MsgFilterXxx can result
 +       with QS_Xx flags to be used to isolate which message check to test for.
 +       ATM, we look at all messages and the filters are sent to co_MsqFindMessage
 +       and there, it is cross checked.
 +       Example: Wine server/queue.c is_keyboard_msg, check_msg_filter and
 +                filter_contains_hw_range.
 +    */
 +   RemoveMessages = RemoveMsg & PM_REMOVE;
 +
 +/*
 +   If no filter is specified, messages are processed in the following order:
 +
 +    * Sent messages
 +    * Posted messages
 +    * Input (hardware) messages and system internal events
 +    * Sent messages (again)
 +    * WM_PAINT messages
 +    * WM_TIMER messages
 + */
 +CheckMessages:
 +
++   HitTest = HTNOWHERE;
++
 +   Present = FALSE;
 +
 +   KeQueryTickCount(&LargeTickCount);
 +   ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
 +
 +   /* Dispatch sent messages here. */
 +   while (co_MsqDispatchOneSentMessage(ThreadQueue))
 +      ;
 +
 +   /* Now look for a quit message. */
 +
 +   if (ThreadQueue->QuitPosted)
 +   {
 +      /* According to the PSDK, WM_QUIT messages are always returned, regardless
 +         of the filter specified */
 +      Msg->Msg.hwnd = NULL;
 +      Msg->Msg.message = WM_QUIT;
 +      Msg->Msg.wParam = ThreadQueue->QuitExitCode;
 +      Msg->Msg.lParam = 0;
 +      Msg->FreeLParam = FALSE;
 +      if (RemoveMessages)
 +      {
 +         ThreadQueue->QuitPosted = FALSE;
 +      }
 +      goto MsgExit;
 +   }
 +
 +   /* Now check for normal messages. */
 +   Present = co_MsqFindMessage( ThreadQueue,
 +                                FALSE,
 +                                RemoveMessages,
 +                                Window,
 +                                MsgFilterMin,
 +                                MsgFilterMax,
 +                               &Message );
 +   if (Present)
 +   {
 +      RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
 +      if (RemoveMessages)
 +      {
 +         MsqDestroyMessage(Message);
 +      }
 +      goto MessageFound;
 +   }
 +
 +   /* Check for hardware events. */
 +   Present = co_MsqFindMessage( ThreadQueue,
 +                                TRUE,
 +                                RemoveMessages,
 +                                Window,
 +                                MsgFilterMin,
 +                                MsgFilterMax,
 +                               &Message );
 +   if (Present)
 +   {
 +      RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
 +      if (RemoveMessages)
 +      {
 +         MsqDestroyMessage(Message);
 +      }
 +      goto MessageFound;
 +   }
 +
 +   /* Check for sent messages again. */
 +   while (co_MsqDispatchOneSentMessage(ThreadQueue))
 +      ;
 +
 +   /* Check for paint messages. */
 +   if ( IntGetPaintMessage( Window,
 +                            MsgFilterMin,
 +                            MsgFilterMax,
 +                            pti,
 +                            &Msg->Msg,
 +                            RemoveMessages))
 +   {
 +      Msg->FreeLParam = FALSE;
 +      goto MsgExit;
 +   }
 +
 +   if (PostTimerMessages(Window))
 +      goto CheckMessages;
 +
 +   if(Present)
 +   {
 +MessageFound:
 +
 +      if(RemoveMessages)
 +      {
 +         PWINDOW_OBJECT MsgWindow = NULL;
 +
 +         /* Mouse message process */
 +
 +         if( Msg->Msg.hwnd &&
 +            ( MsgWindow = UserGetWindowObject(Msg->Msg.hwnd) ) &&
 +             Msg->Msg.message >= WM_MOUSEFIRST &&
 +             Msg->Msg.message <= WM_MOUSELAST )
 +         {
 +            USHORT HitTest;
 +
 +            UserRefObjectCo(MsgWindow, &Ref);
 +
 +            if ( co_IntTranslateMouseMessage( ThreadQueue,
 +                                              &Msg->Msg,
 +                                              &HitTest,
 +                                              TRUE))
 +         /* FIXME - check message filter again, if the message doesn't match anymore,
 +                    search again */
 +            {
 +               UserDerefObjectCo(MsgWindow);
 +               /* eat the message, search again */
 +               goto CheckMessages;
 +            }
 +
 +            if(ThreadQueue->CaptureWindow == NULL)
 +            {
 +               co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
 +
 +               if ( ( Msg->Msg.message != WM_MOUSEMOVE &&
 +                      Msg->Msg.message != WM_NCMOUSEMOVE ) &&
 +                     IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
 +                     co_IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest) )
 +               {
 +                  UserDerefObjectCo(MsgWindow);
 +                  /* eat the message, search again */
 +                  goto CheckMessages;
 +               }
 +            }
 +
 +            UserDerefObjectCo(MsgWindow);
 +         }
 +         else
 +         {
 +            co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
 +         }
 +
 +//         if(MsgWindow)
 +//         {
 +//            UserDereferenceObject(MsgWindow);
 +//         }
 +
 +         goto MsgExit;
 +      }
 +
 +      if ( ( Msg->Msg.hwnd &&
 +             Msg->Msg.message >= WM_MOUSEFIRST &&
 +             Msg->Msg.message <= WM_MOUSELAST ) &&
 +           co_IntTranslateMouseMessage( ThreadQueue,
 +                                       &Msg->Msg,
 +                                       &HitTest,
 +                                        FALSE) )
 +    /* FIXME - check message filter again, if the message doesn't match anymore,
 +               search again */
 +      {
 +         /* eat the message, search again */
 +         goto CheckMessages;
 +      }
 +
 +MsgExit:
 +      if ( ISITHOOKED(WH_MOUSE) && IS_MOUSE_MESSAGE(Msg->Msg.message))
 +      {
 +          if(!ProcessMouseMessage(&Msg->Msg, HitTest, RemoveMsg))
 +                {
 +                        return FALSE;
 +                }
 +        }
 +
 +      if ( ISITHOOKED(WH_KEYBOARD) && IS_KBD_MESSAGE(Msg->Msg.message))
 +      {
 +          if(!ProcessKeyboardMessage(&Msg->Msg, RemoveMsg))
 +          {
 +              return FALSE;
 +          }
 +      }
 +      // The WH_GETMESSAGE hook enables an application to monitor messages about to
 +      // be returned by the GetMessage or PeekMessage function.
 +      if (ISITHOOKED(WH_GETMESSAGE))
 +      {
 +         //DPRINT1("Peek WH_GETMESSAGE -> %x\n",&Msg);
 +         co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)&Msg->Msg);
 +      }
 +      return TRUE;
 +   }
 +
 +   return Present;
 +}
 +
 +static NTSTATUS FASTCALL
 +CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
 +{
 +   NTSTATUS Status;
 +
 +   PVOID KernelMem;
 +   UINT Size;
 +
 +   *KernelModeMsg = *UserModeMsg;
 +
 +   /* See if this message type is present in the table */
 +   if (NULL == MsgMemoryEntry)
 +   {
 +      /* Not present, no copying needed */
 +      return STATUS_SUCCESS;
 +   }
 +
 +   /* Determine required size */
 +   Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
 +
 +   if (0 != Size)
 +   {
 +      /* Allocate kernel mem */
 +      KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
 +      if (NULL == KernelMem)
 +      {
 +         DPRINT1("Not enough memory to copy message to kernel mem\n");
 +         return STATUS_NO_MEMORY;
 +      }
 +      KernelModeMsg->lParam = (LPARAM) KernelMem;
 +
 +      /* Copy data if required */
 +      if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
 +      {
 +         Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
 +         if (! NT_SUCCESS(Status))
 +         {
 +            DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
 +            ExFreePoolWithTag(KernelMem, TAG_MSG);
 +            return Status;
 +         }
 +      }
 +      else
 +      {
 +         /* Make sure we don't pass any secrets to usermode */
 +         RtlZeroMemory(KernelMem, Size);
 +      }
 +   }
 +   else
 +   {
 +      KernelModeMsg->lParam = 0;
 +   }
 +
 +   return STATUS_SUCCESS;
 +}
 +
 +static NTSTATUS FASTCALL
 +CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
 +{
 +   NTSTATUS Status;
 +   PMSGMEMORY MsgMemoryEntry;
 +   UINT Size;
 +
 +   /* See if this message type is present in the table */
 +   MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
 +   if (NULL == MsgMemoryEntry)
 +   {
 +      /* Not present, no copying needed */
 +      return STATUS_SUCCESS;
 +   }
 +
 +   /* Determine required size */
 +   Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
 +
 +   if (0 != Size)
 +   {
 +      /* Copy data if required */
 +      if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
 +      {
 +         Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
 +         if (! NT_SUCCESS(Status))
 +         {
 +            DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
 +            ExFreePool((PVOID) KernelModeMsg->lParam);
 +            return Status;
 +         }
 +      }
 +
 +      ExFreePool((PVOID) KernelModeMsg->lParam);
 +   }
 +
 +   return STATUS_SUCCESS;
 +}
 +
 +static BOOL FASTCALL
 +co_IntWaitMessage( PWINDOW_OBJECT Window,
 +                   UINT MsgFilterMin,
 +                   UINT MsgFilterMax )
 +{
 +   PTHREADINFO pti;
 +   PUSER_MESSAGE_QUEUE ThreadQueue;
 +   NTSTATUS Status = STATUS_SUCCESS;
 +   USER_MESSAGE Msg;
 +
 +   pti = PsGetCurrentThreadWin32Thread();
 +   ThreadQueue = pti->MessageQueue;
 +
 +   do
 +   {
 +      if ( co_IntPeekMessage( &Msg,
 +                               Window,
 +                               MsgFilterMin,
 +                               MsgFilterMax,
 +                               PM_NOREMOVE))
 +      {
 +         return TRUE;
 +      }
 +      /* Nothing found. Wait for new messages. */
 +      Status = co_MsqWaitForNewMessages( ThreadQueue,
 +                                         Window,
 +                                         MsgFilterMin,
 +                                         MsgFilterMax);
 +   }
 +   while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
 +           STATUS_TIMEOUT == Status );
 +
 +   if (!NT_SUCCESS(Status))
 +   {
 +      SetLastNtError(Status);
 +      DPRINT1("Exit co_IntWaitMessage on error!\n");
 +   }
 +
 +   return FALSE;
 +}
 +
 +BOOL FASTCALL
 +co_IntGetPeekMessage( PMSG pMsg,
 +                      HWND hWnd,
 +                      UINT MsgFilterMin,
 +                      UINT MsgFilterMax,
 +                      UINT RemoveMsg,
 +                      BOOL bGMSG )
 +{
 +   BOOL Present;
 +   PWINDOW_OBJECT Window;
 +   USER_MESSAGE Msg;
 +
 +   if ( hWnd == HWND_TOPMOST ||
 +        hWnd == HWND_BROADCAST )
 +      hWnd = HWND_BOTTOM;
 +
 +   /* Validate input */
 +   if (hWnd && hWnd != HWND_BOTTOM)
 +   {
 +      if (!(Window = UserGetWindowObject(hWnd)))
 +      {
 +         if (bGMSG)
 +            return -1;
 +         else
 +            return FALSE;
 +      }
 +   }
 +   else
 +   {
 +      Window = (PWINDOW_OBJECT)hWnd;
 +   }
 +
 +   if (MsgFilterMax < MsgFilterMin)
 +   {
 +      MsgFilterMin = 0;
 +      MsgFilterMax = 0;
 +   }
 +
 +   do
 +   {
 +      Present = co_IntPeekMessage( &Msg,
 +                                    Window,
 +                                    MsgFilterMin,
 +                                    MsgFilterMax,
 +                                    RemoveMsg );
 +      if (Present)
 +      {
 +         RtlCopyMemory( pMsg, &Msg.Msg, sizeof(MSG));
 +
 +         if (bGMSG)
 +            return (WM_QUIT != pMsg->message);
 +         else
 +            return TRUE;
 +      }
 +
 +      if ( bGMSG && !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
 +      {
 +         return -1;
 +      }
 +      else
 +      {
 +         if (!(RemoveMsg & PM_NOYIELD))
 +         {
 +         // Yield this thread!
 +            UserLeave();
 +            ZwYieldExecution();
 +            UserEnterExclusive();
 +         // Fall through to fail.
 +         }
 +      }
 +   }
 +   while( bGMSG && !Present );
 +
 +   return FALSE;
 +}
 +
 +BOOL FASTCALL
 +UserPostThreadMessage( DWORD idThread,
 +                       UINT Msg,
 +                       WPARAM wParam,
 +                       LPARAM lParam )
 +{
 +   MSG Message;
 +   PETHREAD peThread;
 +   PTHREADINFO pThread;
 +   LARGE_INTEGER LargeTickCount;
 +   NTSTATUS Status;
 +
 +   DPRINT1("UserPostThreadMessage wParam 0x%x  lParam 0x%x\n", wParam,lParam);
 +
 +   if (FindMsgMemory(Msg) != 0)
 +   {
 +      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
 +      return FALSE;
 +   }
 +
 +   Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
 +
 +   if( Status == STATUS_SUCCESS )
 +   {
 +      pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
 +      if( !pThread ||
 +          !pThread->MessageQueue ||
 +         (pThread->TIF_flags & TIF_INCLEANUP))
 +      {
 +         ObDereferenceObject( peThread );
 +         return FALSE;
 +      }
 +
 +      Message.hwnd = NULL;
 +      Message.message = Msg;
 +      Message.wParam = wParam;
 +      Message.lParam = lParam;
 +      Message.pt = gpsi->ptCursor;
 +
 +      KeQueryTickCount(&LargeTickCount);
 +      pThread->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
 +      MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
 +      ObDereferenceObject( peThread );
 +      return TRUE;
 +   }
 +   else
 +   {
 +      SetLastNtError( Status );
 +   }
 +   return FALSE;
 +}
 +
 +BOOL FASTCALL
 +UserPostMessage( HWND Wnd,
 +                 UINT Msg,
 +                 WPARAM wParam,
 +                 LPARAM lParam )
 +{
 +   PTHREADINFO pti;
 +   MSG Message;
 +   LARGE_INTEGER LargeTickCount;
 +
 +   if (FindMsgMemory(Msg) != 0)
 +   {
 +      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
 +      return FALSE;
 +   }
 +
 +   if (!Wnd)
 +      return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
 +                                    Msg,
 +                                    wParam,
 +                                    lParam);
 +
 +   if (Wnd == HWND_BROADCAST)
 +   {
 +      HWND *List;
 +      PWINDOW_OBJECT DesktopWindow;
 +      ULONG i;
 +
 +      DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
 +      List = IntWinListChildren(DesktopWindow);
 +
 +      if (List != NULL)
 +      {
 +         UserPostMessage(DesktopWindow->hSelf, Msg, wParam, lParam);
 +         for (i = 0; List[i]; i++)
 +            UserPostMessage(List[i], Msg, wParam, lParam);
 +         ExFreePool(List);
 +      }
 +   }
 +   else
 +   {
 +      PWINDOW_OBJECT Window;
 +
 +      Window = UserGetWindowObject(Wnd);
 +      if ( !Window || !Window->Wnd )
 +      {
 +         return FALSE;
 +      }
 +
 +      pti = Window->Wnd->head.pti;
 +      if ( pti->TIF_flags & TIF_INCLEANUP )
 +      {
 +         DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
 +         return FALSE;
 +      }
 +
 +      if ( Window->state & WINDOWSTATUS_DESTROYING )
 +      {
 +         DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
 +         /* FIXME - last error code? */
 +         return FALSE;
 +      }
 +
 +      if (WM_QUIT == Msg)
 +      {
 +          MsqPostQuitMessage(Window->pti->MessageQueue, wParam);
 +      }
 +      else
 +      {
 +         Message.hwnd = Wnd;
 +         Message.message = Msg;
 +         Message.wParam = wParam;
 +         Message.lParam = lParam;
 +         Message.pt = gpsi->ptCursor;
 +         KeQueryTickCount(&LargeTickCount);
 +         pti->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
 +         MsqPostMessage(Window->pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
 +      }
 +   }
 +   return TRUE;
 +}
 +
 +
 +LRESULT FASTCALL
 +co_IntSendMessage( HWND hWnd,
 +                   UINT Msg,
 +                   WPARAM wParam,
 +                   LPARAM lParam )
 +{
 +   ULONG_PTR Result = 0;
 +   if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
 +   {
 +      return (LRESULT)Result;
 +   }
 +   return 0;
 +}
 +
 +static
 +LRESULT FASTCALL
 +co_IntSendMessageTimeoutSingle( HWND hWnd,
 +                                UINT Msg,
 +                                WPARAM wParam,
 +                                LPARAM lParam,
 +                                UINT uFlags,
 +                                UINT uTimeout,
 +                                ULONG_PTR *uResult )
 +{
 +   ULONG_PTR Result;
 +   NTSTATUS Status;
 +   PWINDOW_OBJECT Window = NULL;
 +   PMSGMEMORY MsgMemoryEntry;
 +   INT lParamBufferSize;
 +   LPARAM lParamPacked;
 +   PTHREADINFO Win32Thread;
 +   DECLARE_RETURN(LRESULT);
 +   USER_REFERENCE_ENTRY Ref;
 +
 +   if (!(Window = UserGetWindowObject(hWnd)))
 +   {
 +       RETURN( FALSE);
 +   }
 +
 +   UserRefObjectCo(Window, &Ref);
 +
 +   Win32Thread = PsGetCurrentThreadWin32Thread();
 +
 +   IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
 +
 +   if ( NULL != Win32Thread &&
 +        Window->pti->MessageQueue == Win32Thread->MessageQueue)
 +   {
 +      if (Win32Thread->TIF_flags & TIF_INCLEANUP)
 +      {
 +         /* Never send messages to exiting threads */
 +          RETURN( FALSE);
 +      }
 +
 +      /* See if this message type is present in the table */
 +      MsgMemoryEntry = FindMsgMemory(Msg);
 +      if (NULL == MsgMemoryEntry)
 +      {
 +         lParamBufferSize = -1;
 +      }
 +      else
 +      {
 +         lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
 +      }
 +
 +      if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
 +      {
 +          DPRINT1("Failed to pack message parameters\n");
 +          RETURN( FALSE);
 +      }
 +
 +      Result = (ULONG_PTR)co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
 +                                               !Window->Wnd->Unicode,
 +                                                hWnd,
 +                                                Msg,
 +                                                wParam,
 +                                                lParamPacked,
 +                                                lParamBufferSize );
 +      if(uResult)
 +      {
 +         *uResult = Result;
 +      }
 +
 +      IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
 +
 +      if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
 +      {
 +         DPRINT1("Failed to unpack message parameters\n");
 +         RETURN( TRUE);
 +      }
 +
 +      RETURN( TRUE);
 +   }
 +
 +   if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->pti->MessageQueue))
 +   {
 +      /* FIXME - Set a LastError? */
 +      RETURN( FALSE);
 +   }
 +
 +   if (Window->state & WINDOWSTATUS_DESTROYING)
 +   {
 +      /* FIXME - last error? */
 +      DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
 +      RETURN( FALSE);
 +   }
 +
 +   do
 +   {
 +      Status = co_MsqSendMessage( Window->pti->MessageQueue,
 +                                                       hWnd,
 +                                                        Msg,
 +                                                     wParam,
 +                                                     lParam,
 +                                                   uTimeout,
 +                                      (uFlags & SMTO_BLOCK),
 +                                                 MSQ_NORMAL,
 +                                                    uResult );
 +   }
 +   while ((STATUS_TIMEOUT == Status) &&
 +          (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
 +          !MsqIsHung(Window->pti->MessageQueue));
 +
 +   IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
 +
 +   if (STATUS_TIMEOUT == Status)
 +   {
 +/*
 +   MSDN says:
 +      Microsoft Windows 2000: If GetLastError returns zero, then the function
 +      timed out.
 +      XP+ : If the function fails or times out, the return value is zero.
 +      To get extended error information, call GetLastError. If GetLastError
 +      returns ERROR_TIMEOUT, then the function timed out.
 + */
 +      SetLastWin32Error(ERROR_TIMEOUT);
 +      RETURN( FALSE);
 +   }
 +   else if (! NT_SUCCESS(Status))
 +   {
 +      SetLastNtError(Status);
 +      RETURN( FALSE);
 +   }
 +
 +   RETURN( TRUE);
 +
 +CLEANUP:
 +   if (Window) UserDerefObjectCo(Window);
 +   END_CLEANUP;
 +}
 +
 +LRESULT FASTCALL
 +co_IntSendMessageTimeout( HWND hWnd,
 +                          UINT Msg,
 +                          WPARAM wParam,
 +                          LPARAM lParam,
 +                          UINT uFlags,
 +                          UINT uTimeout,
 +                          ULONG_PTR *uResult )
 +{
 +   PWINDOW_OBJECT DesktopWindow;
 +   HWND *Children;
 +   HWND *Child;
 +
 +   if (HWND_BROADCAST != hWnd)
 +   {
 +      return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
 +   }
 +
 +   DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
 +   if (NULL == DesktopWindow)
 +   {
 +      SetLastWin32Error(ERROR_INTERNAL_ERROR);
 +      return 0;
 +   }
 +
 +   /* Send message to the desktop window too! */
 +   co_IntSendMessageTimeoutSingle(DesktopWindow->hSelf, Msg, wParam, lParam, uFlags, uTimeout, uResult);
 +
 +   Children = IntWinListChildren(DesktopWindow);
 +   if (NULL == Children)
 +   {
 +      return 0;
 +   }
 +
 +   for (Child = Children; NULL != *Child; Child++)
 +   {
 +      co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
 +   }
 +
 +   ExFreePool(Children);
 +
 +   return (LRESULT) TRUE;
 +}
 +
 +LRESULT FASTCALL co_IntSendMessageNoWait(HWND hWnd,
 +                                         UINT Msg,
 +                                         WPARAM wParam,
 +                                         LPARAM lParam)
 +{
 +   ULONG_PTR Result = 0;
 +   co_IntSendMessageWithCallBack(hWnd,
 +                                 Msg,
 +                                 wParam,
 +                                 lParam,
 +                                 NULL,
 +                                 0,
 +                                 &Result);
 +   return Result;
 +}
 +
 +LRESULT FASTCALL
 +co_IntSendMessageWithCallBack( HWND hWnd,
 +                               UINT Msg,
 +                               WPARAM wParam,
 +                               LPARAM lParam,
 +                               SENDASYNCPROC CompletionCallback,
 +                               ULONG_PTR CompletionCallbackContext,
 +                               ULONG_PTR *uResult)
 +{
 +   ULONG_PTR Result;
 +   PWINDOW_OBJECT Window = NULL;
 +   PMSGMEMORY MsgMemoryEntry;
 +   INT lParamBufferSize;
 +   LPARAM lParamPacked;
 +   PTHREADINFO Win32Thread;
 +   DECLARE_RETURN(LRESULT);
 +   USER_REFERENCE_ENTRY Ref;
 +   PUSER_SENT_MESSAGE Message;
 +
 +   if (!(Window = UserGetWindowObject(hWnd)))
 +   {
 +       RETURN(FALSE);
 +   }
 +
 +   UserRefObjectCo(Window, &Ref);
 +
 +   if (Window->state & WINDOWSTATUS_DESTROYING)
 +   {
 +      /* FIXME - last error? */
 +      DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
 +      RETURN(FALSE);
 +   }
 +
 +   Win32Thread = PsGetCurrentThreadWin32Thread();
 +
 +   IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
 +
 +   if (Win32Thread == NULL)
 +   {
 +     ASSERT(FALSE);
 +     RETURN(FALSE);
 +   }
 +
 +   if (Win32Thread->TIF_flags & TIF_INCLEANUP)
 +   {
 +      /* Never send messages to exiting threads */
 +       RETURN(FALSE);
 +   }
 +
 +   /* See if this message type is present in the table */
 +   MsgMemoryEntry = FindMsgMemory(Msg);
 +   if (NULL == MsgMemoryEntry)
 +   {
 +      lParamBufferSize = -1;
 +   }
 +   else
 +   {
 +      lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
 +   }
 +
 +   if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->pti->MessageQueue != Win32Thread->MessageQueue)))
 +   {
 +       DPRINT1("Failed to pack message parameters\n");
 +       RETURN( FALSE);
 +   }
 +
 +   /* If this is not a callback and it can be sent now, then send it. */
 +   if ((Window->pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
 +   {
 +
 +      Result = (ULONG_PTR)co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
 +                                               !Window->Wnd->Unicode,
 +                                                hWnd,
 +                                                Msg,
 +                                                wParam,
 +                                                lParamPacked,
 +                                                lParamBufferSize );
 +      if(uResult)
 +      {
 +         *uResult = Result;
 +      }
 +   }
 +
 +   IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
 +
 +   if ((Window->pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
 +   {
 +      if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
 +      {
 +         DPRINT1("Failed to unpack message parameters\n");
 +      }
 +      RETURN(TRUE);
 +   }
 +
 +   if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
 +   {
 +      DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
 +      return STATUS_INSUFFICIENT_RESOURCES;
 +   }
 +
 +   Message->Msg.hwnd = hWnd;
 +   Message->Msg.message = Msg;
 +   Message->Msg.wParam = wParam;
 +   Message->Msg.lParam = lParamPacked;
 +   Message->CompletionEvent = NULL;
 +   Message->Result = 0;
 +   Message->SenderQueue = NULL; //Win32Thread->MessageQueue;
 +
 +   IntReferenceMessageQueue(Window->pti->MessageQueue);
 +   Message->CompletionCallback = CompletionCallback;
 +   Message->CompletionCallbackContext = CompletionCallbackContext;
 +   Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
 +   Message->HasPackedLParam = (lParamBufferSize > 0);
 +
 +   InsertTailList(&Window->pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
 +   IntDereferenceMessageQueue(Window->pti->MessageQueue);
 +
 +   RETURN(TRUE);
 +
 +CLEANUP:
 +   if (Window) UserDerefObjectCo(Window);
 +   END_CLEANUP;
 +}
 +
 +/* This function posts a message if the destination's message queue belongs to
 +   another thread, otherwise it sends the message. It does not support broadcast
 +   messages! */
 +LRESULT FASTCALL
 +co_IntPostOrSendMessage( HWND hWnd,
 +                         UINT Msg,
 +                         WPARAM wParam,
 +                         LPARAM lParam )
 +{
 +   ULONG_PTR Result;
 +   PTHREADINFO pti;
 +   PWINDOW_OBJECT Window;
 +
 +   if ( hWnd == HWND_BROADCAST )
 +   {
 +      return 0;
 +   }
 +
 +   if(!(Window = UserGetWindowObject(hWnd)))
 +   {
 +      return 0;
 +   }
 +
 +   pti = PsGetCurrentThreadWin32Thread();
 +
 +   if ( Window->pti->MessageQueue != pti->MessageQueue &&
 +        FindMsgMemory(Msg) == 0 )
 +   {
 +      Result = UserPostMessage(hWnd, Msg, wParam, lParam);
 +   }
 +   else
 +   {
 +      if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
 +      {
 +         Result = 0;
 +      }
 +   }
 +
 +   return (LRESULT)Result;
 +}
 +
 +LRESULT FASTCALL
 +co_IntDoSendMessage( HWND hWnd,
 +                     UINT Msg,
 +                     WPARAM wParam,
 +                     LPARAM lParam,
 +                     PDOSENDMESSAGE dsm,
 +                     PNTUSERSENDMESSAGEINFO UnsafeInfo )
 +{
 +   PTHREADINFO pti;
 +   LRESULT Result = TRUE;
 +   NTSTATUS Status;
 +   PWINDOW_OBJECT Window = NULL;
 +   NTUSERSENDMESSAGEINFO Info;
 +   MSG UserModeMsg;
 +   MSG KernelModeMsg;
 +   PMSGMEMORY MsgMemoryEntry;
 +
 +   RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
 +
 +   /* FIXME: Call hooks. */
 +   if (HWND_BROADCAST != hWnd)
 +   {
 +      Window = UserGetWindowObject(hWnd);
 +      if ( !Window || !Window->Wnd )
 +      {
 +         /* Tell usermode to not touch this one */
 +         Info.HandledByKernel = TRUE;
 +         MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
 +         return 0;
 +      }
 +   }
 +
 +   /* Check for an exiting window. */
 +   if (Window && Window->state & WINDOWSTATUS_DESTROYING)
 +   {
 +      DPRINT1("co_IntDoSendMessage Window Exiting!\n");
 +   }
 +
 +   /* See if the current thread can handle the message */
 +   pti = PsGetCurrentThreadWin32Thread();
 +
 +   // This is checked in user mode!!!!!!!
 +   if ( HWND_BROADCAST != hWnd &&
 +        NULL != pti &&
 +        Window->pti->MessageQueue == pti->MessageQueue &&
 +       !ISITHOOKED(WH_CALLWNDPROC) &&
 +       !ISITHOOKED(WH_CALLWNDPROCRET) &&
 +        ( Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST ) )
 +   {
 +      /* Gather the information usermode needs to call the window proc directly */
 +      Info.HandledByKernel = FALSE;
 +
 +      Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
 +                                sizeof(BOOL));
 +      if (! NT_SUCCESS(Status))
 +      {
 +         Info.Ansi = ! Window->Wnd->Unicode;
 +      }
 +
 +      Info.Ansi = !Window->Wnd->Unicode;
 +      Info.Proc = Window->Wnd->lpfnWndProc;
 +   }
 +   else
 +   {
 +      /* Must be handled by other thread */
 +//      if (HWND_BROADCAST != hWnd)
 +//      {
 +//         UserDereferenceObject(Window);
 +//      }
 +      Info.HandledByKernel = TRUE;
 +      UserModeMsg.hwnd = hWnd;
 +      UserModeMsg.message = Msg;
 +      UserModeMsg.wParam = wParam;
 +      UserModeMsg.lParam = lParam;
 +      MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
 +
 +      Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
 +      if (! NT_SUCCESS(Status))
 +      {
 +         MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
 +         SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +         return (dsm ? 0 : -1);
 +      }
 +
 +      if(!dsm)
 +      {
 +         Result = co_IntSendMessage( KernelModeMsg.hwnd,
 +                                     KernelModeMsg.message,
 +                                     KernelModeMsg.wParam,
 +                                     KernelModeMsg.lParam );
 +      }
 +      else
 +      {
 +         Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
 +                                            KernelModeMsg.message,
 +                                            KernelModeMsg.wParam,
 +                                            KernelModeMsg.lParam,
 +                                            dsm->uFlags,
 +                                            dsm->uTimeout,
 +                                           &dsm->Result );
 +      }
 +
 +      Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
 +      if (! NT_SUCCESS(Status))
 +      {
 +         MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
 +         SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +         return(dsm ? 0 : -1);
 +      }
 +   }
 +
 +   Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
 +   if (! NT_SUCCESS(Status))
 +   {
 +      SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +   }
 +
 +   return (LRESULT)Result;
 +}
 +
 +
 +BOOL FASTCALL
 +UserSendNotifyMessage( HWND hWnd,
 +                       UINT Msg,
 +                       WPARAM wParam,
 +                       LPARAM lParam )
 +{
 +   BOOL Result = TRUE;
 +
 +   if (FindMsgMemory(Msg) != 0)
 +   {
 +      SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
 +      return FALSE;
 +   }
 +
 +   // Basicly the same as IntPostOrSendMessage
 +   if (hWnd == HWND_BROADCAST) //Handle Broadcast
 +   {
 +      HWND *List;
 +      PWINDOW_OBJECT DesktopWindow;
 +      ULONG i;
 +
 +      DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
 +      List = IntWinListChildren(DesktopWindow);
 +
 +      if (List != NULL)
 +      {
 +         UserSendNotifyMessage(DesktopWindow->hSelf, Msg, wParam, lParam);
 +         for (i = 0; List[i]; i++)
 +         {
 +            UserSendNotifyMessage(List[i], Msg, wParam, lParam);
 +         }
 +         ExFreePool(List);
 +      }
 +   }
 +   else
 +   {
 +     ULONG_PTR PResult;
 +     PTHREADINFO pti;
 +     PWINDOW_OBJECT Window;
 +     MSG Message;
 +
 +      if ( !(Window = UserGetWindowObject(hWnd)) ) return FALSE;
 +
 +      pti = PsGetCurrentThreadWin32Thread();
 +
 +      if (Window->pti->MessageQueue != pti->MessageQueue)
 +      { // Send message w/o waiting for it.
 +         Result = UserPostMessage(hWnd, Msg, wParam, lParam);
 +      }
 +      else
 +      { // Handle message and callback.
 +         Message.hwnd = hWnd;
 +         Message.message = Msg;
 +         Message.wParam = wParam;
 +         Message.lParam = lParam;
 +
 +         Result = co_IntSendMessageTimeoutSingle( hWnd,
 +                                                  Msg,
 +                                                  wParam,
 +                                                  lParam,
 +                                                  SMTO_NORMAL,
 +                                                  0,
 +                                                 &PResult );
 +      }
 +   }
 +   return Result;
 +}
 +
 +
 +DWORD APIENTRY
 +IntGetQueueStatus(BOOL ClearChanges)
 +{
 +   PTHREADINFO pti;
 +   PUSER_MESSAGE_QUEUE Queue;
 +   DWORD Result;
 +   DECLARE_RETURN(DWORD);
 +
 +   DPRINT("Enter IntGetQueueStatus\n");
 +
 +   pti = PsGetCurrentThreadWin32Thread();
 +   Queue = pti->MessageQueue;
 +
 +   Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
 +   if (ClearChanges)
 +   {
 +      Queue->ChangedBits = 0;
 +   }
 +
 +   RETURN(Result);
 +
 +CLEANUP:
 +   DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
 +   END_CLEANUP;
 +}
 +
 +BOOL APIENTRY
 +IntInitMessagePumpHook()
 +{
 +   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
 +   {
 +     ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook++;
 +     return TRUE;
 +   }
 +   return FALSE;
 +}
 +
 +BOOL APIENTRY
 +IntUninitMessagePumpHook()
 +{
 +   if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
 +   {
 +      if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook <= 0)
 +      {
 +         return FALSE;
 +      }
 +      ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook--;
 +      return TRUE;
 +   }
 +   return FALSE;
 +}
 +
 +/** Functions ******************************************************************/
 +
 +BOOL APIENTRY
 +NtUserPostMessage(HWND hWnd,
 +                  UINT Msg,
 +                  WPARAM wParam,
 +                  LPARAM lParam)
 +{
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserPostMessage\n");
 +   UserEnterExclusive();
 +
 +   RETURN( UserPostMessage(hWnd, Msg, wParam, lParam));
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +BOOL APIENTRY
 +NtUserPostThreadMessage(DWORD idThread,
 +                        UINT Msg,
 +                        WPARAM wParam,
 +                        LPARAM lParam)
 +{
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserPostThreadMessage\n");
 +   UserEnterExclusive();
 +
 +   RETURN( UserPostThreadMessage( idThread,
 +                                  Msg,
 +                                  wParam,
 +                                  lParam));
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +DWORD APIENTRY
 +NtUserQuerySendMessage(DWORD Unknown0)
 +{
 +   UNIMPLEMENTED;
 +
 +   return 0;
 +}
 +
 +
 +////////// API on the way out!
 +LRESULT APIENTRY
 +NtUserSendMessageTimeout( HWND hWnd,
 +                          UINT Msg,
 +                          WPARAM wParam,
 +                          LPARAM lParam,
 +                          UINT uFlags,
 +                          UINT uTimeout,
 +                          ULONG_PTR *uResult,
 +                          PNTUSERSENDMESSAGEINFO UnsafeInfo )
 +{
 +   DOSENDMESSAGE dsm;
 +   LRESULT Result;
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserSendMessageTimeout\n");
 +   UserEnterExclusive();
 +
 +   dsm.uFlags = uFlags;
 +   dsm.uTimeout = uTimeout;
 +   Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
 +   if(uResult != NULL && Result != 0)
 +   {
 +      NTSTATUS Status;
 +
 +      Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
 +      if(!NT_SUCCESS(Status))
 +      {
 +         SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +         RETURN( FALSE);
 +      }
 +   }
 +   RETURN( Result);
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +LRESULT APIENTRY
 +NtUserSendMessage( HWND Wnd,
 +                   UINT Msg,
 +                   WPARAM wParam,
 +                   LPARAM lParam,
 +                   PNTUSERSENDMESSAGEINFO UnsafeInfo )
 +{
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserSendMessage\n");
 +   UserEnterExclusive();
 +
 +   RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +//////////
 +
 +BOOL APIENTRY
 +NtUserWaitMessage(VOID)
 +{
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("EnterNtUserWaitMessage\n");
 +   UserEnterExclusive();
 +
 +   RETURN(co_IntWaitMessage(NULL, 0, 0));
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +
 +BOOL APIENTRY
 +NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
 +                  HWND hWnd,
 +                  UINT MsgFilterMin,
 +                  UINT MsgFilterMax )
 +/*
 + * FUNCTION: Get a message from the calling thread's message queue.
 + * ARGUMENTS:
 + *      UnsafeMsg - Pointer to the structure which receives the returned message.
 + *      Wnd - Window whose messages are to be retrieved.
 + *      MsgFilterMin - Integer value of the lowest message value to be
 + *                     retrieved.
 + *      MsgFilterMax - Integer value of the highest message value to be
 + *                     retrieved.
 + */
 +{
 +   BOOL GotMessage;
 +   NTUSERGETMESSAGEINFO Info;
 +   NTSTATUS Status;
 +   /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
 +   PWINDOW_OBJECT Window = NULL;
 +   PMSGMEMORY MsgMemoryEntry;
 +   PVOID UserMem;
 +   UINT Size;
 +   USER_MESSAGE Msg;
 +   DECLARE_RETURN(BOOL);
 +//   USER_REFERENCE_ENTRY Ref;
 +
 +   DPRINT("Enter NtUserGetMessage\n");
 +   UserEnterExclusive();
 +
 +   /* Validate input */
 +   if (hWnd && !(Window = UserGetWindowObject(hWnd)))
 +   {
 +      RETURN(-1);
 +   }
 +
 +//   if (Window) UserRefObjectCo(Window, &Ref);
 +
 +   if (MsgFilterMax < MsgFilterMin)
 +   {
 +      MsgFilterMin = 0;
 +      MsgFilterMax = 0;
 +   }
 +
 +   do
 +   {
 +      GotMessage = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_REMOVE);
 +      if (GotMessage)
 +      {
 +         Info.Msg = Msg.Msg;
 +         /* See if this message type is present in the table */
 +         MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
 +         if (NULL == MsgMemoryEntry)
 +         {
 +            /* Not present, no copying needed */
 +            Info.LParamSize = 0;
 +         }
 +         else
 +         {
 +            /* Determine required size */
 +            Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
 +                                 Info.Msg.lParam);
 +            /* Allocate required amount of user-mode memory */
 +            Info.LParamSize = Size;
 +            UserMem = NULL;
 +            Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
 +                                             &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
 +
 +            if (! NT_SUCCESS(Status))
 +            {
 +               SetLastNtError(Status);
 +               RETURN( (BOOL) -1);
 +            }
 +            /* Transfer lParam data to user-mode mem */
 +            Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
 +            if (! NT_SUCCESS(Status))
 +            {
 +               ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
 +                                   &Info.LParamSize, MEM_DECOMMIT);
 +               SetLastNtError(Status);
 +               RETURN( (BOOL) -1);
 +            }
 +            Info.Msg.lParam = (LPARAM) UserMem;
 +         }
 +         if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
 +         {
 +            ExFreePool((void *) Msg.Msg.lParam);
 +         }
 +         Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
 +         if (! NT_SUCCESS(Status))
 +         {
 +            SetLastNtError(Status);
 +            RETURN( (BOOL) -1);
 +         }
 +      }
 +      else if (! co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax))
 +      {
 +         RETURN( (BOOL) -1);
 +      }
 +   }
 +   while (! GotMessage);
 +
 +   RETURN( WM_QUIT != Info.Msg.message);
 +
 +CLEANUP:
 +//   if (Window) UserDerefObjectCo(Window);
 +
 +   DPRINT("Leave NtUserGetMessage\n");
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +
 +BOOL
 +APIENTRY
 +NtUserGetMessageX(
 +   PMSG pMsg,
 +   HWND hWnd,
 +   UINT MsgFilterMin,
 +   UINT MsgFilterMax)
 +{
 +   MSG Msg;
 +   BOOL Ret = FALSE;
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserGetMessage\n");
 +   UserEnterExclusive();
 +
 +   if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
 +   {
 +      SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +      RETURN( Ret);
 +   }
 +
 +   RtlZeroMemory(&Msg, sizeof(MSG));
 +
 +   Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
 +
 +   if (Ret)
 +   {
 +      _SEH2_TRY
 +      {
 +         ProbeForWrite(pMsg, sizeof(MSG), 1);
 +         RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
 +      }
 +      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +      {
 +         SetLastNtError(_SEH2_GetExceptionCode());
 +         Ret = FALSE;
 +      }
 +      _SEH2_END;
 +   }
 +   RETURN( Ret);
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserGetMessage\n");
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +BOOL APIENTRY
 +NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
 +                  HWND hWnd,
 +                  UINT MsgFilterMin,
 +                  UINT MsgFilterMax,
 +                  UINT RemoveMsg)
 +{
 +   NTSTATUS Status;
 +   BOOL Present;
 +   NTUSERGETMESSAGEINFO Info;
 +   PWINDOW_OBJECT Window;
 +   PMSGMEMORY MsgMemoryEntry;
 +   PVOID UserMem;
 +   UINT Size;
 +   USER_MESSAGE Msg;
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserPeekMessage\n");
 +   UserEnterExclusive();
 +
 +   if (hWnd == (HWND)-1 || hWnd == (HWND)0x0000FFFF || hWnd == (HWND)0xFFFFFFFF)
 +      hWnd = (HWND)1;
 +
 +   /* Validate input */
 +   if (hWnd && hWnd != (HWND)1)
 +   {
 +      if (!(Window = UserGetWindowObject(hWnd)))
 +      {
 +         RETURN(-1);
 +      }
 +   }
 +   else
 +   {
 +      Window = (PWINDOW_OBJECT)hWnd;
 +   }
 +
 +   if (MsgFilterMax < MsgFilterMin)
 +   {
 +      MsgFilterMin = 0;
 +      MsgFilterMax = 0;
 +   }
 +
 +   Present = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, RemoveMsg);
 +   if (Present)
 +   {
 +
 +      Info.Msg = Msg.Msg;
 +      /* See if this message type is present in the table */
 +      MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
 +      if (NULL == MsgMemoryEntry)
 +      {
 +         /* Not present, no copying needed */
 +         Info.LParamSize = 0;
 +      }
 +      else
 +      {
 +         /* Determine required size */
 +         Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
 +                              Info.Msg.lParam);
 +         /* Allocate required amount of user-mode memory */
 +         Info.LParamSize = Size;
 +         UserMem = NULL;
 +         Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
 +                                          &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
 +         if (! NT_SUCCESS(Status))
 +         {
 +            SetLastNtError(Status);
 +            RETURN( (BOOL) -1);
 +         }
 +         /* Transfer lParam data to user-mode mem */
 +         Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
 +         if (! NT_SUCCESS(Status))
 +         {
 +            ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
 +                                &Info.LParamSize, MEM_RELEASE);
 +            SetLastNtError(Status);
 +            RETURN( (BOOL) -1);
 +         }
 +         Info.Msg.lParam = (LPARAM) UserMem;
 +      }
 +      if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
 +      {
 +         ExFreePool((void *) Msg.Msg.lParam);
 +      }
 +      Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
 +      if (! NT_SUCCESS(Status))
 +      {
 +         SetLastNtError(Status);
 +         RETURN( (BOOL) -1);
 +      }
 +   }
 +
 +   RETURN( Present);
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +BOOL
 +APIENTRY
 +NtUserPeekMessageX(
 +   PMSG pMsg,
 +   HWND hWnd,
 +   UINT MsgFilterMin,
 +   UINT MsgFilterMax,
 +   UINT RemoveMsg)
 +{
 +   MSG Msg;
 +   BOOL Ret = FALSE;
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserPeekMessage\n");
 +   UserEnterExclusive();
 +
 +   if ( RemoveMsg & PM_BADMSGFLAGS )
 +   {
 +      SetLastWin32Error(ERROR_INVALID_FLAGS);
 +      RETURN( Ret);
 +   }
 +
 +   RtlZeroMemory(&Msg, sizeof(MSG));
 +
 +   Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
 +
 +   if (Ret)
 +   {
 +      _SEH2_TRY
 +      {
 +         ProbeForWrite(pMsg, sizeof(MSG), 1);
 +         RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
 +      }
 +      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +      {
 +         SetLastNtError(_SEH2_GetExceptionCode());
 +         Ret = FALSE;
 +      }
 +      _SEH2_END;
 +   }
 +   RETURN( Ret);
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +BOOL
 +APIENTRY
 +NtUserCallMsgFilter(
 +   LPMSG lpmsg,
 +   INT code)
 +{
 +   BOOL BadChk = FALSE, Ret = FALSE;
 +   MSG Msg;
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserCallMsgFilter\n");
 +   UserEnterExclusive();
 +   if (lpmsg)
 +   {
 +      _SEH2_TRY
 +      {
 +         ProbeForRead((PVOID)lpmsg,
 +                       sizeof(MSG),
 +                                1);
 +         RtlCopyMemory( &Msg,
 +                (PVOID)lpmsg,
 +                 sizeof(MSG));
 +      }
 +      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +      {
 +         BadChk = TRUE;
 +      }
 +      _SEH2_END;
 +   }
 +   else
 +     RETURN( FALSE);
 +
 +   if (BadChk) RETURN( FALSE);
 +
 +   if ( ISITHOOKED(WH_SYSMSGFILTER) &&
 +        co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
 +   {
 +      Ret = TRUE;
 +   }
 +   else
 +   {
 +      if ( ISITHOOKED(WH_MSGFILTER) )
 +      {
 +         Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
 +      }
 +   }
 +
 +   _SEH2_TRY
 +   {
 +      ProbeForWrite((PVOID)lpmsg,
 +                     sizeof(MSG),
 +                               1);
 +      RtlCopyMemory((PVOID)lpmsg,
 +                            &Msg,
 +                     sizeof(MSG));
 +   }
 +   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +   {
 +      BadChk = TRUE;
 +   }
 +   _SEH2_END;
 +   if (BadChk) RETURN( FALSE);
 +   RETURN( Ret)
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +LRESULT APIENTRY
 +NtUserDispatchMessage(PMSG UnsafeMsgInfo)
 +{
 +  LRESULT Res = 0;
 +  BOOL Hit = FALSE;
 +  MSG SafeMsg;
 +
 +  UserEnterExclusive();
 +  _SEH2_TRY
 +  {
 +    ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
 +    RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
 +  }
 +  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +  {
 +    SetLastNtError(_SEH2_GetExceptionCode());
 +    Hit = TRUE;
 +  }
 +  _SEH2_END;
 +
 +  if (!Hit) Res = IntDispatchMessage(&SafeMsg);
 +
 +  UserLeave();
 +  return Res;
 +}
 +
 +
 +BOOL APIENTRY
 +NtUserTranslateMessage(LPMSG lpMsg,
 +                       UINT flags)
 +{
 +   NTSTATUS Status;
 +   MSG SafeMsg;
 +   DECLARE_RETURN(BOOL);
 +
 +   DPRINT("Enter NtUserTranslateMessage\n");
 +   UserEnterExclusive();
 +
 +   Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
 +   if(!NT_SUCCESS(Status))
 +   {
 +      SetLastNtError(Status);
 +      RETURN( FALSE);
 +   }
 +
 +   RETURN( IntTranslateKbdMessage(&SafeMsg, flags));
 +
 +CLEANUP:
 +   DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
 +   UserLeave();
 +   END_CLEANUP;
 +}
 +
 +BOOL APIENTRY
 +NtUserMessageCall(
 +   HWND hWnd,
 +   UINT Msg,
 +   WPARAM wParam,
 +   LPARAM lParam,
 +   ULONG_PTR ResultInfo,
 +   DWORD dwType, // fnID?
 +   BOOL Ansi)
 +{
 +   LRESULT lResult = 0;
 +   BOOL Ret = FALSE;
 +   BOOL BadChk = FALSE;
 +   PWINDOW_OBJECT Window = NULL;
 +   USER_REFERENCE_ENTRY Ref;
 +
 +   UserEnterExclusive();
 +
 +   /* Validate input */
 +   if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
 +   {
 +      UserLeave();
 +      return FALSE;
 +   }
 +   switch(dwType)
 +   {
 +      case FNID_DEFWINDOWPROC:
 +         UserRefObjectCo(Window, &Ref);
 +         lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
 +         Ret = TRUE;
 +         UserDerefObjectCo(Window);
 +      break;
 +      case FNID_SENDNOTIFYMESSAGE:
 +         Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
 +      break;
 +      case FNID_BROADCASTSYSTEMMESSAGE:
 +      {
 +         BROADCASTPARM parm;
 +         DWORD_PTR RetVal = 0;
 +
 +         if (ResultInfo)
 +         {
 +            _SEH2_TRY
 +            {
 +               ProbeForWrite((PVOID)ResultInfo,
 +                         sizeof(BROADCASTPARM),
 +                                             1);
 +               RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
 +            }
 +            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +            {
 +               BadChk = TRUE;
 +            }
 +            _SEH2_END;
 +            if (BadChk) break;
 +         }
 +         else
 +           break;
 +
 +         if ( parm.recipients & BSM_ALLDESKTOPS ||
 +              parm.recipients == BSM_ALLCOMPONENTS )
 +         {
 +         }
 +         else if (parm.recipients & BSM_APPLICATIONS)
 +         {
 +            if (parm.flags & BSF_QUERY)
 +            {
 +               if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
 +               {
 +                  co_IntSendMessageTimeout( HWND_BROADCAST,
 +                                            Msg,
 +                                            wParam,
 +                                            lParam,
 +                                            SMTO_ABORTIFHUNG,
 +                                            2000,
 +                                            &RetVal);
 +               }
 +               else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
 +               {
 +                  co_IntSendMessageTimeout( HWND_BROADCAST,
 +                                            Msg,
 +                                            wParam,
 +                                            lParam,
 +                                            SMTO_NOTIMEOUTIFNOTHUNG,
 +                                            2000,
 +                                            &RetVal);
 +               }
 +               else
 +               {
 +                  co_IntSendMessageTimeout( HWND_BROADCAST,
 +                                            Msg,
 +                                            wParam,
 +                                            lParam,
 +                                            SMTO_NORMAL,
 +                                            2000,
 +                                            &RetVal);
 +               }
 +            }
 +            else if (parm.flags & BSF_POSTMESSAGE)
 +            {
 +               Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
 +            }
 +            else if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
 +            {
 +               Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
 +            }
 +         }
 +      }
 +      break;
 +      case FNID_SENDMESSAGECALLBACK:
 +      {
 +         PCALL_BACK_INFO CallBackInfo = (PCALL_BACK_INFO)ResultInfo;
 +
 +         if (!CallBackInfo)
 +            break;
 +
 +         if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
 +             CallBackInfo->CallBack, CallBackInfo->Context, NULL))
 +         {
 +            DPRINT1("Callback failure!\n");
 +         }
 +      }
 +      break;
 +      // CallNextHook bypass.
 +      case FNID_CALLWNDPROC:
 +      case FNID_CALLWNDPROCRET:
 +      {
 +         PCLIENTINFO ClientInfo = GetWin32ClientInfo();
 +         PHOOK NextObj, Hook = ClientInfo->phkCurrent;
 +
 +         if (!ClientInfo || !Hook) break;
 +
 +         UserReferenceObject(Hook);
 +
 +         if (Hook->Thread && (Hook->Thread != PsGetCurrentThread()))
 +         {
 +            UserDereferenceObject(Hook);
 +            break;
 +         }
 +
 +         NextObj = IntGetNextHook(Hook);
 +         ClientInfo->phkCurrent = NextObj;
 +
 +         if ( Hook->HookId == WH_CALLWNDPROC)
 +         {
 +            CWPSTRUCT CWP;
 +            CWP.hwnd    = hWnd;
 +            CWP.message = Msg;
 +            CWP.wParam  = wParam;
 +            CWP.lParam  = lParam;
 +            DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
 +
 +            lResult = co_IntCallHookProc( Hook->HookId,
 +                                          HC_ACTION,
 +                                        ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
 +                                         (LPARAM)&CWP,
 +                                          Hook->Proc,
 +                                          Hook->Ansi,
 +                                          &Hook->ModuleName);
 +         }
 +         else
 +         {
 +            CWPRETSTRUCT CWPR;
 +            CWPR.hwnd    = hWnd;
 +            CWPR.message = Msg;
 +            CWPR.wParam  = wParam;
 +            CWPR.lParam  = lParam;
 +            CWPR.lResult = ClientInfo->dwHookData;
 +
 +            lResult = co_IntCallHookProc( Hook->HookId,
 +                                          HC_ACTION,
 +                                        ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
 +                                         (LPARAM)&CWPR,
 +                                          Hook->Proc,
 +                                          Hook->Ansi,
 +                                          &Hook->ModuleName);
 +         }
 +         UserDereferenceObject(Hook);
 +         lResult = (LRESULT) NextObj;
 +      }
 +      break;
 +   }
 +
 +   switch(dwType)
 +   {
 +      case FNID_DEFWINDOWPROC:
 +      case FNID_CALLWNDPROC:
 +      case FNID_CALLWNDPROCRET:
 +         if (ResultInfo)
 +         {
 +            _SEH2_TRY
 +            {
 +                ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
 +                RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
 +            }
 +            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +            {
 +                BadChk = TRUE;
 +            }
 +            _SEH2_END;
 +         }
 +         break;
 +      default:
 +         break;
 +   }
 +
 +   UserLeave();
 +
 +   return BadChk ? FALSE : Ret;
 +}
 +
 +#define INFINITE 0xFFFFFFFF
 +#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
 +
 +DWORD
 +APIENTRY
 +NtUserWaitForInputIdle(
 +   IN HANDLE hProcess,
 +   IN DWORD dwMilliseconds,
 +   IN BOOL Unknown2)
 +{
 +  PEPROCESS Process;
 +  PPROCESSINFO W32Process;
 +  NTSTATUS Status;
 +  HANDLE Handles[2];
 +  LARGE_INTEGER Timeout;
 +  ULONGLONG StartTime, Run, Elapsed = 0;
 +
 +  UserEnterExclusive();
 +
 +  Status = ObReferenceObjectByHandle(hProcess,
 +                                     PROCESS_QUERY_INFORMATION,
 +                                     PsProcessType,
 +                                     UserMode,
 +                                     (PVOID*)&Process,
 +                                     NULL);
 +
 +  if (!NT_SUCCESS(Status))
 +  {
 +     UserLeave();
 +     SetLastNtError(Status);
 +     return WAIT_FAILED;
 +  }
 +
 +  W32Process = (PPROCESSINFO)Process->Win32Process;
 +  if (!W32Process)
 +  {
 +      ObDereferenceObject(Process);
 +      UserLeave();
 +      SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +      return WAIT_FAILED;
 +  }
 +
 +  EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
 +
 +  Handles[0] = Process;
 +  Handles[1] = W32Process->InputIdleEvent;
 +
 +  if (!Handles[1])
 +  {
 +      ObDereferenceObject(Process);
 +      UserLeave();
 +      return STATUS_SUCCESS;  /* no event to wait on */
 +  }
 +
 +  StartTime = EngGetTickCount();
 +
 +  Run = dwMilliseconds;
 +
 +  DPRINT("WFII: waiting for %p\n", Handles[1] );
 +  do
 +  {
 +     Timeout.QuadPart = Run - Elapsed;
 +     UserLeave();
 +     Status = KeWaitForMultipleObjects( 2,
 +                                        Handles,
 +                                        WaitAny,
 +                                        UserRequest,
 +                                        UserMode,
 +                                        FALSE,
 +                             dwMilliseconds == INFINITE ? NULL : &Timeout,
 +                                        NULL);
 +     UserEnterExclusive();
 +
 +     if (!NT_SUCCESS(Status))
 +     {
 +        SetLastNtError(Status);
 +        Status = WAIT_FAILED;
 +        goto WaitExit;
 +     }
 +
 +     switch (Status)
 +     {
 +        case STATUS_WAIT_0:
 +           Status = WAIT_FAILED;
 +           goto WaitExit;
 +
 +        case STATUS_WAIT_2:
 +        {
 +           USER_MESSAGE Msg;
 +           co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
 +           break;
 +        }
 +
 +        case STATUS_USER_APC:
 +        case STATUS_ALERTED:
 +        case STATUS_TIMEOUT:
 +           DPRINT1("WFII: timeout\n");
 +           Status = STATUS_TIMEOUT;
 +           goto WaitExit;
 +
 +        default:
 +           DPRINT1("WFII: finished\n");
 +           Status = STATUS_SUCCESS;
 +           goto WaitExit;
 +     }
 +
 +     if (dwMilliseconds != INFINITE)
 +     {
 +        Elapsed = EngGetTickCount() - StartTime;
 +
 +        if (Elapsed > Run)
 +           Status = STATUS_TIMEOUT;
 +           break;
 +     }
 +  }
 +  while (1);
 +
 +WaitExit:
 +  if (W32Process->InputIdleEvent)
 +  {
 +     EngFreeMem((PVOID)W32Process->InputIdleEvent);
 +     W32Process->InputIdleEvent = NULL;
 +  }
 +  ObDereferenceObject(Process);
 +  UserLeave();
 +  return Status;
 +}
 +
 +/* EOF */
index 1f8fe79,0000000..ae988ae
mode 100644,000000..100644
--- /dev/null
@@@ -1,619 -1,0 +1,615 @@@
-   if (dc->prgnVis == NULL)
-   {
-     dc->prgnVis = IntSysCreateRectpRgn(0, 0, 0, 0);
-     GDIOBJ_CopyOwnership(hdc, ((PROSRGNDATA)dc->prgnVis)->BaseObject.hHmgr);
-   }
 +/*
 + *  ReactOS W32 Subsystem
 + *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  This program is distributed in the hope that it will be useful,
 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + *  GNU General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License along
 + *  with this program; if not, write to the Free Software Foundation, Inc.,
 + *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +
 +#include <win32k.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +int FASTCALL
 +CLIPPING_UpdateGCRegion(DC* Dc)
 +{
 +   PROSRGNDATA CombinedRegion;
 +   HRGN hRgnVis = Dc->prgnVis->BaseObject.hHmgr;
 +
 +    // would prefer this, but the rest of the code sucks
 +//    ASSERT(Dc->rosdc.hGCClipRgn);
 +//    ASSERT(Dc->rosdc.hClipRgn);
 +   if (!Dc->prgnVis)
 +   {
 +      DPRINT1("Warning, prgnVis is NULL!\n");
 +   }
 +   else
 +   {
 +       hRgnVis = Dc->prgnVis->BaseObject.hHmgr ;
 +   }
 +
 +
 +   if (Dc->rosdc.hGCClipRgn == NULL)
 +      Dc->rosdc.hGCClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
 +
 +   if (Dc->rosdc.hClipRgn == NULL)
 +      NtGdiCombineRgn(Dc->rosdc.hGCClipRgn, hRgnVis, 0, RGN_COPY);
 +   else
 +      NtGdiCombineRgn(Dc->rosdc.hGCClipRgn, Dc->rosdc.hClipRgn, hRgnVis, RGN_AND);
 +
 +   NtGdiOffsetRgn(Dc->rosdc.hGCClipRgn, Dc->ptlDCOrig.x, Dc->ptlDCOrig.y);
 +
 +   if((CombinedRegion = RGNOBJAPI_Lock(Dc->rosdc.hGCClipRgn, NULL)))
 +   {
 +     CLIPOBJ *CombinedClip;
 +
 +     CombinedClip = IntEngCreateClipRegion(CombinedRegion->rdh.nCount,
 +        CombinedRegion->Buffer,
 +        &CombinedRegion->rdh.rcBound);
 +
 +     RGNOBJAPI_Unlock(CombinedRegion);
 +
 +     if ( !CombinedClip )
 +     {
 +       DPRINT1("IntEngCreateClipRegion() failed\n");
 +       return ERROR;
 +     }
 +
 +     if(Dc->rosdc.CombinedClip != NULL)
 +       IntEngDeleteClipRegion(Dc->rosdc.CombinedClip);
 +
 +      Dc->rosdc.CombinedClip = CombinedClip ;
 +   }
 +
 +   return NtGdiOffsetRgn(Dc->rosdc.hGCClipRgn, -Dc->ptlDCOrig.x, -Dc->ptlDCOrig.y);
 +}
 +
 +INT FASTCALL
 +GdiSelectVisRgn(HDC hdc, HRGN hrgn)
 +{
 +  int retval;
 +  DC *dc;
 +
 +  if (!hrgn)
 +  {
 +      SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +      return ERROR;
 +  }
 +  if (!(dc = DC_LockDc(hdc)))
 +  {
 +      SetLastWin32Error(ERROR_INVALID_HANDLE);
 +      return ERROR;
 +  }
 +
 +  dc->fs &= ~DC_FLAG_DIRTY_RAO;
 +
++  ASSERT (dc->prgnVis != NULL);
 +
 +  retval = NtGdiCombineRgn(((PROSRGNDATA)dc->prgnVis)->BaseObject.hHmgr, hrgn, 0, RGN_COPY);
 +  if ( retval != ERROR )
 +  {
 +    NtGdiOffsetRgn(((PROSRGNDATA)dc->prgnVis)->BaseObject.hHmgr, -dc->ptlDCOrig.x, -dc->ptlDCOrig.y);
 +    CLIPPING_UpdateGCRegion(dc);
 +  }
 +  DC_UnlockDc(dc);
 +
 +  return retval;
 +}
 +
 +
 +int FASTCALL GdiExtSelectClipRgn(PDC dc,
 +                                 HRGN hrgn,
 +                                 int fnMode)
 +{
 +  //  dc->fs &= ~DC_FLAG_DIRTY_RAO;
 +
 +  if (!hrgn)
 +  {
 +    if (fnMode == RGN_COPY)
 +    {
 +      if (dc->rosdc.hClipRgn != NULL)
 +      {
 +        REGION_FreeRgnByHandle(dc->rosdc.hClipRgn);
 +        dc->rosdc.hClipRgn = NULL;
 +      }
 +    }
 +    else
 +    {
 +      SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +      return ERROR;
 +    }
 +  }
 +  else
 +  {
 +    if (!dc->rosdc.hClipRgn)
 +    {
 +      RECTL rect;
 +      if(dc->prgnVis)
 +      {
 +              REGION_GetRgnBox(dc->prgnVis, &rect);
 +        dc->rosdc.hClipRgn = IntSysCreateRectRgnIndirect(&rect);
 +      }
 +      else
 +      {
 +        dc->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
 +      }
 +    }
 +    if(fnMode == RGN_COPY)
 +    {
 +      NtGdiCombineRgn(dc->rosdc.hClipRgn, hrgn, 0, fnMode);
 +    }
 +    else
 +      NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, hrgn, fnMode);
 +  }
 +
 +  return CLIPPING_UpdateGCRegion(dc);
 +}
 +
 +
 +int APIENTRY NtGdiExtSelectClipRgn(HDC  hDC,
 +                                HRGN  hrgn,
 +                               int  fnMode)
 +{
 +  int retval;
 +  DC *dc;
 +
 +  if (!(dc = DC_LockDc(hDC)))
 +  {
 +      SetLastWin32Error(ERROR_INVALID_HANDLE);
 +      return ERROR;
 +  }
 +
 +  retval = GdiExtSelectClipRgn ( dc, hrgn, fnMode );
 +
 +  DC_UnlockDc(dc);
 +  return retval;
 +}
 +
 +INT FASTCALL
 +GdiGetClipBox(HDC hDC, PRECTL rc)
 +{
 +   INT retval;
 +   PDC dc;
 +   PROSRGNDATA pRgnNew, pRgn = NULL;
 +   BOOL Unlock = FALSE; //Small hack
 +
 +   if (!(dc = DC_LockDc(hDC)))
 +   {
 +      return ERROR;
 +   }
 +
 +   /* FIXME! Rao and Vis only! */
 +   if (dc->prgnAPI) // APIRGN
 +   {
 +      pRgn = dc->prgnAPI;
 +   }
 +   else if (dc->dclevel.prgnMeta) // METARGN
 +   {
 +      pRgn = dc->dclevel.prgnMeta;
 +   }
 +   else
 +   {
 +         Unlock = TRUE ;
 +       pRgn = REGION_LockRgn(dc->rosdc.hClipRgn); // CLIPRGN
 +   }
 +
 +   if (pRgn)
 +   {
 +      pRgnNew = IntSysCreateRectpRgn( 0, 0, 0, 0 );
 +
 +        if (!pRgnNew)
 +      {
 +         DC_UnlockDc(dc);
 +               if(Unlock) REGION_UnlockRgn(pRgn);
 +         return ERROR;
 +      }
 +
 +      IntGdiCombineRgn(pRgnNew, dc->prgnVis, pRgn, RGN_AND);
 +
 +      retval = REGION_GetRgnBox(pRgnNew, rc);
 +
 +        REGION_FreeRgnByHandle(pRgnNew->BaseObject.hHmgr);
 +
 +      DC_UnlockDc(dc);
 +        if(Unlock) REGION_UnlockRgn(pRgn);
 +      return retval;
 +   }
 +
 +   retval = REGION_GetRgnBox(dc->prgnVis, rc);
 +   IntDPtoLP(dc, (LPPOINT)rc, 2);
 +   DC_UnlockDc(dc);
 +
 +   return retval;
 +}
 +
 +INT APIENTRY
 +NtGdiGetAppClipBox(HDC hDC, PRECTL rc)
 +{
 +  INT Ret;
 +  NTSTATUS Status = STATUS_SUCCESS;
 +  RECTL Saferect;
 +
 +  Ret = GdiGetClipBox(hDC, &Saferect);
 +
 +  _SEH2_TRY
 +  {
 +    ProbeForWrite(rc,
 +                  sizeof(RECT),
 +                  1);
 +    *rc = Saferect;
 +  }
 +  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +  {
 +    Status = _SEH2_GetExceptionCode();
 +  }
 +  _SEH2_END;
 +
 +  if(!NT_SUCCESS(Status))
 +  {
 +    SetLastNtError(Status);
 +    return ERROR;
 +  }
 +
 +  return Ret;
 +}
 +
 +int APIENTRY NtGdiExcludeClipRect(HDC  hDC,
 +                         int  LeftRect,
 +                         int  TopRect,
 +                         int  RightRect,
 +                         int  BottomRect)
 +{
 +   INT Result;
 +   RECTL Rect;
 +   HRGN NewRgn;
 +   PDC dc = DC_LockDc(hDC);
 +
 +   if (!dc)
 +   {
 +      SetLastWin32Error(ERROR_INVALID_HANDLE);
 +      return ERROR;
 +   }
 +
 +   Rect.left = LeftRect;
 +   Rect.top = TopRect;
 +   Rect.right = RightRect;
 +   Rect.bottom = BottomRect;
 +
 +   IntLPtoDP(dc, (LPPOINT)&Rect, 2);
 +
 +   NewRgn = IntSysCreateRectRgnIndirect(&Rect);
 +   if (!NewRgn)
 +   {
 +      Result = ERROR;
 +   }
 +   else
 +   {
 +      if (!dc->rosdc.hClipRgn)
 +      {
 +         dc->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
 +         NtGdiCombineRgn(dc->rosdc.hClipRgn, ((PROSRGNDATA)dc->prgnVis)->BaseObject.hHmgr, NewRgn, RGN_DIFF);
 +         Result = SIMPLEREGION;
 +      }
 +      else
 +      {
 +         Result = NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, NewRgn, RGN_DIFF);
 +      }
 +      REGION_FreeRgnByHandle(NewRgn);
 +   }
 +   if (Result != ERROR)
 +      CLIPPING_UpdateGCRegion(dc);
 +
 +   DC_UnlockDc(dc);
 +
 +   return Result;
 +}
 +
 +int APIENTRY NtGdiIntersectClipRect(HDC  hDC,
 +                           int  LeftRect,
 +                           int  TopRect,
 +                           int  RightRect,
 +                           int  BottomRect)
 +{
 +   INT Result;
 +   RECTL Rect;
 +   HRGN NewRgn;
 +   PDC dc = DC_LockDc(hDC);
 +
 +   DPRINT("NtGdiIntersectClipRect(%x, %d,%d-%d,%d)\n",
 +      hDC, LeftRect, TopRect, RightRect, BottomRect);
 +
 +   if (!dc)
 +   {
 +      SetLastWin32Error(ERROR_INVALID_HANDLE);
 +      return ERROR;
 +   }
 +
 +   Rect.left = LeftRect;
 +   Rect.top = TopRect;
 +   Rect.right = RightRect;
 +   Rect.bottom = BottomRect;
 +
 +   IntLPtoDP(dc, (LPPOINT)&Rect, 2);
 +
 +   NewRgn = IntSysCreateRectRgnIndirect(&Rect);
 +   if (!NewRgn)
 +   {
 +      Result = ERROR;
 +   }
 +   else if (!dc->rosdc.hClipRgn)
 +   {
 +      dc->rosdc.hClipRgn = NewRgn;
 +      Result = SIMPLEREGION;
 +   }
 +   else
 +   {
 +      Result = NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, NewRgn, RGN_AND);
 +      REGION_FreeRgnByHandle(NewRgn);
 +   }
 +   if (Result != ERROR)
 +      CLIPPING_UpdateGCRegion(dc);
 +
 +   DC_UnlockDc(dc);
 +
 +   return Result;
 +}
 +
 +int APIENTRY NtGdiOffsetClipRgn(HDC  hDC,
 +                       int  XOffset,
 +                       int  YOffset)
 +{
 +  INT Result;
 +  DC *dc;
 +
 +  if(!(dc = DC_LockDc(hDC)))
 +  {
 +    SetLastWin32Error(ERROR_INVALID_HANDLE);
 +    return ERROR;
 +  }
 +
 +  if(dc->rosdc.hClipRgn != NULL)
 +  {
 +    Result = NtGdiOffsetRgn(dc->rosdc.hClipRgn,
 +                            XOffset,
 +                            YOffset);
 +    CLIPPING_UpdateGCRegion(dc);
 +  }
 +  else
 +  {
 +    Result = NULLREGION;
 +  }
 +
 +  DC_UnlockDc(dc);
 +  return Result;
 +}
 +
 +BOOL APIENTRY NtGdiPtVisible(HDC  hDC,
 +                    int  X,
 +                    int  Y)
 +{
 +  HRGN rgn;
 +  DC *dc;
 +
 +  if(!(dc = DC_LockDc(hDC)))
 +  {
 +    SetLastWin32Error(ERROR_INVALID_HANDLE);
 +    return FALSE;
 +  }
 +
 +  rgn = dc->rosdc.hGCClipRgn;
 +  DC_UnlockDc(dc);
 +
 +  return (rgn ? NtGdiPtInRegion(rgn, X, Y) : FALSE);
 +}
 +
 +BOOL APIENTRY NtGdiRectVisible(HDC  hDC,
 +                      LPRECT UnsafeRect)
 +{
 +   NTSTATUS Status = STATUS_SUCCESS;
 +   PROSRGNDATA Rgn;
 +   PDC dc = DC_LockDc(hDC);
 +   BOOL Result = FALSE;
 +   RECTL Rect;
 +
 +   if (!dc)
 +   {
 +      SetLastWin32Error(ERROR_INVALID_HANDLE);
 +      return FALSE;
 +   }
 +
 +   _SEH2_TRY
 +   {
 +      ProbeForRead(UnsafeRect,
 +                   sizeof(RECT),
 +                   1);
 +      Rect = *UnsafeRect;
 +   }
 +   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +   {
 +      Status = _SEH2_GetExceptionCode();
 +   }
 +   _SEH2_END;
 +
 +   if(!NT_SUCCESS(Status))
 +   {
 +      DC_UnlockDc(dc);
 +      SetLastNtError(Status);
 +      return FALSE;
 +   }
 +
 +   if (dc->rosdc.hGCClipRgn)
 +   {
 +      if((Rgn = (PROSRGNDATA)RGNOBJAPI_Lock(dc->rosdc.hGCClipRgn, NULL)))
 +      {
 +         IntLPtoDP(dc, (LPPOINT)&Rect, 2);
 +         Result = REGION_RectInRegion(Rgn, &Rect);
 +         RGNOBJAPI_Unlock(Rgn);
 +      }
 +   }
 +   DC_UnlockDc(dc);
 +
 +   return Result;
 +}
 +
 +int
 +FASTCALL
 +IntGdiSetMetaRgn(PDC pDC)
 +{
 +  INT Ret = ERROR;
 +  PROSRGNDATA TempRgn;
 +
 +  if ( pDC->dclevel.prgnMeta )
 +  {
 +     if ( pDC->dclevel.prgnClip )
 +     {
 +        TempRgn = IntSysCreateRectpRgn(0,0,0,0);
 +        if (TempRgn)
 +        {
 +           Ret = IntGdiCombineRgn( TempRgn,
 +                     pDC->dclevel.prgnMeta,
 +                     pDC->dclevel.prgnClip,
 +                                   RGN_AND);
 +           if ( Ret )
 +           {
 +              GDIOBJ_ShareUnlockObjByPtr(pDC->dclevel.prgnMeta);
 +              if (!((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.ulShareCount)
 +                 REGION_Delete(pDC->dclevel.prgnMeta);
 +
 +              pDC->dclevel.prgnMeta = TempRgn;
 +
 +              GDIOBJ_ShareUnlockObjByPtr(pDC->dclevel.prgnClip);
 +              if (!((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.ulShareCount)
 +                 REGION_Delete(pDC->dclevel.prgnClip);
 +
 +              pDC->dclevel.prgnClip = NULL;
 +
 +              IntGdiReleaseRaoRgn(pDC);
 +           }
 +           else
 +              REGION_Delete(TempRgn);
 +        }
 +     }
 +     else
 +        Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
 +  }
 +  else
 +  {
 +     if ( pDC->dclevel.prgnClip )
 +     {
 +        Ret = REGION_Complexity(pDC->dclevel.prgnClip);
 +        pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
 +        pDC->dclevel.prgnClip = NULL;
 +     }
 +     else
 +       Ret = SIMPLEREGION;
 +  }
 +  return Ret;
 +}
 +
 +
 +int APIENTRY NtGdiSetMetaRgn(HDC  hDC)
 +{
 +  INT Ret;
 +  PDC pDC = DC_LockDc(hDC);
 +
 +  if (!pDC)
 +  {
 +     SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +     return ERROR;
 +  }
 +  Ret = IntGdiSetMetaRgn(pDC);
 +
 +  DC_UnlockDc(pDC);
 +  return Ret;
 +}
 +
 +INT FASTCALL
 +NEW_CLIPPING_UpdateGCRegion(PDC pDC)
 +{
 +  CLIPOBJ * co;
 +
 +  /* Must have VisRgn set to a valid state! */
 +  if (!pDC->prgnVis) return ERROR;
 +
 +  if (pDC->prgnAPI)
 +  {
 +     REGION_Delete(pDC->prgnAPI);
 +     pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
 +  }
 +
 +  if (pDC->prgnRao)
 +  {
 +     REGION_Delete(pDC->prgnRao);
 +     pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
 +  }
 +
 +  if (pDC->dclevel.prgnMeta && pDC->dclevel.prgnClip)
 +  {
 +     IntGdiCombineRgn( pDC->prgnAPI,
 +                       pDC->dclevel.prgnClip,
 +                       pDC->dclevel.prgnMeta,
 +                       RGN_AND);
 +  }
 +  else
 +  {
 +     if (pDC->dclevel.prgnClip)
 +     {
 +        IntGdiCombineRgn( pDC->prgnAPI,
 +                          pDC->dclevel.prgnClip,
 +                          NULL,
 +                          RGN_COPY);
 +     }
 +     else if (pDC->dclevel.prgnMeta)
 +     {
 +        IntGdiCombineRgn( pDC->prgnAPI,
 +                          pDC->dclevel.prgnMeta,
 +                          NULL,
 +                          RGN_COPY);
 +     }
 +  }
 +
 +  IntGdiCombineRgn( pDC->prgnRao,
 +                    pDC->prgnVis,
 +                    pDC->prgnAPI,
 +                    RGN_AND);
 +
 +  RtlCopyMemory(&pDC->erclClip,
 +                &((PROSRGNDATA)pDC->prgnRao)->rdh.rcBound,
 +                sizeof(RECTL));
 +
 +  pDC->fs &= ~DC_FLAG_DIRTY_RAO;
 +
 +  IntGdiOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
 +
 +  // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
 +  // the rects from region objects rects in pClipRgn->Buffer.
 +  // With pDC->co.pClipRgn->Buffer,
 +  // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
 +
 +  co = IntEngCreateClipRegion( ((PROSRGNDATA)pDC->prgnRao)->rdh.nCount,
 +                               ((PROSRGNDATA)pDC->prgnRao)->Buffer,
 +                                 &pDC->erclClip);
 +  if (co)
 +  {
 +    if (pDC->rosdc.CombinedClip != NULL)
 +      IntEngDeleteClipRegion(pDC->rosdc.CombinedClip);
 +
 +    pDC->rosdc.CombinedClip = co;
 +  }
 +
 +  return IntGdiOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
 +}
 +
 +/* EOF */
index 20ad506,0000000..83f53fa
mode 100644,000000..100644
--- /dev/null
@@@ -1,4296 -1,0 +1,4302 @@@
-                           LPSIZE Size)
 +/*
 + * FreeType font engine interface
 + *
 + * Copyright 2001 Huw D M Davies for CodeWeavers.
 + * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
 + *
 + * This file contains the WineEng* functions.
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 + */
 +/*
 + *
 + * Addaped for the use in ReactOS.
 + *
 + */
 +/*
 + * PROJECT:         ReactOS win32 kernel mode subsystem
 + * LICENSE:         GPL - See COPYING in the top level directory
 + * FILE:            subsystems/win32/win32k/objects/freetype.c
 + * PURPOSE:         Freetype library support
 + * PROGRAMMER:
 + */
 +
 +/** Includes ******************************************************************/
 +
 +#include <win32k.h>
 +
 +#include <ft2build.h>
 +#include FT_FREETYPE_H
 +#include FT_GLYPH_H
 +#include FT_TYPE1_TABLES_H
 +#include <freetype/tttables.h>
 +#include <freetype/fttrigon.h>
 +#include <freetype/ftglyph.h>
 +#include <freetype/ftbitmap.h>
 +#include <freetype/ftoutln.h>
 +#include <freetype/ftwinfnt.h>
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +#ifndef FT_MAKE_TAG
 +#define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
 +       ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
 +       ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
 +#endif
 +
 +FT_Library  library;
 +
 +typedef struct _FONT_ENTRY
 +{
 +    LIST_ENTRY ListEntry;
 +    FONTGDI *Font;
 +    UNICODE_STRING FaceName;
 +    BYTE NotEnum;
 +} FONT_ENTRY, *PFONT_ENTRY;
 +
 +/* The FreeType library is not thread safe, so we have
 +   to serialize access to it */
 +static FAST_MUTEX FreeTypeLock;
 +
 +static LIST_ENTRY FontListHead;
 +static FAST_MUTEX FontListLock;
 +static BOOL RenderingEnabled = TRUE;
 +
 +#define MAX_FONT_CACHE 256
 +
 +typedef struct _FONT_CACHE_ENTRY
 +{
 +    LIST_ENTRY ListEntry;
 +    int GlyphIndex;
 +    FT_Face Face;
 +    FT_BitmapGlyph BitmapGlyph;
 +    int Height;
 +} FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
 +static LIST_ENTRY FontCacheListHead;
 +static UINT FontCacheNumEntries;
 +
 +static PWCHAR ElfScripts[32] =   /* these are in the order of the fsCsb[0] bits */
 +{
 +    L"Western", /*00*/
 +    L"Central_European",
 +    L"Cyrillic",
 +    L"Greek",
 +    L"Turkish",
 +    L"Hebrew",
 +    L"Arabic",
 +    L"Baltic",
 +    L"Vietnamese", /*08*/
 +    NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
 +    L"Thai",
 +    L"Japanese",
 +    L"CHINESE_GB2312",
 +    L"Hangul",
 +    L"CHINESE_BIG5",
 +    L"Hangul(Johab)",
 +    NULL, NULL, /*23*/
 +    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 +    L"Symbol" /*31*/
 +};
 +
 +/*
 + *  For TranslateCharsetInfo
 + */
 +#define CP_SYMBOL   42
 +#define MAXTCIINDEX 32
 +static const CHARSETINFO FontTci[MAXTCIINDEX] =
 +{
 +    /* ANSI */
 +    { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
 +    { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
 +    { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
 +    { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
 +    { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
 +    { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
 +    { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
 +    { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
 +    /* reserved by ANSI */
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    /* ANSI and OEM */
 +    { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
 +    { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
 +    { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
 +    { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
 +    { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
 +    { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
 +    /* reserved for alternate ANSI and OEM */
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    /* reserved for system */
 +    { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
 +    { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
 +};
 +
 +BOOL FASTCALL
 +InitFontSupport(VOID)
 +{
 +    ULONG ulError;
 +
 +    InitializeListHead(&FontListHead);
 +    InitializeListHead(&FontCacheListHead);
 +    FontCacheNumEntries = 0;
 +    ExInitializeFastMutex(&FontListLock);
 +    ExInitializeFastMutex(&FreeTypeLock);
 +
 +    ulError = FT_Init_FreeType(&library);
 +    if (ulError)
 +    {
 +        DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
 +        return FALSE;
 +    }
 +
 +    IntLoadSystemFonts();
 +
 +    return TRUE;
 +}
 +
 +/*
 + * IntLoadSystemFonts
 + *
 + * Search the system font directory and adds each font found.
 + */
 +
 +VOID FASTCALL
 +IntLoadSystemFonts(VOID)
 +{
 +    OBJECT_ATTRIBUTES ObjectAttributes;
 +    UNICODE_STRING Directory, SearchPattern, FileName, TempString;
 +    IO_STATUS_BLOCK Iosb;
 +    HANDLE hDirectory;
 +    BYTE *DirInfoBuffer;
 +    PFILE_DIRECTORY_INFORMATION DirInfo;
 +    BOOLEAN bRestartScan = TRUE;
 +    NTSTATUS Status;
 +
 +    RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
 +    /* FIXME: Add support for other font types */
 +    RtlInitUnicodeString(&SearchPattern, L"*.ttf");
 +
 +    InitializeObjectAttributes(
 +        &ObjectAttributes,
 +        &Directory,
 +        OBJ_CASE_INSENSITIVE,
 +        NULL,
 +        NULL);
 +
 +    Status = ZwOpenFile(
 +                 &hDirectory,
 +                 SYNCHRONIZE | FILE_LIST_DIRECTORY,
 +                 &ObjectAttributes,
 +                 &Iosb,
 +                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 +                 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
 +
 +    if (NT_SUCCESS(Status))
 +    {
 +        DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
 +        if (DirInfoBuffer == NULL)
 +        {
 +            ZwClose(hDirectory);
 +            return;
 +        }
 +
 +        FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
 +        if (FileName.Buffer == NULL)
 +        {
 +            ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
 +            ZwClose(hDirectory);
 +            return;
 +        }
 +        FileName.Length = 0;
 +        FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
 +
 +        while (1)
 +        {
 +            Status = ZwQueryDirectoryFile(
 +                         hDirectory,
 +                         NULL,
 +                         NULL,
 +                         NULL,
 +                         &Iosb,
 +                         DirInfoBuffer,
 +                         0x4000,
 +                         FileDirectoryInformation,
 +                         FALSE,
 +                         &SearchPattern,
 +                         bRestartScan);
 +
 +            if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
 +            {
 +                break;
 +            }
 +
 +            DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
 +            while (1)
 +            {
 +                TempString.Buffer = DirInfo->FileName;
 +                TempString.Length =
 +                    TempString.MaximumLength = DirInfo->FileNameLength;
 +                RtlCopyUnicodeString(&FileName, &Directory);
 +                RtlAppendUnicodeStringToString(&FileName, &TempString);
 +                IntGdiAddFontResource(&FileName, 0);
 +                if (DirInfo->NextEntryOffset == 0)
 +                    break;
 +                DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
 +            }
 +
 +            bRestartScan = FALSE;
 +        }
 +
 +        ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
 +        ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
 +        ZwClose(hDirectory);
 +    }
 +}
 +
 +
 +/*
 + * IntGdiAddFontResource
 + *
 + * Adds the font resource from the specified file to the system.
 + */
 +
 +INT FASTCALL
 +IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
 +{
 +    FONTGDI *FontGDI;
 +    NTSTATUS Status;
 +    HANDLE FileHandle, KeyHandle;
 +    OBJECT_ATTRIBUTES ObjectAttributes;
 +    PVOID Buffer = NULL;
 +    IO_STATUS_BLOCK Iosb;
 +    INT Error;
 +    FT_Face Face;
 +    ANSI_STRING AnsiFaceName;
 +    PFONT_ENTRY Entry;
 +    PSECTION_OBJECT SectionObject;
 +    ULONG ViewSize = 0;
 +    LARGE_INTEGER SectionSize;
 +    FT_Fixed XScale, YScale;
 +    UNICODE_STRING FontRegPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
 +
 +    /* Open the font file */
 +
 +    InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
 +    Status = ZwOpenFile(
 +                 &FileHandle,
 +                 FILE_GENERIC_READ | SYNCHRONIZE,
 +                 &ObjectAttributes,
 +                 &Iosb,
 +                 FILE_SHARE_READ,
 +                 FILE_SYNCHRONOUS_IO_NONALERT);
 +
 +    if (!NT_SUCCESS(Status))
 +    {
 +        DPRINT("Could not load font file: %wZ\n", FileName);
 +        return 0;
 +    }
 +
 +    SectionSize.QuadPart = 0LL;
 +    Status = MmCreateSection((PVOID)&SectionObject, SECTION_ALL_ACCESS,
 +                             NULL, &SectionSize, PAGE_READONLY,
 +                             SEC_COMMIT, FileHandle, NULL);
 +    if (!NT_SUCCESS(Status))
 +    {
 +        DPRINT("Could not map file: %wZ\n", FileName);
 +        ZwClose(FileHandle);
 +        return 0;
 +    }
 +
 +    ZwClose(FileHandle);
 +
 +    Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
 +    if (!NT_SUCCESS(Status))
 +    {
 +        DPRINT("Could not map file: %wZ\n", FileName);
 +        return Status;
 +    }
 +
 +    IntLockFreeType;
 +    Error = FT_New_Memory_Face(
 +                library,
 +                Buffer,
 +                ViewSize,
 +                0,
 +                &Face);
 +    IntUnLockFreeType;
 +
 +    if (Error)
 +    {
 +        if (Error == FT_Err_Unknown_File_Format)
 +            DPRINT("Unknown font file format\n");
 +        else
 +            DPRINT("Error reading font file (error code: %u)\n", Error);
 +        ObDereferenceObject(SectionObject);
 +        return 0;
 +    }
 +
 +    Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
 +    if (!Entry)
 +    {
 +        FT_Done_Face(Face);
 +        ObDereferenceObject(SectionObject);
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return 0;
 +    }
 +
 +    FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), TAG_FONTOBJ);
 +    if (FontGDI == NULL)
 +    {
 +        FT_Done_Face(Face);
 +        ObDereferenceObject(SectionObject);
 +        ExFreePoolWithTag(Entry, TAG_FONT);
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return 0;
 +    }
 +
 +    FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, FileName->Length + sizeof(WCHAR), TAG_PFF);
 +    if (FontGDI->Filename == NULL)
 +    {
 +        EngFreeMem(FontGDI);
 +        FT_Done_Face(Face);
 +        ObDereferenceObject(SectionObject);
 +        ExFreePoolWithTag(Entry, TAG_FONT);
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return 0;
 +    }
 +    RtlCopyMemory(FontGDI->Filename, FileName->Buffer, FileName->Length);
 +    FontGDI->Filename[FileName->Length / sizeof(WCHAR)] = L'\0';
 +    FontGDI->face = Face;
 +
 +    /* FIXME: Complete text metrics */
 +    XScale = Face->size->metrics.x_scale;
 +    YScale = Face->size->metrics.y_scale;
 +#if 0 /* This (Wine) code doesn't seem to work correctly for us */
 +    FontGDI->TextMetric.tmAscent =  (FT_MulFix(Face->ascender, YScale) + 32) >> 6;
 +    FontGDI->TextMetric.tmDescent = (FT_MulFix(Face->descender, YScale) + 32) >> 6;
 +    FontGDI->TextMetric.tmHeight =  (FT_MulFix(Face->ascender, YScale) -
 +                                     FT_MulFix(Face->descender, YScale)) >> 6;
 +#else
 +    FontGDI->TextMetric.tmAscent  = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
 +    FontGDI->TextMetric.tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
 +    FontGDI->TextMetric.tmHeight = (Face->size->metrics.ascender - Face->size->metrics.descender) >> 6;
 +#endif
 +
 +
 +
 +    DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
 +    DPRINT("Num glyphs: %u\n", Face->num_glyphs);
 +
 +    /* Add this font resource to the font table */
 +
 +    Entry->Font = FontGDI;
 +    Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
 +    RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
 +    RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
 +
 +    if (Characteristics & FR_PRIVATE)
 +    {
 +        PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
 +        IntLockProcessPrivateFonts(Win32Process);
 +        InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
 +        IntUnLockProcessPrivateFonts(Win32Process);
 +    }
 +    else
 +    {
 +        IntLockGlobalFonts;
 +        InsertTailList(&FontListHead, &Entry->ListEntry);
 +        InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
 +        Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
 +        if (NT_SUCCESS(Status))
 +        {
 +            LPWSTR pName = wcsrchr(FileName->Buffer, L'\\');
 +            if (pName)
 +            {
 +                pName++;
 +                ZwSetValueKey(KeyHandle, &Entry->FaceName, 0, REG_SZ, pName, (wcslen(pName) + 1) * sizeof(WCHAR));
 +            }
 +            ZwClose(KeyHandle);
 +        }
 +        IntUnLockGlobalFonts;
 +    }
 +    return 1;
 +}
 +
 +BOOL FASTCALL
 +IntIsFontRenderingEnabled(VOID)
 +{
 +    BOOL Ret = RenderingEnabled;
 +    HDC hDC;
 +
 +    hDC = IntGetScreenDC();
 +    if (hDC)
 +        Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
 +
 +    return Ret;
 +}
 +
 +VOID FASTCALL
 +IntEnableFontRendering(BOOL Enable)
 +{
 +    RenderingEnabled = Enable;
 +}
 +
 +FT_Render_Mode FASTCALL
 +IntGetFontRenderMode(LOGFONTW *logfont)
 +{
 +    switch (logfont->lfQuality)
 +    {
 +    case NONANTIALIASED_QUALITY:
 +        return FT_RENDER_MODE_MONO;
 +    case DRAFT_QUALITY:
 +        return FT_RENDER_MODE_LIGHT;
 +        /*    case CLEARTYPE_QUALITY:
 +                return FT_RENDER_MODE_LCD; */
 +    }
 +    return FT_RENDER_MODE_NORMAL;
 +}
 +
 +
 +NTSTATUS FASTCALL
 +TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
 +{
 +    PTEXTOBJ TextObj;
 +
 +    TextObj = TEXTOBJ_AllocTextWithHandle();
 +    if (!TextObj)
 +    {
 +        return STATUS_NO_MEMORY;
 +    }
 +
 +    *NewFont = TextObj->BaseObject.hHmgr;
 +    RtlCopyMemory(&TextObj->logfont.elfEnumLogfontEx.elfLogFont, lf, sizeof(LOGFONTW));
 +    if (lf->lfEscapement != lf->lfOrientation)
 +    {
 +        /* this should really depend on whether GM_ADVANCED is set */
 +        TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
 +            TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
 +    }
 +    TEXTOBJ_UnlockText(TextObj);
 +
 +    return STATUS_SUCCESS;
 +}
 +
 +/*************************************************************************
 + * TranslateCharsetInfo
 + *
 + * Fills a CHARSETINFO structure for a character set, code page, or
 + * font. This allows making the correspondance between different labelings
 + * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
 + * of the same encoding.
 + *
 + * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
 + * only one codepage should be set in *Src.
 + *
 + * RETURNS
 + *   TRUE on success, FALSE on failure.
 + *
 + */
 +static BOOLEAN APIENTRY
 +IntTranslateCharsetInfo(PDWORD Src, /* [in]
 +                         if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
 +                         if flags == TCI_SRCCHARSET: a character set value
 +                         if flags == TCI_SRCCODEPAGE: a code page value */
 +                        LPCHARSETINFO Cs, /* [out] structure to receive charset information */
 +                        DWORD Flags /* [in] determines interpretation of lpSrc */)
 +{
 +    int Index = 0;
 +
 +    switch (Flags)
 +    {
 +    case TCI_SRCFONTSIG:
 +        while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX)
 +        {
 +            Index++;
 +        }
 +        break;
 +    case TCI_SRCCODEPAGE:
 +        while ( *Src != FontTci[Index].ciACP && Index < MAXTCIINDEX)
 +        {
 +            Index++;
 +        }
 +        break;
 +    case TCI_SRCCHARSET:
 +        while ( *Src != FontTci[Index].ciCharset && Index < MAXTCIINDEX)
 +        {
 +            Index++;
 +        }
 +        break;
 +    default:
 +        return FALSE;
 +    }
 +
 +    if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
 +    {
 +        return FALSE;
 +    }
 +
 +    RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
 +
 +    return TRUE;
 +}
 +
 +
 +static BOOL face_has_symbol_charmap(FT_Face ft_face)
 +{
 +    int i;
 +
 +    for(i = 0; i < ft_face->num_charmaps; i++)
 +    {
 +        if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
 +            return TRUE;
 +    }
 +    return FALSE;
 +}
 +
 +static void FASTCALL
 +FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin)
 +{
 +    FT_Fixed XScale, YScale;
 +    int Ascent, Descent;
 +    FT_Face Face = FontGDI->face;
 +
 +    XScale = Face->size->metrics.x_scale;
 +    YScale = Face->size->metrics.y_scale;
 +
 +    if (pWin)
 +    {
 +        TM->tmHeight           = pWin->pixel_height;
 +        TM->tmAscent           = pWin->ascent;
 +        TM->tmDescent          = TM->tmHeight - TM->tmAscent;
 +        TM->tmInternalLeading  = pWin->internal_leading;
 +        TM->tmExternalLeading  = pWin->external_leading;
 +        TM->tmAveCharWidth     = pWin->avg_width;
 +        TM->tmMaxCharWidth     = pWin->max_width;
 +        TM->tmWeight           = pWin->weight;
 +        TM->tmOverhang         = 0;
 +        TM->tmDigitizedAspectX = pWin->horizontal_resolution;
 +        TM->tmDigitizedAspectY = pWin->vertical_resolution;
 +        TM->tmFirstChar        = pWin->first_char;
 +        TM->tmLastChar         = pWin->last_char;
 +        TM->tmDefaultChar      = pWin->default_char + pWin->first_char;
 +        TM->tmBreakChar        = pWin->break_char + pWin->first_char;
 +        TM->tmItalic           = pWin->italic;
 +        TM->tmUnderlined       = FontGDI->Underline;
 +        TM->tmStruckOut        = FontGDI->StrikeOut;
 +        TM->tmPitchAndFamily   = pWin->pitch_and_family;
 +        TM->tmCharSet          = pWin->charset;
 +        return;
 +    }
 +
 +    if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
 +    {
 +        Ascent = pHori->Ascender;
 +        Descent = -pHori->Descender;
 +    }
 +    else
 +    {
 +        Ascent = pOS2->usWinAscent;
 +        Descent = pOS2->usWinDescent;
 +    }
 +
 +#if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
 +    TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
 +    TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
 +#else /* This (ros) code was previously affected by a FreeType bug, but it works now */
 +    TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
 +    TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
 +#endif
 +    TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
 +
 +    TM->tmHeight = TM->tmAscent + TM->tmDescent;
 +
 +    /* MSDN says:
 +     *  el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
 +     */
 +    TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
 +                                    - ((Ascent + Descent)
 +                                       - (pHori->Ascender - pHori->Descender)),
 +                                    YScale) + 32) >> 6);
 +
 +    TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
 +    if (TM->tmAveCharWidth == 0)
 +    {
 +        TM->tmAveCharWidth = 1;
 +    }
 +
 +    /* Correct forumla to get the maxcharwidth from unicode and ansi font */
 +    TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
 +
 +    TM->tmWeight = pOS2->usWeightClass;
 +    TM->tmOverhang = 0;
 +    TM->tmDigitizedAspectX = 96;
 +    TM->tmDigitizedAspectY = 96;
 +    if (face_has_symbol_charmap(Face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
 +    {
 +        USHORT cpOEM, cpAnsi;
 +
 +        EngGetCurrentCodePage(&cpOEM, &cpAnsi);
 +        TM->tmFirstChar = 0;
 +        switch(cpAnsi)
 +        {
 +        case 1257: /* Baltic */
 +            TM->tmLastChar = 0xf8fd;
 +            break;
 +        default:
 +            TM->tmLastChar = 0xf0ff;
 +        }
 +        TM->tmBreakChar = 0x20;
 +        TM->tmDefaultChar = 0x1f;
 +    }
 +    else
 +    {
 +        TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
 +        TM->tmLastChar = pOS2->usLastCharIndex;   /* Should be min(cmap_last, os2_last) */
 +
 +        if(pOS2->usFirstCharIndex <= 1)
 +            TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
 +        else if (pOS2->usFirstCharIndex > 0xff)
 +            TM->tmBreakChar = 0x20;
 +        else
 +            TM->tmBreakChar = pOS2->usFirstCharIndex;
 +        TM->tmDefaultChar = TM->tmBreakChar - 1;
 +    }
 +    TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
 +    TM->tmUnderlined = FontGDI->Underline;
 +    TM->tmStruckOut  = FontGDI->StrikeOut;
 +
 +    /* Yes TPMF_FIXED_PITCH is correct; braindead api */
 +    if (! FT_IS_FIXED_WIDTH(Face))
 +    {
 +        TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
 +    }
 +    else
 +    {
 +        TM->tmPitchAndFamily = 0;
 +    }
 +
 +    switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
 +    {
 +    case PAN_FAMILY_SCRIPT:
 +        TM->tmPitchAndFamily |= FF_SCRIPT;
 +        break;
 +    case PAN_FAMILY_DECORATIVE:
 +        TM->tmPitchAndFamily |= FF_DECORATIVE;
 +        break;
 +
 +    case PAN_ANY:
 +    case PAN_NO_FIT:
 +    case PAN_FAMILY_TEXT_DISPLAY:
 +    case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
 +                               /* which is clearly not what the panose spec says. */
 +        if (TM->tmPitchAndFamily == 0) /* fixed */
 +        {
 +            TM->tmPitchAndFamily = FF_MODERN;
 +        }
 +        else
 +        {
 +            switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
 +            {
 +            case PAN_ANY:
 +            case PAN_NO_FIT:
 +            default:
 +                TM->tmPitchAndFamily |= FF_DONTCARE;
 +                break;
 +
 +            case PAN_SERIF_COVE:
 +            case PAN_SERIF_OBTUSE_COVE:
 +            case PAN_SERIF_SQUARE_COVE:
 +            case PAN_SERIF_OBTUSE_SQUARE_COVE:
 +            case PAN_SERIF_SQUARE:
 +            case PAN_SERIF_THIN:
 +            case PAN_SERIF_BONE:
 +            case PAN_SERIF_EXAGGERATED:
 +            case PAN_SERIF_TRIANGLE:
 +                TM->tmPitchAndFamily |= FF_ROMAN;
 +                break;
 +
 +            case PAN_SERIF_NORMAL_SANS:
 +            case PAN_SERIF_OBTUSE_SANS:
 +            case PAN_SERIF_PERP_SANS:
 +            case PAN_SERIF_FLARED:
 +            case PAN_SERIF_ROUNDED:
 +                TM->tmPitchAndFamily |= FF_SWISS;
 +                break;
 +            }
 +        }
 +        break;
 +    default:
 +        TM->tmPitchAndFamily |= FF_DONTCARE;
 +    }
 +
 +    if (FT_IS_SCALABLE(Face))
 +    {
 +        TM->tmPitchAndFamily |= TMPF_VECTOR;
 +    }
 +    if (FT_IS_SFNT(Face))
 +    {
 +        TM->tmPitchAndFamily |= TMPF_TRUETYPE;
 +    }
 +
 +    TM->tmCharSet = DEFAULT_CHARSET;
 +}
 +
 +/*************************************************************
 + * IntGetOutlineTextMetrics
 + *
 + */
 +INT FASTCALL
 +IntGetOutlineTextMetrics(PFONTGDI FontGDI,
 +                         UINT Size,
 +                         OUTLINETEXTMETRICW *Otm)
 +{
 +    unsigned Needed;
 +    TT_OS2 *pOS2;
 +    TT_HoriHeader *pHori;
 +    TT_Postscript *pPost;
 +    FT_Fixed XScale, YScale;
 +    ANSI_STRING FamilyNameA, StyleNameA;
 +    UNICODE_STRING FamilyNameW, StyleNameW, Regular;
 +    FT_WinFNT_HeaderRec Win;
 +    FT_Error Error;
 +    char *Cp;
 +
 +    Needed = sizeof(OUTLINETEXTMETRICW);
 +
 +    RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
 +    RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
 +
 +    RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
 +    RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
 +
 +    /* These names should be read from the TT name table */
 +
 +    /* length of otmpFamilyName */
 +    Needed += FamilyNameW.Length + sizeof(WCHAR);
 +
 +    RtlInitUnicodeString(&Regular, L"regular");
 +    /* length of otmpFaceName */
 +    if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
 +    {
 +        Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */
 +    }
 +    else
 +    {
 +        Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
 +    }
 +
 +    /* length of otmpStyleName */
 +    Needed += StyleNameW.Length + sizeof(WCHAR);
 +
 +    /* length of otmpFullName */
 +    Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
 +
 +    if (Size < Needed)
 +    {
 +        RtlFreeUnicodeString(&FamilyNameW);
 +        RtlFreeUnicodeString(&StyleNameW);
 +        return Needed;
 +    }
 +
 +    XScale = FontGDI->face->size->metrics.x_scale;
 +    YScale = FontGDI->face->size->metrics.y_scale;
 +
 +    IntLockFreeType;
 +    pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
 +    if (NULL == pOS2)
 +    {
 +        IntUnLockFreeType;
 +        DPRINT1("Can't find OS/2 table - not TT font?\n");
 +        RtlFreeUnicodeString(&StyleNameW);
 +        RtlFreeUnicodeString(&FamilyNameW);
 +        return 0;
 +    }
 +
 +    pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
 +    if (NULL == pHori)
 +    {
 +        IntUnLockFreeType;
 +        DPRINT1("Can't find HHEA table - not TT font?\n");
 +        RtlFreeUnicodeString(&StyleNameW);
 +        RtlFreeUnicodeString(&FamilyNameW);
 +        return 0;
 +    }
 +
 +    pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */
 +
 +    Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
 +
 +    Otm->otmSize = Needed;
 +
 +//  FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
 +    if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
 +    {
 +        FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
 +        FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
 +    }
 +
 +    RtlCopyMemory(&Otm->otmTextMetrics, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
 +
 +    Otm->otmFiller = 0;
 +    RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
 +    Otm->otmfsSelection = pOS2->fsSelection;
 +    Otm->otmfsType = pOS2->fsType;
 +    Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
 +    Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
 +    Otm->otmItalicAngle = 0; /* POST table */
 +    Otm->otmEMSquare = FontGDI->face->units_per_EM;
 +    Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
 +    Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
 +    Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
 +    Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
 +    Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
 +    Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6;
 +    Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6;
 +    Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6;
 +    Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6;
 +    Otm->otmMacAscent = FontGDI->TextMetric.tmAscent;
 +    Otm->otmMacDescent = -FontGDI->TextMetric.tmDescent;
 +    Otm->otmMacLineGap = Otm->otmLineGap;
 +    Otm->otmusMinimumPPEM = 0; /* TT Header */
 +    Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
 +    Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
 +    Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
 +    Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
 +    Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
 +    Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
 +    Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
 +    Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
 +    Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
 +    Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
 +    if (!pPost)
 +    {
 +        Otm->otmsUnderscoreSize = 0;
 +        Otm->otmsUnderscorePosition = 0;
 +    }
 +    else
 +    {
 +        Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
 +        Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
 +    }
 +
 +    IntUnLockFreeType;
 +
 +    /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
 +    Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
 +    Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
 +    wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
 +    Cp += FamilyNameW.Length + sizeof(WCHAR);
 +    Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
 +    wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
 +    Cp += StyleNameW.Length + sizeof(WCHAR);
 +    Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
 +    wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
 +    if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
 +    {
 +        wcscat((WCHAR*) Cp, L" ");
 +        wcscat((WCHAR*) Cp, StyleNameW.Buffer);
 +        Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
 +    }
 +    else
 +    {
 +        Cp += FamilyNameW.Length + sizeof(WCHAR);
 +    }
 +    Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
 +    wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
 +    wcscat((WCHAR*) Cp, L" ");
 +    wcscat((WCHAR*) Cp, StyleNameW.Buffer);
 +
 +    RtlFreeUnicodeString(&StyleNameW);
 +    RtlFreeUnicodeString(&FamilyNameW);
 +
 +    return Needed;
 +}
 +
 +static PFONTGDI FASTCALL
 +FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
 +{
 +    PLIST_ENTRY Entry;
 +    PFONT_ENTRY CurrentEntry;
 +    ANSI_STRING EntryFaceNameA;
 +    UNICODE_STRING EntryFaceNameW;
 +    FONTGDI *FontGDI;
 +
 +    Entry = Head->Flink;
 +    while (Entry != Head)
 +    {
 +        CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
 +
 +        FontGDI = CurrentEntry->Font;
 +        ASSERT(FontGDI);
 +
 +        RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
 +        RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
 +        if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
 +        {
 +            EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
 +            EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
 +        }
 +
 +        if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
 +        {
 +            RtlFreeUnicodeString(&EntryFaceNameW);
 +            return FontGDI;
 +        }
 +
 +        RtlFreeUnicodeString(&EntryFaceNameW);
 +        Entry = Entry->Flink;
 +    }
 +
 +    return NULL;
 +}
 +
 +static PFONTGDI FASTCALL
 +FindFaceNameInLists(PUNICODE_STRING FaceName)
 +{
 +    PPROCESSINFO Win32Process;
 +    PFONTGDI Font;
 +
 +    /* Search the process local list */
 +    Win32Process = PsGetCurrentProcessWin32Process();
 +    IntLockProcessPrivateFonts(Win32Process);
 +    Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
 +    IntUnLockProcessPrivateFonts(Win32Process);
 +    if (NULL != Font)
 +    {
 +        return Font;
 +    }
 +
 +    /* Search the global list */
 +    IntLockGlobalFonts;
 +    Font = FindFaceNameInList(FaceName, &FontListHead);
 +    IntUnLockGlobalFonts;
 +
 +    return Font;
 +}
 +
 +static void FASTCALL
 +FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
 +{
 +    ANSI_STRING StyleA;
 +    UNICODE_STRING StyleW;
 +    TT_OS2 *pOS2;
 +    FONTSIGNATURE fs;
 +    CHARSETINFO CharSetInfo;
 +    unsigned i, Size;
 +    OUTLINETEXTMETRICW *Otm;
 +    LOGFONTW *Lf;
 +    TEXTMETRICW *TM;
 +    NEWTEXTMETRICW *Ntm;
 +    DWORD fs0;
 +
 +    RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
 +    Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
 +    Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
 +    if (!Otm)
 +    {
 +        return;
 +    }
 +    IntGetOutlineTextMetrics(FontGDI, Size, Otm);
 +
 +    Lf = &Info->EnumLogFontEx.elfLogFont;
 +    TM = &Otm->otmTextMetrics;
 +
 +    Lf->lfHeight = TM->tmHeight;
 +    Lf->lfWidth = TM->tmAveCharWidth;
 +    Lf->lfWeight = TM->tmWeight;
 +    Lf->lfItalic = TM->tmItalic;
 +    Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
 +    Lf->lfCharSet = TM->tmCharSet;
 +    Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
 +    Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
 +    Lf->lfQuality = PROOF_QUALITY;
 +
 +    Ntm = &Info->NewTextMetricEx.ntmTm;
 +    Ntm->tmHeight = TM->tmHeight;
 +    Ntm->tmAscent = TM->tmAscent;
 +    Ntm->tmDescent = TM->tmDescent;
 +    Ntm->tmInternalLeading = TM->tmInternalLeading;
 +    Ntm->tmExternalLeading = TM->tmExternalLeading;
 +    Ntm->tmAveCharWidth = TM->tmAveCharWidth;
 +    Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
 +    Ntm->tmWeight = TM->tmWeight;
 +    Ntm->tmOverhang = TM->tmOverhang;
 +    Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
 +    Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
 +    Ntm->tmFirstChar = TM->tmFirstChar;
 +    Ntm->tmLastChar = TM->tmLastChar;
 +    Ntm->tmDefaultChar = TM->tmDefaultChar;
 +    Ntm->tmBreakChar = TM->tmBreakChar;
 +    Ntm->tmItalic = TM->tmItalic;
 +    Ntm->tmUnderlined = TM->tmUnderlined;
 +    Ntm->tmStruckOut = TM->tmStruckOut;
 +    Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
 +    Ntm->tmCharSet = TM->tmCharSet;
 +    Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
 +
 +    if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
 +
 +    if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
 +
 +    Ntm->ntmSizeEM = Otm->otmEMSquare;
 +    Ntm->ntmCellHeight = 0;
 +    Ntm->ntmAvgWidth = 0;
 +
 +    Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
 +                      ? TRUETYPE_FONTTYPE : 0);
 +
 +    if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
 +        Info->FontType |= RASTER_FONTTYPE;
 +
 +    ExFreePoolWithTag(Otm, TAG_GDITEXT);
 +
 +    wcsncpy(Info->EnumLogFontEx.elfLogFont.lfFaceName, FaceName, LF_FACESIZE);
 +    wcsncpy(Info->EnumLogFontEx.elfFullName, FaceName, LF_FULLFACESIZE);
 +    RtlInitAnsiString(&StyleA, FontGDI->face->style_name);
 +    RtlAnsiStringToUnicodeString(&StyleW, &StyleA, TRUE);
 +    wcsncpy(Info->EnumLogFontEx.elfStyle, StyleW.Buffer, LF_FACESIZE);
 +    RtlFreeUnicodeString(&StyleW);
 +
 +    Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
 +    Info->EnumLogFontEx.elfScript[0] = L'\0';
 +    IntLockFreeType;
 +    pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
 +    IntUnLockFreeType;
 +    if (NULL != pOS2)
 +    {
 +        fs.fsCsb[0] = pOS2->ulCodePageRange1;
 +        fs.fsCsb[1] = pOS2->ulCodePageRange2;
 +        fs.fsUsb[0] = pOS2->ulUnicodeRange1;
 +        fs.fsUsb[1] = pOS2->ulUnicodeRange2;
 +        fs.fsUsb[2] = pOS2->ulUnicodeRange3;
 +        fs.fsUsb[3] = pOS2->ulUnicodeRange4;
 +
 +        if (0 == pOS2->version)
 +        {
 +            FT_UInt Dummy;
 +
 +            if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
 +                fs.fsCsb[0] |= FS_LATIN1;
 +            else
 +                fs.fsCsb[0] |= FS_SYMBOL;
 +        }
 +        if (fs.fsCsb[0] == 0)
 +        { /* let's see if we can find any interesting cmaps */
 +            for (i = 0; i < FontGDI->face->num_charmaps; i++)
 +            {
 +                switch (FontGDI->face->charmaps[i]->encoding)
 +                {
 +                case FT_ENCODING_UNICODE:
 +                case FT_ENCODING_APPLE_ROMAN:
 +                    fs.fsCsb[0] |= FS_LATIN1;
 +                    break;
 +                case FT_ENCODING_MS_SYMBOL:
 +                    fs.fsCsb[0] |= FS_SYMBOL;
 +                    break;
 +                default:
 +                    break;
 +                }
 +            }
 +        }
 +        for (i = 0; i < MAXTCIINDEX; i++)
 +        {
 +            fs0 = 1L << i;
 +            if (fs.fsCsb[0] & fs0)
 +            {
 +                if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
 +                {
 +                    CharSetInfo.ciCharset = DEFAULT_CHARSET;
 +                }
 +                if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
 +                {
 +                    Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
 +                    if (NULL != ElfScripts[i])
 +                        wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
 +                    else
 +                    {
 +                        DPRINT1("Unknown elfscript for bit %d\n", i);
 +                    }
 +                }
 +            }
 +        }
 +        Info->NewTextMetricEx.ntmFontSig = fs;
 +    }
 +}
 +
 +static int FASTCALL
 +FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
 +{
 +    DWORD i;
 +    UNICODE_STRING InfoFaceName;
 +
 +    for (i = 0; i < InfoEntries; i++)
 +    {
 +        RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
 +        if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE))
 +        {
 +            return i;
 +        }
 +    }
 +
 +    return -1;
 +}
 +
 +static BOOLEAN FASTCALL
 +FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
 +                  PFONTFAMILYINFO Info, DWORD InfoEntries)
 +{
 +    UNICODE_STRING LogFontFaceName;
 +
 +    RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
 +    if (0 != LogFontFaceName.Length
 +            && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE))
 +    {
 +        return FALSE;
 +    }
 +
 +    return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
 +}
 +
 +static BOOLEAN FASTCALL
 +GetFontFamilyInfoForList(LPLOGFONTW LogFont,
 +                         PFONTFAMILYINFO Info,
 +                         DWORD *Count,
 +                         DWORD Size,
 +                         PLIST_ENTRY Head)
 +{
 +    PLIST_ENTRY Entry;
 +    PFONT_ENTRY CurrentEntry;
 +    ANSI_STRING EntryFaceNameA;
 +    UNICODE_STRING EntryFaceNameW;
 +    FONTGDI *FontGDI;
 +
 +    Entry = Head->Flink;
 +    while (Entry != Head)
 +    {
 +        CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
 +
 +        FontGDI = CurrentEntry->Font;
 +        ASSERT(FontGDI);
 +
 +        RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
 +        RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
 +        if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
 +        {
 +            EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
 +            EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
 +        }
 +
 +        if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
 +        {
 +            if (*Count < Size)
 +            {
 +                FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
 +            }
 +            (*Count)++;
 +        }
 +        RtlFreeUnicodeString(&EntryFaceNameW);
 +        Entry = Entry->Flink;
 +    }
 +
 +    return TRUE;
 +}
 +
 +typedef struct FontFamilyInfoCallbackContext
 +{
 +    LPLOGFONTW LogFont;
 +    PFONTFAMILYINFO Info;
 +    DWORD Count;
 +    DWORD Size;
 +} FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
 +
 +static NTSTATUS APIENTRY
 +FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
 +                                    IN PVOID ValueData, IN ULONG ValueLength,
 +                                    IN PVOID Context, IN PVOID EntryContext)
 +{
 +    PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
 +    UNICODE_STRING RegistryName, RegistryValue;
 +    int Existing;
 +    PFONTGDI FontGDI;
 +
 +    if (REG_SZ != ValueType)
 +    {
 +        return STATUS_SUCCESS;
 +    }
 +    InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
 +    RtlInitUnicodeString(&RegistryName, ValueName);
 +
 +    /* Do we need to include this font family? */
 +    if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
 +                          min(InfoContext->Count, InfoContext->Size)))
 +    {
 +        RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
 +        Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
 +                                      min(InfoContext->Count, InfoContext->Size));
 +        if (0 <= Existing)
 +        {
 +            /* We already have the information about the "real" font. Just copy it */
 +            if (InfoContext->Count < InfoContext->Size)
 +            {
 +                InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
 +                wcsncpy(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
 +                        RegistryName.Buffer, LF_FACESIZE);
 +            }
 +            InfoContext->Count++;
 +            return STATUS_SUCCESS;
 +        }
 +
 +        /* Try to find information about the "real" font */
 +        FontGDI = FindFaceNameInLists(&RegistryValue);
 +        if (NULL == FontGDI)
 +        {
 +            /* "Real" font not found, discard this registry entry */
 +            return STATUS_SUCCESS;
 +        }
 +
 +        /* Return info about the "real" font but with the name of the alias */
 +        if (InfoContext->Count < InfoContext->Size)
 +        {
 +            FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
 +                               RegistryName.Buffer, FontGDI);
 +        }
 +        InfoContext->Count++;
 +        return STATUS_SUCCESS;
 +    }
 +
 +    return STATUS_SUCCESS;
 +}
 +
 +static BOOLEAN FASTCALL
 +GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
 +                                PFONTFAMILYINFO Info,
 +                                DWORD *Count,
 +                                DWORD Size)
 +{
 +    RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
 +    FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
 +    NTSTATUS Status;
 +
 +    /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes
 +       The real work is done in the registry callback function */
 +    Context.LogFont = LogFont;
 +    Context.Info = Info;
 +    Context.Count = *Count;
 +    Context.Size = Size;
 +
 +    QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
 +    QueryTable[0].Flags = 0;
 +    QueryTable[0].Name = NULL;
 +    QueryTable[0].EntryContext = NULL;
 +    QueryTable[0].DefaultType = REG_NONE;
 +    QueryTable[0].DefaultData = NULL;
 +    QueryTable[0].DefaultLength = 0;
 +
 +    QueryTable[1].QueryRoutine = NULL;
 +    QueryTable[1].Name = NULL;
 +
 +    Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
 +                                    L"SysFontSubstitutes",
 +                                    QueryTable,
 +                                    &Context,
 +                                    NULL);
 +    if (NT_SUCCESS(Status))
 +    {
 +        *Count = Context.Count;
 +    }
 +
 +    return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
 +}
 +
 +BOOL
 +FASTCALL
 +ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
 +{
 +    if ( lprs )
 +    {
 +        lprs->nSize = sizeof(RASTERIZER_STATUS);
 +        lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
 +        lprs->nLanguageID = gusLanguageID;
 +        return TRUE;
 +    }
 +    SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +    return FALSE;
 +}
 +
 +
 +FT_BitmapGlyph APIENTRY
 +ftGdiGlyphCacheGet(
 +    FT_Face Face,
 +    INT GlyphIndex,
 +    INT Height)
 +{
 +    PLIST_ENTRY CurrentEntry;
 +    PFONT_CACHE_ENTRY FontEntry;
 +
 +    CurrentEntry = FontCacheListHead.Flink;
 +    while (CurrentEntry != &FontCacheListHead)
 +    {
 +        FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
 +        if (FontEntry->Face == Face &&
 +                FontEntry->GlyphIndex == GlyphIndex &&
 +                FontEntry->Height == Height)
 +            break;
 +        CurrentEntry = CurrentEntry->Flink;
 +    }
 +
 +    if (CurrentEntry == &FontCacheListHead)
 +    {
 +        return NULL;
 +    }
 +
 +    RemoveEntryList(CurrentEntry);
 +    InsertHeadList(&FontCacheListHead, CurrentEntry);
 +    return FontEntry->BitmapGlyph;
 +}
 +
 +FT_BitmapGlyph APIENTRY
 +ftGdiGlyphCacheSet(
 +    FT_Face Face,
 +    INT GlyphIndex,
 +    INT Height,
 +    FT_GlyphSlot GlyphSlot,
 +    FT_Render_Mode RenderMode)
 +{
 +    FT_Glyph GlyphCopy;
 +    INT error;
 +    PFONT_CACHE_ENTRY NewEntry;
 +    FT_Bitmap AlignedBitmap;
 +    FT_BitmapGlyph BitmapGlyph;
 +
 +    error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
 +    if (error)
 +    {
 +        DPRINT1("Failure caching glyph.\n");
 +        return NULL;
 +    };
 +
 +    error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
 +    if (error)
 +    {
 +        DPRINT1("Failure rendering glyph.\n");
 +        return NULL;
 +    };
 +
 +    NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
 +    if (!NewEntry)
 +    {
 +        DPRINT1("Alloc failure caching glyph.\n");
 +        FT_Done_Glyph(GlyphCopy);
 +        return NULL;
 +    }
 +
 +    BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
 +    FT_Bitmap_New(&AlignedBitmap);
 +    if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
 +    {
 +        DPRINT1("Conversion failed\n");
 +        FT_Done_Glyph((FT_Glyph)BitmapGlyph);
 +        return NULL;
 +    }
 +
 +    FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
 +    BitmapGlyph->bitmap = AlignedBitmap;
 +
 +    NewEntry->GlyphIndex = GlyphIndex;
 +    NewEntry->Face = Face;
 +    NewEntry->BitmapGlyph = BitmapGlyph;
 +    NewEntry->Height = Height;
 +
 +    InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
 +    if (FontCacheNumEntries++ > MAX_FONT_CACHE)
 +    {
 +        NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
 +        FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
 +        RemoveTailList(&FontCacheListHead);
 +        ExFreePool(NewEntry);
 +        FontCacheNumEntries--;
 +    }
 +
 +    return BitmapGlyph;
 +}
 +
 +
 +static
 +void
 +FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
 +{
 +    pt->x.value = vec->x >> 6;
 +    pt->x.fract = (vec->x & 0x3f) << 10;
 +    pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
 +    pt->y.value = vec->y >> 6;
 +    pt->y.fract = (vec->y & 0x3f) << 10;
 +    pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
 +    return;
 +}
 +
 +/*
 +   This function builds an FT_Fixed from a float. It puts the integer part
 +   in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
 +   It fails if the integer part of the float number is greater than SHORT_MAX.
 +*/
 +static __inline FT_Fixed FT_FixedFromFloat(float f)
 +{
 +    short value = f;
 +    unsigned short fract = (f - value) * 0xFFFF;
 +    return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
 +}
 +
 +/*
 +   This function builds an FT_Fixed from a FIXED. It simply put f.value
 +   in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
 +*/
 +static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
 +{
 +    return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
 +}
 +
 +/*
 + * Based on WineEngGetGlyphOutline
 + *
 + */
 +ULONG
 +FASTCALL
 +ftGdiGetGlyphOutline(
 +    PDC dc,
 +    WCHAR wch,
 +    UINT iFormat,
 +    LPGLYPHMETRICS pgm,
 +    ULONG cjBuf,
 +    PVOID pvBuf,
 +    LPMAT2 pmat2,
 +    BOOL bIgnoreRotation)
 +{
 +    static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
 +    PDC_ATTR pdcattr;
 +    PTEXTOBJ TextObj;
 +    PFONTGDI FontGDI;
 +    HFONT hFont = 0;
 +    GLYPHMETRICS gm;
 +    ULONG Size;
 +    FT_Face ft_face;
 +    FT_UInt glyph_index;
 +    DWORD width, height, pitch, needed = 0;
 +    FT_Bitmap ft_bitmap;
 +    FT_Error error;
 +    INT left, right, top = 0, bottom = 0;
 +    FT_Angle angle = 0;
 +    FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
 +    FLOAT eM11, widthRatio = 1.0;
 +    FT_Matrix transMat = identityMat;
 +    BOOL needsTransform = FALSE;
 +    INT orientation;
 +    LONG aveWidth;
 +    INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
 +    OUTLINETEXTMETRICW *potm;
 +    int n = 0;
 +    FT_CharMap found = 0, charmap;
 +    XFORM xForm;
 +
 +    DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
 +           cjBuf, pvBuf, pmat2);
 +
 +    pdcattr = dc->pdcattr;
 +
 +    MatrixS2XForm(&xForm, &dc->dclevel.mxWorldToDevice);
 +    eM11 = xForm.eM11;
 +
 +    hFont = pdcattr->hlfntNew;
 +    TextObj = RealizeFontInit(hFont);
 +
 +    if (!TextObj)
 +    {
 +        SetLastWin32Error(ERROR_INVALID_HANDLE);
 +        return GDI_ERROR;
 +    }
 +    FontGDI = ObjToGDI(TextObj->Font, FONT);
 +    ft_face = FontGDI->face;
 +
 +    aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
 +    orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
 +
 +    Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
 +    potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
 +    if (!potm)
 +    {
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        TEXTOBJ_UnlockText(TextObj);
 +        return GDI_ERROR;
 +    }
 +    IntGetOutlineTextMetrics(FontGDI, Size, potm);
 +
 +    IntLockFreeType;
 +
 +    /* During testing, I never saw this used. In here just incase.*/
 +    if (ft_face->charmap == NULL)
 +    {
 +        DPRINT("WARNING: No charmap selected!\n");
 +        DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
 +
 +        for (n = 0; n < ft_face->num_charmaps; n++)
 +        {
 +            charmap = ft_face->charmaps[n];
 +            DPRINT("found charmap encoding: %u\n", charmap->encoding);
 +            if (charmap->encoding != 0)
 +            {
 +                found = charmap;
 +                break;
 +            }
 +        }
 +        if (!found)
 +        {
 +            DPRINT1("WARNING: Could not find desired charmap!\n");
 +        }
 +        error = FT_Set_Charmap(ft_face, found);
 +        if (error)
 +        {
 +            DPRINT1("WARNING: Could not set the charmap!\n");
 +        }
 +    }
 +
 +//  FT_Set_Pixel_Sizes(ft_face,
 +//                     TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
 +    /* FIXME should set character height if neg */
 +//                     (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
 +//                      TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
 +
 +    TEXTOBJ_UnlockText(TextObj);
 +
 +    if (iFormat & GGO_GLYPH_INDEX)
 +    {
 +        glyph_index = wch;
 +        iFormat &= ~GGO_GLYPH_INDEX;
 +    }
 +    else  glyph_index = FT_Get_Char_Index(ft_face, wch);
 +
 +    if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
 +        load_flags |= FT_LOAD_NO_BITMAP;
 +
 +    if (iFormat & GGO_UNHINTED)
 +    {
 +        load_flags |= FT_LOAD_NO_HINTING;
 +        iFormat &= ~GGO_UNHINTED;
 +    }
 +
 +    error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
 +    if (error)
 +    {
 +        DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
 +        IntUnLockFreeType;
 +        if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT);
 +        return GDI_ERROR;
 +    }
 +    IntUnLockFreeType;
 +
 +    if (aveWidth && potm)
 +    {
 +        widthRatio = (FLOAT)aveWidth * eM11 /
 +                     (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
 +    }
 +
 +    left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
 +    right = (INT)((ft_face->glyph->metrics.horiBearingX +
 +                   ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
 +
 +    adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
 +    lsb = left >> 6;
 +    bbx = (right - left) >> 6;
 +
 +    DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
 +
 +    IntLockFreeType;
 +
 +    /* Scaling transform */
 +    if (aveWidth)
 +    {
 +        FT_Matrix scaleMat;
 +        DPRINT("Scaling Trans!\n");
 +        scaleMat.xx = FT_FixedFromFloat(widthRatio);
 +        scaleMat.xy = 0;
 +        scaleMat.yx = 0;
 +        scaleMat.yy = (1 << 16);
 +        FT_Matrix_Multiply(&scaleMat, &transMat);
 +        needsTransform = TRUE;
 +    }
 +
 +    /* Slant transform */
 +    if (potm->otmTextMetrics.tmItalic)
 +    {
 +        FT_Matrix slantMat;
 +        DPRINT("Slant Trans!\n");
 +        slantMat.xx = (1 << 16);
 +        slantMat.xy = ((1 << 16) >> 2);
 +        slantMat.yx = 0;
 +        slantMat.yy = (1 << 16);
 +        FT_Matrix_Multiply(&slantMat, &transMat);
 +        needsTransform = TRUE;
 +    }
 +
 +    /* Rotation transform */
 +    if (orientation)
 +    {
 +        FT_Matrix rotationMat;
 +        FT_Vector vecAngle;
 +        DPRINT("Rotation Trans!\n");
 +        angle = FT_FixedFromFloat((float)orientation / 10.0);
 +        FT_Vector_Unit(&vecAngle, angle);
 +        rotationMat.xx = vecAngle.x;
 +        rotationMat.xy = -vecAngle.y;
 +        rotationMat.yx = -rotationMat.xy;
 +        rotationMat.yy = rotationMat.xx;
 +        FT_Matrix_Multiply(&rotationMat, &transMat);
 +        needsTransform = TRUE;
 +    }
 +
 +    /* Extra transformation specified by caller */
 +    if (pmat2)
 +    {
 +        FT_Matrix extraMat;
 +        DPRINT("MAT2 Matrix Trans!\n");
 +        extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
 +        extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
 +        extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
 +        extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
 +        FT_Matrix_Multiply(&extraMat, &transMat);
 +        needsTransform = TRUE;
 +    }
 +
 +    if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT); /* It looks like we are finished with potm ATM.*/
 +
 +    if (!needsTransform)
 +    {
 +        DPRINT("No Need to be Transformed!\n");
 +        top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
 +        bottom = (ft_face->glyph->metrics.horiBearingY -
 +                  ft_face->glyph->metrics.height) & -64;
 +        gm.gmCellIncX = adv;
 +        gm.gmCellIncY = 0;
 +    }
 +    else
 +    {
 +        INT xc, yc;
 +        FT_Vector vec;
 +        for (xc = 0; xc < 2; xc++)
 +        {
 +            for (yc = 0; yc < 2; yc++)
 +            {
 +                vec.x = (ft_face->glyph->metrics.horiBearingX +
 +                         xc * ft_face->glyph->metrics.width);
 +                vec.y = ft_face->glyph->metrics.horiBearingY -
 +                        yc * ft_face->glyph->metrics.height;
 +                DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
 +                FT_Vector_Transform(&vec, &transMat);
 +                if (xc == 0 && yc == 0)
 +                {
 +                    left = right = vec.x;
 +                    top = bottom = vec.y;
 +                }
 +                else
 +                {
 +                    if (vec.x < left) left = vec.x;
 +                    else if (vec.x > right) right = vec.x;
 +                    if (vec.y < bottom) bottom = vec.y;
 +                    else if (vec.y > top) top = vec.y;
 +                }
 +            }
 +        }
 +        left = left & -64;
 +        right = (right + 63) & -64;
 +        bottom = bottom & -64;
 +        top = (top + 63) & -64;
 +
 +        DPRINT("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
 +        vec.x = ft_face->glyph->metrics.horiAdvance;
 +        vec.y = 0;
 +        FT_Vector_Transform(&vec, &transMat);
 +        gm.gmCellIncX = (vec.x+63) >> 6;
 +        gm.gmCellIncY = -((vec.y+63) >> 6);
 +    }
 +    gm.gmBlackBoxX = (right - left) >> 6;
 +    gm.gmBlackBoxY = (top - bottom) >> 6;
 +    gm.gmptGlyphOrigin.x = left >> 6;
 +    gm.gmptGlyphOrigin.y = top >> 6;
 +
 +    DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
 +           gm.gmCellIncX, gm.gmCellIncY,
 +           gm.gmBlackBoxX, gm.gmBlackBoxY,
 +           gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
 +
 +    IntUnLockFreeType;
 +
 +    if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
 +
 +    if (iFormat == GGO_METRICS)
 +    {
 +        DPRINT("GGO_METRICS Exit!\n");
 +        return 1; /* FIXME */
 +    }
 +
 +    if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
 +    {
 +        DPRINT1("loaded a bitmap\n");
 +        return GDI_ERROR;
 +    }
 +
 +    switch (iFormat)
 +    {
 +    case GGO_BITMAP:
 +        width = gm.gmBlackBoxX;
 +        height = gm.gmBlackBoxY;
 +        pitch = ((width + 31) >> 5) << 2;
 +        needed = pitch * height;
 +
 +        if (!pvBuf || !cjBuf) break;
 +
 +        switch (ft_face->glyph->format)
 +        {
 +        case ft_glyph_format_bitmap:
 +        {
 +            BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
 +            INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
 +            INT h = ft_face->glyph->bitmap.rows;
 +            while (h--)
 +            {
 +                RtlCopyMemory(dst, src, w);
 +                src += ft_face->glyph->bitmap.pitch;
 +                dst += pitch;
 +            }
 +            break;
 +        }
 +
 +        case ft_glyph_format_outline:
 +            ft_bitmap.width = width;
 +            ft_bitmap.rows = height;
 +            ft_bitmap.pitch = pitch;
 +            ft_bitmap.pixel_mode = ft_pixel_mode_mono;
 +            ft_bitmap.buffer = pvBuf;
 +
 +            IntLockFreeType;
 +            if (needsTransform)
 +            {
 +                FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
 +            }
 +            FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
 +            /* Note: FreeType will only set 'black' bits for us. */
 +            RtlZeroMemory(pvBuf, needed);
 +            FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
 +            IntUnLockFreeType;
 +            break;
 +
 +        default:
 +            DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
 +            return GDI_ERROR;
 +        }
 +        break;
 +
 +    case GGO_GRAY2_BITMAP:
 +    case GGO_GRAY4_BITMAP:
 +    case GGO_GRAY8_BITMAP:
 +    {
 +        unsigned int mult, row, col;
 +        BYTE *start, *ptr;
 +
 +        width = gm.gmBlackBoxX;
 +        height = gm.gmBlackBoxY;
 +        pitch = (width + 3) / 4 * 4;
 +        needed = pitch * height;
 +
 +        if (!pvBuf || !cjBuf) break;
 +
 +        switch (ft_face->glyph->format)
 +        {
 +        case ft_glyph_format_bitmap:
 +        {
 +            BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
 +            INT h = ft_face->glyph->bitmap.rows;
 +            INT x;
 +            while (h--)
 +            {
 +                for (x = 0; x < pitch; x++)
 +                {
 +                    if (x < ft_face->glyph->bitmap.width)
 +                        dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
 +                    else
 +                        dst[x] = 0;
 +                }
 +                src += ft_face->glyph->bitmap.pitch;
 +                dst += pitch;
 +            }
 +            return needed;
 +        }
 +        case ft_glyph_format_outline:
 +        {
 +            ft_bitmap.width = width;
 +            ft_bitmap.rows = height;
 +            ft_bitmap.pitch = pitch;
 +            ft_bitmap.pixel_mode = ft_pixel_mode_grays;
 +            ft_bitmap.buffer = pvBuf;
 +
 +            IntLockFreeType;
 +            if (needsTransform)
 +            {
 +                FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
 +            }
 +            FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
 +            RtlZeroMemory(ft_bitmap.buffer, cjBuf);
 +            FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
 +            IntUnLockFreeType;
 +
 +            if (iFormat == GGO_GRAY2_BITMAP)
 +                mult = 4;
 +            else if (iFormat == GGO_GRAY4_BITMAP)
 +                mult = 16;
 +            else if (iFormat == GGO_GRAY8_BITMAP)
 +                mult = 64;
 +            else
 +            {
 +                return GDI_ERROR;
 +            }
 +        }
 +        default:
 +            DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
 +            return GDI_ERROR;
 +        }
 +        start = pvBuf;
 +        for (row = 0; row < height; row++)
 +        {
 +            ptr = start;
 +            for (col = 0; col < width; col++, ptr++)
 +            {
 +                *ptr = (((int)*ptr) * mult + 128) / 256;
 +            }
 +            start += pitch;
 +        }
 +        break;
 +    }
 +
 +    case GGO_NATIVE:
 +    {
 +        int contour, point = 0, first_pt;
 +        FT_Outline *outline = &ft_face->glyph->outline;
 +        TTPOLYGONHEADER *pph;
 +        TTPOLYCURVE *ppc;
 +        DWORD pph_start, cpfx, type;
 +
 +        if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
 +
 +        IntLockFreeType;
 +        if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
 +
 +        for (contour = 0; contour < outline->n_contours; contour++)
 +        {
 +            pph_start = needed;
 +            pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
 +            first_pt = point;
 +            if (pvBuf)
 +            {
 +                pph->dwType = TT_POLYGON_TYPE;
 +                FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
 +            }
 +            needed += sizeof(*pph);
 +            point++;
 +            while (point <= outline->contours[contour])
 +            {
 +                ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
 +                type = (outline->tags[point] & FT_Curve_Tag_On) ?
 +                       TT_PRIM_LINE : TT_PRIM_QSPLINE;
 +                cpfx = 0;
 +                do
 +                {
 +                    if (pvBuf)
 +                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
 +                    cpfx++;
 +                    point++;
 +                }
 +                while (point <= outline->contours[contour] &&
 +                        (outline->tags[point] & FT_Curve_Tag_On) ==
 +                        (outline->tags[point-1] & FT_Curve_Tag_On));
 +
 +                /* At the end of a contour Windows adds the start point, but
 +                   only for Beziers */
 +                if (point > outline->contours[contour] &&
 +                        !(outline->tags[point-1] & FT_Curve_Tag_On))
 +                {
 +                    if (pvBuf)
 +                        FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
 +                    cpfx++;
 +                }
 +                else if (point <= outline->contours[contour] &&
 +                         outline->tags[point] & FT_Curve_Tag_On)
 +                {
 +                    /* add closing pt for bezier */
 +                    if (pvBuf)
 +                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
 +                    cpfx++;
 +                    point++;
 +                }
 +                if (pvBuf)
 +                {
 +                    ppc->wType = type;
 +                    ppc->cpfx = cpfx;
 +                }
 +                needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
 +            }
 +            if (pvBuf) pph->cb = needed - pph_start;
 +        }
 +        IntUnLockFreeType;
 +        break;
 +    }
 +    case GGO_BEZIER:
 +    {
 +        /* Convert the quadratic Beziers to cubic Beziers.
 +           The parametric eqn for a cubic Bezier is, from PLRM:
 +           r(t) = at^3 + bt^2 + ct + r0
 +           with the control points:
 +           r1 = r0 + c/3
 +           r2 = r1 + (c + b)/3
 +           r3 = r0 + c + b + a
 +
 +           A quadratic Beizer has the form:
 +           p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
 +
 +           So equating powers of t leads to:
 +           r1 = 2/3 p1 + 1/3 p0
 +           r2 = 2/3 p1 + 1/3 p2
 +           and of course r0 = p0, r3 = p2
 +         */
 +
 +        int contour, point = 0, first_pt;
 +        FT_Outline *outline = &ft_face->glyph->outline;
 +        TTPOLYGONHEADER *pph;
 +        TTPOLYCURVE *ppc;
 +        DWORD pph_start, cpfx, type;
 +        FT_Vector cubic_control[4];
 +        if (cjBuf == 0) pvBuf = NULL;
 +
 +        if (needsTransform && pvBuf)
 +        {
 +            IntLockFreeType;
 +            FT_Outline_Transform(outline, &transMat);
 +            IntUnLockFreeType;
 +        }
 +
 +        for (contour = 0; contour < outline->n_contours; contour++)
 +        {
 +            pph_start = needed;
 +            pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
 +            first_pt = point;
 +            if (pvBuf)
 +            {
 +                pph->dwType = TT_POLYGON_TYPE;
 +                FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
 +            }
 +            needed += sizeof(*pph);
 +            point++;
 +            while (point <= outline->contours[contour])
 +            {
 +                ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
 +                type = (outline->tags[point] & FT_Curve_Tag_On) ?
 +                       TT_PRIM_LINE : TT_PRIM_CSPLINE;
 +                cpfx = 0;
 +                do
 +                {
 +                    if (type == TT_PRIM_LINE)
 +                    {
 +                        if (pvBuf)
 +                            FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
 +                        cpfx++;
 +                        point++;
 +                    }
 +                    else
 +                    {
 +                        /* Unlike QSPLINEs, CSPLINEs always have their endpoint
 +                           so cpfx = 3n */
 +
 +                        /* FIXME: Possible optimization in endpoint calculation
 +                           if there are two consecutive curves */
 +                        cubic_control[0] = outline->points[point-1];
 +                        if (!(outline->tags[point-1] & FT_Curve_Tag_On))
 +                        {
 +                            cubic_control[0].x += outline->points[point].x + 1;
 +                            cubic_control[0].y += outline->points[point].y + 1;
 +                            cubic_control[0].x >>= 1;
 +                            cubic_control[0].y >>= 1;
 +                        }
 +                        if (point+1 > outline->contours[contour])
 +                            cubic_control[3] = outline->points[first_pt];
 +                        else
 +                        {
 +                            cubic_control[3] = outline->points[point+1];
 +                            if (!(outline->tags[point+1] & FT_Curve_Tag_On))
 +                            {
 +                                cubic_control[3].x += outline->points[point].x + 1;
 +                                cubic_control[3].y += outline->points[point].y + 1;
 +                                cubic_control[3].x >>= 1;
 +                                cubic_control[3].y >>= 1;
 +                            }
 +                        }
 +                        /* r1 = 1/3 p0 + 2/3 p1
 +                           r2 = 1/3 p2 + 2/3 p1 */
 +                        cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
 +                        cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
 +                        cubic_control[2] = cubic_control[1];
 +                        cubic_control[1].x += (cubic_control[0].x + 1) / 3;
 +                        cubic_control[1].y += (cubic_control[0].y + 1) / 3;
 +                        cubic_control[2].x += (cubic_control[3].x + 1) / 3;
 +                        cubic_control[2].y += (cubic_control[3].y + 1) / 3;
 +                        if (pvBuf)
 +                        {
 +                            FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
 +                            FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
 +                            FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
 +                        }
 +                        cpfx += 3;
 +                        point++;
 +                    }
 +                }
 +                while (point <= outline->contours[contour] &&
 +                        (outline->tags[point] & FT_Curve_Tag_On) ==
 +                        (outline->tags[point-1] & FT_Curve_Tag_On));
 +                /* At the end of a contour Windows adds the start point,
 +                   but only for Beziers and we've already done that.
 +                */
 +                if (point <= outline->contours[contour] &&
 +                        outline->tags[point] & FT_Curve_Tag_On)
 +                {
 +                    /* This is the closing pt of a bezier, but we've already
 +                      added it, so just inc point and carry on */
 +                    point++;
 +                }
 +                if (pvBuf)
 +                {
 +                    ppc->wType = type;
 +                    ppc->cpfx = cpfx;
 +                }
 +                needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
 +            }
 +            if (pvBuf) pph->cb = needed - pph_start;
 +        }
 +        break;
 +    }
 +
 +    default:
 +        DPRINT1("Unsupported format %d\n", iFormat);
 +        return GDI_ERROR;
 +    }
 +
 +    DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
 +    return needed;
 +}
 +
 +BOOL
 +FASTCALL
 +TextIntGetTextExtentPoint(PDC dc,
 +                          PTEXTOBJ TextObj,
 +                          LPCWSTR String,
 +                          INT Count,
 +                          ULONG MaxExtent,
 +                          LPINT Fit,
 +                          LPINT Dx,
-         glyph_index = FT_Get_Char_Index(face, *String);
++                          LPSIZE Size,
++                          FLONG fl)
 +{
 +    PFONTGDI FontGDI;
 +    FT_Face face;
 +    FT_GlyphSlot glyph;
 +    FT_BitmapGlyph realglyph;
 +    INT error, n, glyph_index, i, previous;
 +    ULONGLONG TotalWidth = 0;
 +    FT_CharMap charmap, found = NULL;
 +    BOOL use_kerning;
 +    FT_Render_Mode RenderMode;
 +    BOOLEAN Render;
 +
 +    FontGDI = ObjToGDI(TextObj->Font, FONT);
 +
 +    face = FontGDI->face;
 +    if (NULL != Fit)
 +    {
 +        *Fit = 0;
 +    }
 +
 +    IntLockFreeType;
 +    if (face->charmap == NULL)
 +    {
 +        DPRINT("WARNING: No charmap selected!\n");
 +        DPRINT("This font face has %d charmaps\n", face->num_charmaps);
 +
 +        for (n = 0; n < face->num_charmaps; n++)
 +        {
 +            charmap = face->charmaps[n];
 +            DPRINT("found charmap encoding: %u\n", charmap->encoding);
 +            if (charmap->encoding != 0)
 +            {
 +                found = charmap;
 +                break;
 +            }
 +        }
 +
 +        if (! found)
 +        {
 +            DPRINT1("WARNING: Could not find desired charmap!\n");
 +        }
 +
 +        error = FT_Set_Charmap(face, found);
 +        if (error)
 +        {
 +            DPRINT1("WARNING: Could not set the charmap!\n");
 +        }
 +    }
 +
 +    Render = IntIsFontRenderingEnabled();
 +    if (Render)
 +        RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
 +    else
 +        RenderMode = FT_RENDER_MODE_MONO;
 +
 +    error = FT_Set_Pixel_Sizes(face,
 +                               TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
 +                               /* FIXME should set character height if neg */
 +                               (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
 +                                - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
 +                                TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
 +    if (error)
 +    {
 +        DPRINT1("Error in setting pixel sizes: %u\n", error);
 +    }
 +
 +    use_kerning = FT_HAS_KERNING(face);
 +    previous = 0;
 +
 +    for (i = 0; i < Count; i++)
 +    {
-         Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]);
++        if (fl & GTEF_INDICES)
++            glyph_index = *String;
++        else
++            glyph_index = FT_Get_Char_Index(face, *String);
++
 +        if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
 +                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
 +        {
 +            error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
 +            if (error)
 +            {
 +                DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
 +                break;
 +            }
 +
 +            glyph = face->glyph;
 +            realglyph = ftGdiGlyphCacheSet(face, glyph_index,
 +                                           TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
 +            if (!realglyph)
 +            {
 +                DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
 +                break;
 +            }
 +        }
 +
 +        /* retrieve kerning distance */
 +        if (use_kerning && previous && glyph_index)
 +        {
 +            FT_Vector delta;
 +            FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
 +            TotalWidth += delta.x;
 +        }
 +
 +        TotalWidth += realglyph->root.advance.x >> 10;
 +
 +        if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
 +        {
 +            *Fit = i + 1;
 +        }
 +        if (NULL != Dx)
 +        {
 +            Dx[i] = (TotalWidth + 32) >> 6;
 +        }
 +
 +        previous = glyph_index;
 +        String++;
 +    }
 +    IntUnLockFreeType;
 +
 +    Size->cx = (TotalWidth + 32) >> 6;
 +    Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight);
 +    Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
 +
 +    return TRUE;
 +}
 +
 +
 +INT
 +FASTCALL
 +ftGdiGetTextCharsetInfo(
 +    PDC Dc,
 +    LPFONTSIGNATURE lpSig,
 +    DWORD dwFlags)
 +{
 +    PDC_ATTR pdcattr;
 +    UINT Ret = DEFAULT_CHARSET, i;
 +    HFONT hFont;
 +    PTEXTOBJ TextObj;
 +    PFONTGDI FontGdi;
 +    FONTSIGNATURE fs;
 +    TT_OS2 *pOS2;
 +    FT_Face Face;
 +    CHARSETINFO csi;
 +    DWORD cp, fs0;
 +    USHORT usACP, usOEM;
 +
 +    pdcattr = Dc->pdcattr;
 +    hFont = pdcattr->hlfntNew;
 +    TextObj = RealizeFontInit(hFont);
 +
 +    if (!TextObj)
 +    {
 +        SetLastWin32Error(ERROR_INVALID_HANDLE);
 +        return Ret;
 +    }
 +    FontGdi = ObjToGDI(TextObj->Font, FONT);
 +    Face = FontGdi->face;
 +    TEXTOBJ_UnlockText(TextObj);
 +
 +    IntLockFreeType;
 +    pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
 +    IntUnLockFreeType;
 +    memset(&fs, 0, sizeof(FONTSIGNATURE));
 +    if (NULL != pOS2)
 +    {
 +        fs.fsCsb[0] = pOS2->ulCodePageRange1;
 +        fs.fsCsb[1] = pOS2->ulCodePageRange2;
 +        fs.fsUsb[0] = pOS2->ulUnicodeRange1;
 +        fs.fsUsb[1] = pOS2->ulUnicodeRange2;
 +        fs.fsUsb[2] = pOS2->ulUnicodeRange3;
 +        fs.fsUsb[3] = pOS2->ulUnicodeRange4;
 +        if (pOS2->version == 0)
 +        {
 +            FT_UInt dummy;
 +
 +            if (FT_Get_First_Char( Face, &dummy ) < 0x100)
 +                fs.fsCsb[0] |= FS_LATIN1;
 +            else
 +                fs.fsCsb[0] |= FS_SYMBOL;
 +        }
 +    }
 +    DPRINT("Csb 1=%x  0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
 +    if (fs.fsCsb[0] == 0)
 +    { /* let's see if we can find any interesting cmaps */
 +        for (i = 0; i < Face->num_charmaps; i++)
 +        {
 +            switch (Face->charmaps[i]->encoding)
 +            {
 +            case FT_ENCODING_UNICODE:
 +            case FT_ENCODING_APPLE_ROMAN:
 +                fs.fsCsb[0] |= FS_LATIN1;
 +                break;
 +            case FT_ENCODING_MS_SYMBOL:
 +                fs.fsCsb[0] |= FS_SYMBOL;
 +                break;
 +            default:
 +                break;
 +            }
 +        }
 +    }
 +    if (lpSig)
 +    {
 +        RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
 +    }
 +
 +    RtlGetDefaultCodePage(&usACP, &usOEM);
 +    cp = usACP;
 +
 +    if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
 +        if (csi.fs.fsCsb[0] & fs.fsCsb[0])
 +        {
 +            DPRINT("Hit 1\n");
 +            Ret = csi.ciCharset;
 +            goto Exit;
 +        }
 +
 +    for (i = 0; i < MAXTCIINDEX; i++)
 +    {
 +        fs0 = 1L << i;
 +        if (fs.fsCsb[0] & fs0)
 +        {
 +            if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
 +            {
 +                //*cp = csi.ciACP;
 +                DPRINT("Hit 2\n");
 +                Ret = csi.ciCharset;
 +                goto Exit;
 +            }
 +            else
 +                DPRINT1("TCI failing on %x\n", fs0);
 +        }
 +    }
 +Exit:
 +    DPRINT("CharSet %d CodePage %d\n",csi.ciCharset, csi.ciACP);
 +    return (MAKELONG(csi.ciACP, csi.ciCharset));
 +}
 +
 +
 +DWORD
 +FASTCALL
 +ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
 +{
 +    DWORD size = 0;
 +    DWORD num_ranges = 0;
 +    FT_Face face = Font->face;
 +
 +    if (face->charmap->encoding == FT_ENCODING_UNICODE)
 +    {
 +        FT_UInt glyph_code = 0;
 +        FT_ULong char_code, char_code_prev;
 +
 +        char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
 +
 +        DPRINT("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
 +               face->num_glyphs, glyph_code, char_code);
 +
 +        if (!glyph_code) return 0;
 +
 +        if (glyphset)
 +        {
 +            glyphset->ranges[0].wcLow = (USHORT)char_code;
 +            glyphset->ranges[0].cGlyphs = 0;
 +            glyphset->cGlyphsSupported = 0;
 +        }
 +
 +        num_ranges = 1;
 +        while (glyph_code)
 +        {
 +            if (char_code < char_code_prev)
 +            {
 +                DPRINT1("expected increasing char code from FT_Get_Next_Char\n");
 +                return 0;
 +            }
 +            if (char_code - char_code_prev > 1)
 +            {
 +                num_ranges++;
 +                if (glyphset)
 +                {
 +                    glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
 +                    glyphset->ranges[num_ranges - 1].cGlyphs = 1;
 +                    glyphset->cGlyphsSupported++;
 +                }
 +            }
 +            else if (glyphset)
 +            {
 +                glyphset->ranges[num_ranges - 1].cGlyphs++;
 +                glyphset->cGlyphsSupported++;
 +            }
 +            char_code_prev = char_code;
 +            char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
 +        }
 +    }
 +    else
 +        DPRINT1("encoding %u not supported\n", face->charmap->encoding);
 +
 +    size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
 +    if (glyphset)
 +    {
 +        glyphset->cbThis = size;
 +        glyphset->cRanges = num_ranges;
 +    }
 +    return size;
 +}
 +
 +
 +BOOL
 +FASTCALL
 +ftGdiGetTextMetricsW(
 +    HDC hDC,
 +    PTMW_INTERNAL ptmwi)
 +{
 +    PDC dc;
 +    PDC_ATTR pdcattr;
 +    PTEXTOBJ TextObj;
 +    PFONTGDI FontGDI;
 +    FT_Face Face;
 +    TT_OS2 *pOS2;
 +    TT_HoriHeader *pHori;
 +    FT_WinFNT_HeaderRec Win;
 +    ULONG Error;
 +    NTSTATUS Status = STATUS_SUCCESS;
 +
 +    if (!ptmwi)
 +    {
 +        SetLastWin32Error(STATUS_INVALID_PARAMETER);
 +        return FALSE;
 +    }
 +
 +    if (!(dc = DC_LockDc(hDC)))
 +    {
 +        SetLastWin32Error(ERROR_INVALID_HANDLE);
 +        return FALSE;
 +    }
 +    pdcattr = dc->pdcattr;
 +    TextObj = RealizeFontInit(pdcattr->hlfntNew);
 +    if (NULL != TextObj)
 +    {
 +        FontGDI = ObjToGDI(TextObj->Font, FONT);
 +
 +        Face = FontGDI->face;
 +        IntLockFreeType;
 +        Error = FT_Set_Pixel_Sizes(Face,
 +                                   TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
 +                                   /* FIXME should set character height if neg */
 +                                   (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
 +                                    - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
 +                                    TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
 +        IntUnLockFreeType;
 +        if (0 != Error)
 +        {
 +            DPRINT1("Error in setting pixel sizes: %u\n", Error);
 +            Status = STATUS_UNSUCCESSFUL;
 +        }
 +        else
 +        {
 +            Status = STATUS_SUCCESS;
 +
 +            IntLockFreeType;
 +            pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
 +            if (NULL == pOS2)
 +            {
 +                DPRINT1("Can't find OS/2 table - not TT font?\n");
 +                Status = STATUS_INTERNAL_ERROR;
 +            }
 +
 +            pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
 +            if (NULL == pHori)
 +            {
 +                DPRINT1("Can't find HHEA table - not TT font?\n");
 +                Status = STATUS_INTERNAL_ERROR;
 +            }
 +
 +            Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
 +
 +            IntUnLockFreeType;
 +
 +            if (NT_SUCCESS(Status))
 +            {
 +                if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
 +                {
 +                    FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
 +                    FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
 +                }
 +
 +                RtlCopyMemory(&ptmwi->TextMetric, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
 +                /* FIXME: Fill Diff member */
 +                RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
 +            }
 +        }
 +        TEXTOBJ_UnlockText(TextObj);
 +    }
 +    else
 +    {
 +        Status = STATUS_INVALID_HANDLE;
 +    }
 +    DC_UnlockDc(dc);
 +
 +    if (!NT_SUCCESS(Status))
 +    {
 +        SetLastNtError(Status);
 +        return FALSE;
 +    }
 +    return TRUE;
 +}
 +
 +
 +DWORD
 +FASTCALL
 +ftGdiGetFontData(
 +    PFONTGDI FontGdi,
 +    DWORD Table,
 +    DWORD Offset,
 +    PVOID Buffer,
 +    DWORD Size)
 +{
 +    DWORD Result = GDI_ERROR;
 +
 +    IntLockFreeType;
 +
 +    if (FT_IS_SFNT(FontGdi->face))
 +    {
 +        if (Table)
 +            Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
 +                    (Table << 8 & 0xFF0000);
 +
 +        if (!Buffer) Size = 0;
 +
 +        if (Buffer && Size)
 +        {
 +            FT_Error Error;
 +            FT_ULong Needed = 0;
 +
 +            Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
 +
 +            if ( !Error && Needed < Size) Size = Needed;
 +        }
 +        if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
 +            Result = Size;
 +    }
 +
 +    IntUnLockFreeType;
 +
 +    return Result;
 +}
 +
 +static UINT FASTCALL
 +GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
 +{
 +    ANSI_STRING EntryFaceNameA;
 +    UNICODE_STRING EntryFaceNameW;
 +    unsigned Size;
 +    OUTLINETEXTMETRICW *Otm;
 +    LONG WeightDiff;
 +    NTSTATUS Status;
 +    UINT Score = 1;
 +
 +    RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
 +    Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
 +    if (NT_SUCCESS(Status))
 +    {
 +        if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
 +        {
 +            EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
 +            EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
 +        }
 +        if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
 +        {
 +            Score += 49;
 +        }
 +        RtlFreeUnicodeString(&EntryFaceNameW);
 +    }
 +
 +    Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
 +    Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
 +    if (NULL == Otm)
 +    {
 +        return Score;
 +    }
 +    IntGetOutlineTextMetrics(FontGDI, Size, Otm);
 +
 +    if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
 +            (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
 +    {
 +        Score += 25;
 +    }
 +    if (LogFont->lfWeight != FW_DONTCARE)
 +    {
 +        if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
 +        {
 +            WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
 +        }
 +        else
 +        {
 +            WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
 +        }
 +        Score += (1000 - WeightDiff) / (1000 / 25);
 +    }
 +    else
 +    {
 +        Score += 25;
 +    }
 +
 +    ExFreePool(Otm);
 +
 +    return Score;
 +}
 +
 +static __inline VOID
 +FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
 +                     PUNICODE_STRING FaceName, PLIST_ENTRY Head)
 +{
 +    PLIST_ENTRY Entry;
 +    PFONT_ENTRY CurrentEntry;
 +    FONTGDI *FontGDI;
 +    UINT Score;
 +
 +    Entry = Head->Flink;
 +    while (Entry != Head)
 +    {
 +        CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
 +
 +        FontGDI = CurrentEntry->Font;
 +        ASSERT(FontGDI);
 +
 +        Score = GetFontScore(LogFont, FaceName, FontGDI);
 +        if (*MatchScore == 0 || *MatchScore < Score)
 +        {
 +            *FontObj = GDIToObj(FontGDI, FONT);
 +            *MatchScore = Score;
 +        }
 +        Entry = Entry->Flink;
 +    }
 +}
 +
 +static __inline BOOLEAN
 +SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
 +                        LPCWSTR Key)
 +{
 +    RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
 +    NTSTATUS Status;
 +    UNICODE_STRING Value;
 +
 +    RtlInitUnicodeString(&Value, NULL);
 +
 +    QueryTable[0].QueryRoutine = NULL;
 +    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
 +                          RTL_QUERY_REGISTRY_REQUIRED;
 +    QueryTable[0].Name = FaceName->Buffer;
 +    QueryTable[0].EntryContext = &Value;
 +    QueryTable[0].DefaultType = REG_NONE;
 +    QueryTable[0].DefaultData = NULL;
 +    QueryTable[0].DefaultLength = 0;
 +
 +    QueryTable[1].QueryRoutine = NULL;
 +    QueryTable[1].Name = NULL;
 +
 +    Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
 +                                    Key,
 +                                    QueryTable,
 +                                    NULL,
 +                                    NULL);
 +    if (NT_SUCCESS(Status))
 +    {
 +        RtlFreeUnicodeString(FaceName);
 +        *FaceName = Value;
 +    }
 +
 +    return NT_SUCCESS(Status);
 +}
 +
 +static __inline void
 +SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
 +{
 +    if (10 < Level) /* Enough is enough */
 +    {
 +        return;
 +    }
 +
 +    if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
 +            SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
 +    {
 +        SubstituteFontFamily(FaceName, Level + 1);
 +    }
 +}
 +
 +static
 +VOID
 +FASTCALL
 +IntFontType(PFONTGDI Font)
 +{
 +    PS_FontInfoRec psfInfo;
 +    FT_ULong tmp_size = 0;
 +
 +    if (FT_HAS_MULTIPLE_MASTERS(Font->face))
 +        Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
 +    if (FT_HAS_VERTICAL( Font->face ))
 +        Font->FontObj.flFontType |= FO_VERT_FACE;
 +    if (FT_IS_SCALABLE( Font->face ))
 +        Font->FontObj.flFontType |= FO_TYPE_RASTER;
 +    if (FT_IS_SFNT(Font->face))
 +    {
 +        Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
 +        if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
 +            Font->FontObj.flFontType |= FO_POSTSCRIPT;
 +    }
 +    if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
 +    {
 +        Font->FontObj.flFontType |= FO_POSTSCRIPT;
 +    }
 +    /* check for the presence of the 'CFF ' table to check if the font is Type1 */
 +    if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
 +    {
 +        Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
 +    }
 +}
 +
 +NTSTATUS
 +FASTCALL
 +TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
 +{
 +    NTSTATUS Status = STATUS_SUCCESS;
 +    PTEXTOBJ TextObj;
 +    UNICODE_STRING FaceName;
 +    PPROCESSINFO Win32Process;
 +    UINT MatchScore;
 +
 +    if (!pTextObj)
 +    {
 +        TextObj = TEXTOBJ_LockText(FontHandle);
 +        if (NULL == TextObj)
 +        {
 +            return STATUS_INVALID_HANDLE;
 +        }
 +
 +        if (TextObj->fl & TEXTOBJECT_INIT)
 +        {
 +            TEXTOBJ_UnlockText(TextObj);
 +            return STATUS_SUCCESS;
 +        }
 +    }
 +    else
 +        TextObj = pTextObj;
 +
 +    if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
 +    {
 +        if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
 +        return STATUS_NO_MEMORY;
 +    }
 +    SubstituteFontFamily(&FaceName, 0);
 +    MatchScore = 0;
 +    TextObj->Font = NULL;
 +
 +    /* First search private fonts */
 +    Win32Process = PsGetCurrentProcessWin32Process();
 +    IntLockProcessPrivateFonts(Win32Process);
 +    FindBestFontFromList(&TextObj->Font, &MatchScore,
 +                         &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
 +                         &Win32Process->PrivateFontListHead);
 +    IntUnLockProcessPrivateFonts(Win32Process);
 +
 +    /* Search system fonts */
 +    IntLockGlobalFonts;
 +    FindBestFontFromList(&TextObj->Font, &MatchScore,
 +                         &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
 +                         &FontListHead);
 +    IntUnLockGlobalFonts;
 +    if (NULL == TextObj->Font)
 +    {
 +        DPRINT1("Requested font %S not found, no fonts loaded at all\n",
 +                TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
 +        Status = STATUS_NOT_FOUND;
 +    }
 +    else
 +    {
 +        PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
 +        // Need hdev, when freetype is loaded need to create DEVOBJ for
 +        // Consumer and Producer.
 +        TextObj->Font->iUniq = 1; // Now it can be cached.
 +        IntFontType(FontGdi);
 +        FontGdi->flType = TextObj->Font->flFontType;
 +        FontGdi->flRealizedType = 0;
 +        FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
 +        FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
 +        TextObj->fl |= TEXTOBJECT_INIT;
 +        Status = STATUS_SUCCESS;
 +    }
 +
 +    RtlFreeUnicodeString(&FaceName);
 +    if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
 +
 +    ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
 +
 +    return Status;
 +}
 +
 +
 +static
 +BOOL
 +FASTCALL
 +IntGetFullFileName(
 +    POBJECT_NAME_INFORMATION NameInfo,
 +    ULONG Size,
 +    PUNICODE_STRING FileName)
 +{
 +    NTSTATUS Status;
 +    OBJECT_ATTRIBUTES ObjectAttributes;
 +    HANDLE hFile;
 +    IO_STATUS_BLOCK IoStatusBlock;
 +    ULONG Desired;
 +
 +    InitializeObjectAttributes(&ObjectAttributes,
 +                               FileName,
 +                               OBJ_CASE_INSENSITIVE,
 +                               NULL,
 +                               NULL);
 +
 +    Status = ZwOpenFile(
 +                 &hFile,
 +                 0, //FILE_READ_ATTRIBUTES,
 +                 &ObjectAttributes,
 +                 &IoStatusBlock,
 +                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 +                 0);
 +
 +    if (!NT_SUCCESS(Status))
 +    {
 +        DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
 +        return FALSE;
 +    }
 +
 +    Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
 +    ZwClose(hFile);
 +    if (!NT_SUCCESS(Status))
 +    {
 +        DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
 +        return FALSE;
 +    }
 +
 +    return TRUE;
 +}
 +
 +BOOL
 +FASTCALL
 +IntGdiGetFontResourceInfo(
 +    PUNICODE_STRING FileName,
 +    PVOID pBuffer,
 +    DWORD *pdwBytes,
 +    DWORD dwType)
 +{
 +    UNICODE_STRING EntryFileName;
 +    POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
 +    PLIST_ENTRY ListEntry;
 +    PFONT_ENTRY FontEntry;
 +    FONTFAMILYINFO Info;
 +    ULONG Size;
 +    BOOL bFound = FALSE;
 +
 +    /* Create buffer for full path name */
 +    Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
 +    NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
 +    if (!NameInfo1)
 +    {
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return FALSE;
 +    }
 +
 +    /* Get the full path name */
 +    if (!IntGetFullFileName(NameInfo1, Size, FileName))
 +    {
 +        ExFreePool(NameInfo1);
 +        return FALSE;
 +    }
 +
 +    /* Create a buffer for the entries' names */
 +    NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
 +    if (!NameInfo2)
 +    {
 +        ExFreePool(NameInfo1);
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return FALSE;
 +    }
 +
 +    /* Try to find the pathname in the global font list */
 +    IntLockGlobalFonts;
 +    for (ListEntry = FontListHead.Flink;
 +            ListEntry != &FontListHead;
 +            ListEntry = ListEntry->Flink)
 +    {
 +        FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
 +        if (FontEntry->Font->Filename != NULL)
 +        {
 +            RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
 +            if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
 +            {
 +                if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
 +                {
 +                    /* found */
 +                    FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
 +                    bFound = TRUE;
 +                    break;
 +                }
 +            }
 +        }
 +    }
 +    IntUnLockGlobalFonts;
 +
 +    /* Free the buffers */
 +    ExFreePool(NameInfo1);
 +    ExFreePool(NameInfo2);
 +
 +    if (!bFound && dwType != 5)
 +    {
 +        /* Font could not be found in system table
 +           dwType == 5 will still handle this */
 +        return FALSE;
 +    }
 +
 +    switch (dwType)
 +    {
 +    case 0: /* FIXME: returns 1 or 2, don't know what this is atm */
 +        *(DWORD*)pBuffer = 1;
 +        *pdwBytes = sizeof(DWORD);
 +        break;
 +
 +    case 1: /* Copy the full font name */
 +        Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
 +        Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
 +        RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
 +        // FIXME: Do we have to zeroterminate?
 +        *pdwBytes = Size;
 +        break;
 +
 +    case 2: /* Copy a LOGFONTW structure */
 +        Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
 +        RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
 +        *pdwBytes = sizeof(LOGFONTW);
 +        break;
 +
 +    case 3: /* FIXME: What exactly is copied here? */
 +        *(DWORD*)pBuffer = 1;
 +        *pdwBytes = sizeof(DWORD*);
 +        break;
 +
 +    case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
 +        *(BOOL*)pBuffer = !bFound;
 +        *pdwBytes = sizeof(BOOL);
 +        break;
 +
 +    default:
 +        return FALSE;
 +    }
 +
 +    return TRUE;
 +}
 +
 +
 +BOOL
 +FASTCALL
 +ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
 +{
 +    if (FT_HAS_FIXED_SIZES(Font->face))
 +        Info->iTechnology = RI_TECH_BITMAP;
 +    else
 +    {
 +        if (FT_IS_SCALABLE(Font->face))
 +            Info->iTechnology = RI_TECH_SCALABLE;
 +        else
 +            Info->iTechnology = RI_TECH_FIXED;
 +    }
 +    Info->iUniq = Font->FontObj.iUniq;
 +    Info->dwUnknown = -1;
 +    return TRUE;
 +}
 +
 +
 +DWORD
 +FASTCALL
 +ftGdiGetKerningPairs( PFONTGDI Font,
 +                      DWORD cPairs,
 +                      LPKERNINGPAIR pKerningPair)
 +{
 +    DWORD Count = 0;
 +    INT i = 0;
 +    FT_Face face = Font->face;
 +
 +    if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
 +    {
 +        FT_UInt previous_index = 0, glyph_index = 0;
 +        FT_ULong char_code, char_previous;
 +        FT_Vector delta;
 +
 +        char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
 +
 +        IntLockFreeType;
 +
 +        while (glyph_index)
 +        {
 +            if (previous_index && glyph_index)
 +            {
 +                FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
 +
 +                if (pKerningPair && cPairs)
 +                {
 +                    pKerningPair[i].wFirst      = char_previous;
 +                    pKerningPair[i].wSecond     = char_code;
 +                    pKerningPair[i].iKernAmount = delta.x;
 +                    i++;
 +                    if (i == cPairs) break;
 +                }
 +                Count++;
 +            }
 +            previous_index = glyph_index;
 +            char_previous = char_code;
 +            char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
 +        }
 +        IntUnLockFreeType;
 +    }
 +    return Count;
 +}
 +
 +
 +//////////////////
 +//
 +// Functions needing sorting.
 +//
 +///////////////
 +int APIENTRY
 +NtGdiGetFontFamilyInfo(HDC Dc,
 +                       LPLOGFONTW UnsafeLogFont,
 +                       PFONTFAMILYINFO UnsafeInfo,
 +                       DWORD Size)
 +{
 +    NTSTATUS Status;
 +    LOGFONTW LogFont;
 +    PFONTFAMILYINFO Info;
 +    DWORD Count;
 +    PPROCESSINFO Win32Process;
 +
 +    /* Make a safe copy */
 +    Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
 +    if (! NT_SUCCESS(Status))
 +    {
 +        SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +        return -1;
 +    }
 +
 +    /* Allocate space for a safe copy */
 +    Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), TAG_GDITEXT);
 +    if (NULL == Info)
 +    {
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return -1;
 +    }
 +
 +    /* Enumerate font families in the global list */
 +    IntLockGlobalFonts;
 +    Count = 0;
 +    if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
 +    {
 +        IntUnLockGlobalFonts;
 +        ExFreePool(Info);
 +        return -1;
 +    }
 +    IntUnLockGlobalFonts;
 +
 +    /* Enumerate font families in the process local list */
 +    Win32Process = PsGetCurrentProcessWin32Process();
 +    IntLockProcessPrivateFonts(Win32Process);
 +    if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
 +                                   &Win32Process->PrivateFontListHead))
 +    {
 +        IntUnLockProcessPrivateFonts(Win32Process);
 +        ExFreePool(Info);
 +        return -1;
 +    }
 +    IntUnLockProcessPrivateFonts(Win32Process);
 +
 +    /* Enumerate font families in the registry */
 +    if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
 +    {
 +        ExFreePool(Info);
 +        return -1;
 +    }
 +
 +    /* Return data to caller */
 +    if (0 != Count)
 +    {
 +        Status = MmCopyToCaller(UnsafeInfo, Info,
 +                                (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
 +        if (! NT_SUCCESS(Status))
 +        {
 +            ExFreePool(Info);
 +            SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +            return -1;
 +        }
 +    }
 +
 +    ExFreePool(Info);
 +
 +    return Count;
 +}
 +
 +BOOL
 +APIENTRY
 +GreExtTextOutW(
 +    IN HDC hDC,
 +    IN INT XStart,
 +    IN INT YStart,
 +    IN UINT fuOptions,
 +    IN OPTIONAL PRECTL lprc,
 +    IN LPWSTR String,
 +    IN INT Count,
 +    IN OPTIONAL LPINT Dx,
 +    IN DWORD dwCodePage)
 +{
 +    /*
 +     * FIXME:
 +     * Call EngTextOut, which does the real work (calling DrvTextOut where
 +     * appropriate)
 +     */
 +
 +    DC *dc;
 +    PDC_ATTR pdcattr;
 +    SURFOBJ *SurfObj;
 +    SURFACE *psurf = NULL;
 +    int error, glyph_index, n, i;
 +    FT_Face face;
 +    FT_GlyphSlot glyph;
 +    FT_BitmapGlyph realglyph;
 +    LONGLONG TextLeft, RealXStart;
 +    ULONG TextTop, previous, BackgroundLeft;
 +    FT_Bool use_kerning;
 +    RECTL DestRect, MaskRect, DummyRect = {0, 0, 0, 0};
 +    POINTL SourcePoint, BrushOrigin;
 +    HBITMAP HSourceGlyph;
 +    SURFOBJ *SourceGlyphSurf;
 +    SIZEL bitSize;
 +    FT_CharMap found = 0, charmap;
 +    INT yoff;
 +    FONTOBJ *FontObj;
 +    PFONTGDI FontGDI;
 +    PTEXTOBJ TextObj = NULL;
 +    EXLATEOBJ exloRGB2Dst, exloDst2RGB;
 +    FT_Render_Mode RenderMode;
 +    BOOLEAN Render;
 +    POINT Start;
 +    BOOL DoBreak = FALSE;
 +    PPALETTE ppalDst;
 +    USHORT DxShift;
 +
 +    // TODO: Write test-cases to exactly match real Windows in different
 +    // bad parameters (e.g. does Windows check the DC or the RECT first?).
 +    dc = DC_LockDc(hDC);
 +    if (!dc)
 +    {
 +        SetLastWin32Error(ERROR_INVALID_HANDLE);
 +        return FALSE;
 +    }
 +    if (dc->dctype == DC_TYPE_INFO)
 +    {
 +        DC_UnlockDc(dc);
 +        /* Yes, Windows really returns TRUE in this case */
 +        return TRUE;
 +    }
 +
 +    pdcattr = dc->pdcattr;
 +
 +    if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
 +    {
 +        if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
 +            DC_vUpdateBackgroundBrush(dc);
 +    }
 +
 +    /* Check if String is valid */
 +    if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
 +    {
 +        SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +        goto fail;
 +    }
 +
 +    DxShift = fuOptions & ETO_PDY ? 1 : 0;
 +
 +    if (PATH_IsPathOpen(dc->dclevel))
 +    {
 +        if (!PATH_ExtTextOut( dc,
 +                              XStart,
 +                              YStart,
 +                              fuOptions,
 +                              (const RECTL *)lprc,
 +                              String,
 +                              Count,
 +                              (const INT *)Dx)) goto fail;
 +        goto good;
 +    }
 +
 +    if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
 +    {
 +        IntLPtoDP(dc, (POINT *)lprc, 2);
 +    }
 +
 +    Start.x = XStart;
 +    Start.y = YStart;
 +    IntLPtoDP(dc, &Start, 1);
 +
 +    RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
 +    YStart = Start.y + dc->ptlDCOrig.y;
 +
 +    SourcePoint.x = 0;
 +    SourcePoint.y = 0;
 +    MaskRect.left = 0;
 +    MaskRect.top = 0;
 +    BrushOrigin.x = 0;
 +    BrushOrigin.y = 0;
 +
 +    if ((fuOptions & ETO_OPAQUE) && lprc)
 +    {
 +        DestRect.left   = lprc->left;
 +        DestRect.top    = lprc->top;
 +        DestRect.right  = lprc->right;
 +        DestRect.bottom = lprc->bottom;
 +
 +        IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
 +
 +        DestRect.left   += dc->ptlDCOrig.x;
 +        DestRect.top    += dc->ptlDCOrig.y;
 +        DestRect.right  += dc->ptlDCOrig.x;
 +        DestRect.bottom += dc->ptlDCOrig.y;
 +
 +        DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect);
 +
 +        if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
 +            DC_vUpdateBackgroundBrush(dc);
 +
 +        IntEngBitBlt(
 +            &dc->dclevel.pSurface->SurfObj,
 +            NULL,
 +            NULL,
 +            dc->rosdc.CombinedClip,
 +            NULL,
 +            &DestRect,
 +            &SourcePoint,
 +            &SourcePoint,
 +            &dc->eboBackground.BrushObject,
 +            &BrushOrigin,
 +            ROP3_TO_ROP4(PATCOPY));
 +        fuOptions &= ~ETO_OPAQUE;
 +        DC_vFinishBlit(dc, NULL);
 +    }
 +    else
 +    {
 +        if (pdcattr->jBkMode == OPAQUE)
 +        {
 +            fuOptions |= ETO_OPAQUE;
 +        }
 +    }
 +
 +    TextObj = RealizeFontInit(pdcattr->hlfntNew);
 +    if (TextObj == NULL)
 +    {
 +        goto fail;
 +    }
 +
 +    FontObj = TextObj->Font;
 +    ASSERT(FontObj);
 +    FontGDI = ObjToGDI(FontObj, FONT);
 +    ASSERT(FontGDI);
 +
 +    IntLockFreeType;
 +    face = FontGDI->face;
 +    if (face->charmap == NULL)
 +    {
 +        DPRINT("WARNING: No charmap selected!\n");
 +        DPRINT("This font face has %d charmaps\n", face->num_charmaps);
 +
 +        for (n = 0; n < face->num_charmaps; n++)
 +        {
 +            charmap = face->charmaps[n];
 +            DPRINT("found charmap encoding: %u\n", charmap->encoding);
 +            if (charmap->encoding != 0)
 +            {
 +                found = charmap;
 +                break;
 +            }
 +        }
 +        if (!found)
 +        {
 +            DPRINT1("WARNING: Could not find desired charmap!\n");
 +        }
 +        error = FT_Set_Charmap(face, found);
 +        if (error)
 +        {
 +            DPRINT1("WARNING: Could not set the charmap!\n");
 +        }
 +    }
 +
 +    Render = IntIsFontRenderingEnabled();
 +    if (Render)
 +        RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
 +    else
 +        RenderMode = FT_RENDER_MODE_MONO;
 +
 +    error = FT_Set_Pixel_Sizes(
 +                face,
 +                TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
 +                /* FIXME should set character height if neg */
 +                (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
 +                 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
 +                 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
 +    if (error)
 +    {
 +        DPRINT1("Error in setting pixel sizes: %u\n", error);
 +        IntUnLockFreeType;
 +        goto fail;
 +    }
 +
 +    /*
 +     * Process the vertical alignment and determine the yoff.
 +     */
 +
 +    if (pdcattr->lTextAlign & TA_BASELINE)
 +        yoff = 0;
 +    else if (pdcattr->lTextAlign & TA_BOTTOM)
 +        yoff = -face->size->metrics.descender >> 6;
 +    else /* TA_TOP */
 +        yoff = face->size->metrics.ascender >> 6;
 +
 +    use_kerning = FT_HAS_KERNING(face);
 +    previous = 0;
 +
 +    /*
 +     * Process the horizontal alignment and modify XStart accordingly.
 +     */
 +
 +    if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
 +    {
 +        ULONGLONG TextWidth = 0;
 +        LPCWSTR TempText = String;
 +        int Start;
 +
 +        /*
 +         * Calculate width of the text.
 +         */
 +
 +        if (NULL != Dx)
 +        {
 +            Start = Count < 2 ? 0 : Count - 2;
 +            TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
 +        }
 +        else
 +        {
 +            Start = 0;
 +        }
 +        TempText = String + Start;
 +
 +        for (i = Start; i < Count; i++)
 +        {
 +            if (fuOptions & ETO_GLYPH_INDEX)
 +                glyph_index = *TempText;
 +            else
 +                glyph_index = FT_Get_Char_Index(face, *TempText);
 +
 +            if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
 +                                                 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
 +            {
 +                error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
 +                if (error)
 +                {
 +                    DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
 +                }
 +
 +                glyph = face->glyph;
 +                realglyph = ftGdiGlyphCacheSet(face, glyph_index,
 +                                               TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
 +                if (!realglyph)
 +                {
 +                    DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
 +                    IntUnLockFreeType;
 +                    goto fail;
 +                }
 +
 +            }
 +            /* retrieve kerning distance */
 +            if (use_kerning && previous && glyph_index)
 +            {
 +                FT_Vector delta;
 +                FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
 +                TextWidth += delta.x;
 +            }
 +
 +            TextWidth += realglyph->root.advance.x >> 10;
 +
 +            previous = glyph_index;
 +            TempText++;
 +        }
 +
 +        previous = 0;
 +
 +        if (pdcattr->lTextAlign & TA_RIGHT)
 +        {
 +            RealXStart -= TextWidth;
 +        }
 +        else
 +        {
 +            RealXStart -= TextWidth / 2;
 +        }
 +    }
 +
 +    TextLeft = RealXStart;
 +    TextTop = YStart;
 +    BackgroundLeft = (RealXStart + 32) >> 6;
 +
 +    /* Lock blit with a dummy rect */
 +    DC_vPrepareDCsForBlit(dc, DummyRect, NULL, DummyRect);
 +
 +    psurf = dc->dclevel.pSurface ;
 +    SurfObj = &psurf->SurfObj ;
 +
 +    /* Create the xlateobj */
 +    if (psurf->ppal)
 +    {
 +        ppalDst = psurf->ppal;
 +        GDIOBJ_IncrementShareCount(&ppalDst->BaseObject);
 +    }
 +    else
 +        // Destination palette obtained from the hDC
 +        ppalDst = PALETTE_ShareLockPalette(dc->ppdev->devinfo.hpalDefault);
 +    ASSERT(ppalDst);
 +    EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, ppalDst, 0, 0, 0);
 +    EXLATEOBJ_vInitialize(&exloDst2RGB, ppalDst, &gpalRGB, 0, 0, 0);
 +    PALETTE_ShareUnlockPalette(ppalDst);
 +
 +    if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
 +        DC_vUpdateBackgroundBrush(dc) ;
 +
 +    if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
 +        DC_vUpdateTextBrush(dc) ;
 +
 +    /*
 +     * The main rendering loop.
 +     */
 +    for (i = 0; i < Count; i++)
 +    {
 +        if (fuOptions & ETO_GLYPH_INDEX)
 +            glyph_index = *String;
 +        else
 +            glyph_index = FT_Get_Char_Index(face, *String);
 +
 +        if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
 +                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
 +        {
 +            error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
 +            if (error)
 +            {
 +                DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
 +                IntUnLockFreeType;
 +                goto fail2;
 +            }
 +            glyph = face->glyph;
 +            realglyph = ftGdiGlyphCacheSet(face,
 +                                           glyph_index,
 +                                           TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
 +                                           glyph,
 +                                           RenderMode);
 +            if (!realglyph)
 +            {
 +                DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
 +                IntUnLockFreeType;
 +                goto fail2;
 +            }
 +        }
 +
 +        /* retrieve kerning distance and move pen position */
 +        if (use_kerning && previous && glyph_index && NULL == Dx)
 +        {
 +            FT_Vector delta;
 +            FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
 +            TextLeft += delta.x;
 +        }
 +        DPRINT("TextLeft: %d\n", TextLeft);
 +        DPRINT("TextTop: %d\n", TextTop);
 +        DPRINT("Advance: %d\n", realglyph->root.advance.x);
 +
 +        if (fuOptions & ETO_OPAQUE)
 +        {
 +            DestRect.left = BackgroundLeft;
 +            DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
 +            DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
 +            DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
 +            MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
 +            IntEngBitBlt(
 +                &psurf->SurfObj,
 +                NULL,
 +                NULL,
 +                dc->rosdc.CombinedClip,
 +                NULL,
 +                &DestRect,
 +                &SourcePoint,
 +                &SourcePoint,
 +                &dc->eboBackground.BrushObject,
 +                &BrushOrigin,
 +                ROP3_TO_ROP4(PATCOPY));
 +            MouseSafetyOnDrawEnd(dc->ppdev);
 +            BackgroundLeft = DestRect.right;
 +
 +        }
 +
 +        DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
 +        DestRect.right = DestRect.left + realglyph->bitmap.width;
 +        DestRect.top = TextTop + yoff - realglyph->top;
 +        DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
 +
 +        bitSize.cx = realglyph->bitmap.width;
 +        bitSize.cy = realglyph->bitmap.rows;
 +        MaskRect.right = realglyph->bitmap.width;
 +        MaskRect.bottom = realglyph->bitmap.rows;
 +
 +        /*
 +         * We should create the bitmap out of the loop at the biggest possible
 +         * glyph size. Then use memset with 0 to clear it and sourcerect to
 +         * limit the work of the transbitblt.
 +         */
 +
 +        HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
 +                                       BMF_8BPP, BMF_TOPDOWN,
 +                                       realglyph->bitmap.buffer);
 +        if ( !HSourceGlyph )
 +        {
 +            DPRINT1("WARNING: EngLockSurface() failed!\n");
 +            // FT_Done_Glyph(realglyph);
 +            IntUnLockFreeType;
 +            goto fail2;
 +        }
 +        SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
 +        if ( !SourceGlyphSurf )
 +        {
 +            EngDeleteSurface((HSURF)HSourceGlyph);
 +            DPRINT1("WARNING: EngLockSurface() failed!\n");
 +            IntUnLockFreeType;
 +            goto fail2;
 +        }
 +
 +        /*
 +         * Use the font data as a mask to paint onto the DCs surface using a
 +         * brush.
 +         */
 +
 +        if (lprc &&
 +                (fuOptions & ETO_CLIPPED) &&
 +                DestRect.right >= lprc->right + dc->ptlDCOrig.x)
 +        {
 +            // We do the check '>=' instead of '>' to possibly save an iteration
 +            // through this loop, since it's breaking after the drawing is done,
 +            // and x is always incremented.
 +            DestRect.right = lprc->right + dc->ptlDCOrig.x;
 +            DoBreak = TRUE;
 +        }
 +        MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
 +        IntEngMaskBlt(
 +            SurfObj,
 +            SourceGlyphSurf,
 +            dc->rosdc.CombinedClip,
 +            &exloRGB2Dst.xlo,
 +            &exloDst2RGB.xlo,
 +            &DestRect,
 +            (PPOINTL)&MaskRect,
 +            &dc->eboText.BrushObject,
 +            &BrushOrigin);
 +        MouseSafetyOnDrawEnd(dc->ppdev) ;
 +
 +        EngUnlockSurface(SourceGlyphSurf);
 +        EngDeleteSurface((HSURF)HSourceGlyph);
 +
 +        if (DoBreak)
 +        {
 +            break;
 +        }
 +
 +        if (NULL == Dx)
 +        {
 +            TextLeft += realglyph->root.advance.x >> 10;
 +             DPRINT("new TextLeft: %d\n", TextLeft);
 +        }
 +        else
 +        {
 +            TextLeft += Dx[i<<DxShift] << 6;
 +             DPRINT("new TextLeft2: %d\n", TextLeft);
 +        }
 +
 +        if (DxShift)
 +        {
 +            TextTop -= Dx[2 * i + 1] << 6;
 +        }
 +
 +        previous = glyph_index;
 +
 +        String++;
 +    }
 +    IntUnLockFreeType;
 +
 +    DC_vFinishBlit(dc, NULL) ;
 +    EXLATEOBJ_vCleanup(&exloRGB2Dst);
 +    EXLATEOBJ_vCleanup(&exloDst2RGB);
 +    if (TextObj != NULL)
 +        TEXTOBJ_UnlockText(TextObj);
 +good:
 +    DC_UnlockDc( dc );
 +
 +    return TRUE;
 +
 +fail2:
 +    EXLATEOBJ_vCleanup(&exloRGB2Dst);
 +    EXLATEOBJ_vCleanup(&exloDst2RGB);
 +fail:
 +    if (TextObj != NULL)
 +        TEXTOBJ_UnlockText(TextObj);
 +
 +    DC_UnlockDc(dc);
 +
 +    return FALSE;
 +}
 +
 +#define STACK_TEXT_BUFFER_SIZE 100
 +BOOL
 +APIENTRY
 +NtGdiExtTextOutW(
 +    IN HDC hDC,
 +    IN INT XStart,
 +    IN INT YStart,
 +    IN UINT fuOptions,
 +    IN OPTIONAL LPRECT UnsafeRect,
 +    IN LPWSTR UnsafeString,
 +    IN INT Count,
 +    IN OPTIONAL LPINT UnsafeDx,
 +    IN DWORD dwCodePage)
 +{
 +    BOOL Result = FALSE;
 +    NTSTATUS Status = STATUS_SUCCESS;
 +    RECTL SafeRect;
 +    BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
 +    PVOID Buffer = LocalBuffer;
 +    LPWSTR SafeString = NULL;
 +    LPINT SafeDx = NULL;
 +    ULONG BufSize, StringSize, DxSize = 0;
 +
 +    /* Check if String is valid */
 +    if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
 +    {
 +        SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +        return FALSE;
 +    }
 +
 +    if (Count > 0)
 +    {
 +        /* Calculate buffer size for string and Dx values */
 +        BufSize = StringSize = Count * sizeof(WCHAR);
 +        if (UnsafeDx)
 +        {
 +            /* If ETO_PDY is specified, we have pairs of INTs */
 +            DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
 +            BufSize += DxSize;
 +        }
 +
 +        /* Check if our local buffer is large enough */
 +        if (BufSize > STACK_TEXT_BUFFER_SIZE)
 +        {
 +            /* It's not, allocate a temp buffer */
 +            Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, TAG_GDITEXT);
 +            if (!Buffer)
 +            {
 +                return FALSE;
 +            }
 +        }
 +
 +        /* Probe and copy user mode data to the buffer */
 +        _SEH2_TRY
 +        {
 +            /* Put the Dx before the String to assure alignment of 4 */
 +            SafeString = (LPWSTR)(((ULONG_PTR)Buffer) + DxSize);
 +
 +            /* Probe and copy the string */
 +            ProbeForRead(UnsafeString, StringSize, 1);
 +            memcpy((PVOID)SafeString, UnsafeString, StringSize);
 +
 +            /* If we have Dx values... */
 +            if (UnsafeDx)
 +            {
 +                /* ... probe and copy them */
 +                SafeDx = Buffer;
 +                ProbeForRead(UnsafeDx, DxSize, 1);
 +                memcpy(SafeDx, UnsafeDx, DxSize);
 +            }
 +        }
 +        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +        {
 +            Status = _SEH2_GetExceptionCode();
 +        }
 +        _SEH2_END
 +        if (!NT_SUCCESS(Status))
 +        {
 +            goto cleanup;
 +        }
 +    }
 +
 +    /* If we have a rect, copy it */
 +    if (UnsafeRect)
 +    {
 +        _SEH2_TRY
 +        {
 +            ProbeForRead(UnsafeRect, sizeof(RECT), 1);
 +            SafeRect = *UnsafeRect;
 +        }
 +        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +        {
 +            Status = _SEH2_GetExceptionCode();
 +        }
 +        _SEH2_END
 +        if (!NT_SUCCESS(Status))
 +        {
 +            goto cleanup;
 +        }
 +    }
 +
 +    /* Finally call the internal routine */
 +    Result = GreExtTextOutW(hDC,
 +                            XStart,
 +                            YStart,
 +                            fuOptions,
 +                            &SafeRect,
 +                            SafeString,
 +                            Count,
 +                            SafeDx,
 +                            dwCodePage);
 +
 +cleanup:
 +    /* If we allocated a buffer, free it */
 +    if (Buffer != LocalBuffer)
 +    {
 +        ExFreePoolWithTag(Buffer, TAG_GDITEXT);
 +    }
 +
 +    return Result;
 +}
 +
 +
 +/*
 +* @implemented
 +*/
 +BOOL
 +APIENTRY
 +NtGdiGetCharABCWidthsW(
 +    IN HDC hDC,
 +    IN UINT FirstChar,
 +    IN ULONG Count,
 +    IN OPTIONAL PWCHAR pwch,
 +    IN FLONG fl,
 +    OUT PVOID Buffer)
 +{
 +    LPABC SafeBuff;
 +    LPABCFLOAT SafeBuffF = NULL;
 +    PDC dc;
 +    PDC_ATTR pdcattr;
 +    PTEXTOBJ TextObj;
 +    PFONTGDI FontGDI;
 +    FT_Face face;
 +    FT_CharMap charmap, found = NULL;
 +    UINT i, glyph_index, BufferSize;
 +    HFONT hFont = 0;
 +    NTSTATUS Status = STATUS_SUCCESS;
 +
 +    if (pwch)
 +    {
 +        _SEH2_TRY
 +        {
 +            ProbeForRead(pwch,
 +            sizeof(PWSTR),
 +            1);
 +        }
 +        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +        {
 +            Status = _SEH2_GetExceptionCode();
 +        }
 +        _SEH2_END;
 +    }
 +    if (!NT_SUCCESS(Status))
 +    {
 +        SetLastWin32Error(Status);
 +        return FALSE;
 +    }
 +
 +    if (!Buffer)
 +    {
 +        SetLastWin32Error(ERROR_INVALID_PARAMETER);
 +        return FALSE;
 +    }
 +
 +    BufferSize = Count * sizeof(ABC); // Same size!
 +    SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
 +    if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
 +    if (SafeBuff == NULL)
 +    {
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return FALSE;
 +    }
 +
 +    dc = DC_LockDc(hDC);
 +    if (dc == NULL)
 +    {
 +        ExFreePool(SafeBuff);
 +        SetLastWin32Error(ERROR_INVALID_HANDLE);
 +        return FALSE;
 +    }
 +    pdcattr = dc->pdcattr;
 +    hFont = pdcattr->hlfntNew;
 +    TextObj = RealizeFontInit(hFont);
 +    DC_UnlockDc(dc);
 +
 +    if (TextObj == NULL)
 +    {
 +        ExFreePool(SafeBuff);
 +        SetLastWin32Error(ERROR_INVALID_HANDLE);
 +        return FALSE;
 +    }
 +
 +    FontGDI = ObjToGDI(TextObj->Font, FONT);
 +
 +    face = FontGDI->face;
 +    if (face->charmap == NULL)
 +    {
 +        for (i = 0; i < face->num_charmaps; i++)
 +        {
 +            charmap = face->charmaps[i];
 +            if (charmap->encoding != 0)
 +            {
 +                found = charmap;
 +                break;
 +            }
 +        }
 +
 +        if (!found)
 +        {
 +            DPRINT1("WARNING: Could not find desired charmap!\n");
 +            ExFreePool(SafeBuff);
 +            SetLastWin32Error(ERROR_INVALID_HANDLE);
 +            return FALSE;
 +        }
 +
 +        IntLockFreeType;
 +        FT_Set_Charmap(face, found);
 +        IntUnLockFreeType;
 +    }
 +
 +    IntLockFreeType;
 +    FT_Set_Pixel_Sizes(face,
 +                       TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
 +                       /* FIXME should set character height if neg */
 +                       (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
 +                        TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
 +
 +    for (i = FirstChar; i < FirstChar+Count; i++)
 +    {
 +        int adv, lsb, bbx, left, right;
 +
 +        if (pwch)
 +        {
 +            if (fl & GCABCW_INDICES)
 +                glyph_index = pwch[i - FirstChar];
 +            else
 +                glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]);
 +        }
 +        else
 +        {
 +            if (fl & GCABCW_INDICES)
 +                glyph_index = i;
 +            else
 +                glyph_index = FT_Get_Char_Index(face, i);
 +        }
 +        FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
 +
 +        left = (INT)face->glyph->metrics.horiBearingX  & -64;
 +        right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
 +        adv  = (face->glyph->advance.x + 32) >> 6;
 +
 +//      int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
 +//      DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same!*/
 +
 +        lsb = left >> 6;
 +        bbx = (right - left) >> 6;
 +        /*
 +              DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
 +         */
 +        if (!fl)
 +        {
 +            SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
 +            SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
 +            SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
 +        }
 +        else
 +        {
 +            SafeBuff[i - FirstChar].abcA = lsb;
 +            SafeBuff[i - FirstChar].abcB = bbx;
 +            SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
 +        }
 +    }
 +    IntUnLockFreeType;
 +    TEXTOBJ_UnlockText(TextObj);
 +    Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
 +    if (! NT_SUCCESS(Status))
 +    {
 +        SetLastNtError(Status);
 +        ExFreePool(SafeBuff);
 +        return FALSE;
 +    }
 +    ExFreePool(SafeBuff);
 +    DPRINT("NtGdiGetCharABCWidths Worked!\n");
 +    return TRUE;
 +}
 +
 +/*
 +* @implemented
 +*/
 +BOOL
 +APIENTRY
 +NtGdiGetCharWidthW(
 +    IN HDC hDC,
 +    IN UINT FirstChar,
 +    IN UINT Count,
 +    IN OPTIONAL PWCHAR pwc,
 +    IN FLONG fl,
 +    OUT PVOID Buffer)
 +{
 +    NTSTATUS Status = STATUS_SUCCESS;
 +    LPINT SafeBuff;
 +    PFLOAT SafeBuffF = NULL;
 +    PDC dc;
 +    PDC_ATTR pdcattr;
 +    PTEXTOBJ TextObj;
 +    PFONTGDI FontGDI;
 +    FT_Face face;
 +    FT_CharMap charmap, found = NULL;
 +    UINT i, glyph_index, BufferSize;
 +    HFONT hFont = 0;
 +
 +    if (pwc)
 +    {
 +        _SEH2_TRY
 +        {
 +            ProbeForRead(pwc,
 +            sizeof(PWSTR),
 +            1);
 +        }
 +        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +        {
 +            Status = _SEH2_GetExceptionCode();
 +        }
 +        _SEH2_END;
 +    }
 +    if (!NT_SUCCESS(Status))
 +    {
 +        SetLastWin32Error(Status);
 +        return FALSE;
 +    }
 +
 +    BufferSize = Count * sizeof(INT); // Same size!
 +    SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
 +    if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
 +    if (SafeBuff == NULL)
 +    {
 +        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
 +        return FALSE;
 +    }
 +
 +    dc = DC_LockDc(hDC);
 +    if (dc == NULL)
 +    {
 +        ExFreePool(SafeBuff);
 +        SetLastWin32Error(ERROR_INVALID_HANDLE);
 +        return FALSE;
 +    }
 +    pdcattr = dc->pdcattr;
 +    hFont = pdcattr->hlfntNew;
 +    TextObj = RealizeFontInit(hFont);
 +    DC_UnlockDc(dc);
 +
 +    if (TextObj == NULL)
 +    {
 +        ExFreePool(SafeBuff);
 +        SetLastWin32Error(ERROR_INVALID_HANDLE);
 +        return FALSE;
 +    }
 +
 +    FontGDI = ObjToGDI(TextObj->Font, FONT);
 +
 +    face = FontGDI->face;
 +    if (face->charmap == NULL)
 +    {
 +        for (i = 0; i < face->num_charmaps; i++)
 +        {
 +            charmap = face->charmaps[i];
 +            if (charmap->encoding != 0)
 +            {
 +                found = charmap;
 +                break;
 +            }
 +        }
 +
 +        if (!found)
 +        {
 +            DPRINT1("WARNING: Could not find desired charmap!\n");
 +            ExFreePool(SafeBuff);
 +            SetLastWin32Error(ERROR_INVALID_HANDLE);
 +            return FALSE;
 +        }
 +
 +        IntLockFreeType;
 +        FT_Set_Charmap(face, found);
 +        IntUnLockFreeType;
 +    }
 +
 +    IntLockFreeType;
 +    FT_Set_Pixel_Sizes(face,
 +                       TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
 +                       /* FIXME should set character height if neg */
 +                       (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
 +