/*
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS GDI32
 * PURPOSE:          GDI DirectX inteface
 * FILE:             lib/gdi32/misc/gdientry.c
 * PROGRAMERS:       Alex Ionescu (alex@relsoft.net)
 *                   Magnus Olsen (magnus@greatlord.com)
 */

/* INCLUDES ******************************************************************/

#include "precomp.h"

/* DATA **********************************************************************/

HANDLE ghDirectDraw;
ULONG gcDirectDraw;

#define GetDdHandle(Handle) ((HANDLE)Handle ? (HANDLE)Handle : ghDirectDraw)



/* CALLBACKS *****************************************************************/

/*
 * @implemented
 *
 * DdAddAttachedSurface
 */
DWORD
WINAPI
DdAddAttachedSurface(LPDDHAL_ADDATTACHEDSURFACEDATA Attach)
{
    /* Call win32k */
    return NtGdiDdAddAttachedSurface((HANDLE)Attach->lpDDSurface->hDDSurface,
                                     (HANDLE)Attach->lpSurfAttached->hDDSurface,
                                     (PDD_ADDATTACHEDSURFACEDATA)Attach);
}

/*
 * @implemented
 *
 * DdBlt
 */
DWORD
WINAPI
DdBlt(LPDDHAL_BLTDATA Blt)
{
    HANDLE Surface = 0;

    /* Use the right surface */
    if (Blt->lpDDSrcSurface)
    {
        Surface = (HANDLE)Blt->lpDDSrcSurface->hDDSurface;
    }

    /* Call win32k */
    return NtGdiDdBlt((HANDLE)Blt->lpDDDestSurface->hDDSurface, Surface, (PDD_BLTDATA)Blt);
}

/*
 * @implemented
 *
 * DdDestroySurface
 */
DWORD
WINAPI
DdDestroySurface(LPDDHAL_DESTROYSURFACEDATA pDestroySurface)
{
    DWORD Return = DDHAL_DRIVER_NOTHANDLED;
    BOOL RealDestroy;

    if (pDestroySurface->lpDDSurface->hDDSurface)
    {
        /* Check if we shoudl really destroy it */
        RealDestroy = !(pDestroySurface->lpDDSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) ||
                      !(pDestroySurface->lpDDSurface->dwFlags & DDRAWISURF_INVALID);

        /* Call win32k */
        Return = NtGdiDdDestroySurface((HANDLE)pDestroySurface->lpDDSurface->hDDSurface, RealDestroy);
    }

    return Return;
}

/*
 * @implemented
 *
 * DdFlip
 */
DWORD
WINAPI
DdFlip(LPDDHAL_FLIPDATA Flip)
{
    /* Note :
    * See http://msdn2.microsoft.com/en-us/library/ms794213.aspx and
    * http://msdn2.microsoft.com/en-us/library/ms792675.aspx
    */

    HANDLE hSurfaceCurrentLeft = NULL;
    HANDLE hSurfaceTargetLeft = NULL;

    /* Auto flip off or on */
    if (Flip->dwFlags & DDFLIP_STEREO )
    {
        if ( (Flip->lpSurfTargLeft) &&
                (Flip->lpSurfCurrLeft))
        {
            /* Auto flip on */
            hSurfaceTargetLeft = (HANDLE) Flip->lpSurfTargLeft->hDDSurface;
            hSurfaceCurrentLeft = (HANDLE) Flip->lpSurfCurrLeft->hDDSurface;
        }
    }

    /* Call win32k */
    return NtGdiDdFlip( (HANDLE) Flip->lpSurfCurr->hDDSurface,
                        (HANDLE) Flip->lpSurfTarg->hDDSurface,
                        hSurfaceCurrentLeft,
                        hSurfaceTargetLeft,
                        (PDD_FLIPDATA) Flip);
}

/*
 * @implemented
 *
 * DdLock
 */
DWORD
WINAPI
DdLock(LPDDHAL_LOCKDATA Lock)
{

    /* Call win32k */
    return NtGdiDdLock((HANDLE)Lock->lpDDSurface->hDDSurface,
                       (PDD_LOCKDATA)Lock,
                       (HANDLE)Lock->lpDDSurface->hDC);
}

/*
 * @implemented
 *
 * DdUnlock
 */
DWORD
WINAPI
DdUnlock(LPDDHAL_UNLOCKDATA Unlock)
{
    /* Call win32k */
    return NtGdiDdUnlock((HANDLE)Unlock->lpDDSurface->hDDSurface,
                         (PDD_UNLOCKDATA)Unlock);
}

/*
 * @implemented
 *
 * DdGetBltStatus
 */
DWORD
WINAPI
DdGetBltStatus(LPDDHAL_GETBLTSTATUSDATA GetBltStatus)
{
    /* Call win32k */
    return NtGdiDdGetBltStatus((HANDLE)GetBltStatus->lpDDSurface->hDDSurface,
                               (PDD_GETBLTSTATUSDATA)GetBltStatus);
}

/*
 * @implemented
 *
 * DdGetBltStatus
 */
DWORD
WINAPI
DdGetFlipStatus(LPDDHAL_GETFLIPSTATUSDATA GetFlipStatus)
{
    /* Call win32k */
    return NtGdiDdGetFlipStatus((HANDLE)GetFlipStatus->lpDDSurface->hDDSurface,
                                (PDD_GETFLIPSTATUSDATA)GetFlipStatus);
}

/*
 * @implemented
 *
 * DdUpdateOverlay
 */
DWORD
WINAPI
DdUpdateOverlay(LPDDHAL_UPDATEOVERLAYDATA UpdateOverlay)
{

    /* We have to handle this manually here */
    if (UpdateOverlay->dwFlags & DDOVER_KEYDEST)
    {
        /* Use the override */
        UpdateOverlay->dwFlags &= ~DDOVER_KEYDEST;
        UpdateOverlay->dwFlags |=  DDOVER_KEYDESTOVERRIDE;

        /* Set the overlay */
        UpdateOverlay->overlayFX.dckDestColorkey =
            UpdateOverlay->lpDDDestSurface->ddckCKDestOverlay;
    }
    if (UpdateOverlay->dwFlags & DDOVER_KEYSRC)
    {
        /* Use the override */
        UpdateOverlay->dwFlags &= ~DDOVER_KEYSRC;
        UpdateOverlay->dwFlags |=  DDOVER_KEYSRCOVERRIDE;

        /* Set the overlay */
        UpdateOverlay->overlayFX.dckSrcColorkey =
            UpdateOverlay->lpDDSrcSurface->ddckCKSrcOverlay;
    }

    /* Call win32k */
    return NtGdiDdUpdateOverlay((HANDLE)UpdateOverlay->lpDDDestSurface->hDDSurface,
                                (HANDLE)UpdateOverlay->lpDDSrcSurface->hDDSurface,
                                (PDD_UPDATEOVERLAYDATA)UpdateOverlay);
}

/*
 * @implemented
 *
 * DdSetOverlayPosition
 */
DWORD
WINAPI
DdSetOverlayPosition(LPDDHAL_SETOVERLAYPOSITIONDATA SetOverlayPosition)
{
    /* Call win32k */
    return NtGdiDdSetOverlayPosition( (HANDLE)SetOverlayPosition->lpDDSrcSurface->hDDSurface,
                                      (HANDLE)SetOverlayPosition->lpDDDestSurface->hDDSurface,
                                      (PDD_SETOVERLAYPOSITIONDATA) SetOverlayPosition);
}

/*
 * @implemented
 *
 * DdWaitForVerticalBlank
 */
DWORD
WINAPI
DdWaitForVerticalBlank(LPDDHAL_WAITFORVERTICALBLANKDATA WaitForVerticalBlank)
{
    /* Call win32k */
    return NtGdiDdWaitForVerticalBlank(GetDdHandle(
                                           WaitForVerticalBlank->lpDD->hDD),
                                       (PDD_WAITFORVERTICALBLANKDATA)
                                       WaitForVerticalBlank);
}

/*
 * @implemented
 *
 * DdCanCreateSurface
 */
DWORD
WINAPI
DdCanCreateSurface(LPDDHAL_CANCREATESURFACEDATA CanCreateSurface)
{
    /*
     * Note : This functions are basic same, in win32k
     * NtGdiDdCanCreateD3DBuffer and  NtGdiDdCanCreateSurface are mergs
     * toghter in win32k at end and retrurn same data, it is still sepreated
     * at user mode but in kmode it is not.
     */

    /* Call win32k */
    return NtGdiDdCanCreateSurface(GetDdHandle(CanCreateSurface->lpDD->hDD),
                                   (PDD_CANCREATESURFACEDATA)CanCreateSurface);
}

/*
 * @implemented
 *
 * DdCreateSurface
 */
