/*++
 *
 *  WOW v1.0
 *
 *  Copyright (c) 1991, Microsoft Corporation
 *
 *  WDIB.C
 *  DIB.DRV support
 *
 *  History:
 *  28-Apr-1994 Sudeep Bharati
 *  Created.
 *
--*/


#include "precomp.h"
#pragma hdrstop
#include "wowgdip.h"
#include "wdib.h"
#include "memapi.h"

MODNAME(wdib.c);

#define CJSCAN(width,planes,bits) ((((width)*(planes)*(bits)+31) & ~31) / 8)
#define ABS(X) (((X) < 0 ) ? -(X) : (X))

BOOL W32CheckDibColorIndices(LPBITMAPINFOHEADER lpbmi);

// VGA colors
RGBQUAD rgbVGA[] = {
//    Blue  Green   Red   
      0x00, 0x00, 0x00, 0,    // 0  ; black
      0x00, 0x00, 0x80, 0,    // 1  ; dark red
      0x00, 0x80, 0x00, 0,    // 2  ; dark green
      0x00, 0x80, 0x80, 0,    // 3  ; mustard
      0x80, 0x00, 0x00, 0,    // 4  ; dark blue
      0x80, 0x00, 0x80, 0,    // 5  ; purple
      0x80, 0x80, 0x00, 0,    // 6  ; dark turquoise
      0xc0, 0xc0, 0xc0, 0,    // 7  ; gray
      0x80, 0x80, 0x80, 0,    // 8  ; dark gray
      0x00, 0x00, 0xff, 0,    // 9  ; red
      0x00, 0xff, 0x00, 0,    // a  ; green
      0x00, 0xff, 0xff, 0,    // b  ; yellow
      0xff, 0x00, 0x00, 0,    // c  ; blue
      0xff, 0x00, 0xff, 0,    // d  ; magenta
      0xff, 0xff, 0x00, 0,    // e  ; cyan
      0xff, 0xff, 0xff, 0     // f  ; white
};                        

RGBQUAD rgb4[] = {
      0xc0, 0xdc, 0xc0, 0,    // 8
      0xf0, 0xca, 0xa6, 0,    // 9
      0xf0, 0xfb, 0xff, 0,    // 246
      0xa4, 0xa0, 0xa0, 0     // 247
};



PDIBINFO pDibInfoHead = NULL;
PDIBSECTIONINFO pDibSectionInfoHead = NULL;

