
/***************************************************************************
**
**    $Header:   D:/ECB2S/SRC/LOG/DIBAPI.CPP   1.2.1.5   17 Apr 1997 15:48:00   ZJRD  $
**
**    $Log:   D:/ECB2S/SRC/LOG/DIBAPI.CPP  $
** 
**    Rev 1.2.1.5   17 Apr 1997 15:48:00   ZJRD
** No change.
** 
**    Rev 1.2.1.4   16 Apr 1997 10:19:16   ZJRD
** No change.
** 
**    Rev 1.2.1.3   10 Apr 1997 15:30:42   ZJRD
** 2.09F
** 
**    Rev 1.2.1.1   03 Apr 1997 15:11:38   ZJRD
** No change.
** 
**    Rev 1.2.1.0   28 Mar 1997 10:16:38   ZJRD
** easy pack sld 2.09d
** 
**    Rev 1.1   19 Mar 1997 11:27:46   ZJRD
** No change.
** 
**    Rev 1.0   12 Mar 1997 14:45:44   ZJRD
** Initial revision.
** 
**    Rev 1.7.1.0.1.2   09 Dec 1996 10:14:16   ZJRD
** EasyPack/SLD Version 2.0P
** 
**    Rev 1.7.1.0.1.0   11 Nov 1996 12:57:32   ZJRD
** EasyPack/SLD Version 2.01
** 
**    Rev 1.7.1.4   09 Sep 1996 13:13:40   ZJRD
** No change.
** 
**    Rev 1.7.1.3   05 Sep 1996 11:25:12   ZJRD
** No change.
** 
**    Rev 1.7.1.2   02 Sep 1996 09:52:20   ZJRD
** No change.
** 
**    Rev 1.7.1.1   28 Aug 1996 15:44:46   ZJRD
** No change.
** 
**    Rev 1.7.1.0   12 Aug 1996 10:50:00   ZJRD
** EasyPack/SLD Version 1.98
** 
**    Rev 1.5   05 Jun 1996 14:52:10   ZJRD
** No change.
** 
**    Rev 1.4   29 May 1996 09:28:16   ZJRD
** No change.
** 
**    Rev 1.3   16 May 1996 09:08:38   ZJRD
** No change.
** 
**    Rev 1.2   10 May 1996 09:08:06   ZJRD
** No change.
** 
**    Rev 1.1   02 May 1996 10:25:36   ZJRD
** EasyPack/SLD Version 1.92
** 
**    Rev 1.31   18 Apr 1996 13:00:18   Shirley
** No change.
** 
**    Rev 1.30   12 Apr 1996 10:35:36   Shirley
** EasyPack/SLD Version 1.90
** 
**    Rev 1.28   15 Feb 1996 08:51:00   Shirley
** No change.
** 
**    Rev 1.27   12 Feb 1996 14:05:42   Shirley
** No change.
** 
**    Rev 1.26   06 Feb 1996 15:32:14   Shirley
** No change.
** 
**    Rev 1.25   06 Feb 1996 13:46:28   Shirley
** No change.
** 
**    Rev 1.24   01 Feb 1996 10:20:00   Shirley
** No change.
** 
**    Rev 1.23   26 Jan 1996 09:16:52   Shirley
** No change.
** 
**    Rev 1.22   25 Jan 1996 13:16:46   Shirley
** No change.
** 
**    Rev 1.21   24 Jan 1996 10:34:40   Shirley
** No change.
** 
**    Rev 1.20   23 Jan 1996 11:25:28   Shirley
** No change.
** 
**    Rev 1.19   18 Jan 1996 10:07:34   Shirley
** No change.
** 
**    Rev 1.18   15 Jan 1996 16:16:26   Shirley
** No change.
** 
**    Rev 1.17   04 Jan 1996 11:08:34   Shirley
** No change.
** 
**    Rev 1.16   30 Nov 1995 09:09:08   Shirley
** No change.
** 
**    Rev 1.15   28 Nov 1995 15:31:54   Shirley
** No change.
** 
**    Rev 1.14   21 Nov 1995 11:18:46   Shirley
** No change.
** 
**    Rev 1.13   13 Nov 1995 09:27:32   Shirley
** No change.
** 
**    Rev 1.12   12 Nov 1995 11:31:04   Shirley
** No change.
** 
**    Rev 1.11   08 Nov 1995 16:28:50   Shirley
** No change.
** 
**    Rev 1.10   08 Nov 1995 12:45:18   Shirley
** No change.
** 
**    Rev 1.9   02 Nov 1995 10:05:38   Shirley
** No change.
** 
**    Rev 1.8   27 Oct 1995 16:47:10   Shirley
** No change.
** 
**    Rev 1.7   27 Oct 1995 13:45:00   Shirley
** No change.
** 
**    Rev 1.6   25 Oct 1995 14:26:22   Shirley
** No change.
** 
**    Rev 1.5   18 Oct 1995 14:49:16   Shirley
** No change.
** 
**    Rev 1.4   13 Oct 1995 13:19:24   Shirley
** No change.
** 
**    Rev 1.3   29 Sep 1995 09:52:52   Shirley
** No change.
** 
**    Rev 1.2   20 Sep 1995 10:52:42   Shirley
** No change.
** 
**    Rev 1.1   15 Sep 1995 09:44:48   Shirley
** No change.
** 
**    Rev 1.0   07 Sep 1995 09:53:26   Shirley
** Initial revision.
**
****************************************************************************/