DWORD
WINAPI
DdCreateSurface(LPDDHAL_CREATESURFACEDATA pCreateSurface)
{
    DWORD Return = DDHAL_DRIVER_NOTHANDLED;
    ULONG SurfaceCount = pCreateSurface->dwSCnt;
    DD_SURFACE_LOCAL DdSurfaceLocal;
    DD_SURFACE_MORE DdSurfaceMore;
    DD_SURFACE_GLOBAL DdSurfaceGlobal;

    HANDLE hPrevSurface, hSurface;

    PDD_SURFACE_LOCAL pDdSurfaceLocal = NULL;
    PDD_SURFACE_MORE pDdSurfaceMore = NULL;
    PDD_SURFACE_GLOBAL pDdSurfaceGlobal = NULL;

    PDD_SURFACE_LOCAL ptmpDdSurfaceLocal = NULL;
    PDD_SURFACE_MORE ptmpDdSurfaceMore = NULL;
    PDD_SURFACE_GLOBAL ptmpDdSurfaceGlobal = NULL;
    PHANDLE phSurface = NULL, puhSurface = NULL;
    ULONG i;
    LPDDSURFACEDESC pSurfaceDesc = NULL;

    /* TODO: Optimize speed. Most games/dx apps/programs do not want one surface, they want at least two.
     * So we need increase the stack to contain two surfaces instead of one. This will increase
     * the speed of the apps when allocating buffers. How to increase the surface stack space:
     * we need to create a struct for DD_SURFACE_LOCAL DdSurfaceLocal, DD_SURFACE_MORE DdSurfaceMore
     * DD_SURFACE_GLOBAL DdSurfaceGlobal, HANDLE hPrevSurface, hSurface like
     * struct { DD_SURFACE_LOCAL DdSurfaceLocal1, DD_SURFACE_LOCAL DdSurfaceLocal2 }
     * in a way that it may contain two surfaces, maybe even four. We need to watch what is most common before
     * we create the size. Activate this IF when you start doing the optimze and please also
     * take reports from users which value they got here.
     */
#if 1
    {
        char buffer[1024];
        \
        sprintf ( buffer, "Function %s : Optimze max to %d Surface ? (%s:%d)\n", __FUNCTION__, (int)SurfaceCount,__FILE__,__LINE__ );
        OutputDebugStringA(buffer);
    }
#endif

    /* Check how many surfaces there are */
    if (SurfaceCount != 1)
    {
        /* We got more than one surface, so we need to allocate memory for them */
        pDdSurfaceLocal = (PDD_SURFACE_LOCAL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(DD_SURFACE_LOCAL) * SurfaceCount ));
        pDdSurfaceMore = (PDD_SURFACE_MORE) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(DD_SURFACE_MORE) * SurfaceCount ));
        pDdSurfaceGlobal = (PDD_SURFACE_GLOBAL)  HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(DD_SURFACE_GLOBAL) * SurfaceCount ));
        phSurface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(HANDLE) * SurfaceCount ));
        puhSurface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(HANDLE) * SurfaceCount ));

        /* Check if we successfully allocated all memory we need */
        if ((pDdSurfaceLocal == NULL) || (pDdSurfaceMore == NULL) || (pDdSurfaceGlobal == NULL) || (phSurface == NULL) || (puhSurface == NULL))
        {
            pCreateSurface->ddRVal = DDERR_OUTOFMEMORY;

            if ( pDdSurfaceLocal != NULL )
            {
                HeapFree(GetProcessHeap(), 0, pDdSurfaceLocal);
            }

            if ( pDdSurfaceMore != NULL )
            {
                HeapFree(GetProcessHeap(), 0, pDdSurfaceMore);
            }

            if ( pDdSurfaceGlobal != NULL )
            {
                HeapFree(GetProcessHeap(), 0, pDdSurfaceGlobal);
            }

            if ( phSurface != NULL )
            {
                HeapFree(GetProcessHeap(), 0, phSurface);
            }

            if ( puhSurface != NULL )
            {
                HeapFree(GetProcessHeap(), 0, puhSurface);
            }

            return DDHAL_DRIVER_HANDLED;
        }
    }
    else
    {
        /* We'll use what we have on the stack */
        pDdSurfaceLocal = &DdSurfaceLocal;
        pDdSurfaceMore = &DdSurfaceMore;
        pDdSurfaceGlobal = &DdSurfaceGlobal;
        phSurface = &hPrevSurface;
        puhSurface = &hSurface;

        /* Clear the structures */
        RtlZeroMemory(&DdSurfaceLocal, sizeof(DdSurfaceLocal));
        RtlZeroMemory(&DdSurfaceGlobal, sizeof(DdSurfaceGlobal));
        RtlZeroMemory(&DdSurfaceMore, sizeof(DdSurfaceMore));
    }

    /* check if we got a surface or not */
    if (SurfaceCount!=0)
    {
        /* Loop for each surface */
        ptmpDdSurfaceGlobal = pDdSurfaceGlobal;
        ptmpDdSurfaceLocal = pDdSurfaceLocal;
        ptmpDdSurfaceMore = pDdSurfaceMore;
        pSurfaceDesc = pCreateSurface->lpDDSurfaceDesc;

        for (i = 0; i < SurfaceCount; i++)
        {
            LPDDRAWI_DDRAWSURFACE_LCL lcl = pCreateSurface->lplpSList[i];
            LPDDRAWI_DDRAWSURFACE_GBL gpl = pCreateSurface->lplpSList[i]->lpGbl;

            phSurface[i] = (HANDLE)lcl->hDDSurface;
            ptmpDdSurfaceLocal->ddsCaps.dwCaps = lcl->ddsCaps.dwCaps;

            ptmpDdSurfaceLocal->dwFlags = (ptmpDdSurfaceLocal->dwFlags &
                                           (0xB0000000 | DDRAWISURF_INMASTERSPRITELIST |
                                            DDRAWISURF_HELCB | DDRAWISURF_FRONTBUFFER |
                                            DDRAWISURF_BACKBUFFER | DDRAWISURF_INVALID |
                                            DDRAWISURF_DCIBUSY | DDRAWISURF_DCILOCK)) |
                                          (lcl->dwFlags & DDRAWISURF_DRIVERMANAGED);

            ptmpDdSurfaceGlobal->wWidth = gpl->wWidth;
            ptmpDdSurfaceGlobal->wHeight = gpl->wHeight;
            ptmpDdSurfaceGlobal->lPitch = gpl->lPitch;
            ptmpDdSurfaceGlobal->fpVidMem = gpl->fpVidMem;
            ptmpDdSurfaceGlobal->dwBlockSizeX = gpl->dwBlockSizeX;
            ptmpDdSurfaceGlobal->dwBlockSizeY = gpl->dwBlockSizeY;

            if (lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT)
            {
                RtlCopyMemory( &ptmpDdSurfaceGlobal->ddpfSurface ,
                               &gpl->ddpfSurface,
                               sizeof(DDPIXELFORMAT));

                ptmpDdSurfaceGlobal->ddpfSurface.dwSize = sizeof(DDPIXELFORMAT);
            }
            else
            {
                RtlCopyMemory( &ptmpDdSurfaceGlobal->ddpfSurface ,
                               &gpl->lpDD->vmiData.ddpfDisplay,
                               sizeof(DDPIXELFORMAT));
            }

            /* Note if lcl->lpSurfMore is NULL zero out
             * ptmpDdSurfaceMore->ddsCapsEx.dwCaps2,
             * dwCaps3, dwCaps4, ptmpDdSurfaceMore->dwSurfaceHandle
             */
            if (lcl->lpSurfMore)
            {
                ptmpDdSurfaceMore->ddsCapsEx.dwCaps2 = lcl->lpSurfMore->ddsCapsEx.dwCaps2;
                ptmpDdSurfaceMore->ddsCapsEx.dwCaps3 = lcl->lpSurfMore->ddsCapsEx.dwCaps3;
                ptmpDdSurfaceMore->ddsCapsEx.dwCaps4 = lcl->lpSurfMore->ddsCapsEx.dwCaps4;
                ptmpDdSurfaceMore->dwSurfaceHandle = lcl->lpSurfMore->dwSurfaceHandle;
            }


            /* count to next SurfaceCount */
            ptmpDdSurfaceGlobal = (PDD_SURFACE_GLOBAL) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceGlobal)) + sizeof(DD_SURFACE_GLOBAL));
            ptmpDdSurfaceLocal = (PDD_SURFACE_LOCAL) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceLocal)) + sizeof(DD_SURFACE_LOCAL));
            ptmpDdSurfaceMore = (PDD_SURFACE_MORE) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceMore)) + sizeof(DD_SURFACE_MORE));
        }
    }

    /* Call win32k now */
    pCreateSurface->ddRVal = DDERR_GENERIC;

    Return = NtGdiDdCreateSurface(GetDdHandle(pCreateSurface->lpDD->hDD),
                                  (HANDLE *)phSurface,
                                  pSurfaceDesc,
                                  pDdSurfaceGlobal,
                                  pDdSurfaceLocal,
                                  pDdSurfaceMore,
                                  (PDD_CREATESURFACEDATA)pCreateSurface,
                                  puhSurface);

    if (SurfaceCount == 0)
    {
        pCreateSurface->ddRVal = DDERR_GENERIC;
    }
    else
    {
        ptmpDdSurfaceMore = pDdSurfaceMore;
        ptmpDdSurfaceGlobal = pDdSurfaceGlobal;
        ptmpDdSurfaceLocal = pDdSurfaceLocal;

        for (i=0; i<SurfaceCount; i++)
        {
            LPDDRAWI_DDRAWSURFACE_LCL lcl = pCreateSurface->lplpSList[i];
            LPDDRAWI_DDRAWSURFACE_GBL gpl = pCreateSurface->lplpSList[i]->lpGbl;

            gpl->lPitch = ptmpDdSurfaceGlobal->lPitch;
            gpl->fpVidMem = ptmpDdSurfaceGlobal->fpVidMem;
            gpl->dwBlockSizeX = ptmpDdSurfaceGlobal->dwBlockSizeX;
            gpl->dwBlockSizeY = ptmpDdSurfaceGlobal->dwBlockSizeY;

            if (lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT)
            {
                RtlCopyMemory( &gpl->ddpfSurface, &ptmpDdSurfaceGlobal->ddpfSurface , sizeof(DDPIXELFORMAT));
            }

            if (pCreateSurface->ddRVal != DD_OK)
            {
                gpl->fpVidMem = 0;
                if (lcl->hDDSurface)
                {
                    NtGdiDdDeleteSurfaceObject( (HANDLE)lcl->hDDSurface);
                }
                lcl->hDDSurface = 0;
            }
            else
            {

                lcl->hDDSurface = (ULONG_PTR) puhSurface[i];
            }

            lcl->ddsCaps.dwCaps = ptmpDdSurfaceLocal->ddsCaps.dwCaps;
            if (lcl->lpSurfMore)
            {
                lcl->lpSurfMore->ddsCapsEx.dwCaps2 = ptmpDdSurfaceMore->ddsCapsEx.dwCaps2;
                lcl->lpSurfMore->ddsCapsEx.dwCaps3 = ptmpDdSurfaceMore->ddsCapsEx.dwCaps3;
                lcl->lpSurfMore->ddsCapsEx.dwCaps4 = ptmpDdSurfaceMore->ddsCapsEx.dwCaps4;
            }

            /* count to next SurfaceCount */
            ptmpDdSurfaceGlobal = (PDD_SURFACE_GLOBAL) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceGlobal)) + sizeof(DD_SURFACE_GLOBAL));
            ptmpDdSurfaceLocal = (PDD_SURFACE_LOCAL) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceLocal)) + sizeof(DD_SURFACE_LOCAL));
            ptmpDdSurfaceMore = (PDD_SURFACE_MORE) (((PBYTE) ((ULONG_PTR) ptmpDdSurfaceMore)) + sizeof(DD_SURFACE_MORE));
        }
    }

    /* Check if we have to free all our local allocations */
    if (SurfaceCount > 1)
    {
        if ( pDdSurfaceLocal != NULL )
        {
            HeapFree(GetProcessHeap(), 0, pDdSurfaceLocal);
        }

        if ( pDdSurfaceMore != NULL )
        {
            HeapFree(GetProcessHeap(), 0, pDdSurfaceMore);
        }

        if ( pDdSurfaceGlobal != NULL )
        {
            HeapFree(GetProcessHeap(), 0, pDdSurfaceGlobal);
        }

        if ( phSurface != NULL )
        {
            HeapFree(GetProcessHeap(), 0, phSurface);
        }

        if ( puhSurface != NULL )
        {
            HeapFree(GetProcessHeap(), 0, puhSurface);
        }
    }

    /* Return */
    return Return;
}