HDC W32HandleDibDrv (PVPVOID vpbmi16)
{
    HDC             hdcMem = NULL;
    HBITMAP         hbm = NULL;
    PVOID           pvBits, pvIntelBits;
    STACKBMI32      bmi32;
    LPBITMAPINFO    lpbmi32;
    DWORD           dwClrUsed,nSize,nAlignmentSpace;
    PBITMAPINFOHEADER16 pbmi16;
    INT             nbmiSize,nBytesWritten;
    HANDLE          hfile=NULL,hsec=NULL;
    ULONG           RetVal,OriginalSelLimit,SelectorLimit,OriginalFlags;
    PARM16          Parm16;
    CHAR            pchTempFile[MAX_PATH];
    BOOL            bRet = FALSE;
    PVPVOID         vpBase16 = (PVPVOID) ((ULONG) vpbmi16 & 0xffff0000);

    if ((hdcMem = W32FindAndLockDibInfo((USHORT)HIWORD(vpbmi16))) != (HDC)NULL) {
        return hdcMem;
    }

    // First create a memory device context compatible to
    // the app's current screen
    if ((hdcMem = CreateCompatibleDC (NULL)) == NULL) {
        LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateCompatibleDC failed\n"));
        return NULL;
    }

    // Copy bmi16 to bmi32. DIB.DRV only supports DIB_RGB_COLORS
    lpbmi32 = CopyBMI16ToBMI32(
                     vpbmi16,
                     (LPBITMAPINFO)&bmi32,
                     (WORD) DIB_RGB_COLORS);

    // this hack for Director 4.0 does essentially what WFW does
    // if this bitmap is 0 sized, just return an hDC for something simple
    if(bmi32.bmiHeader.biSizeImage == 0 &&
       (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_DIBDRVIMAGESIZEZERO)) {
        LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv:Zero biSizeImage, returning memory DC!\n"));
        return hdcMem;
    }

    try {

        // Copy the wholething into a temp file. First get a temp file name
        if ((nSize = GetTempPath (MAX_PATH, pchTempFile)) == 0 ||
             nSize >= MAX_PATH)
            goto hdd_err;

        if (GetTempFileName (pchTempFile,
                             "DIB",
                             0,
                             pchTempFile) == 0)
            goto hdd_err;

        if ((hfile = CreateFile (pchTempFile,
                                GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_WRITE,
                                NULL,
                                CREATE_ALWAYS,
                                (FILE_ATTRIBUTE_NORMAL |
                                 FILE_ATTRIBUTE_TEMPORARY |
                                 FILE_FLAG_DELETE_ON_CLOSE),
                                NULL)) == INVALID_HANDLE_VALUE) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateFile failed\n"));
            goto hdd_err;
        }

        // call back to get the size of the global object
        // associated with vpbmi16
        Parm16.WndProc.wParam = HIWORD(vpbmi16);

        CallBack16(RET_GETDIBSIZE,
                   &Parm16,
                   0,
                   (PVPVOID)&SelectorLimit);

        Parm16.WndProc.wParam = HIWORD(vpbmi16);

        if (SelectorLimit == 0xffffffff || SelectorLimit == 0) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv Invalid Selector %x\n",HIWORD(vpbmi16)));
            goto hdd_err;
        }

        SelectorLimit++;

        OriginalSelLimit = SelectorLimit;

        CallBack16(RET_GETDIBFLAGS,
                   &Parm16,
                   0,
                   (PVPVOID)&OriginalFlags);

        if (OriginalFlags == 0x4) { //GA_DGROUP
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv GA_DGROUP Not Handled\n"));
            goto hdd_err;
        }

        GETVDMPTR(vpBase16, SelectorLimit, pbmi16);

        nbmiSize = GetBMI16Size(vpbmi16, (WORD) DIB_RGB_COLORS, &dwClrUsed);

        // Under NT CreateDIBSection will fail if the offset to the bits
        // is not dword aligned. So we may have to add some space at the top
        // of the section to get the offset correctly aligned.

        nAlignmentSpace = (nbmiSize+LOWORD(vpbmi16)) % 4;

        if (nAlignmentSpace) {
            if (WriteFile (hfile,
                           pbmi16,
                           nAlignmentSpace,
                           &nBytesWritten,
                           NULL) == FALSE ||
                           nBytesWritten != (INT) nAlignmentSpace)
            goto hdd_err;
        }

        //
        // detect a clinical case of bitedit screwing around dib.drv 
        // 
        // code below is using dib macros declared in wdib.h
        // namely:
        //      DibNumColors - yields max number of colors in dib
        //      DibColors    - yields pointer to a dib color table
        //  
        // Function W32CheckDibColorIndices checks to see if DIB color
        // table looks like a number (defined usually by biClrImportant)
        // of WORD indices in a sequential order (0, 1, 2, ...)
        // if this is the case, app is trying to use undocumented feature 
        // of DIB.DRV that turns color matching off in this case. 
        // Since we cannot enforce that rule, we approximate it by filling
        // color table by a number of known (and always same) entries
        // When blitting occurs, no color matching will be performed (when 
        // both target and destination are of this very nature).
        // For no reason at all we fill color table with vga colors. 
        // Sequential indices could have worked just as well. 
        //    
        // Modifications are made to memory pointed to by lpbmi32

        if (W32CheckDibColorIndices((LPBITMAPINFOHEADER)lpbmi32)) {
            INT i, nColors;
            LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER)lpbmi32;
            LPRGBQUAD lprgbq = (LPRGBQUAD)DibColors(lpbmi);

            nColors = DibNumColors(lpbmi);
            lpbmi->biClrImportant = nColors;

            switch (lpbmi->biBitCount) {
                case 1:
                    lprgbq[0] = rgbVGA[0];
                    lprgbq[1] = rgbVGA[0x0f];
                    break;

                case 4:
                    RtlCopyMemory(lprgbq, rgbVGA, sizeof(rgbVGA));
                    break;
                    
                case 8:
                    RtlCopyMemory(lprgbq,     rgbVGA,   8*sizeof(RGBQUAD));
                    RtlCopyMemory(lprgbq+248, rgbVGA+8, 8*sizeof(RGBQUAD));
                    RtlCopyMemory(lprgbq+8,   rgb4,   2*sizeof(RGBQUAD));
                    RtlCopyMemory(lprgbq+246, rgb4+2, 2*sizeof(RGBQUAD));
                    for (i = 10; i < 246; ++i) {
                        lprgbq[i].rgbBlue = i; 
                        lprgbq[i].rgbGreen= 0;
                        lprgbq[i].rgbRed  = 0;
                        lprgbq[i].rgbReserved = 0;
                    }
                    break;

                default: // this should never happen
                    break;
            }            
        }

        if (WriteFile (hfile,
                       pbmi16,
                       SelectorLimit,
                       &nBytesWritten,
                       NULL) == FALSE || nBytesWritten != (INT) SelectorLimit)
            goto hdd_err;

        if (SelectorLimit < 64*1024) {
            if (SetFilePointer (hfile,
                                64*1024+nAlignmentSpace,
                                NULL,
                                FILE_BEGIN) == -1)
                goto hdd_err;

            if (SetEndOfFile (hfile) == FALSE)
                goto hdd_err;

            SelectorLimit = 64*1024;
        }

        if ((hsec = CreateFileMapping (hfile,
                                       NULL,
                                       PAGE_READWRITE | SEC_COMMIT,
                                       0,
                                       SelectorLimit+nAlignmentSpace,
                                       NULL)) == NULL) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateFileMapping Failed\n"));
            goto hdd_err;
        }

        // Now create the DIB section
        if ((hbm = CreateDIBSection (hdcMem,
                                lpbmi32,
                                DIB_RGB_COLORS,
                                &pvBits,
                                hsec,
                                nAlignmentSpace + LOWORD(vpbmi16) + nbmiSize
                                )) == NULL) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv CreateDibSection Failed\n"));
            goto hdd_err;
        }

        FREEVDMPTR(pbmi16);

        if((pvBits = MapViewOfFile(hsec,
                         FILE_MAP_WRITE,
                         0,
                         0,
                         SelectorLimit+nAlignmentSpace)) == NULL) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv MapViewOfFile Failed\n"));
            goto hdd_err;
        }

        pvBits = (PVOID) ((ULONG)pvBits + nAlignmentSpace);

        SelectObject (hdcMem, hbm);

        GdiSetBatchLimit(1);