/////////////////////////////////////////////////////////////////////////////
//
//  File name:  DIBAPI.CPP
//
//  Description:The implement file for the DIB APIs:
//
//      PaintDIB()          - Painting routine for a DIB
//      CreateDIBPalette()  - Creates a palette from a DIB
//      FindDIBBits()       - Returns a pointer to the DIB bits
//      DIBWidth()          - Gets the width of the DIB
//      DIBHeight()         - Gets the height of the DIB
//      PaletteSize()       - Gets the size required to store the DIB's palette
//      DIBNumColors()      - Calculates the number of colors
//                            in the DIB's color table
//      CopyHandle()        - Makes a copy of the given global memory block
//      SaveDIB()           - Saves the specified dib in a file
//      ReadDIBFile()       - Loads a DIB from a file
//
//  Author:     Roger Zhang
//
//  Date:       08/18/95
//
//  Modification:
//
//      1. 08/18/95, Initial version 
//
//
//  Copyright (C) 1995 Microtek International. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <math.h>
#include <io.h>
#include <direct.h>
#include <errno.h>
#include "dibapi.h"

// Dib Header Marker - used in writing DIBs to files
#define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B')

/////////////////////////////////////////////////////////////////////////////
//
//  Name:   PaintDIB()
//
//  Description:Painting routine for a DIB.  Calls StretchDIBits() or
//      SetDIBitsToDevice() to paint the DIB.  The DIB is
//      output to the specified DC, at the coordinates given
//      in lpDCRect.  The area of the DIB to be output is
//      given by lpDIBRect.
//
//  Input:  
//      HDC hDC          - DC to do output to
//
//      LPRECT lpDCRect  - rectangle on DC to do output to
//
//      HDIB hDIB        - handle to global memory with a DIB spec
//                            in it followed by the DIB bits
//
//      LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect
//
//      CPalette* pPal   - pointer to CPalette containing DIB's palette
//
//
//  Output: None
//
//  Return: TRUE if DIB was drawn, FALSE otherwise
//
/////////////////////////////////////////////////////////////////////////////