/*
 * @implemented
 *
 * DdSetColorKey
 */
DWORD
WINAPI
DdSetColorKey(LPDDHAL_SETCOLORKEYDATA pSetColorKey)
{
    /* Call win32k */
    return NtGdiDdSetColorKey((HANDLE)pSetColorKey->lpDDSurface->hDDSurface,
                              (PDD_SETCOLORKEYDATA)pSetColorKey);
}

/*
 * @implemented
 *
 * DdGetScanLine
 */
DWORD
WINAPI
DdGetScanLine(LPDDHAL_GETSCANLINEDATA pGetScanLine)
{
    /* Call win32k */
    return NtGdiDdGetScanLine(GetDdHandle(pGetScanLine->lpDD->hDD),
                              (PDD_GETSCANLINEDATA)pGetScanLine);
}


/*
 * @implemented
 *
 * DvpCreateVideoPort
 */
BOOL
WINAPI
DvpCreateVideoPort(LPDDHAL_CREATEVPORTDATA pDvdCreatePort)
{
    pDvdCreatePort->lpVideoPort->hDDVideoPort =
        NtGdiDvpCreateVideoPort(GetDdHandle(pDvdCreatePort->lpDD->lpGbl->hDD),
                                (PDD_CREATEVPORTDATA) pDvdCreatePort);

    return TRUE;
}

/*
 * @implemented
 *
 * DvpCreateVideoPort
 */
DWORD
WINAPI
DvpDestroyVideoPort(LPDDHAL_DESTROYVPORTDATA pDvdDestoryPort)
{
    return NtGdiDvpDestroyVideoPort(pDvdDestoryPort->lpVideoPort->hDDVideoPort, (PDD_DESTROYVPORTDATA)pDvdDestoryPort);
}

/*
 * @implemented
 *
 * DvpCreateVideoPort
 */
DWORD
WINAPI
DvpFlipVideoPort(LPDDHAL_FLIPVPORTDATA pDvdPortFlip)
{
    return NtGdiDvpFlipVideoPort(pDvdPortFlip->lpVideoPort->hDDVideoPort,
                                 (HANDLE)pDvdPortFlip->lpSurfCurr->hDDSurface,
                                 (HANDLE)pDvdPortFlip->lpSurfTarg->hDDSurface,
                                 (PDD_FLIPVPORTDATA) pDvdPortFlip);
}

/*
 * @implemented
 *
 * DvpGetVideoPortBandwidth
 */
DWORD
WINAPI
DvpGetVideoPortBandwidth(LPDDHAL_GETVPORTBANDWIDTHDATA pDvdPortBandWidth)
{
    return NtGdiDvpGetVideoPortBandwidth(pDvdPortBandWidth->lpVideoPort->hDDVideoPort, (PDD_GETVPORTBANDWIDTHDATA)pDvdPortBandWidth);
}

/*
 * @implemented
 *
 * DvpColorControl
 */
DWORD
WINAPI
DvpColorControl(LPDDHAL_VPORTCOLORDATA pDvdPortColorControl)
{
    return NtGdiDvpColorControl(pDvdPortColorControl->lpVideoPort->hDDVideoPort, (PDD_VPORTCOLORDATA) pDvdPortColorControl);
}

/*
 * @implemented
 *
 * DvpGetVideoSignalStatus
 */
DWORD
WINAPI
DvpGetVideoSignalStatus(LPDDHAL_GETVPORTSIGNALDATA pDvdPortVideoSignalStatus)
{
    return NtGdiDvpGetVideoSignalStatus(pDvdPortVideoSignalStatus->lpVideoPort->hDDVideoPort, (PDD_GETVPORTSIGNALDATA) pDvdPortVideoSignalStatus);
}

/*
 * @implemented
 *
 * DvpGetVideoPortFlipStatus
 */
DWORD
WINAPI
DvpGetVideoPortFlipStatus(LPDDHAL_GETVPORTFLIPSTATUSDATA pDvdPortVideoPortFlipStatus)
{
    return NtGdiDvpGetVideoPortFlipStatus(GetDdHandle(pDvdPortVideoPortFlipStatus->lpDD->lpGbl->hDD), (PDD_GETVPORTFLIPSTATUSDATA) pDvdPortVideoPortFlipStatus);

}

/*
 * @implemented
 *
 * DvpCanCreateVideoPort
 */
DWORD
WINAPI
DvpCanCreateVideoPort(LPDDHAL_CANCREATEVPORTDATA pDvdCanCreateVideoPort)
{
    return NtGdiDvpCanCreateVideoPort(GetDdHandle(pDvdCanCreateVideoPort->lpDD->lpGbl->hDD), (PDD_CANCREATEVPORTDATA) pDvdCanCreateVideoPort);
}
/*
 * @implemented
 *
 * DvpWaitForVideoPortSync
 */
DWORD
WINAPI
DvpWaitForVideoPortSync(LPDDHAL_WAITFORVPORTSYNCDATA pDvdWaitForVideoPortSync)
{
    return NtGdiDvpWaitForVideoPortSync(pDvdWaitForVideoPortSync->lpVideoPort->hDDVideoPort,  (PDD_WAITFORVPORTSYNCDATA) pDvdWaitForVideoPortSync);
}

/*
 * @implemented
 *
 * DvpUpdateVideoPort
 */
DWORD
WINAPI
DvpUpdateVideoPort(LPDDHAL_UPDATEVPORTDATA pDvdUpdateVideoPort)
{
    /*
     * Windows XP limit to max 10 handles of videoport surface and Vbi
     * ReactOS doing same to keep compatible, if it is more that 10
     * videoport surface or vbi the stack will be curpted in windows xp
     * ReactOS safe guard againts that
     *
     */

    HANDLE phSurfaceVideo[10];
    HANDLE phSurfaceVbi[10];

    if (pDvdUpdateVideoPort->dwFlags != DDRAWI_VPORTSTOP)
    {
        DWORD dwNumAutoflip;
        DWORD dwNumVBIAutoflip;

        /* Take copy of lplpDDSurface for the handle value will be modify in dxg */
        dwNumAutoflip = pDvdUpdateVideoPort->dwNumAutoflip;
        if ((dwNumAutoflip == 0) &&
                (pDvdUpdateVideoPort->lplpDDSurface == 0))
        {
            dwNumAutoflip++;
        }

        if (dwNumAutoflip != 0)
        {
            if (dwNumAutoflip>10)
            {
                dwNumAutoflip = 10;
            }
            memcpy(phSurfaceVideo,pDvdUpdateVideoPort->lplpDDSurface,dwNumAutoflip*sizeof(HANDLE));
        }

        /* Take copy of lplpDDVBISurface for the handle value will be modify in dxg */
        dwNumVBIAutoflip = pDvdUpdateVideoPort->dwNumVBIAutoflip;
        if ( (dwNumVBIAutoflip == 0) &&
                (pDvdUpdateVideoPort->lplpDDVBISurface == 0) )
        {
            dwNumVBIAutoflip++;
        }

        if (dwNumVBIAutoflip != 0)
        {
            if (dwNumVBIAutoflip>10)
            {
                dwNumVBIAutoflip = 10;
            }
            memcpy(phSurfaceVbi,pDvdUpdateVideoPort->lplpDDVBISurface,dwNumVBIAutoflip*sizeof(HANDLE));
        }
    }

    /* Call Win32k */
    return NtGdiDvpUpdateVideoPort(pDvdUpdateVideoPort->lpVideoPort->hDDVideoPort,phSurfaceVideo,phSurfaceVbi, (PDD_UPDATEVPORTDATA)pDvdUpdateVideoPort);
}

/*
 * @implemented
 *
 * DvpWaitForVideoPortSync
 */
DWORD
WINAPI
DvpGetVideoPortField(LPDDHAL_FLIPVPORTDATA pDvdGetVideoPortField)
{
    return NtGdiDvpGetVideoPortField(pDvdGetVideoPortField->lpVideoPort->hDDVideoPort, (PDD_GETVPORTFIELDDATA)pDvdGetVideoPortField);
}

/*
 * @implemented
 *
 * DvpWaitForVideoPortSync
 */
DWORD
WINAPI
DvpGetVideoPortInputFormats(LPDDHAL_GETVPORTINPUTFORMATDATA pDvdGetVideoPortInputFormat)
{
    return NtGdiDvpGetVideoPortInputFormats(pDvdGetVideoPortInputFormat->lpVideoPort->hDDVideoPort, (PDD_GETVPORTINPUTFORMATDATA) pDvdGetVideoPortInputFormat);
}

/*
 * @implemented
 *
 * DvpGetVideoPortLine
 */
DWORD
WINAPI
DvpGetVideoPortLine(LPDDHAL_GETVPORTLINEDATA pDvdGetVideoPortLine)
{
    return NtGdiDvpGetVideoPortLine(pDvdGetVideoPortLine->lpVideoPort->hDDVideoPort, (PDD_GETVPORTLINEDATA)pDvdGetVideoPortLine);
}

/*
 * @implemented
 *
 * DvpGetVideoPortOutputFormats
 */