#ifndef i386
        if (!NT_SUCCESS(VdmAddVirtualMemory((ULONG)pvBits,
                                            (ULONG)SelectorLimit,
                                            (PULONG)&pvIntelBits))) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv VdmAddVirtualMemory failed\n"));
            goto hdd_err;
        }

        // On risc platforms, the intel base + the intel linear address
        // of the DIB section is not equal to the DIB section's process
        // address. This is because of the VdmAddVirtualMemory call
        // above. So here we zap the correct address into the flataddress
        // array.
        if (!VdmAddDescriptorMapping(HIWORD(vpbmi16),
                                    (USHORT) ((SelectorLimit+65535)/65536),
                                    (ULONG) pvIntelBits,
                                    (ULONG) pvBits)) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv VdmAddDescriptorMapping failed\n"));
            goto hdd_err;
        }

#else
        pvIntelBits = pvBits;
#endif

        // Finally set the selectors to the new DIB
        Parm16.WndProc.wParam = HIWORD(vpbmi16);
        Parm16.WndProc.lParam = (LONG)pvIntelBits;
        Parm16.WndProc.wMsg   = 0x10; // GA_NOCOMPACT
        Parm16.WndProc.hwnd   = 1;    // set so it's not randomly 0

        CallBack16(RET_SETDIBSEL,
                   &Parm16,
                   0,
                   (PVPVOID)&RetVal);

        if (!RetVal) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::W32HandleDibDrv Callback set_sel_for_dib failed\n"));
            goto hdd_err;
        }


        // Store all the relevant information so that DeleteDC could
        // free all the resources later.
        if (W32AddDibInfo(hdcMem, 
                          hfile, 
                          hsec, 
                          nAlignmentSpace,
                          pvBits, 
                          pvIntelBits, 
                          hbm, 
                          OriginalSelLimit,
                          (USHORT)OriginalFlags,
                          (USHORT)((HIWORD(vpbmi16)))) == FALSE) 
            goto hdd_err;


        // Finally spit out the dump for debugging
        LOGDEBUG(6,("\t\tWOW::W32HandleDibDrv hdc=%04x nAlignment=%04x\n\t\tNewDib=%x OldDib=%04x:%04x DibSize=%x DibFlags=%x\n",hdcMem,nAlignmentSpace,pvBits,HIWORD(vpbmi16),LOWORD(vpbmi16),OriginalSelLimit,(USHORT)OriginalFlags));

        bRet = TRUE;
