/*******************************************************************************
 *                                                                             *
 *  MODULE  : DIB.C                                                            *
 *                                                                             *
 *  DESCRIPTION : Routines for dealing with Device Independent Bitmaps.        *
 *                                                                             *
 *  FUNCTIONS   : OpenDIB()       - Opens DIB file and creates a memory DIB    *
 *                                                                             *
 *        WriteDIB()          - Writes a global handle in CF_DIB format        *
 *                  to a file.                                                 *
 *                                                                             *
 *        DibInfo()       - Retrieves the info. block associated               *
 *                  with a CF_DIB format memory block.                         *
 *                                                                             *
 *        CreateBIPalette()   - Creates a GDI palette given a pointer          *
 *                  to a BITMAPINFO structure.                                 *
 *                                                                             *
 *        CreateDibPalette()  - Creates a GDI palette given a HANDLE           *
 *                  to a BITMAPINFO structure.                                 *
 *                                                                             *
 *        ReadDibBitmapInfo() - Reads a file in DIB format and returns         *
 *                  a global handle to it's BITMAPINFO                         *
 *                                                                             *
 *        PaletteSize()       - Calculates the palette size in bytes           *
 *                  of given DIB                                               *
 *                                                                             *
 *        DibNumColors()      - Determines the number of colors in DIB         *
 *                                                                             *
 *        BitmapFromDib()     - Creates a DDB given a global handle to         *
 *                  a block in CF_DIB format.                                  *
 *                                                                             *
 *        DibFromBitmap()     - Creates a DIB repr. the DDB passed in.         *
 *                                                                             *
 *        DrawBitmap()        - Draws a bitmap at specified position           *
 *                  in the DC.                                                 *
 *                                                                             *
 *        DibBlt()        - Draws a bitmap in CIF_DIB format using             *
 *                  SetDIBitsToDevice()                                        *
 *                                                                             *
 *        StretchDibBlt()     - Draws a bitmap in CIF_DIB format using         *
 *                  StretchDIBits()                                            *
 *                                                                             *
 *        lread()         - Private routine to read more than 64k              *
 *                                                                             *
 *        lwrite()        - Private routine to write more than 64k             *
 *                                                                             *
 *******************************************************************************/

#include <windows.h>
#include <stdlib.h>

#include "dib.h"
HCURSOR hcurSave;

/****************************************************************************
 *                                                                          *
 *  FUNCTION   :OpenDIB(LPWSTR szFile)                                      *
 *                                                                          *
 *  PURPOSE    :Open a DIB file and create a MEMORY DIB, a memory handle    *
 *      containing BITMAPINFO, palette data and the bits.                   *
 *                                                                          *
 *  RETURNS    :A handle to the DIB.                                        *
 *                                                                          *
 ****************************************************************************/