DWORD
WINAPI
DvpGetVideoPortOutputFormats(LPDDHAL_GETVPORTLINEDATA pDvdGetVideoPortOutputFormat)
{
    return NtGdiDvpGetVideoPortLine(pDvdGetVideoPortOutputFormat->lpVideoPort->hDDVideoPort, (PDD_GETVPORTLINEDATA)pDvdGetVideoPortOutputFormat);
}

/*
 * @implemented
 *
 * DvpGetVideoPortConnectInfo
 */
DWORD
WINAPI
DvpGetVideoPortConnectInfo(LPDDHAL_GETVPORTCONNECTDATA pDvdGetVideoPortInfo)
{
    return NtGdiDvpGetVideoPortConnectInfo( GetDdHandle( pDvdGetVideoPortInfo->lpDD->lpGbl->hDD) , (PDD_GETVPORTCONNECTDATA) pDvdGetVideoPortInfo);
}

/*
 * @implemented
 *
 * DdGetAvailDriverMemory
 */
DWORD
WINAPI
DdGetAvailDriverMemory(LPDDHAL_GETAVAILDRIVERMEMORYDATA pDdGetAvailDriverMemory)
{
    return NtGdiDdGetAvailDriverMemory(GetDdHandle( pDdGetAvailDriverMemory->lpDD->hDD), (PDD_GETAVAILDRIVERMEMORYDATA) pDdGetAvailDriverMemory);
}

/*
 * @implemented
 *
 * DdAlphaBlt
 */
DWORD
WINAPI
DdAlphaBlt(LPDDHAL_BLTDATA pDdAlphaBlt)
{
    HANDLE hDDSrcSurface = 0;

    if (pDdAlphaBlt->lpDDSrcSurface != 0)
    {
        hDDSrcSurface = (HANDLE) pDdAlphaBlt->lpDDSrcSurface->hDDSurface;
    }

    return NtGdiDdAlphaBlt((HANDLE)pDdAlphaBlt->lpDDDestSurface->hDDSurface, hDDSrcSurface, (PDD_BLTDATA)&pDdAlphaBlt);
}

/*
 * @implemented
 *
 * DdCreateSurfaceEx
 */
DWORD
WINAPI
DdCreateSurfaceEx(LPDDHAL_CREATESURFACEEXDATA pDdCreateSurfaceEx)
{
    pDdCreateSurfaceEx->ddRVal = NtGdiDdCreateSurfaceEx( GetDdHandle(pDdCreateSurfaceEx->lpDDLcl->lpGbl->hDD),
                                 (HANDLE)pDdCreateSurfaceEx->lpDDSLcl->hDDSurface,
                                 pDdCreateSurfaceEx->lpDDSLcl->lpSurfMore->dwSurfaceHandle);
    return TRUE;
}

/*
 * @implemented
 *
 * DdColorControl
 */
DWORD
WINAPI
DdColorControl(LPDDHAL_COLORCONTROLDATA pDdColorControl)
{
    return NtGdiDdColorControl( (HANDLE) pDdColorControl->lpDDSurface->hDDSurface, (PDD_COLORCONTROLDATA) &pDdColorControl);
}

/*
 * @implemented
 *
 * DdSetExclusiveMode
 */
DWORD
WINAPI
DdSetExclusiveMode(LPDDHAL_SETEXCLUSIVEMODEDATA pDdSetExclusiveMode)
{
    return NtGdiDdSetExclusiveMode( GetDdHandle(pDdSetExclusiveMode->lpDD->hDD), (PDD_SETEXCLUSIVEMODEDATA) &pDdSetExclusiveMode);
}

/*
 * @implemented
 *
 * DdFlipToGDISurface
 */
DWORD
WINAPI
DdFlipToGDISurface(LPDDHAL_FLIPTOGDISURFACEDATA pDdFlipToGDISurface)
{
    return NtGdiDdFlipToGDISurface( GetDdHandle(pDdFlipToGDISurface->lpDD->hDD), (PDD_FLIPTOGDISURFACEDATA) &pDdFlipToGDISurface);
}