BOOL WINAPI PaintDIB(HDC     hDC,
                    LPRECT  lpDCRect,
                    HDIB    hDIB,
                    LPRECT  lpDIBRect,
                    CPalette* pPal)
{
    LPSTR    lpDIBHdr;            // Pointer to BITMAPINFOHEADER
    LPSTR    lpDIBBits;           // Pointer to DIB bits
    BOOL     bSuccess=FALSE;      // Success/fail flag
    HPALETTE hPal=NULL;           // Our DIB's palette
    HPALETTE hOldPal=NULL;        // Previous palette

    /* Check for valid DIB handle */
    if (hDIB == NULL)
        return FALSE;

    /* Lock down the DIB, and get a pointer to the beginning of the bit
     *  buffer
     */
    lpDIBHdr  = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
    lpDIBBits = ::FindDIBBits(lpDIBHdr);

    // Get the DIB's palette, then select it into DC
    if (pPal != NULL)
    {
        hPal = (HPALETTE) pPal->m_hObject;

        // Select as background since we have
        // already realized in forground if needed
        hOldPal = ::SelectPalette(hDC, hPal, TRUE);
    }

    /* Make sure to use the stretching mode best for color pictures */
    ::SetStretchBltMode(hDC, COLORONCOLOR);

    /* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */
    if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDIBRect)) &&
       (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
        bSuccess = ::SetDIBitsToDevice(hDC,                    // hDC
                                   lpDCRect->left,             // DestX
                                   lpDCRect->top,              // DestY
                                   RECTWIDTH(lpDCRect),        // nDestWidth
                                   RECTHEIGHT(lpDCRect),       // nDestHeight
                                   lpDIBRect->left,            // SrcX
                                   (int)DIBHeight(lpDIBHdr) -
                                      lpDIBRect->top -
                                      RECTHEIGHT(lpDIBRect),   // SrcY
                                   0,                          // nStartScan
                                   (WORD)DIBHeight(lpDIBHdr),  // nNumScans
                                   lpDIBBits,                  // lpBits
                                   (LPBITMAPINFO)lpDIBHdr,     // lpBitsInfo
                                   DIB_RGB_COLORS);            // wUsage
   else
      bSuccess = ::StretchDIBits(hDC,                          // hDC
                               lpDCRect->left,                 // DestX
                               lpDCRect->top,                  // DestY
                               RECTWIDTH(lpDCRect),            // nDestWidth
                               RECTHEIGHT(lpDCRect),           // nDestHeight
                               lpDIBRect->left,                // SrcX
                               lpDIBRect->top,                 // SrcY
                               RECTWIDTH(lpDIBRect),           // wSrcWidth
                               RECTHEIGHT(lpDIBRect),          // wSrcHeight
                               lpDIBBits,                      // lpBits
                               (LPBITMAPINFO)lpDIBHdr,         // lpBitsInfo
                               DIB_RGB_COLORS,                 // wUsage
                               SRCCOPY);                       // dwROP

   ::GlobalUnlock((HGLOBAL) hDIB);

    /* Reselect old palette */
    if (hOldPal != NULL)
    {
        ::SelectPalette(hDC, hOldPal, TRUE);
    }

   return bSuccess;
}

/////////////////////////////////////////////////////////////////////////////
//
//  Name:   CreateDIBPalette()
//
//  Description: This function creates a palette from a DIB by allocating 
//      memory for the logical palette, reading and storing the colors from 
//      the DIB's color table into the logical palette, creating a palette 
//      from this logical palette, and then returning the palette's handle. 
//      This allows the DIB to be displayed using the best possible colors 
//      (important for DIBs with 256 or more colors).
//
//  Input:  
//      HDIB hDIB        - specifies the DIB
//
//  Output: 
//      HPALETTE         - specifies the palette
//
//  Return: 
//
/////////////////////////////////////////////////////////////////////////////

BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* pPal)
{
    LPLOGPALETTE lpPal;      // pointer to a logical palette
    HANDLE hLogPal;          // handle to a logical palette
    HPALETTE hPal = NULL;    // handle to a palette
    int i;                   // loop index
    WORD wNumColors;         // number of colors in color table
    LPSTR lpbi;              // pointer to packed-DIB
    LPBITMAPINFO lpbmi;      // pointer to BITMAPINFO structure (Win3.0)
    LPBITMAPCOREINFO lpbmc;  // pointer to BITMAPCOREINFO structure (old)
    BOOL bWinStyleDIB;       // flag which signifies whether this is a Win3.0 DIB
    BOOL bResult = FALSE;

    /* if handle to DIB is invalid, return FALSE */

    if (hDIB == NULL)
      return FALSE;

   lpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);

   /* get pointer to BITMAPINFO (Win 3.0) */
   lpbmi = (LPBITMAPINFO)lpbi;

   /* get pointer to BITMAPCOREINFO (old 1.x) */
   lpbmc = (LPBITMAPCOREINFO)lpbi;

   /* get the number of colors in the DIB */
   wNumColors = ::DIBNumColors(lpbi);

   if (wNumColors != 0)
   {
        /* allocate memory block for logical palette */
        hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
                                    + sizeof(PALETTEENTRY)
                                    * wNumColors);

        /* if not enough memory, clean up and return NULL */
        if (hLogPal == 0)
        {
            ::GlobalUnlock((HGLOBAL) hDIB);
            return FALSE;
        }

        lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);

        /* set version and number of palette entries */
        lpPal->palVersion = PALVERSION;
        lpPal->palNumEntries = (WORD)wNumColors;

        /* is this a Win 3.0 DIB? */
        bWinStyleDIB = IS_WIN30_DIB(lpbi);
        for (i = 0; i < (int)wNumColors; i++)
        {
            if (bWinStyleDIB)
            {
                lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
                lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
                lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
                lpPal->palPalEntry[i].peFlags = 0;
            }
            else
            {
                lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
                lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
                lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
                lpPal->palPalEntry[i].peFlags = 0;
            }
        }

        /* create the palette and get handle to it */
        bResult = pPal->CreatePalette(lpPal);
        ::GlobalUnlock((HGLOBAL) hLogPal);
        ::GlobalFree((HGLOBAL) hLogPal);
    }

    ::GlobalUnlock((HGLOBAL) hDIB);

    return bResult;
}

/*************************************************************************
 *
 * FindDIBBits()
 *
 * Parameter:
 *
 * LPSTR lpbi       - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * LPSTR            - pointer to the DIB bits
 *
 * Description:
 *
 * This function calculates the address of the DIB's bits and returns a
 * pointer to the DIB bits.
 *
 ************************************************************************/


LPSTR WINAPI FindDIBBits(LPSTR lpbi)
{
    return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi));
}


/*************************************************************************
 *
 * DIBWidth()
 *
 * Parameter:
 *
 * LPSTR lpbi       - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * DWORD            - width of the DIB
 *
 * Description:
 *
 * This function gets the width of the DIB from the BITMAPINFOHEADER
 * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
 * width field if it is an other-style DIB.
 *
 ************************************************************************/


DWORD WINAPI DIBWidth(LPSTR lpDIB)
{
    LPBITMAPINFOHEADER lpbmi;  // pointer to a Win 3.0-style DIB
    LPBITMAPCOREHEADER lpbmc;  // pointer to an other-style DIB

    /* point to the header (whether Win 3.0 and old) */

    lpbmi = (LPBITMAPINFOHEADER)lpDIB;
    lpbmc = (LPBITMAPCOREHEADER)lpDIB;

    /* return the DIB width if it is a Win 3.0 DIB */
    if (IS_WIN30_DIB(lpDIB))
        return lpbmi->biWidth;
    else  /* it is an other-style DIB, so return its width */
        return (DWORD)lpbmc->bcWidth;
}


/*************************************************************************
 *
 * DIBHeight()
 *
 * Parameter:
 *
 * LPSTR lpbi       - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * DWORD            - height of the DIB
 *
 * Description:
 *
 * This function gets the height of the DIB from the BITMAPINFOHEADER
 * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
 * height field if it is an other-style DIB.
 *
 ************************************************************************/


DWORD WINAPI DIBHeight(LPSTR lpDIB)
{
    LPBITMAPINFOHEADER lpbmi;  // pointer to a Win 3.0-style DIB
    LPBITMAPCOREHEADER lpbmc;  // pointer to an other-style DIB

    /* point to the header (whether old or Win 3.0 */

    lpbmi = (LPBITMAPINFOHEADER)lpDIB;
    lpbmc = (LPBITMAPCOREHEADER)lpDIB;

    /* return the DIB height if it is a Win 3.0 DIB */
    if (IS_WIN30_DIB(lpDIB))
        return lpbmi->biHeight;
    else  /* it is an other-style DIB, so return its height */
        return (DWORD)lpbmc->bcHeight;
}