HANDLE OpenDIB (szFile)
LPWSTR szFile;
{
    unsigned        fh;
    BITMAPINFOHEADER    bi;
    LPBITMAPINFOHEADER  lpbi;
    DWORD       dwLen = 0;
    DWORD       dwBits;
    HANDLE      hdib;
    HANDLE      h;
    OFSTRUCT        of;
    char sz[256];

    /* Open the file and read the DIB information */
    wcstombs(sz,szFile,256);
    fh = OpenFile(sz, &of, OF_READ);
    if (fh == -1)
        return NULL;

    hdib = ReadDibBitmapInfo(fh);
    if (!hdib)
        return NULL;
    DibInfo(hdib,&bi);

    /* Calculate the memory needed to hold the DIB */
    dwBits = bi.biSizeImage;
    dwLen  = bi.biSize + (DWORD)PaletteSize (&bi) + dwBits;

    /* Try to increase the size of the bitmap info. buffer to hold the DIB */
    h = GlobalReAlloc(hdib, dwLen, GHND);
    if (!h)
    {
        GlobalFree(hdib);
        hdib = NULL;
    }
    else
        hdib = h;

    /* Read in the bits */
    if (hdib)
    {
        lpbi = (VOID FAR *)GlobalLock(hdib);
        lread(fh, (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi), dwBits);
        GlobalUnlock(hdib);
    }
    _lclose(fh);

    return hdib;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : WriteDIB(LPWSTR szFile,HANDLE hdib)                        *
 *                                                                          *
 *  PURPOSE    : Write a global handle in CF_DIB format to a file.          *
 *                                                                          *
 *  RETURNS    : TRUE  - if successful.                                     *
 *       FALSE - otherwise                                                  *
 *                                                                          *
 ****************************************************************************/
BOOL WriteDIB (szFile, hdib)
LPWSTR szFile;
HANDLE hdib;
{
    BITMAPFILEHEADER    hdr;
    LPBITMAPINFOHEADER  lpbi;
    int                 fh;
    OFSTRUCT            of;
    char sz[256];

    if (!hdib)
        return FALSE;

    wcstombs(sz,szFile,256);
    fh = OpenFile (sz, &of, OF_CREATE|OF_READWRITE);
    if (fh == -1)
        return FALSE;

    lpbi = (VOID FAR *)GlobalLock (hdib);

    /* Fill in the fields of the file header */
    hdr.bfType      = BFT_BITMAP;
    hdr.bfSize      = GlobalSize (hdib) + sizeof (BITMAPFILEHEADER);
    hdr.bfReserved1 = 0;
    hdr.bfReserved2 = 0;
    hdr.bfOffBits   = (DWORD)sizeof(BITMAPFILEHEADER) + lpbi->biSize +
        PaletteSize(lpbi);

    /* Write the file header */
    _lwrite (fh, (LPSTR)&hdr, sizeof (BITMAPFILEHEADER));

    /* Write the DIB header and the bits */
    lwrite (fh, (LPSTR)lpbi, GlobalSize (hdib));

    GlobalUnlock (hdib);
    _lclose (fh);
    return TRUE;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DibInfo(HANDLE hbi,LPBITMAPINFOHEADER lpbi)                *
 *                                                                          *
 *  PURPOSE    : Retrieves the DIB info associated with a CF_DIB            *
 *       format memory block.                                               *
 *                                                                          *
 *  RETURNS    : TRUE  - if successful.                                     *
 *       FALSE - otherwise                                                  *
 *                                                                          *
 ****************************************************************************/
BOOL DibInfo (hbi, lpbi)
HANDLE hbi;
LPBITMAPINFOHEADER lpbi;
{
    if (hbi)
    {
        *lpbi = *(LPBITMAPINFOHEADER)GlobalLock (hbi);

        /* fill in the default fields */
        if (lpbi->biSize != sizeof (BITMAPCOREHEADER))
        {
            if (lpbi->biSizeImage == 0L)
                lpbi->biSizeImage =
                    WIDTHBYTES(lpbi->biWidth*lpbi->biBitCount) * lpbi->biHeight;

            if (lpbi->biClrUsed == 0L)
                lpbi->biClrUsed = DibNumColors (lpbi);
        }
        GlobalUnlock (hbi);
        return TRUE;
    }
    return FALSE;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : CreateBIPalette(LPBITMAPINFOHEADER lpbi)                   *
 *                                                                          *
 *  PURPOSE    : Given a Pointer to a BITMAPINFO struct will create a       *
 *       a GDI palette object from the color table.                         *
 *                                                                          *
 *  RETURNS    : A handle to the palette.                                   *
 *                                                                          *
 ****************************************************************************/
HPALETTE CreateBIPalette (lpbi)
LPBITMAPINFOHEADER lpbi;
{
    LOGPALETTE  *pPal;
    HPALETTE    hpal = NULL;
    WORD        nNumColors;
    BYTE        red;
    BYTE        green;
    BYTE        blue;
    int         i;
    RGBQUAD FAR *pRgb;

    if (!lpbi)
        return NULL;

    if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
        return NULL;

    /* Get a pointer to the color table and the number of colors in it */
    pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->biSize);
    nNumColors = DibNumColors(lpbi);

    if (nNumColors)
    {
        /* Allocate for the logical palette structure */
        pPal = (LOGPALETTE*)LocalAlloc(LPTR,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
        if (!pPal)
            return NULL;

        pPal->palNumEntries = nNumColors;
        pPal->palVersion    = PALVERSION;

        /* Fill in the palette entries from the DIB color table and
         * create a logical color palette.
         */
        for (i = 0; i < nNumColors; i++)
        {
            pPal->palPalEntry[i].peRed   = pRgb[i].rgbRed;
            pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
            pPal->palPalEntry[i].peBlue  = pRgb[i].rgbBlue;
            pPal->palPalEntry[i].peFlags = (BYTE)0;
        }
        hpal = CreatePalette(pPal);
        LocalFree((HANDLE)pPal);
    }
    else if (lpbi->biBitCount == 24)
    {
        /* A 24 bitcount DIB has no color table entries so, set the number of
         * to the maximum value (256).
         */
        nNumColors = MAXPALETTE;
        pPal = (LOGPALETTE*)LocalAlloc(LPTR,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
        if (!pPal)
            return NULL;

        pPal->palNumEntries = nNumColors;
        pPal->palVersion    = PALVERSION;

        red = green = blue = 0;

        /* Generate 256 (= 8*8*4) RGB combinations to fill the palette
         * entries.
         */
        for (i = 0; i < pPal->palNumEntries; i++)
        {
            pPal->palPalEntry[i].peRed   = red;
            pPal->palPalEntry[i].peGreen = green;
            pPal->palPalEntry[i].peBlue  = blue;
            pPal->palPalEntry[i].peFlags = (BYTE)0;

            if (!(red += 32))
                if (!(green += 32))
                    blue += 64;
        }
        hpal = CreatePalette(pPal);
        LocalFree((HANDLE)pPal);
    }
    return hpal;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : CreateDibPalette(HANDLE hbi)                               *
 *                                                                          *
 *  PURPOSE    : Given a Global HANDLE to a BITMAPINFO Struct               *
 *       will create a GDI palette object from the color table.             *
 *       (BITMAPINFOHEADER format DIBs only)                                *
 *                                                                          *
 *  RETURNS    : A handle to the palette.                                   *
 *                                                                          *
 ****************************************************************************/
HPALETTE CreateDibPalette (hbi)
HANDLE hbi;
{
    HPALETTE hpal;

    if (!hbi)
        return NULL;
    hpal = CreateBIPalette((LPBITMAPINFOHEADER)GlobalLock(hbi));
    GlobalUnlock(hbi);
    return hpal;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : ReadDibBitmapInfo(int fh)                                  *
 *                                                                          *
 *  PURPOSE    : Will read a file in DIB format and return a global HANDLE  *
 *       to it's BITMAPINFO.  This function will work with both             *
 *       "old" (BITMAPCOREHEADER) and "new" (BITMAPINFOHEADER)              *
 *       bitmap formats, but will always return a "new" BITMAPINFO          *
 *                                                                          *
 *  RETURNS    : A handle to the BITMAPINFO of the DIB in the file.         *
 *                                                                          *
 ****************************************************************************/
HANDLE ReadDibBitmapInfo (fh)
int fh;
{
    DWORD     off;
    HANDLE    hbi = NULL;
    int       size;
    int       i;
    WORD      nNumColors;

    RGBQUAD FAR       *pRgb;
    BITMAPINFOHEADER   bi;
    BITMAPCOREHEADER   bc;
    LPBITMAPINFOHEADER lpbi;
    BITMAPFILEHEADER   bf;
    DWORD          dwWidth = 0;
    DWORD          dwHeight = 0;
    WORD           wPlanes, wBitCount;

    if (fh == -1)
        return NULL;

    /* Reset file pointer and read file header */
    off = _llseek(fh, 0L, SEEK_CUR);
    if (sizeof (bf) != _lread (fh, (LPSTR)&bf, sizeof (bf)))
        return FALSE;

    /* Do we have a RC HEADER? */
    if (!ISDIB (bf.bfType))
    {
        bf.bfOffBits = 0L;
        _llseek (fh, off, SEEK_SET);
    }
    if (sizeof (bi) != _lread (fh, (LPSTR)&bi, sizeof(bi)))
        return FALSE;

    nNumColors = DibNumColors (&bi);

    /* Check the nature (BITMAPINFO or BITMAPCORE) of the info. block
     * and extract the field information accordingly. If a BITMAPCOREHEADER,
     * transfer it's field information to a BITMAPINFOHEADER-style block
     */
    switch (size = (int)bi.biSize)
    {
    case sizeof (BITMAPINFOHEADER):
        break;

    case sizeof (BITMAPCOREHEADER):
        bc = *(BITMAPCOREHEADER*)&bi;
        dwWidth   = (DWORD)bc.bcWidth;
        dwHeight  = (DWORD)bc.bcHeight;
        wPlanes   = bc.bcPlanes;
        wBitCount = bc.bcBitCount;
        bi.biSize           = sizeof(BITMAPINFOHEADER);
        bi.biWidth          = dwWidth;
        bi.biHeight         = dwHeight;
        bi.biPlanes         = wPlanes;
        bi.biBitCount       = wBitCount;
        bi.biCompression    = BI_RGB;
        bi.biSizeImage      = 0;
        bi.biXPelsPerMeter  = 0;
        bi.biYPelsPerMeter  = 0;
        bi.biClrUsed        = nNumColors;
        bi.biClrImportant   = nNumColors;
        _llseek (fh, (LONG)sizeof (BITMAPCOREHEADER) - sizeof (BITMAPINFOHEADER), SEEK_CUR);
        break;

    default:
        /* Not a DIB! */
        return NULL;
    }

    /*  Fill in some default values if they are zero */
    if (bi.biSizeImage == 0)
    {
        bi.biSizeImage = WIDTHBYTES ((DWORD)bi.biWidth * bi.biBitCount)
            * bi.biHeight;
    }
    if (bi.biClrUsed == 0)
        bi.biClrUsed = DibNumColors(&bi);

    /* Allocate for the BITMAPINFO structure and the color table. */
    hbi = GlobalAlloc (GHND, (LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
    if (!hbi)
        return NULL;
    lpbi = (VOID FAR *)GlobalLock (hbi);
    *lpbi = bi;

    /* Get a pointer to the color table */
    pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + bi.biSize);
    if (nNumColors)
    {
        if (size == sizeof(BITMAPCOREHEADER))
        {
            /* Convert a old color table (3 byte RGBTRIPLEs) to a new
             * color table (4 byte RGBQUADs)
             */
            _lread (fh, (LPSTR)pRgb, nNumColors * sizeof(RGBTRIPLE));

            for (i = nNumColors - 1; i >= 0; i--)
            {
                RGBQUAD rgb;

                rgb.rgbRed  = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed;
                rgb.rgbBlue = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue;
                rgb.rgbGreen    = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen;
                rgb.rgbReserved = (BYTE)0;

                pRgb[i] = rgb;
            }
        }
        else
            _lread(fh,(LPSTR)pRgb,nNumColors * sizeof(RGBQUAD));
    }

    if (bf.bfOffBits != 0L)
        _llseek(fh,off + bf.bfOffBits,SEEK_SET);

    GlobalUnlock(hbi);
    return hbi;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   :  PaletteSize(VOID FAR * pv)                                *
 *                                                                          *
 *  PURPOSE    :  Calculates the palette size in bytes. If the info. block  *
 *        is of the BITMAPCOREHEADER type, the number of colors is          *
 *        multiplied by 3 to give the palette size, otherwise the           *
 *        number of colors is multiplied by 4.                              *
 *                                                                          *
 *  RETURNS    :  Palette size in number of bytes.                          *
 *                                                                          *
 ****************************************************************************/
WORD PaletteSize (pv)
VOID FAR * pv;
{
    LPBITMAPINFOHEADER lpbi;
    WORD NumColors;

    lpbi      = (LPBITMAPINFOHEADER)pv;
    NumColors = DibNumColors(lpbi);

    if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
        return NumColors * sizeof(RGBTRIPLE);
    else
        return NumColors * sizeof(RGBQUAD);
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DibNumColors(VOID FAR * pv)                                *
 *                                                                          *
 *  PURPOSE    : Determines the number of colors in the DIB by looking at   *
 *       the BitCount filed in the info block.                              *
 *                                                                          *
 *  RETURNS    : The number of colors in the DIB.                           *
 *                                                                          *
 ****************************************************************************/
WORD DibNumColors (pv)
VOID FAR * pv;
{
    int bits;
    LPBITMAPINFOHEADER lpbi;
    LPBITMAPCOREHEADER lpbc;

    lpbi = ((LPBITMAPINFOHEADER)pv);
    lpbc = ((LPBITMAPCOREHEADER)pv);

    /*  With the BITMAPINFO format headers, the size of the palette
     *  is in biClrUsed, whereas in the BITMAPCORE - style headers, it
     *  is dependent on the bits per pixel ( = 2 raised to the power of
     *  bits/pixel).
     */
    if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
    {
        if (lpbi->biClrUsed != 0)
            return (WORD)lpbi->biClrUsed;
        bits = lpbi->biBitCount;
    }
    else
        bits = lpbc->bcBitCount;

    switch (bits)
    {
    case 1:
        return 2;
    case 4:
        return 16;
    case 8:
        return 256;
    default:
        /* A 24 bitcount DIB has no color table */
        return 0;
    }
}
/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DibFromBitmap()                                            *
 *                                                                          *
 *  PURPOSE    : Will create a global memory block in DIB format that       *
 *       represents the Device-dependent bitmap (DDB) passed in.            *
 *                                                                          *
 *  RETURNS    : A handle to the DIB                                        *
 *                                                                          *
 ****************************************************************************/
HANDLE DibFromBitmap (hbm, biStyle, biBits, hpal)
HBITMAP      hbm;
DWORD        biStyle;
WORD         biBits;
HPALETTE     hpal;
{
    BITMAP bm;
    BITMAPINFOHEADER bi;
    BITMAPINFOHEADER FAR *lpbi;
    DWORD dwLen;
    HANDLE hdib;
    HANDLE h;
    HDC hdc;

    if (!hbm)
        return NULL;

    if (hpal == NULL)
        hpal = GetStockObject(DEFAULT_PALETTE);

    GetObject(hbm,sizeof(bm),(LPSTR)&bm);

    if (biBits == 0)
        biBits =  bm.bmPlanes * bm.bmBitsPixel;

    bi.biSize           = sizeof(BITMAPINFOHEADER);
    bi.biWidth          = bm.bmWidth;
    bi.biHeight         = bm.bmHeight;
    bi.biPlanes         = 1;
    bi.biBitCount       = biBits;
    bi.biCompression    = biStyle;
    bi.biSizeImage      = 0;
    bi.biXPelsPerMeter  = 0;
    bi.biYPelsPerMeter  = 0;
    bi.biClrUsed        = 0;
    bi.biClrImportant   = 0;

    dwLen  = bi.biSize + PaletteSize(&bi);

    hdc = GetDC(NULL);
    hpal = SelectPalette(hdc,hpal,FALSE);
    RealizePalette(hdc);

    hdib = GlobalAlloc(GHND,dwLen);

    if (!hdib)
    {
        SelectPalette(hdc,hpal,FALSE);
        ReleaseDC(NULL,hdc);
        return NULL;
    }

    lpbi = (VOID FAR *)GlobalLock(hdib);

    *lpbi = bi;

    /*  call GetDIBits with a NULL lpBits param, so it will calculate the
     *  biSizeImage field for us
     */
    GetDIBits(hdc, hbm, 0, (WORD)bi.biHeight,
    NULL, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);

    bi = *lpbi;
    GlobalUnlock(hdib);

    /* If the driver did not fill in the biSizeImage field, make one up */
    if (bi.biSizeImage == 0)
    {
        bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;

        if (biStyle != BI_RGB)
            bi.biSizeImage = (bi.biSizeImage * 3) / 2;
    }

    /*  realloc the buffer big enough to hold all the bits */
    dwLen = bi.biSize + PaletteSize(&bi) + bi.biSizeImage;
    if (h = GlobalReAlloc(hdib,dwLen,0))
        hdib = h;
    else
    {
        GlobalFree(hdib);
        hdib = NULL;

        SelectPalette(hdc,hpal,FALSE);
        ReleaseDC(NULL,hdc);
        return hdib;
    }

    /*  call GetDIBits with a NON-NULL lpBits param, and actualy get the
     *  bits this time
     */
    lpbi = (VOID FAR *)GlobalLock(hdib);

    if (GetDIBits( hdc,
        hbm,
        0,
        (WORD)bi.biHeight,
        (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi),
        (LPBITMAPINFO)lpbi, DIB_RGB_COLORS) == 0)
    {
        GlobalUnlock(hdib);
        hdib = NULL;
        SelectPalette(hdc,hpal,FALSE);
        ReleaseDC(NULL,hdc);
        return NULL;
    }

    bi = *lpbi;
    GlobalUnlock(hdib);

    SelectPalette(hdc,hpal,FALSE);
    ReleaseDC(NULL,hdc);
    return hdib;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : BitmapFromDib(HANDLE hdib, HPALETTE hpal)                  *
 *                                                                          *
 *  PURPOSE    : Will create a DDB (Device Dependent Bitmap) given a global *
 *       handle to a memory block in CF_DIB format                          *
 *                                                                          *
 *  RETURNS    : A handle to the DDB.                                       *
 *                                                                          *
 ****************************************************************************/
HBITMAP BitmapFromDib (hdib, hpal)
HANDLE     hdib;
HPALETTE   hpal;
{
    LPBITMAPINFOHEADER  lpbi;
    HPALETTE    hpalT;
    HDC         hdc;
    HBITMAP     hbm;

    StartWait();

    if (!hdib)
        return NULL;

    lpbi = (VOID FAR *)GlobalLock(hdib);

    if (!lpbi)
        return NULL;

    hdc = GetDC(NULL);

    if (hpal)
    {
        hpalT = SelectPalette(hdc,hpal,FALSE);
        RealizePalette(hdc);     // GDI Bug...????
    }

    hbm = CreateDIBitmap(hdc,
        (LPBITMAPINFOHEADER)lpbi,
        (LONG)CBM_INIT,
        (LPSTR)lpbi + lpbi->biSize + PaletteSize(lpbi),
        (LPBITMAPINFO)lpbi,
        DIB_RGB_COLORS );

    if (hpal)
        SelectPalette(hdc,hpalT,FALSE);

    ReleaseDC(NULL,hdc);
    GlobalUnlock(hdib);

    EndWait();

    return hbm;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DrawBitmap(HDC hdc, int x, int y, HBITMAP hbm, DWORD rop)  *
 *                                                                          *
 *  PURPOSE    : Draws bitmap <hbm> at the specifed position in DC <hdc>    *
 *                                                                          *
 *  RETURNS    : Return value of BitBlt()                                   *
 *                                                                          *
 ****************************************************************************/
BOOL DrawBitmap (hdc, x, y, hbm, rop)
HDC    hdc;
int    x, y;
HBITMAP    hbm;
DWORD      rop;
{
    HDC       hdcBits;
    BITMAP    bm;
    BOOL      f;

    if (!hdc || !hbm)
        return FALSE;

    hdcBits = CreateCompatibleDC(hdc);
    GetObject(hbm,sizeof(BITMAP),(LPSTR)&bm);
    SelectObject(hdcBits,hbm);
    f = BitBlt(hdc,0,0,bm.bmWidth,bm.bmHeight,hdcBits,0,0,rop);
    DeleteDC(hdcBits);

    return f;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : DibBlt( HDC hdc,                                           *
 *           int x0, int y0,                                                *
 *           int dx, int dy,                                                *
 *           HANDLE hdib,                                                   *
 *           int x1, int y1,                                                *
 *           LONG rop)                                                      *
 *                                                                          *
 *  PURPOSE    : Draws a bitmap in CF_DIB format, using SetDIBits to device.*
 *       taking the same parameters as BitBlt().                            *
 *                                                                          *
 *  RETURNS    : TRUE  - if function succeeds.                              *
 *       FALSE - otherwise.                                                 *
 *                                                                          *
 ****************************************************************************/
BOOL DibBlt (hdc, x0, y0, dx, dy, hdib, x1, y1, rop)
HDC    hdc;
int    x0, y0, dx, dy;
HANDLE     hdib;
int    x1, y1;
LONG       rop;
{
    LPBITMAPINFOHEADER   lpbi;
    LPSTR        pBuf;

    if (!hdib)
        return PatBlt(hdc,x0,y0,dx,dy,rop);

    lpbi = (VOID FAR *)GlobalLock(hdib);

    if (!lpbi)
        return FALSE;

    pBuf = (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi);
    SetDIBitsToDevice (hdc, x0, y0, dx, dy,
               x1,y1,
               x1,
               dy,
               pBuf, (LPBITMAPINFO)lpbi,
               DIB_RGB_COLORS );

    GlobalUnlock(hdib);
    return TRUE;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : StretchDibBlt( HDC hdc,                                    *
 *              int x, int y,                                               *
 *              int dx, int dy,                                             *
 *              HANDLE hdib,                                                *
 *              int x0, int y0,                                             *
 *              int dx0, int dy0,                                           *
 *              LONG rop)                                                   *
 *                                                                          *
 *  PURPOSE    : Draws a bitmap in CF_DIB format, using StretchDIBits()     *
 *       taking the same parameters as StretchBlt().                        *
 *                                                                          *
 *  RETURNS    : TRUE  - if function succeeds.                              *
 *       FALSE - otherwise.                                                 *
 *                                                                          *
 ****************************************************************************/
BOOL StretchDibBlt (hdc, x, y, dx, dy, hdib, x0, y0, dx0, dy0, rop)
HDC hdc;
int x, y;
int dx, dy;
HANDLE hdib;
int x0, y0;
int dx0, dy0;
LONG rop;

{
    LPBITMAPINFOHEADER lpbi;
    LPSTR    pBuf;
    BOOL     f;

    if (!hdib)
        return PatBlt(hdc,x,y,dx,dy,rop);

    lpbi = (VOID FAR *)GlobalLock(hdib);

    if (!lpbi)
        return FALSE;

    pBuf = (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi);

    f = StretchDIBits ( hdc,
            x, y,
            dx, dy,
            x0, y0,
            dx0, dy0,
            pBuf, (LPBITMAPINFO)lpbi,
            DIB_RGB_COLORS,
            rop);

    GlobalUnlock(hdib);
    return f;
}

 /************* PRIVATE ROUTINES TO READ/WRITE MORE THAN 64K ***************/
/****************************************************************************
 *                                                                          *
 *  FUNCTION   : lread(int fh, VOID FAR *pv, DWORD ul)                      *
 *                                                                          *
 *  PURPOSE    : Reads data in steps of 32k till all the data has been read.*
 *                                                                          *
 *  RETURNS    : 0 - If read did not proceed correctly.                     *
 *       number of bytes read otherwise.                                    *
 *                                                                          *
 ****************************************************************************/
DWORD PASCAL lread (fh, pv, ul)
int       fh;
VOID far      *pv;
DWORD         ul;
{
    DWORD     ulT = ul;
    BYTE      *hp = pv;

    while (ul > (DWORD)MAXREAD)
    {
        if (_lread(fh, (LPSTR)hp, (WORD)MAXREAD) != MAXREAD)
            return 0;
        ul -= MAXREAD;
        hp += MAXREAD;
    }
    if (_lread(fh, (LPSTR)hp, (WORD)ul) != (WORD)ul)
        return 0;
    return ulT;
}

/****************************************************************************
 *                                                                          *
 *  FUNCTION   : lwrite(int fh, VOID FAR *pv, DWORD ul)                     *
 *                                                                          *
 *  PURPOSE    : Writes data in steps of 32k till all the data is written.  *
 *                                                                          *
 *  RETURNS    : 0 - If write did not proceed correctly.                    *
 *       number of bytes written otherwise.                                 *
 *                                                                          *
 ****************************************************************************/
DWORD PASCAL lwrite (fh, pv, ul)
int      fh;
VOID FAR     *pv;
DWORD        ul;
{
    DWORD     ulT = ul;
    BYTE      *hp = pv;

    while (ul > MAXREAD)
    {
        if (_lwrite(fh, (LPSTR)hp, (WORD)MAXREAD) != MAXREAD)
            return 0;
        ul -= MAXREAD;
        hp += MAXREAD;
    }
    if (_lwrite(fh, (LPSTR)hp, (WORD)ul) != (WORD)ul)
        return 0;
    return ulT;
}