/* TODO */
DWORD
WINAPI
DdGetDriverInfo(LPDDHAL_GETDRIVERINFODATA pData)
{
    DDHAL_GETDRIVERINFODATA pDrvInfoData;
    DWORD retValue = DDHAL_DRIVER_NOTHANDLED;
    HANDLE hDD;

    /* FIXME add SEH around this functions */

    RtlZeroMemory(&pDrvInfoData, sizeof (DDHAL_GETDRIVERINFODATA));
    RtlCopyMemory(&pDrvInfoData.guidInfo, &pData->guidInfo, sizeof(GUID));

    hDD = GetDdHandle(pData->dwContext);

    pDrvInfoData.dwSize = sizeof (DDHAL_GETDRIVERINFODATA);
    pDrvInfoData.ddRVal = DDERR_GENERIC;
    pDrvInfoData.dwContext = (ULONG_PTR)hDD;


    /* Videoport Callbacks check and setup for DirectX/ ReactX */
    if (IsEqualGUID(&pData->guidInfo, &GUID_VideoPortCallbacks))
    {
        DDHAL_DDVIDEOPORTCALLBACKS  pDvdPort;
        DDHAL_DDVIDEOPORTCALLBACKS* pUserDvdPort = (DDHAL_DDVIDEOPORTCALLBACKS *)pData->lpvData;

        /* Clear internal out buffer and set it up*/
        RtlZeroMemory(&pDvdPort, DDVIDEOPORTCALLBACKSSIZE);
        pDvdPort.dwSize = DDVIDEOPORTCALLBACKSSIZE;

        /* set up internal buffer */
        pDrvInfoData.lpvData = (PVOID)&pDvdPort;
        pDrvInfoData.dwExpectedSize = DDVIDEOPORTCALLBACKSSIZE ;

        /* Call win32k */
        retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);

        /* Setup user out buffer and convert kmode callbacks to user mode */
        pUserDvdPort->dwSize = DDVIDEOPORTCALLBACKSSIZE;
        pUserDvdPort->dwFlags = pDrvInfoData.dwFlags =  0;

        pUserDvdPort->dwFlags = (pDrvInfoData.dwFlags & ~(DDHAL_VPORT32_CREATEVIDEOPORT | DDHAL_VPORT32_FLIP |
                                 DDHAL_VPORT32_DESTROY | DDHAL_VPORT32_UPDATE | DDHAL_VPORT32_WAITFORSYNC)) |
                                (DDHAL_VPORT32_CREATEVIDEOPORT | DDHAL_VPORT32_FLIP |
                                 DDHAL_VPORT32_DESTROY | DDHAL_VPORT32_UPDATE);

        pData->dwActualSize = DDVIDEOPORTCALLBACKSSIZE;
        pUserDvdPort->CreateVideoPort = (LPDDHALVPORTCB_CREATEVIDEOPORT) DvpCreateVideoPort;
        pUserDvdPort->FlipVideoPort = (LPDDHALVPORTCB_FLIP) DvpFlipVideoPort;
        pUserDvdPort->DestroyVideoPort = (LPDDHALVPORTCB_DESTROYVPORT) DvpDestroyVideoPort;
        pUserDvdPort->UpdateVideoPort = (LPDDHALVPORTCB_UPDATE) DvpUpdateVideoPort;

        if (pDvdPort.CanCreateVideoPort)
        {
            pUserDvdPort->CanCreateVideoPort = (LPDDHALVPORTCB_CANCREATEVIDEOPORT) DvpCanCreateVideoPort;
        }

        if (pDvdPort.GetVideoPortBandwidth)
        {
            pUserDvdPort->GetVideoPortBandwidth = (LPDDHALVPORTCB_GETBANDWIDTH) DvpGetVideoPortBandwidth;
        }

        if (pDvdPort.GetVideoPortInputFormats)
        {
            pUserDvdPort->GetVideoPortInputFormats = (LPDDHALVPORTCB_GETINPUTFORMATS) DvpGetVideoPortInputFormats;
        }

        if (pDvdPort.GetVideoPortOutputFormats)
        {
            pUserDvdPort->GetVideoPortOutputFormats = (LPDDHALVPORTCB_GETOUTPUTFORMATS) DvpGetVideoPortOutputFormats;
        }

        if (pDvdPort.GetVideoPortField)
        {
            pUserDvdPort->GetVideoPortField = (LPDDHALVPORTCB_GETFIELD) DvpGetVideoPortField;
        }

        if (pDvdPort.GetVideoPortLine)
        {
            pUserDvdPort->GetVideoPortLine = (LPDDHALVPORTCB_GETLINE) DvpGetVideoPortLine;
        }

        if (pDvdPort.GetVideoPortConnectInfo)
        {
            pUserDvdPort->GetVideoPortConnectInfo = (LPDDHALVPORTCB_GETVPORTCONNECT) DvpGetVideoPortConnectInfo;
        }

        if (pDvdPort.GetVideoPortFlipStatus)
        {
            pUserDvdPort->GetVideoPortFlipStatus = (LPDDHALVPORTCB_GETFLIPSTATUS) DvpGetVideoPortFlipStatus;
        }

        if (pDvdPort.WaitForVideoPortSync)
        {
            pUserDvdPort->WaitForVideoPortSync = (LPDDHALVPORTCB_WAITFORSYNC) DvpWaitForVideoPortSync;
        }

        if (pDvdPort.GetVideoSignalStatus)
        {
            pUserDvdPort->GetVideoSignalStatus = (LPDDHALVPORTCB_GETSIGNALSTATUS) DvpGetVideoSignalStatus;
        }

        if (pDvdPort.ColorControl)
        {
            pUserDvdPort->ColorControl = (LPDDHALVPORTCB_COLORCONTROL) DvpColorControl;
        }

        /* Windows XP never repot back the true return value,
         *  it only report back if we have a driver or not
         *  ReactOS keep this behoir to be compatible with
         *  Windows XP
         */
        pData->ddRVal = retValue;
    }

    /* Color Control Callbacks check and setup for DirectX/ ReactX */
    if (IsEqualGUID(&pData->guidInfo, &GUID_ColorControlCallbacks))
    {
        DDHAL_DDCOLORCONTROLCALLBACKS  pColorControl;
        DDHAL_DDCOLORCONTROLCALLBACKS* pUserColorControl = (DDHAL_DDCOLORCONTROLCALLBACKS *)pData->lpvData;

        /* Clear internal out buffer and set it up*/
        RtlZeroMemory(&pColorControl, DDCOLORCONTROLCALLBACKSSIZE);
        pColorControl.dwSize = DDCOLORCONTROLCALLBACKSSIZE;

        /* set up internal buffer */
        pDrvInfoData.lpvData = (PVOID)&pColorControl;
        pDrvInfoData.dwExpectedSize = DDCOLORCONTROLCALLBACKSSIZE ;

        /* Call win32k */
        retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);

        pData->dwActualSize = DDCOLORCONTROLCALLBACKSSIZE;
        pData->dwFlags = pDrvInfoData.dwFlags;

        pUserColorControl->dwSize = DDCOLORCONTROLCALLBACKSSIZE;
        pUserColorControl->dwFlags = pUserColorControl->dwFlags;

        if (pColorControl.ColorControl != NULL)
        {
            pUserColorControl->ColorControl = (LPDDHALCOLORCB_COLORCONTROL) DdColorControl;
        }

        /* Windows XP never repot back the true return value,
         *  it only report back if we have a driver or not
         *  ReactOS keep this behoir to be compatible with
         *  Windows XP
         */
        pData->ddRVal = retValue;
    }

    /* Misc Callbacks check and setup for DirectX/ ReactX */
    else if (IsEqualGUID(&pData->guidInfo, &GUID_MiscellaneousCallbacks))
    {
        DDHAL_DDMISCELLANEOUSCALLBACKS  pMisc;
        DDHAL_DDMISCELLANEOUSCALLBACKS* pUserMisc = (DDHAL_DDMISCELLANEOUSCALLBACKS *)pData->lpvData;

        /* Clear internal out buffer and set it up*/
        RtlZeroMemory(&pMisc, DDMISCELLANEOUSCALLBACKSSIZE);
        pMisc.dwSize = DDMISCELLANEOUSCALLBACKSSIZE;

        /* set up internal buffer */
        pDrvInfoData.lpvData = (PVOID)&pMisc;
        pDrvInfoData.dwExpectedSize = DDMISCELLANEOUSCALLBACKSSIZE ;

        /* Call win32k */
        retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);

        pData->dwActualSize = DDMISCELLANEOUSCALLBACKSSIZE;

        /* Only one callbacks are supported */
        pUserMisc->dwFlags = pMisc.dwFlags & DDHAL_MISCCB32_GETAVAILDRIVERMEMORY;
        pUserMisc->GetAvailDriverMemory = (LPDDHAL_GETAVAILDRIVERMEMORY) DdGetAvailDriverMemory;

        /* This callbacks are only for win9x and theirfor it is not longer use in NT or ReactOS
         * pUserMisc->UpdateNonLocalHeap;
         * pUserMisc->GetHeapAlignment;
         * pUserMisc->GetSysmemBltStatus; */

        /* Windows XP never repot back the true return value,
         *  it only report back if we have a driver or not
         *  ReactOS keep this behoir to be compatible with
         *  Windows XP
         */
        pData->ddRVal = retValue;
    }

    /* Misc 2 Callbacks check and setup for DirectX/ ReactX */
    else if (IsEqualGUID(&pData->guidInfo, &GUID_Miscellaneous2Callbacks))
    {
        DDHAL_DDMISCELLANEOUS2CALLBACKS  pMisc;
        DDHAL_DDMISCELLANEOUS2CALLBACKS* pUserMisc = (DDHAL_DDMISCELLANEOUS2CALLBACKS *)pData->lpvData;

        /* Clear internal out buffer and set it up*/
        RtlZeroMemory(&pMisc, DDMISCELLANEOUS2CALLBACKSSIZE);
        pMisc.dwSize = DDMISCELLANEOUS2CALLBACKSSIZE;

        /* set up internal buffer */
        pDrvInfoData.lpvData = (PVOID)&pMisc;
        pDrvInfoData.dwExpectedSize = DDMISCELLANEOUS2CALLBACKSSIZE ;

        /* Call win32k */
        retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);

        pData->dwActualSize = DDMISCELLANEOUS2CALLBACKSSIZE;

        pUserMisc->dwFlags = pMisc.dwFlags;

        /* This functions are not documneted in MSDN for this struct, here is directx/reactx alpha blend */
        if ( pMisc.Reserved )
        {
            pUserMisc->Reserved = (LPVOID) DdAlphaBlt;
        }

        if ( pMisc.CreateSurfaceEx )
        {
            pUserMisc->CreateSurfaceEx = (LPDDHAL_CREATESURFACEEX) DdCreateSurfaceEx;
        }

        if ( pMisc.GetDriverState )
        {
            pUserMisc->GetDriverState = (LPDDHAL_GETDRIVERSTATE) NtGdiDdGetDriverState;
        }

        /* NOTE : pUserMisc->DestroyDDLocal is outdated and are not beign tuch */

        /* Windows XP never repot back the true return value,
         *  it only report back if we have a driver or not
         *  ReactOS keep this behoir to be compatible with
         *  Windows XP
         */
        pData->ddRVal = retValue;
    }

    /* NT Callbacks check and setup for DirectX/ ReactX */
    else if (IsEqualGUID(&pData->guidInfo, &GUID_NTCallbacks))
    {
        /* MS does not have DHAL_* version of this callbacks
         * so we are force using PDD_* callbacks here
         */
        DD_NTCALLBACKS  pNtKernel;
        PDD_NTCALLBACKS pUserNtKernel = (PDD_NTCALLBACKS)pData->lpvData;

        /* Clear internal out buffer and set it up*/
        RtlZeroMemory(&pNtKernel, sizeof(DD_NTCALLBACKS));
        pNtKernel.dwSize = sizeof(DD_NTCALLBACKS);

        /* set up internal buffer */
        pDrvInfoData.lpvData = (PVOID)&pNtKernel;
        pDrvInfoData.dwExpectedSize = sizeof(DD_NTCALLBACKS) ;

        /* Call win32k */
        retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);

        pData->dwActualSize = sizeof(DD_NTCALLBACKS);

        pUserNtKernel->dwSize = sizeof(DD_NTCALLBACKS);
        pUserNtKernel->dwFlags = pNtKernel.dwFlags;
        pUserNtKernel->FreeDriverMemory = 0;

        if (pNtKernel.SetExclusiveMode)
        {
            pUserNtKernel->SetExclusiveMode = (PDD_SETEXCLUSIVEMODE) DdSetExclusiveMode;
        }

        if (pNtKernel.FlipToGDISurface)
        {
            pUserNtKernel->FlipToGDISurface = (PDD_FLIPTOGDISURFACE) DdFlipToGDISurface;
        }

        /* Windows XP never repot back the true return value,
         *  it only report back if we have a driver or not
         *  ReactOS keep this behoir to be compatible with
         *  Windows XP
         */
        pData->ddRVal = retValue;
    }

    /* D3D Callbacks version 2 check and setup for DirectX/ ReactX */
    else if (IsEqualGUID(&pData->guidInfo, &GUID_D3DCallbacks2))
    {
        // FIXME GUID_D3DCallbacks2
    }

    /* D3D Callbacks version 3 check and setup for DirectX/ ReactX */
    else if (IsEqualGUID(&pData->guidInfo, &GUID_D3DCallbacks3))
    {
        // FIXME GUID_D3DCallbacks3
    }

    /* D3DParseUnknownCommand Callbacks check and setup for DirectX/ ReactX */
    else if (IsEqualGUID(&pData->guidInfo, &GUID_D3DParseUnknownCommandCallback))
    {
        // FIXME GUID_D3DParseUnknownCommandCallback
    }

    /* MotionComp Callbacks check and setup for DirectX/ ReactX */
    else if (IsEqualGUID(&pData->guidInfo, &GUID_MotionCompCallbacks))
    {
        // FIXME GUID_MotionCompCallbacks
    }

    /* FIXME VPE2 Callbacks check and setup for DirectX/ ReactX */
    //else if (IsEqualGUID(&pData->guidInfo, &GUID_VPE2Callbacks))
    //{
    // FIXME GUID_VPE2Callbacks
    //}
    else
    {
        /* set up internal buffer */
        pDrvInfoData.dwExpectedSize = pData->dwExpectedSize;
        pDrvInfoData.lpvData = pData->lpvData;

        /* We do not cover all callbacks for user mode, they are only cover by kmode */
        retValue = NtGdiDdGetDriverInfo(hDD, (PDD_GETDRIVERINFODATA)&pDrvInfoData);

        /* Setup return data */
        pData->dwActualSize = pDrvInfoData.dwActualSize;
        pData->lpvData = pDrvInfoData.lpvData;
        /* Windows XP never repot back the true return value,
         *  it only report back if we have a driver or not
         *  ReactOS keep this behoir to be compatible with
         *  Windows XP
         */
        pData->ddRVal = retValue;
    }

    return retValue;
}


/*
 * @implemented
 *
 * D3dContextCreate
 */
BOOL
WINAPI
D3dContextCreate(LPD3DHAL_CONTEXTCREATEDATA pdcci)
{
    HANDLE hSurfZ = NULL;

    if (pdcci->lpDDSZLcl)
    {
        hSurfZ = (HANDLE)pdcci->lpDDSZLcl->hDDSurface;
    }

    return  NtGdiD3dContextCreate(GetDdHandle(pdcci->lpDDLcl->hDD),
                                  (HANDLE)pdcci->lpDDSLcl->hDDSurface,
                                  hSurfZ,
                                  (D3DNTHAL_CONTEXTCREATEI *)pdcci);
}

/*
 * @implemented
 *
 * DdCanCreateD3DBuffer
 */
DWORD
WINAPI
DdCanCreateD3DBuffer(LPDDHAL_CANCREATESURFACEDATA CanCreateD3DBuffer)
{
    /*
     * Note : This functions are basic same, in win32k
     * NtGdiDdCanCreateD3DBuffer and  NtGdiDdCanCreateSurface are mergs
     * toghter in win32k at end and retrurn same data, it is still sepreated
     * at user mode but in kmode it is not.
     */

    /* Call win32k */
    return NtGdiDdCanCreateD3DBuffer(GetDdHandle(CanCreateD3DBuffer->lpDD->hDD),
                                     (PDD_CANCREATESURFACEDATA)CanCreateD3DBuffer);
}