/*************************************************************************
 *
 * PaletteSize()
 *
 * Parameter:
 *
 * LPSTR lpbi       - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * WORD             - size of the color palette of the DIB
 *
 * Description:
 *
 * This function gets the size required to store the DIB's palette by
 * multiplying the number of colors by the size of an RGBQUAD (for a
 * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an other-
 * style DIB).
 *
 ************************************************************************/


WORD WINAPI PaletteSize(LPSTR lpbi)
{
   /* calculate the size required by the palette */
   if (IS_WIN30_DIB (lpbi))
      return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD));
   else
      return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE));
}


/*************************************************************************
 *
 * DIBNumColors()
 *
 * Parameter:
 *
 * LPSTR lpbi       - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * WORD             - number of colors in the color table
 *
 * Description:
 *
 * This function calculates the number of colors in the DIB's color table
 * by finding the bits per pixel for the DIB (whether Win3.0 or other-style
 * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
 * if 24, no colors in color table.
 *
 ************************************************************************/


WORD WINAPI DIBNumColors(LPSTR lpbi)
{
    WORD wBitCount;  // DIB bit count

    /*  If this is a Windows-style DIB, the number of colors in the
     *  color table can be less than the number of bits per pixel
     *  allows for (i.e. lpbi->biClrUsed can be set to some value).
     *  If this is the case, return the appropriate value.
     */

    if (IS_WIN30_DIB(lpbi))
    {
        DWORD dwClrUsed;

        dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
        if (dwClrUsed != 0)
            return (WORD)dwClrUsed;
    }

    /*  Calculate the number of colors in the color table based on
     *  the number of bits per pixel for the DIB.
     */
    if (IS_WIN30_DIB(lpbi))
        wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
    else
        wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;

    /* return number of colors based on bits per pixel */
    switch (wBitCount)
    {
        case 1:
            return 2;

        case 4:
            return 16;

        case 8:
            return 256;

        default:
            return 0;
    }
}


//////////////////////////////////////////////////////////////////////////
//// Clipboard support

//---------------------------------------------------------------------
//
// Function:   CopyHandle (from SDK DibView sample clipbrd.c)
//
// Purpose:    Makes a copy of the given global memory block.  Returns
//             a handle to the new memory block (NULL on error).
//
//             Routine stolen verbatim out of ShowDIB.
//
// Parms:      h == Handle to global memory to duplicate.
//
// Returns:    Handle to new global memory block.
//
//---------------------------------------------------------------------

HANDLE WINAPI CopyHandle (HANDLE h)
{
    BYTE huge *lpCopy;
    BYTE huge *lp;
    HANDLE     hCopy;
    DWORD      dwLen;

    if (h == NULL)
        return NULL;

    dwLen = ::GlobalSize((HGLOBAL) h);

    if ((hCopy = (HANDLE) ::GlobalAlloc (GHND, dwLen)) != NULL)
    {
        lpCopy = (BYTE huge *) ::GlobalLock((HGLOBAL) hCopy);
        lp     = (BYTE huge *) ::GlobalLock((HGLOBAL) h);

        while (dwLen--)
            *lpCopy++ = *lp++;

        ::GlobalUnlock((HGLOBAL) hCopy);
        ::GlobalUnlock((HGLOBAL) h);
    }

    return hCopy;
}

/*************************************************************************
 *
 * SaveDIB()
 *
 * Saves the specified DIB into the specified CFile.  The CFile
 * is opened and closed by the caller.
 *
 * Parameters:
 *
 * HDIB hDib - Handle to the dib to save
 *
 * CFile& file - open CFile used to save DIB
 *
 * Return value: TRUE if successful, else FALSE or CFileException
 *
 *************************************************************************/