hdd_err:;
    }
    finally {
        if (!bRet) {

            if (hdcMem) {    
                DeleteDC (hdcMem);
                hdcMem = NULL;
            }
            if (hfile)
                CloseHandle (hfile);

            if (hsec)
                CloseHandle (hsec);

            if (hbm)
                CloseHandle (hbm);
        }
    }
    return hdcMem;
}


BOOL W32AddDibInfo (
    HDC hdcMem,
    HANDLE hfile,
    HANDLE hsec,
    ULONG  nalignment,
    PVOID  newdib,
    PVOID  newIntelDib,
    HBITMAP hbm,
    ULONG dibsize,
    USHORT originaldibflags,
    USHORT originaldibsel
    )
{
    PDIBINFO pdi;
    
    if ((pdi = malloc_w (sizeof (DIBINFO))) == NULL)
        return FALSE;

    pdi->di_hdc     = hdcMem;
    pdi->di_hfile   = hfile;
    pdi->di_hsec    = hsec;
    pdi->di_nalignment    = nalignment;
    pdi->di_newdib  = newdib;
    pdi->di_newIntelDib = newIntelDib;
    pdi->di_hbm     = hbm;
    pdi->di_dibsize = dibsize;
    pdi->di_originaldibsel = originaldibsel;
    pdi->di_originaldibflags = originaldibflags;
    pdi->di_next    = pDibInfoHead;
    pdi->di_lockcount = 1;
    pDibInfoHead    = pdi;

    return TRUE;
}

BOOL W32FreeDibInfoHandle(PDIBINFO pdi, PDIBINFO pdiLast)
{
    if (W32RestoreOldDib (pdi) == 0) {
        LOGDEBUG(LOG_ALWAYS,("\nWOW::W32RestoreDib failed\n"));
        return FALSE;
    }
#ifndef i386
    VdmRemoveVirtualMemory((ULONG)pdi->di_newIntelDib);
#endif
    UnmapViewOfFile ((LPVOID)((ULONG)pdi->di_newdib - pdi->di_nalignment));

    DeleteObject (pdi->di_hbm);
    CloseHandle (pdi->di_hsec);
    CloseHandle (pdi->di_hfile);

    DeleteDC(pdi->di_hdc);
    W32FreeDibInfo (pdi, pdiLast);

    return TRUE;
}


BOOL    W32CheckAndFreeDibInfo (HDC hdc)
{
    PDIBINFO pdi = pDibInfoHead,pdiLast=NULL;

    while (pdi) {
        if (pdi->di_hdc == hdc){

            if (--pdi->di_lockcount) {
                //
                // This must be a releasedc within a nested call to createdc.
                // Just return, as this should be released again later.
                //
                LOGDEBUG(LOG_ALWAYS, ("\nW32CheckAndFreeDibInfo: lockcount!=0\n"));
                return TRUE;
            }

            return W32FreeDibInfoHandle(pdi, pdiLast);
        }
        pdiLast = pdi;
        pdi = pdi->di_next;
    }

    return FALSE;
}

VOID W32FreeDibInfo (PDIBINFO pdiCur, PDIBINFO pdiLast)
{
    if (pdiLast == NULL)
        pDibInfoHead = pdiCur->di_next;
    else
        pdiLast->di_next = pdiCur->di_next;

    free_w (pdiCur);
}