/*
 * @implemented
 *
 * DdCreateD3DBuffer
 */
DWORD
WINAPI
DdCreateD3DBuffer(LPDDHAL_CREATESURFACEDATA pCreateSurface)
{
    HANDLE puhSurface = 0;
    DDRAWI_DDRAWSURFACE_GBL *pSurfGBL;
    DDRAWI_DDRAWSURFACE_LCL *pSurfLcl;
    DD_SURFACE_GLOBAL puSurfaceGlobalData;
    DD_SURFACE_MORE puSurfaceMoreData;
    DD_SURFACE_LOCAL puSurfaceLocalData;
    DWORD retValue;

    /* Zero all local memory pointer */
    RtlZeroMemory(&puSurfaceGlobalData, sizeof(DD_SURFACE_GLOBAL) );
    RtlZeroMemory(&puSurfaceMoreData, sizeof(DD_SURFACE_MORE) ) ;
    RtlZeroMemory(&puSurfaceLocalData, sizeof(DD_SURFACE_LOCAL) );

    pCreateSurface->dwSCnt = 1;
    pSurfLcl = pCreateSurface->lplpSList[0];
    pSurfGBL = pSurfLcl->lpGbl;

    /* Convert DDRAWI_DDRAWSURFACE_GBL to DD_SURFACE_GLOBAL */
    puSurfaceGlobalData.wWidth = pSurfGBL->wWidth;
    puSurfaceGlobalData.wHeight = pSurfGBL->wHeight;
    puSurfaceGlobalData.dwLinearSize = pSurfGBL->dwLinearSize;
    puSurfaceGlobalData.fpVidMem = pSurfGBL->fpVidMem;
    puSurfaceGlobalData.dwBlockSizeX = pSurfGBL->dwBlockSizeX;
    puSurfaceGlobalData.dwBlockSizeY = pSurfGBL->dwBlockSizeY;

    /* Convert DDRAWI_DDRAWSURFACE_MORE to DD_SURFACE_MORE */
    puSurfaceMoreData.dwSurfaceHandle = pSurfLcl->lpSurfMore->dwSurfaceHandle;
    puSurfaceMoreData.ddsCapsEx.dwCaps2 = pSurfLcl->lpSurfMore->ddsCapsEx.dwCaps2;
    puSurfaceMoreData.ddsCapsEx.dwCaps3 = pSurfLcl->lpSurfMore->ddsCapsEx.dwCaps3;
    puSurfaceMoreData.ddsCapsEx.dwCaps4 = pSurfLcl->lpSurfMore->ddsCapsEx.dwCaps4;

    /* Convert DDRAWI_DDRAWSURFACE_LCL to DD_SURFACE_LOCAL */
    puSurfaceLocalData.dwFlags = pSurfLcl->dwFlags;
    puSurfaceLocalData.ddsCaps.dwCaps = pSurfLcl->ddsCaps.dwCaps;

    /* Call win32k */
    retValue = NtGdiDdCreateD3DBuffer( GetDdHandle(pCreateSurface->lpDD->hDD),
                                       (HANDLE*)&pSurfLcl->hDDSurface,
                                       pCreateSurface->lpDDSurfaceDesc,
                                       &puSurfaceGlobalData,
                                       &puSurfaceLocalData,
                                       &puSurfaceMoreData,
                                       (DD_CREATESURFACEDATA *) pCreateSurface,
                                       &puhSurface);

    /* Setup surface handle if we got one back  */
    if ( puhSurface != NULL )
    {
        pCreateSurface->lplpSList[0]->hDDSurface = (ULONG_PTR)puhSurface;
    }

    /* Convert DD_SURFACE_GLOBAL to DDRAWI_DDRAWSURFACE_GBL */
    pSurfGBL->dwLinearSize = puSurfaceGlobalData.dwLinearSize;
    pSurfGBL->fpVidMem = puSurfaceGlobalData.fpVidMem;
    pSurfGBL->dwBlockSizeX = puSurfaceGlobalData.dwBlockSizeX;
    pSurfGBL->dwBlockSizeY = puSurfaceGlobalData.dwBlockSizeY;

    return retValue;
}

/*
 * @implemented
 *
 * DdDestroyD3DBuffer
 */
DWORD
WINAPI
DdDestroyD3DBuffer(LPDDHAL_DESTROYSURFACEDATA pDestroySurface)
{
    DWORD retValue = 0;
    if ( pDestroySurface->lpDDSurface->hDDSurface)
    {
        /* Call win32k */
        retValue = NtGdiDdDestroyD3DBuffer((HANDLE)pDestroySurface->lpDDSurface->hDDSurface);
    }

    return retValue;
}

/*
 * @implemented
 *
 * DdLockD3D
 */
DWORD
WINAPI
DdLockD3D(LPDDHAL_LOCKDATA Lock)
{

    /* Call win32k */
    return NtGdiDdLockD3D((HANDLE)Lock->lpDDSurface->hDDSurface, (PDD_LOCKDATA)Lock);
}

/*
 * @implemented
 *
 * DdUnlockD3D
 */
DWORD
WINAPI
DdUnlockD3D(LPDDHAL_UNLOCKDATA Unlock)
{
    /* Call win32k */
    return NtGdiDdUnlock((HANDLE)Unlock->lpDDSurface->hDDSurface,
                         (PDD_UNLOCKDATA)Unlock);
}


/* PRIVATE FUNCTIONS *********************************************************/

BOOL
WINAPI
bDDCreateSurface(LPDDRAWI_DDRAWSURFACE_LCL pSurface,
                 BOOL bComplete)
{
    DD_SURFACE_LOCAL SurfaceLocal;
    DD_SURFACE_GLOBAL SurfaceGlobal;
    DD_SURFACE_MORE SurfaceMore;

    /* Zero struct */
    RtlZeroMemory(&SurfaceLocal, sizeof(DD_SURFACE_LOCAL));
    RtlZeroMemory(&SurfaceGlobal, sizeof(DD_SURFACE_GLOBAL));
    RtlZeroMemory(&SurfaceMore, sizeof(DD_SURFACE_MORE));

    /* Set up SurfaceLocal struct */
    SurfaceLocal.ddsCaps.dwCaps = pSurface->ddsCaps.dwCaps;
    SurfaceLocal.dwFlags = pSurface->dwFlags;

    /* Set up SurfaceMore struct */
    RtlMoveMemory(&SurfaceMore.ddsCapsEx,
                  &pSurface->ddckCKDestBlt,
                  sizeof(DDSCAPSEX));
    SurfaceMore.dwSurfaceHandle = (DWORD)pSurface->dbnOverlayNode.object_int->lpVtbl;

    /* Set up SurfaceGlobal struct */
    SurfaceGlobal.fpVidMem = pSurface->lpGbl->fpVidMem;
    SurfaceGlobal.dwLinearSize = pSurface->lpGbl->dwLinearSize;
    SurfaceGlobal.wHeight = pSurface->lpGbl->wHeight;
    SurfaceGlobal.wWidth = pSurface->lpGbl->wWidth;

    /* Check if we have a pixel format */
    if (pSurface->dwFlags & DDSD_PIXELFORMAT)
    {
        /* Use global one */
        SurfaceGlobal.ddpfSurface = pSurface->lpGbl->lpDD->vmiData.ddpfDisplay;
        SurfaceGlobal.ddpfSurface.dwSize = sizeof(DDPIXELFORMAT);
    }
    else
    {
        /* Use local one */
        SurfaceGlobal.ddpfSurface = pSurface->lpGbl->lpDD->vmiData.ddpfDisplay;
    }

    /* Create the object */
    pSurface->hDDSurface = (DWORD)NtGdiDdCreateSurfaceObject(GetDdHandle(pSurface->lpGbl->lpDD->hDD),
                           (HANDLE)pSurface->hDDSurface,
                           &SurfaceLocal,
                           &SurfaceMore,
                           &SurfaceGlobal,
                           bComplete);

    /* Return status */
    if (pSurface->hDDSurface) return TRUE;
    return FALSE;
}

/* PUBLIC FUNCTIONS **********************************************************/

/*
 * @implemented
 *
 * GDIEntry 1
 */
BOOL
WINAPI
DdCreateDirectDrawObject(LPDDRAWI_DIRECTDRAW_GBL pDirectDrawGlobal,
                         HDC hdc)
{
    BOOL Return = FALSE;

    /* Check if the global hDC (hdc == 0) is being used */
    if (!hdc)
    {
        /* We'll only allow this if the global object doesn't exist yet */
        if (!ghDirectDraw)
        {
            /* Create the DC */
            if ((hdc = CreateDCW(L"Display", NULL, NULL, NULL)))
            {
                /* Create the DDraw Object */
                ghDirectDraw = NtGdiDdCreateDirectDrawObject(hdc);

                /* Delete our DC */
                DeleteDC(hdc);
            }
        }

        /* If we created the object, or had one ...*/
        if (ghDirectDraw)
        {
            /* Increase count and set success */
            gcDirectDraw++;
            Return = TRUE;
        }

        /* Zero the handle */
        pDirectDrawGlobal->hDD = 0;
    }
    else
    {
        /* Using the per-process object, so create it */
        pDirectDrawGlobal->hDD = (ULONG_PTR)NtGdiDdCreateDirectDrawObject(hdc);

        /* Set the return value */
        Return = pDirectDrawGlobal->hDD ? TRUE : FALSE;
    }

    /* Return to caller */
    return Return;
}

/*
 * @implemented
 *
 * GDIEntry 2
 */