BOOL WINAPI SaveDIB(HDIB hDib, CFile& file)
{
    BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
    LPBITMAPINFOHEADER lpBI;   // Pointer to DIB info structure
    DWORD dwDIBSize;

    if (hDib == NULL)
        return FALSE;

    /*
     * Get a pointer to the DIB memory, the first of which contains
     * a BITMAPINFO structure
     */
    lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
    if (lpBI == NULL)
        return FALSE;

    if (!IS_WIN30_DIB(lpBI))
    {
        ::GlobalUnlock((HGLOBAL) hDib);
        return FALSE;       // It's an other-style DIB (save not supported)
    }

    /*
     * Fill in the fields of the file header
     */

    /* Fill in file type (first 2 bytes must be "BM" for a bitmap) */
    bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM"

    // Calculating the size of the DIB is a bit tricky (if we want to
    // do it right).  The easiest way to do this is to call GlobalSize()
    // on our global handle, but since the size of our global memory may have
    // been padded a few bytes, we may end up writing out a few too
    // many bytes to the file (which may cause problems with some apps).
    //
    // So, instead let's calculate the size manually (if we can)
    //
    // First, find size of header plus size of color table.  Since the
    // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
    // the size of the structure, let's use this.

    dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI);  // Partial Calculation

    // Now calculate the size of the image

    if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
    {
        // It's an RLE bitmap, we can't calculate size, so trust the
        // biSizeImage field

        dwDIBSize += lpBI->biSizeImage;
    }
    else
    {
        DWORD dwBmBitsSize;  // Size of Bitmap Bits only

        // It's not RLE, so size is Width (DWORD aligned) * Height

        dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;

        dwDIBSize += dwBmBitsSize;

        // Now, since we have calculated the correct size, why don't we
        // fill in the biSizeImage field (this will fix any .BMP files which
        // have this field incorrect).

        lpBI->biSizeImage = dwBmBitsSize;
    }


    // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)

    bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
    bmfHdr.bfReserved1 = 0;
    bmfHdr.bfReserved2 = 0;

    /*
     * Now, calculate the offset the actual bitmap bits will be in
     * the file -- It's the Bitmap file header plus the DIB header,
     * plus the size of the color table.
     */
    bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize
                                              + PaletteSize((LPSTR)lpBI);

    TRY
    {
        // Write the file header
        file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
        //
        // Write the DIB header and the bits
        //
        file.WriteHuge(lpBI, dwDIBSize);
    }
    CATCH (CFileException, e)
    {
        ::GlobalUnlock((HGLOBAL) hDib);
        THROW_LAST();
    }
    END_CATCH

    ::GlobalUnlock((HGLOBAL) hDib);
    return TRUE;
}


/*************************************************************************

  Function:  ReadDIBFile (CFile&)

   Purpose:  Reads in the specified DIB file into a global chunk of
             memory.

   Returns:  A handle to a dib (hDIB) if successful.
             NULL if an error occurs.

  Comments:  BITMAPFILEHEADER is stripped off of the DIB.  Everything
             from the end of the BITMAPFILEHEADER structure on is
             returned in the global memory handle.

*************************************************************************/


HDIB WINAPI ReadDIBFile(CFile& file)
{
    BITMAPFILEHEADER bmfHeader;
    DWORD dwBitsSize;
    HDIB hDIB;
    LPSTR pDIB;

    /*
     * get length of DIB in bytes for use when reading
     */

    dwBitsSize = file.GetLength();

    /*
     * Go read the DIB file header and check if it's valid.
     */
    if ((file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) !=
        sizeof(bmfHeader)) || (bmfHeader.bfType != DIB_HEADER_MARKER))
    {
        return NULL;
    }
    /*
     * Allocate memory for DIB
     */
    hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
    if (hDIB == 0)
    {
        return NULL;
    }
    pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);

    /*
     * Go read the bits.
     */
    if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=
        dwBitsSize - sizeof(BITMAPFILEHEADER) )
    {
        ::GlobalUnlock((HGLOBAL) hDIB);
        ::GlobalFree((HGLOBAL) hDIB);
        return NULL;
    }
    ::GlobalUnlock((HGLOBAL) hDIB);
    return hDIB;
}

////////////////////////////////////(EOF)////////////////////////////////////