ULONG W32RestoreOldDib (PDIBINFO pdi)
{
    PARM16          Parm16;
    ULONG           retval;

    // callback to allocate memory and copy the dib from dib section

    Parm16.WndProc.wParam = pdi->di_originaldibsel;
    Parm16.WndProc.lParam = (LONG) (pdi->di_newdib);
    Parm16.WndProc.wMsg = pdi->di_originaldibflags;

    CallBack16(RET_FREEDIBSEL,
               &Parm16,
               0,
               (PVPVOID)&retval);

    return retval;
}


HDC W32FindAndLockDibInfo (USHORT sel)
{
    PDIBINFO pdi = pDibInfoHead;

    while (pdi) {

        if (pdi->di_originaldibsel == sel){
            pdi->di_lockcount++;
            return (pdi->di_hdc);

        }
        pdi = pdi->di_next;

    }
    return (HDC) NULL;
}

//
//  This function is called from krnl386 if GlobalReAlloc or GlobalFree is
//  trying to operate on memory which we suspect is dib-mapped. It finds 
//  dib by original selector and restores it, thus allowing respective function
//  to succeede. Bitedit is the app that does globalrealloc before DeleteDC
//
//

ULONG FASTCALL WK32FindAndReleaseDib(PVDMFRAME pvf)
{
    USHORT sel;
    PFINDANDRELEASEDIB16 parg;
    PDIBINFO pdi;
    PDIBINFO pdiLast = NULL;

    // get the argument pointer, see wowkrnl.h
    GETARGPTR(pvf, sizeof(*parg), parg);

    // get selector from the handle
    sel = parg->hdib | (USHORT)0x01; // "convert to sel"

    // find this said sel in the dibinfo
    pdi = pDibInfoHead;
    while (pdi) {
        if (pdi->di_originaldibsel == sel) {

            // found ! this is what we are releasing or reallocating
            LOGDEBUG(LOG_ALWAYS, ("\nWOW: In FindAndReleaseDIB function %d\n", (DWORD)parg->wFunId));

            // see if we need to nuke...
            if (--pdi->di_lockcount) {
                // the problem with lock count...
                LOGDEBUG(LOG_ALWAYS, ("\nWOW: FindAndReleaseDib failed (lock count!)\n"));
                return FALSE;
            }
            
            return W32FreeDibInfoHandle(pdi, pdiLast);
        }

        pdiLast = pdi;
        pdi = pdi->di_next;
    }

    return FALSE;
}


BOOL W32CheckDibColorIndices(LPBITMAPINFOHEADER lpbmi)
{
    WORD i, nColors;
    LPWORD lpw = (LPWORD)DibColors(lpbmi);

    nColors = DibNumColors(lpbmi);
    if (lpbmi->biClrImportant) {
        nColors = min(nColors, (WORD)lpbmi->biClrImportant);
    }
    
    for (i = 0; i < nColors; ++i) {
        if (*lpw++ != i) {
            return FALSE;
        }
    }

    LOGDEBUG(LOG_ALWAYS, ("\nUndocumented Dib.Drv behaviour used\n"));

    return TRUE;
}

/******************************Public*Routine******************************\
* DIBSection specific calls
*
* History:
*  04-May-1994 -by-  Eric Kutter [erick]
* Wrote it.
\**************************************************************************/

ULONG cjBitmapBitsSize(CONST BITMAPINFO *pbmi)
{
// Check for PM-style DIB

    if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
    {
        LPBITMAPCOREINFO pbmci;
        pbmci = (LPBITMAPCOREINFO)pbmi;
        return(CJSCAN(pbmci->bmciHeader.bcWidth,pbmci->bmciHeader.bcPlanes,
                      pbmci->bmciHeader.bcBitCount) *
                      pbmci->bmciHeader.bcHeight);
    }

// not a core header

    if ((pbmi->bmiHeader.biCompression == BI_RGB) ||
        (pbmi->bmiHeader.biCompression == BI_BITFIELDS))
    {
        return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
                      pbmi->bmiHeader.biBitCount) *
               ABS(pbmi->bmiHeader.biHeight));
    }
    else
    {
        return(pbmi->bmiHeader.biSizeImage);
    }
}