BOOL
WINAPI
DdQueryDirectDrawObject(LPDDRAWI_DIRECTDRAW_GBL pDirectDrawGlobal,
                        LPDDHALINFO pHalInfo,
                        LPDDHAL_DDCALLBACKS pDDCallbacks,
                        LPDDHAL_DDSURFACECALLBACKS pDDSurfaceCallbacks,
                        LPDDHAL_DDPALETTECALLBACKS pDDPaletteCallbacks,
                        LPD3DHAL_CALLBACKS pD3dCallbacks,
                        LPD3DHAL_GLOBALDRIVERDATA pD3dDriverData,
                        LPDDHAL_DDEXEBUFCALLBACKS pD3dBufferCallbacks,
                        LPDDSURFACEDESC pD3dTextureFormats,
                        LPDWORD pdwFourCC,
                        LPVIDMEM pvmList)
{
    PVIDEOMEMORY VidMemList = NULL;
    DD_HALINFO HalInfo;
    D3DNTHAL_CALLBACKS D3dCallbacks;
    D3DNTHAL_GLOBALDRIVERDATA D3dDriverData;
    DD_D3DBUFCALLBACKS D3dBufferCallbacks;
    DWORD CallbackFlags[3];
    DWORD dwNumHeaps=0, FourCCs=0;
    DWORD Flags;
    BOOL retVal = TRUE;

    /* Clear the structures */
    RtlZeroMemory(&HalInfo, sizeof(DD_HALINFO));
    RtlZeroMemory(&D3dCallbacks, sizeof(D3DNTHAL_CALLBACKS));
    RtlZeroMemory(&D3dDriverData, sizeof(D3DNTHAL_GLOBALDRIVERDATA));
    RtlZeroMemory(&D3dBufferCallbacks, sizeof(DD_D3DBUFCALLBACKS));
    RtlZeroMemory(CallbackFlags, sizeof(DWORD)*3);

    /* Note : XP always alloc 24*sizeof(VIDEOMEMORY) of pvmlist so we change it to it */
    if ( (pvmList != NULL) &&
            (pHalInfo->vmiData.dwNumHeaps != 0) )
    {
        VidMemList = (PVIDEOMEMORY) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sizeof(VIDEOMEMORY) * 24 ) * pHalInfo->vmiData.dwNumHeaps);
    }


    /* Do the query */
    if (!NtGdiDdQueryDirectDrawObject(GetDdHandle(pDirectDrawGlobal->hDD),
                                      &HalInfo,
                                      CallbackFlags,
                                      &D3dCallbacks,
                                      &D3dDriverData,
                                      &D3dBufferCallbacks,
                                      pD3dTextureFormats,
                                      &dwNumHeaps,
                                      VidMemList,
                                      &FourCCs,
                                      pdwFourCC))
    {
        /* We failed, free the memory and return */
        retVal = FALSE;
        goto cleanup;
    }

    /* Clear the incoming pointer */
    RtlZeroMemory(pHalInfo, sizeof(DDHALINFO));

    /* Convert all the data */
    pHalInfo->dwSize = sizeof(DDHALINFO);
    pHalInfo->lpDDCallbacks = pDDCallbacks;
    pHalInfo->lpDDSurfaceCallbacks = pDDSurfaceCallbacks;
    pHalInfo->lpDDPaletteCallbacks = pDDPaletteCallbacks;

    /* Check for NT5+ D3D Data */
    if ( (D3dCallbacks.dwSize != 0) &&
            (D3dDriverData.dwSize != 0) )
    {
        /* Write these down */
        pHalInfo->lpD3DGlobalDriverData = (ULONG_PTR)pD3dDriverData;
        pHalInfo->lpD3DHALCallbacks = (ULONG_PTR)pD3dCallbacks;

        /* Check for Buffer Callbacks */
        if (D3dBufferCallbacks.dwSize)
        {
            /* Write this one too */
            pHalInfo->lpDDExeBufCallbacks = pD3dBufferCallbacks;
        }
    }

    /* Continue converting the rest */
    pHalInfo->vmiData.dwFlags = HalInfo.vmiData.dwFlags;
    pHalInfo->vmiData.dwDisplayWidth = HalInfo.vmiData.dwDisplayWidth;
    pHalInfo->vmiData.dwDisplayHeight = HalInfo.vmiData.dwDisplayHeight;
    pHalInfo->vmiData.lDisplayPitch = HalInfo.vmiData.lDisplayPitch;
    pHalInfo->vmiData.fpPrimary = 0;

    RtlCopyMemory( &pHalInfo->vmiData.ddpfDisplay,
                   &HalInfo.vmiData.ddpfDisplay,
                   sizeof(DDPIXELFORMAT));

    pHalInfo->vmiData.dwOffscreenAlign = HalInfo.vmiData.dwOffscreenAlign;
    pHalInfo->vmiData.dwOverlayAlign = HalInfo.vmiData.dwOverlayAlign;
    pHalInfo->vmiData.dwTextureAlign = HalInfo.vmiData.dwTextureAlign;
    pHalInfo->vmiData.dwZBufferAlign = HalInfo.vmiData.dwZBufferAlign;
    pHalInfo->vmiData.dwAlphaAlign = HalInfo.vmiData.dwAlphaAlign;

    pHalInfo->vmiData.dwNumHeaps = dwNumHeaps;
    pHalInfo->vmiData.pvmList = pvmList;

    RtlCopyMemory( &pHalInfo->ddCaps,
                   &HalInfo.ddCaps,
                   sizeof(DDCORECAPS ));

    pHalInfo->ddCaps.dwNumFourCCCodes = FourCCs;
    pHalInfo->lpdwFourCC = pdwFourCC;

    /* always force rope 0x1000 for hal it mean only source copy is supported */
    pHalInfo->ddCaps.dwRops[6] = 0x1000;

    /* Set the HAL flags what ReactX got from the driver
     * Windows XP force setting DDHALINFO_GETDRIVERINFOSET if the driver does not set it
     * and ReactX doing same to keep compatible with drivers, but the driver are
     * force support DdGetDriverInfo acoriding MSDN but it seam some driver do not set
     * this flag even it is being supported. that is mean. It is small hack to keep
     * bad driver working, that trust this is always being setting by it self at end
     */
    pHalInfo->dwFlags = (HalInfo.dwFlags & ~DDHALINFO_GETDRIVERINFOSET) | DDHALINFO_GETDRIVERINFOSET;
    pHalInfo->GetDriverInfo = (LPDDHAL_GETDRIVERINFO) DdGetDriverInfo;

    /* Now check if we got any DD callbacks */
    if (pDDCallbacks)
    {
        /* Zero the structure */
        RtlZeroMemory(pDDCallbacks, sizeof(DDHAL_DDCALLBACKS));
        pDDCallbacks->dwSize = sizeof(DDHAL_DDCALLBACKS);

        /* Set the flags for this structure
         * Windows XP force setting DDHAL_CB32_CREATESURFACE if the driver does not set it
         * and ReactX doing same to keep compatible with drivers, but the driver are
         * force support pDDCallbacks acoriding MSDN but it seam some driver do not set
         * this flag even it is being supported. that is mean. It is small hack to keep
         * bad driver working, that trust this is always being setting by it self at end
        */
        Flags = (CallbackFlags[0] & ~DDHAL_CB32_CREATESURFACE) | DDHAL_CB32_CREATESURFACE;
        pDDCallbacks->dwFlags = Flags;

        /* Write the always-on functions */
        pDDCallbacks->CreateSurface = DdCreateSurface;

        /* Now write the pointers, if applicable */
        if (Flags & DDHAL_CB32_WAITFORVERTICALBLANK)
        {
            pDDCallbacks->WaitForVerticalBlank = DdWaitForVerticalBlank;
        }
        if (Flags & DDHAL_CB32_CANCREATESURFACE)
        {
            pDDCallbacks->CanCreateSurface = DdCanCreateSurface;
        }
        if (Flags & DDHAL_CB32_GETSCANLINE)
        {
            pDDCallbacks->GetScanLine = DdGetScanLine;
        }
    }

    /* Check for DD Surface Callbacks */
    if (pDDSurfaceCallbacks)
    {
        /* Zero the structures */
        RtlZeroMemory(pDDSurfaceCallbacks, sizeof(DDHAL_DDSURFACECALLBACKS));
        pDDSurfaceCallbacks->dwSize  = sizeof(DDHAL_DDSURFACECALLBACKS);

        /* Set the flags for this structure
         * Windows XP force setting DDHAL_SURFCB32_LOCK, DDHAL_SURFCB32_UNLOCK,
         * DDHAL_SURFCB32_SETCOLORKEY, DDHAL_SURFCB32_DESTROYSURFACE if the driver
         * does not set it and ReactX doing same to keep compatible with drivers,
         * but the driver are force support pDDSurfaceCallbacks acoriding MSDN but it seam
         * some driver do not set this flag even it is being supported. that is mean.
         * It is small hack to keep bad driver working, that trust this is always being
         * setting by it self at end
         */

        Flags = (CallbackFlags[1] & ~(DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_UNLOCK |
                                      DDHAL_SURFCB32_SETCOLORKEY | DDHAL_SURFCB32_DESTROYSURFACE)) |
                (DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_UNLOCK |
                 DDHAL_SURFCB32_SETCOLORKEY | DDHAL_SURFCB32_DESTROYSURFACE);

        pDDSurfaceCallbacks->dwFlags = Flags;

        /* Write the always-on functions */
        pDDSurfaceCallbacks->Lock = DdLock;
        pDDSurfaceCallbacks->Unlock = DdUnlock;
        pDDSurfaceCallbacks->SetColorKey = DdSetColorKey;
        pDDSurfaceCallbacks->DestroySurface = DdDestroySurface;

        /* Write the optional ones */
        if (Flags & DDHAL_SURFCB32_FLIP)
        {
            pDDSurfaceCallbacks->Flip = DdFlip;
        }
        if (Flags & DDHAL_SURFCB32_BLT)
        {
            pDDSurfaceCallbacks->Blt = DdBlt;
        }
        if (Flags & DDHAL_SURFCB32_GETBLTSTATUS)
        {
            pDDSurfaceCallbacks->GetBltStatus = DdGetBltStatus;
        }
        if (Flags & DDHAL_SURFCB32_GETFLIPSTATUS)
        {
            pDDSurfaceCallbacks->GetFlipStatus = DdGetFlipStatus;
        }
        if (Flags & DDHAL_SURFCB32_UPDATEOVERLAY)
        {
            pDDSurfaceCallbacks->UpdateOverlay = DdUpdateOverlay;
        }
        if (Flags & DDHAL_SURFCB32_SETOVERLAYPOSITION)
        {
            pDDSurfaceCallbacks->SetOverlayPosition = DdSetOverlayPosition;
        }
        if (Flags & DDHAL_SURFCB32_ADDATTACHEDSURFACE)
        {
            pDDSurfaceCallbacks->AddAttachedSurface = DdAddAttachedSurface;
        }
    }

    /* Check for DD Palette Callbacks, This interface are dead for user mode,
     * only what it can support are being report back.
     */
    if (pDDPaletteCallbacks)
    {
        /* Zero the struct */
        RtlZeroMemory(pDDPaletteCallbacks, sizeof(DDHAL_DDPALETTECALLBACKS));

        /* Write the header */
        pDDPaletteCallbacks->dwSize  = sizeof(DDHAL_DDPALETTECALLBACKS);
        pDDPaletteCallbacks->dwFlags = CallbackFlags[2];
    }

    if (pD3dCallbacks)
    {
        /* Zero the struct */
        RtlZeroMemory(pD3dCallbacks, sizeof(DDHAL_DDEXEBUFCALLBACKS));

        /* Check if we have one */
        if (D3dCallbacks.dwSize)
        {
            /* Write the header */
            pD3dCallbacks->dwSize = sizeof(DDHAL_DDEXEBUFCALLBACKS);

            /* Now check for each callback */
            if (D3dCallbacks.ContextCreate)
            {
                pD3dCallbacks->ContextCreate = (LPD3DHAL_CONTEXTCREATECB) D3dContextCreate;
            }
            if (D3dCallbacks.ContextDestroy)
            {
                pD3dCallbacks->ContextDestroy = (LPD3DHAL_CONTEXTDESTROYCB) NtGdiD3dContextDestroy;
            }
            if (D3dCallbacks.ContextDestroyAll)
            {
                pD3dCallbacks->ContextDestroyAll = (LPD3DHAL_CONTEXTDESTROYALLCB) NtGdiD3dContextDestroyAll;
            }
        }
    }

    /* Check for D3D Driver Data */
    if (pD3dDriverData)
    {
        /* Copy the struct */
        RtlMoveMemory(pD3dDriverData, &D3dDriverData, sizeof(D3DHAL_GLOBALDRIVERDATA));

        /* Write the pointer to the texture formats */
        pD3dDriverData->lpTextureFormats = pD3dTextureFormats;
    }

    /* Check for D3D Buffer Callbacks */
    if (pD3dBufferCallbacks)
    {
        /* Zero the struct */
        RtlZeroMemory(pD3dBufferCallbacks, sizeof(DDHAL_DDEXEBUFCALLBACKS));

        if ( D3dBufferCallbacks.dwSize)
        {
            pD3dBufferCallbacks->dwSize = D3dBufferCallbacks.dwSize;

            pD3dBufferCallbacks->dwFlags = D3dBufferCallbacks.dwFlags;
            if ( D3dBufferCallbacks.CanCreateD3DBuffer)
            {
                pD3dBufferCallbacks->CanCreateExecuteBuffer = (LPDDHALEXEBUFCB_CANCREATEEXEBUF)DdCanCreateD3DBuffer;
            }

            if ( D3dBufferCallbacks.CanCreateD3DBuffer)
            {
                pD3dBufferCallbacks->CreateExecuteBuffer = (LPDDHALEXEBUFCB_CREATEEXEBUF) DdCreateD3DBuffer;
            }

            if ( D3dBufferCallbacks.DestroyD3DBuffer )
            {
                pD3dBufferCallbacks->DestroyExecuteBuffer = (LPDDHALEXEBUFCB_DESTROYEXEBUF) DdDestroyD3DBuffer;
            }

            if ( D3dBufferCallbacks.LockD3DBuffer )
            {
                pD3dBufferCallbacks->LockExecuteBuffer = (LPDDHALEXEBUFCB_LOCKEXEBUF) DdLockD3D;
            }

            if ( D3dBufferCallbacks.UnlockD3DBuffer )
            {
                pD3dBufferCallbacks->UnlockExecuteBuffer = (LPDDHALEXEBUFCB_UNLOCKEXEBUF) DdUnlockD3D;
            }

        }
    }

    /* FIXME VidMemList */