ULONG FASTCALL WG32CreateDIBSection(PVDMFRAME pFrame)
{
    ULONG              ul = 0;
    STACKBMI32         bmi32;
    LPBITMAPINFO       lpbmi32;
    HBITMAP            hbm32;
    PVOID              pv16, pvBits, pvIntelBits;
    PVPVOID            vpbmi16;
    PVOID              pvBits32;
    DWORD              dwArg16;

    register PCREATEDIBSECTION16 parg16;

    GETARGPTR(pFrame, sizeof(CREATEDIBSECTION16), parg16);

    // this is performance hack so we don't generate extra code
    dwArg16 = FETCHDWORD(parg16->f4); // do it once here
    pv16 = (PVOID)GetPModeVDMPointer(dwArg16, sizeof(DWORD)); // aligned here!

    WOW32ASSERTMSG(((parg16->f5 == 0) && (parg16->f6 == 0)),
                   ("WOW:WG32CreateDIBSection, hSection/dwOffset non-null\n"));

    vpbmi16 = (PVPVOID)FETCHDWORD(parg16->f2);
    lpbmi32 = CopyBMI16ToBMI32(vpbmi16,
                               (LPBITMAPINFO)&bmi32,
                               FETCHWORD(parg16->f3));

    hbm32 = CreateDIBSection(HDC32(parg16->f1),
                             lpbmi32,
                             WORD32(parg16->f3),
                             &pvBits,
                             NULL,
                             0);

    if (hbm32 != 0)
    {
        PARM16          Parm16;
        PDIBSECTIONINFO pdi;
        ULONG           SelectorLimit;

        SelectorLimit = (ULONG)cjBitmapBitsSize(lpbmi32);
#ifndef i386
        if (!NT_SUCCESS(VdmAddVirtualMemory((ULONG)pvBits,
                                            SelectorLimit,
                                            (PULONG)&pvIntelBits))) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection VdmAddVirtualMemory failed\n"));
            goto cds_err;
        }

#else
        pvIntelBits = pvBits;
#endif

        // Create a selector array for the bits backed by pvIntelBits

        Parm16.WndProc.wParam = (WORD)-1;           // -1 => allocate selectors
        Parm16.WndProc.lParam = (LONG) pvIntelBits; // backing pointer
        Parm16.WndProc.wMsg = 0x10;                 // GA_NOCOMPACT
        Parm16.WndProc.hwnd = (WORD)((SelectorLimit+65535)/65536);// selector count

        CallBack16(RET_SETDIBSEL,
                   &Parm16,
                   0,
                   (PVPVOID)&pvBits32);

        // 16:16 pointer is still valid as call above makes no difference
        if (pv16 != NULL) {
            *(UNALIGNED PVOID*)pv16 = pvBits32;
        }

        if (pvBits32 == NULL) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection, Callback set_sel_for_dib failed\n"));
            goto cds_err;
        }

#ifndef i386 
        // okay, that was successful - map the descriptors properly

        if (!VdmAddDescriptorMapping(HIWORD(pvBits32),
                                    (USHORT) ((SelectorLimit+65535)/65536),
                                    (ULONG) pvIntelBits,
                                    (ULONG) pvBits)) {
            LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection VdmAddDescriptorMapping failed\n"));
            goto cds_err;
        }
#endif
        
        LOGDEBUG(LOG_ALWAYS, ("\nWOW:CreateDIBSection: [16:16 %x] [Intel %x] [Flat %x]\n", 
                             pvBits32, pvIntelBits, pvBits));

        ul = GETHBITMAP16(hbm32);

        // Add it to the list used for cleanup at DeleteObject time.

        if ((pdi = malloc_w (sizeof (DIBSECTIONINFO))) != NULL) {
            pdi->di_hbm         = (HBITMAP)(HAND16)hbm32;
            pdi->di_pv16        = pvBits32;
#ifndef i386
            pdi->di_newIntelDib = pvIntelBits;
#endif
            pdi->di_next        = pDibSectionInfoHead;
            pDibSectionInfoHead = pdi;

            // need to turn batching off since a DIBSECTION means the app can
            // also draw on the bitmap and we need synchronization.

            GdiSetBatchLimit(1);

            goto cds_ok;
        }
        else {
            // Failure, free the selector array

            Parm16.WndProc.wParam = (WORD)-1;            // -1 => allocate/free
            Parm16.WndProc.lParam = (LONG) pvBits32; // pointer
            Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT
            Parm16.WndProc.hwnd = 0;                     // 0 => free

            CallBack16(RET_SETDIBSEL,
                       &Parm16,
                       0,
                       (PVPVOID)&ul);
#ifndef i386
            VdmRemoveVirtualMemory((ULONG)pvIntelBits);
#endif

        }
    }
    else {
        LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection, CreateDibSection Failed\n"));
    }

cds_err:

    if (hbm32 != 0) {
        DeleteObject(hbm32);
    }
    LOGDEBUG(LOG_ALWAYS,("\nWOW::WG32CreateDibSection returning failure\n"));
    ul = 0;

cds_ok:
    WOW32APIWARN(ul, "CreateDIBSection");

    FREEMISCPTR(pv16);
    FREEARGPTR(parg16);

    return(ul);
}

ULONG FASTCALL WG32GetDIBColorTable(PVDMFRAME pFrame)
{
    ULONG              ul = 0;
    RGBQUAD *          prgb;

    register PGETDIBCOLORTABLE16 parg16;

    GETARGPTR(pFrame, sizeof(GETDIBCOLORTABLE16), parg16);
    GETMISCPTR(parg16->f4,prgb);

    ul = (ULONG)GetDIBColorTable(HDC32(parg16->f1),
                                 parg16->f2,
                                 parg16->f3,
                                 prgb);

    WOW32APIWARN(ul, "GetDIBColorTable");

    if (ul)
        FLUSHVDMPTR(parg16->f4,sizeof(RGBQUAD) * ul,prgb);

    FREEMISCPTR(prgb);
    FREEARGPTR(parg16);

    return(ul);
}

ULONG FASTCALL WG32SetDIBColorTable(PVDMFRAME pFrame)
{
    ULONG              ul = 0;
    RGBQUAD *          prgb;

    register PSETDIBCOLORTABLE16 parg16;

    GETARGPTR(pFrame, sizeof(SETDIBCOLORTABLE16), parg16);
    GETMISCPTR(parg16->f4,prgb);

    ul = (ULONG)SetDIBColorTable(HDC32(parg16->f1),
                                 parg16->f2,
                                 parg16->f3,
                                 prgb);

    WOW32APIWARN(ul, "SetDIBColorTable");

    FREEMISCPTR(prgb);
    FREEARGPTR(parg16);

    return(ul);
}


// DIBSection routines

BOOL W32CheckAndFreeDibSectionInfo (HBITMAP hbm)
{
    PDIBSECTIONINFO pdi = pDibSectionInfoHead,pdiLast=NULL;

    while (pdi) {
        if (pdi->di_hbm == hbm){

            PARM16 Parm16;
            ULONG  ulRet;

            // need to free the selector array for the memory

            Parm16.WndProc.wParam = (WORD)-1;            // selector, -1 == allocate/free
            Parm16.WndProc.lParam = (LONG) pdi->di_pv16; // pointer
            Parm16.WndProc.wMsg = 0x10; // GA_NOCOMPACT
            Parm16.WndProc.hwnd = 0;                     // selector count, 0 == free

            CallBack16(RET_SETDIBSEL,
                       &Parm16,
                       0,
                       (PVPVOID)&ulRet);
#ifndef i386
            VdmRemoveVirtualMemory((ULONG)pdi->di_newIntelDib);
#endif

            if (pdiLast == NULL)
                pDibSectionInfoHead = pdi->di_next;
            else
                pdiLast->di_next = pdi->di_next;

            // now delete the object

            DeleteObject (pdi->di_hbm);

            free_w(pdi);

            return TRUE;
        }
        pdiLast = pdi;
        pdi = pdi->di_next;
    }
    return FALSE;
}