cleanup:
    if (VidMemList)
    {
        HeapFree(GetProcessHeap(), 0, VidMemList);
    }

    return retVal;
}

/*
 * @implemented
 *
 * GDIEntry 3
 */
BOOL
WINAPI
DdDeleteDirectDrawObject(LPDDRAWI_DIRECTDRAW_GBL pDirectDrawGlobal)
{
    BOOL Return = FALSE;

    /* If this is the global object */
    if(pDirectDrawGlobal->hDD)
    {
        /* Free it */
        Return = NtGdiDdDeleteDirectDrawObject((HANDLE)pDirectDrawGlobal->hDD);
        if (Return == TRUE)
        {
            pDirectDrawGlobal->hDD = 0;
        }
    }
    else if (ghDirectDraw)
    {
        /* Always success here */
        Return = TRUE;

        /* Make sure this is the last instance */
        if (!(--gcDirectDraw))
        {
            /* Delete the object */
            Return = NtGdiDdDeleteDirectDrawObject(ghDirectDraw);
            if (Return == TRUE)
            {
                ghDirectDraw = 0;
            }
        }
    }

    /* Return */
    return Return;
}

/*
 * @implemented
 *
 * GDIEntry 4
 */
BOOL
WINAPI
DdCreateSurfaceObject( LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal,
                       BOOL bPrimarySurface)
{
    return bDDCreateSurface(pSurfaceLocal, TRUE);
}


/*
 * @implemented
 *
 * GDIEntry 5
 */
BOOL
WINAPI
DdDeleteSurfaceObject(LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal)
{
    BOOL Return = FALSE;

    /* Make sure there is one */
    if (pSurfaceLocal->hDDSurface)
    {
        /* Delete it */
        Return = NtGdiDdDeleteSurfaceObject((HANDLE)pSurfaceLocal->hDDSurface);
        pSurfaceLocal->hDDSurface = 0;
    }

    return Return;
}

/*
 * @implemented
 *
 * GDIEntry 6
 */
BOOL
WINAPI
DdResetVisrgn(LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal,
              HWND hWnd)
{
    /* Call win32k directly */
    return NtGdiDdResetVisrgn((HANDLE) pSurfaceLocal->hDDSurface, hWnd);
}

/*
 * @implemented
 *
 * GDIEntry 7
 */
HDC
WINAPI
DdGetDC(LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal,
        LPPALETTEENTRY pColorTable)
{
    /* Call win32k directly */
    return NtGdiDdGetDC(pColorTable, (HANDLE) pSurfaceLocal->hDDSurface);
}

/*
 * @implemented
 *
 * GDIEntry 8
 */
BOOL
WINAPI
DdReleaseDC(LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal)
{
    /* Call win32k directly */
    return NtGdiDdReleaseDC((HANDLE) pSurfaceLocal->hDDSurface);
}

/*
 * @unimplemented
 * GDIEntry 9
 */
HBITMAP
WINAPI
DdCreateDIBSection(HDC hdc,
                   CONST BITMAPINFO *pbmi,
                   UINT iUsage,
                   VOID **ppvBits,
                   HANDLE hSectionApp,
                   DWORD dwOffset)
{
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return 0;
}

/*
 * @implemented
 *
 * GDIEntry 10
 */
BOOL
WINAPI
DdReenableDirectDrawObject(LPDDRAWI_DIRECTDRAW_GBL pDirectDrawGlobal,
                           BOOL *pbNewMode)
{
    /* Call win32k directly */
    return NtGdiDdReenableDirectDrawObject(GetDdHandle(pDirectDrawGlobal->hDD),
                                           pbNewMode);
}


/*
 * @implemented
 *
 * GDIEntry 11
 */
BOOL
WINAPI
DdAttachSurface( LPDDRAWI_DDRAWSURFACE_LCL pSurfaceFrom,
                 LPDDRAWI_DDRAWSURFACE_LCL pSurfaceTo)
{
    /* Create Surface if it does not exits one */
    if (!pSurfaceFrom->hDDSurface)
    {
        if (!bDDCreateSurface(pSurfaceFrom, FALSE))
        {
            return FALSE;
        }
    }

    /* Create Surface if it does not exits one */
    if (!pSurfaceTo->hDDSurface)
    {
        if (!bDDCreateSurface(pSurfaceTo, FALSE))
        {
            return FALSE;
        }
    }

    /* Call win32k */
    return NtGdiDdAttachSurface((HANDLE)pSurfaceFrom->hDDSurface,
                                (HANDLE)pSurfaceTo->hDDSurface);
}

/*
 * @implemented
 *
 * GDIEntry 12
 */
VOID
WINAPI
DdUnattachSurface(LPDDRAWI_DDRAWSURFACE_LCL pSurface,
                  LPDDRAWI_DDRAWSURFACE_LCL pSurfaceAttached)
{
    /* Call win32k */
    NtGdiDdUnattachSurface((HANDLE)pSurface->hDDSurface,
                           (HANDLE)pSurfaceAttached->hDDSurface);
}

/*
 * @implemented
 *
 * GDIEntry 13
 */
ULONG
WINAPI
DdQueryDisplaySettingsUniqueness()
{
    return GdiSharedHandleTable->flDeviceUniq;
}

/*
 * @implemented
 *
 * GDIEntry 14
 */
HANDLE
WINAPI
DdGetDxHandle(LPDDRAWI_DIRECTDRAW_LCL pDDraw,
              LPDDRAWI_DDRAWSURFACE_LCL pSurface,
              BOOL bRelease)
{
    HANDLE hDD = NULL;
    HANDLE hSurface = NULL;

    /* Check if we already have a surface */
    if (!pSurface)
    {
        /* We don't have one, use the DirectDraw Object handle instead */
        hDD = GetDdHandle(pDDraw->lpGbl->hDD);
    }
    else
    {
        hSurface = (HANDLE)pSurface->hDDSurface;
    }

    /* Call the API */
    return (HANDLE)NtGdiDdGetDxHandle(hDD, hSurface, bRelease);
}

/*
 * @implemented
 *
 * GDIEntry 15
 */
BOOL
WINAPI
DdSetGammaRamp(LPDDRAWI_DIRECTDRAW_LCL pDDraw,
               HDC hdc,
               LPVOID lpGammaRamp)
{
    /* Call win32k directly */
    return NtGdiDdSetGammaRamp(GetDdHandle(pDDraw->lpGbl->hDD),
                               hdc,
                               lpGammaRamp);
}





