home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 11 / 11.iso / m / m248 / 4.ddi / DIB.C_ / DIB.C
Encoding:
C/C++ Source or Header  |  1993-02-01  |  17.0 KB  |  671 lines

  1. /* 
  2.  
  3.     DIB.C -- User Code - Post a Dib to the Display of APW
  4.     Copyright 1987-1991 Authorware Inc.
  5.  
  6.     Revision History
  7.  
  8.         7/25/91    -    Initial version
  9.  
  10.     General Notes:
  11.  
  12.         The functions contained in this file post objects on the APW display
  13.         manager list.  Once an object is posted it can be displayed by the dll.
  14.  
  15.         Posting objects to APW is accomplished by sending custom messages to the
  16.         APW presentation window.
  17.  
  18.         This main functions of this dll are:
  19.  
  20.             1) DisplayDIB    -    Post an object on the APW display manager list.
  21.                                     The color palette in the DIB may or may not
  22.                                     be used depending on parameters passed in.
  23.             2) EraseDIB        -    Remove an object from the APW display manager list.
  24.             3) DibProc        -  Object handler for posted objects.
  25.  
  26.         All other functions are support functions.
  27.  
  28.         See the tech note on posting objects for a complete discussion on posting
  29.         objects to APW.
  30.  
  31. */
  32. #include <stdlib.h>
  33.  
  34. #ifdef NULL
  35. #undef NULL
  36. #endif
  37.  
  38. #include <windows.h>
  39. #include "apwpost.h"
  40.  
  41. HANDLE    hInst;
  42.  
  43. /* Return codes for DIB functions */
  44. #define DIB_COOL            0
  45. #define DIB_BADFILE        3
  46. #define DIB_MEMORY        4
  47.  
  48. #define    COLOR_WHITE        0xff    // The color white
  49. #define    TOTAL_PALETTE_SIZE    (sizeof(PALETTEENTRY)*255+sizeof(LOGPALETTE))
  50.  
  51. #define VALID_WINDOW(w) ((w) && IsWindow(w))    // Make NULL an invalid window
  52.  
  53.             short    FAR  PASCAL WEP( short bSystemExit );
  54.             short       FAR  PASCAL LibMain( HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine );
  55. static     void        NEAR PASCAL GetDibSize( HANDLE hDib, short FAR *width, short FAR *height );
  56. static     short    NEAR PASCAL LoadDib(short fh, HANDLE FAR *hDib );
  57. static     HANDLE   NEAR PASCAL CreateTheDIB( LPSTR file );
  58. static     WORD        NEAR PASCAL DibNumColors (LPBITMAPINFOHEADER lpbi);
  59. static     WORD        NEAR PASCAL PaletteSize (LPBITMAPINFOHEADER lpbi);
  60. static     void     NEAR PASCAL DibPaint( HANDLE hDib, HDC dc, short left, short top );
  61. static     HANDLE   NEAR PASCAL DibCopy( HANDLE hDib );
  62. static     HPALETTE NEAR PASCAL CreateThePal( HANDLE hDib );
  63. static     long      NEAR PASCAL PostTheDib( HWND wnd, LPSTR dib, short left, short top, BOOL colorpal );
  64.  
  65.  
  66. /* Temporary globals */
  67. static char            dll[_MAX_PATH];
  68. static char            *function_ptr = "DibProc";
  69.  
  70.  
  71. short    FAR PASCAL LibMain( HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, 
  72.                                         LPSTR lpszCmdLine )
  73.  
  74. /*
  75.     Is called by LibEntry.  LibEntry is called by Windows when the DLL is
  76.     loaded.  The LibEntry routine is provided in the LIBENTRY.OBJ in the SDK
  77.     Link Libraries disk.  (The source LIBENTRY.ASM is also provided.)  
  78.  
  79.     LibEntry initializes the DLL's heap, if a HEAPSIZE value is specified
  80.     in the DLL's DEF file.  Then LibEntry calls LibMain.  The LibMain function
  81.     below satisfies that call.
  82.              
  83.     The LibMain function should perform additional initialization tasks
  84.     required by the DLL.  In this example, no initialization tasks are
  85.     required.  LibMain should return a value of 1 if the initialization is
  86.     successful.
  87. */
  88. {
  89.     hInst = hModule;
  90.     return 1;
  91. }
  92.  
  93.  
  94. short FAR PASCAL WEP( short bSystemExit )
  95. /*
  96.     Performs cleanup tasks when the DLL is unloaded.  WEP() is called
  97.     automatically by Windows when the DLL is unloaded (no remaining tasks
  98.     still have the DLL loaded).  It is strongly recommended that a DLL have a
  99.     WEP() function, even if it does nothing but returns success (1), as in
  100.     this example.
  101. */
  102. {
  103.     return 1;
  104. }
  105.  
  106.  
  107. long FAR PASCAL DisplayDIB( HWND wnd, LPSTR dib, short left, short top, BOOL colorpal )
  108. /*
  109.     This function posts the file based DIB pointed to by dib to the APW 
  110.     presentation window at left, top.  
  111.     
  112.     The palette of the DIB will be used by APW if colorpal is TRUE.
  113.  
  114.     Returns:
  115.     
  116.         a unique id to the DIB if it posted
  117.         0 if an error occurs
  118. */
  119. {
  120.     APWC_POSTPB        post;
  121.     long                id=0;
  122.     HANDLE            hDib;
  123.     HPALETTE            hpal;
  124.  
  125.  
  126.     if (!VALID_WINDOW(wnd))
  127.         return 0;
  128.  
  129.     // Who am I
  130.     GetModuleFileName(hInst, dll, sizeof(dll));
  131.  
  132.     /*
  133.         post.size            - size of this structure.
  134.         post.function_ptr    - pointer to the exported name of the procedure which
  135.                                   will handle all messages for the posted object.
  136.  
  137.         post.dll_ptr        - name of the dll - including directory.
  138.         post.rect.left        - upper left corner of the object in APW screen
  139.                                   coordinates.
  140.         post.rect.top        - upper top corner of the object in APW screen
  141.                                   coordinates.
  142.         post.data_ptr        - the address of a block of memory to be stored in
  143.                                   the display managers list which will be passed
  144.                                   to the objects procedure (post.function_ptr).
  145.         post.data_size        - size of whats pointed to by post.data_ptr.
  146.         post.port            - which port the object is to be posted to.
  147.     */
  148.     post.size = sizeof(APWC_POSTPB);
  149.     post.function_ptr = function_ptr;
  150.     post.dll_ptr = dll;
  151.     post.rect.left = left;
  152.     post.rect.top = top;
  153.     post.data_ptr = &hDib;
  154.     post.data_size = sizeof(hDib);
  155.     post.port = STATIC_PORT;
  156.  
  157.     // Load the DIB from the file and return a handle to the DIB.
  158.     if ((hDib = CreateTheDIB(dib)))
  159.     {
  160.  
  161.         if (colorpal)
  162.         {
  163.             // create a palette from the DIB
  164.             hpal = CreateThePal(hDib);
  165.     
  166.             // Set the palette in APW
  167.             if (hpal)
  168.             {
  169.                 // Give palette to APW
  170.                 if (SendMessage(wnd, APWC_SETPAL, hpal, 0L) == 0)
  171.                 {
  172.                     // Cleanup the palette if an error occured in APW and this
  173.                     // palette was not set. Else the palette belongs to APW.
  174.                     DeleteObject(hpal);
  175.                 }
  176.             }
  177.         }
  178.  
  179.         // Get the width and height
  180.         GetDibSize(hDib, &post.rect.right, &post.rect.bottom);
  181.  
  182.         // Complete the rectangle of the object.
  183.         post.rect.right += left;
  184.         post.rect.bottom += top;
  185.  
  186.         // Post the DIB to APW. id is the unique id value.
  187.         id = SendMessage(wnd, APWC_POST, 0, (long)(APWC_POSTPB_PTR)&post);
  188.     }
  189.  
  190.     return id;
  191. }
  192.  
  193.  
  194. BOOL FAR PASCAL EraseDIB( HWND wnd, long id )
  195. /*
  196.     This function unposts the posted object id from the APW display manager
  197.     list.  id must have been previously set by a call to either ShowDib or
  198.     PostDib.
  199.  
  200.     Returns:
  201.  
  202.         TRUE if successfull 
  203.         FALSE if wnd if invalid.
  204. */
  205. {
  206.     if (VALID_WINDOW(wnd))
  207.     {
  208.         SendMessage(wnd, APWC_UNPOST, 0, id);
  209.         return TRUE;
  210.     }
  211.  
  212.     return FALSE;
  213. }
  214.  
  215.  
  216. long FAR PASCAL DibProc( APWN_AB_PTR args, unsigned msg )
  217. /*
  218.     This function is the message handler for posted objects in APW.  When an
  219.     object is posted this function is loaded by APW and starts receiving messages
  220.     from APW.  
  221.     
  222.     The data_ptr field in args is the handle to the DIB.
  223.  
  224.     Returns:
  225.  
  226.         0 always.
  227.         
  228. */
  229. {
  230.     switch (msg)
  231.     {
  232.  
  233.     case APWN_INIT:                // We will ignore this message for dib.ucd
  234.  
  235.         break;
  236.  
  237.     case APWN_DESTROY:            // Free the DIB found at args->data_ptr
  238.  
  239.         if (*((WORD FAR *)args->data_ptr))
  240.         {
  241.             GlobalFree(*((WORD FAR *)args->data_ptr));
  242.             *((WORD FAR *)args->data_ptr) = 0;
  243.         }
  244.         break;
  245.  
  246.     case APWN_PAINT:                // Blt the DIB to the passed dc - palette already set.
  247.  
  248.         if (*((WORD FAR *)args->data_ptr))
  249.             DibPaint(*((WORD FAR *)args->data_ptr), args->wparam, args->rect.left, args->rect.top);
  250.         break;
  251.  
  252.     case APWN_SAVE:                // Make a copy of the DIB to be stored by APW.
  253.  
  254.         if (*((WORD FAR *)args->data_ptr))
  255.             return DibCopy(*((WORD FAR *)args->data_ptr));
  256.  
  257.     case APWN_RESTORE:            // Recreate myself.
  258.  
  259.         // Restore Myself. Since I saved myself as a DIB - I can use the same
  260.         // handle as whats passed to me.
  261.  
  262.         *((WORD FAR *)args->data_ptr) = args->wparam;
  263.         break;
  264.  
  265.     default:
  266.  
  267.         break;
  268.  
  269.     }
  270.  
  271.     return 0L;
  272. }
  273.  
  274.  
  275. static HANDLE NEAR PASCAL CreateTheDIB( LPSTR file )
  276. /*
  277.     This function opens the file pointed to by "file" reads it and create a 
  278.     Windows DIB from it.
  279.  
  280.     Returns:
  281.  
  282.         HANDLE to a DIB
  283.         or 0 for error.
  284. */
  285. {
  286.     OFSTRUCT            of;
  287.     HANDLE            hDib=0;
  288.     HANDLE            fh = -1;
  289.  
  290.     if ((fh = OpenFile(file, &of, OF_READ)) != -1)
  291.     {
  292.         if (LoadDib(fh, &hDib) != DIB_COOL)
  293.             hDib = 0;
  294.  
  295.         _lclose(fh);
  296.     }
  297.  
  298.     return hDib;
  299. }
  300.  
  301.     
  302.  
  303. static short NEAR PASCAL LoadDib(short fh, HANDLE FAR *hDib )
  304. /*
  305.     This function reads the file identified by fh into a GlobalHandle as a 
  306.     Windows DIB.
  307.  
  308.     Returns:
  309.  
  310.         DIB_COOL         - Everything is OK.
  311.         DIB_BADFILE - This is not a legal DIB file.
  312.         DIB_MEMORY    - No memory.
  313. */
  314. {
  315.     unsigned char huge *hpWrkPtr;
  316.     long                    biSize, fsize;
  317.     WORD                    wrksz;
  318.     BITMAPFILEHEADER    fhead;
  319.  
  320.     // seek to the end of the file
  321.     fsize = _llseek(fh,0L,2);            
  322.     if (fsize < sizeof(BITMAPFILEHEADER))
  323.         return DIB_BADFILE;
  324.  
  325.     // go back to the start
  326.     if (_llseek(fh,0L,0) == -1)            
  327.         return DIB_BADFILE;
  328.  
  329.     // Read in the file header
  330.     if (_lread(fh,(LPSTR)&fhead,sizeof(BITMAPFILEHEADER)) < sizeof(BITMAPFILEHEADER))
  331.         return DIB_BADFILE;
  332.     fsize -= sizeof(BITMAPFILEHEADER);
  333.  
  334.     // check header type
  335.     if (fhead.bfType != 0x4d42)            
  336.          return DIB_BADFILE;
  337.  
  338.     // Allocate enough for the DIB
  339.     // add 256 in case it's an 8-bit, BITMAPCOREINFO DIB (the palette table 
  340.     // must be converted from RGBTRIPLE to RGBQUAD)
  341.     // add an additional 28 bytes for the difference between the two header sizes
  342.     //
  343.     *hDib = GlobalAlloc(GMEM_MOVEABLE, fsize + 256 + 28);
  344.     if (!(*hDib))
  345.         return DIB_MEMORY;
  346.  
  347.     hpWrkPtr = GlobalLock(*hDib);
  348.  
  349.     // modifications to deal with the possibility of BITMAPCOREHEADER-style DIB's
  350.     // 12/1/92 JPK
  351.     {
  352.         BITMAPINFOHEADER bihHeader;
  353.         BITMAPCOREHEADER bchHeader;
  354.         short numColors, i;
  355.         DWORD dwBits, dwBytes;
  356.         WORD wPaletteTableSize;
  357.         RGBTRIPLE rgbTriple;
  358.         RGBQUAD FAR * pRGBQUAD;
  359.  
  360.         if (_lread (fh, (LPSTR)&bihHeader, sizeof(DWORD)) < sizeof(DWORD))
  361.             return DIB_BADFILE;
  362.  
  363.         if (bihHeader.biSize != sizeof(BITMAPINFOHEADER)) {
  364.             // it must be a BITMAPCOREHEADER guy, so read in the header, then
  365.             // translate it to the regular format
  366.             //
  367.             if (_lread (fh, (LPSTR)&bchHeader.bcWidth, 
  368.                         sizeof(BITMAPCOREHEADER) - sizeof(DWORD)) < 
  369.                 sizeof(BITMAPCOREHEADER) - sizeof(DWORD)) {
  370.                 GlobalUnlock(*hDib);
  371.                 GlobalFree(*hDib);
  372.                 return DIB_BADFILE;
  373.             }
  374.  
  375.             bihHeader.biSize = sizeof(BITMAPINFOHEADER);
  376.             bihHeader.biWidth    = bchHeader.bcWidth;
  377.             bihHeader.biHeight   = bchHeader.bcHeight;
  378.             bihHeader.biPlanes   = bchHeader.bcPlanes;
  379.             bihHeader.biBitCount = bchHeader.bcBitCount;
  380.             bihHeader.biCompression = BI_RGB;
  381.             bihHeader.biXPelsPerMeter = 0;
  382.             bihHeader.biYPelsPerMeter = 0;
  383.  
  384.             switch (bihHeader.biBitCount) {
  385.               case 1:
  386.                 numColors = 2;
  387.                 break;
  388.               case 4:
  389.                 numColors = 16;
  390.                 break;
  391.               case 8:
  392.                 numColors = 256;
  393.                 break;
  394.               default:
  395.                 /* A 24 bitcount DIB has no color table */
  396.                 numColors = 0;
  397.             }
  398.  
  399.             bihHeader.biClrUsed = numColors;
  400.             bihHeader.biClrImportant = numColors;
  401.  
  402.             dwBits = bihHeader.biWidth * bihHeader.biBitCount * bihHeader.biPlanes;
  403.             dwBytes = (dwBits + 31L) / 32L * 4L;
  404.             bihHeader.biSizeImage = dwBytes * bihHeader.biHeight;
  405.  
  406.             *(LPBITMAPINFOHEADER)hpWrkPtr = bihHeader;
  407.             hpWrkPtr += sizeof(BITMAPINFOHEADER);
  408.  
  409.             pRGBQUAD = (RGBQUAD FAR *)hpWrkPtr;
  410.  
  411.             // read and translate the palette table
  412.             //
  413.             for (i=0; i < bihHeader.biClrUsed; i++) {
  414.                 _lread (fh, (LPSTR)&rgbTriple, sizeof(RGBTRIPLE));
  415.                 pRGBQUAD->rgbBlue =     rgbTriple.rgbtBlue;
  416.                 pRGBQUAD->rgbGreen =    rgbTriple.rgbtGreen;
  417.                 pRGBQUAD->rgbRed =      rgbTriple.rgbtRed;
  418.                 pRGBQUAD->rgbReserved = NULL;
  419.                 pRGBQUAD++;
  420.             }
  421.             hpWrkPtr = (LPSTR)pRGBQUAD;
  422.  
  423.             fsize -= sizeof(BITMAPCOREHEADER) + 
  424.                     bihHeader.biClrUsed * sizeof(RGBTRIPLE);
  425.  
  426.             fhead.bfSize = fsize + sizeof(BITMAPFILEHEADER) + 
  427.                         sizeof(BITMAPINFOHEADER) +
  428.                         bihHeader.biClrUsed * sizeof(RGBQUAD);
  429.  
  430.         } else {
  431.             // it's a "regular" DIB header, so just read in the rest of it
  432.             //
  433.             if (_lread (fh, (LPSTR)&bihHeader.biWidth, 
  434.                         sizeof(BITMAPINFOHEADER) - sizeof(DWORD)) < 
  435.                 sizeof(BITMAPINFOHEADER) - sizeof(DWORD)) {
  436.                 GlobalUnlock(*hDib);
  437.                 GlobalFree(*hDib);
  438.                 return DIB_BADFILE;
  439.             }
  440.  
  441.             *(LPBITMAPINFOHEADER)hpWrkPtr = bihHeader;
  442.             hpWrkPtr += sizeof(BITMAPINFOHEADER);
  443.  
  444.             wPaletteTableSize = bihHeader.biClrUsed * sizeof(RGBQUAD);
  445.  
  446.             if (_lread (fh, hpWrkPtr, wPaletteTableSize) < wPaletteTableSize) {
  447.                 GlobalUnlock(*hDib);
  448.                 GlobalFree(*hDib);
  449.                 return DIB_BADFILE;
  450.             }
  451.             hpWrkPtr += wPaletteTableSize;
  452.  
  453.             fsize -= sizeof(BITMAPINFOHEADER) + wPaletteTableSize;
  454.         }
  455.     }    
  456.  
  457.     biSize = fsize;
  458.  
  459.     // Read in the DIB
  460.     while (biSize > 0L)
  461.     {
  462.        if (biSize > 64000L)
  463.           wrksz = 64000;
  464.        else
  465.           wrksz = (WORD) biSize;
  466.  
  467.       if (!(wrksz = _lread(fh, hpWrkPtr, wrksz)))
  468.         {
  469.             // Error out.
  470.             GlobalUnlock(*hDib);
  471.             GlobalFree(*hDib);
  472.             return DIB_BADFILE;
  473.         }
  474.       hpWrkPtr += wrksz;
  475.         biSize -= wrksz;
  476.     }
  477.  
  478.     GlobalUnlock(*hDib);
  479.     GlobalReAlloc(*hDib, fhead.bfSize, GMEM_MOVEABLE);
  480.  
  481.     return DIB_COOL;
  482. }
  483.  
  484. static void NEAR PASCAL GetDibSize( HANDLE hDib, short FAR *width, short FAR *height )
  485. /*
  486.     This function returns the width and height in pixels of hDib;
  487.     and stores the results in *width and *height.
  488.  
  489.     Returns:
  490.  
  491.         Void
  492. */
  493. {
  494.     LPBITMAPINFOHEADER        lpb;
  495.  
  496.  
  497.     if ((lpb = (LPBITMAPINFOHEADER)GlobalLock(hDib)) != 0L)
  498.     {
  499.         *width = lpb->biWidth;
  500.         *height = lpb->biHeight;
  501.         GlobalUnlock(hDib);
  502.     }
  503. }
  504.     
  505.  
  506. static void NEAR PASCAL DibPaint( HANDLE hDib, HDC dc, short left, short top )
  507. /*
  508.     This function stretches hDib to the passed dc.  It assumes the palette is 
  509.     already set.
  510.  
  511.     Returns:
  512.  
  513.         Void
  514. */
  515. {
  516.    LPBITMAPINFOHEADER lpbi;
  517.    LPSTR         pBuf;
  518.  
  519.    if ((lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib)) != 0L)
  520.     {
  521.        pBuf = (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi);
  522.  
  523.         StretchDIBits(dc, left, top, (WORD)lpbi->biWidth, (WORD)lpbi->biHeight, 0, 0, 
  524.             (WORD)lpbi->biWidth, (WORD)lpbi->biHeight, pBuf, (LPBITMAPINFO)lpbi, 
  525.             DIB_RGB_COLORS, SRCCOPY);
  526.  
  527.         GlobalUnlock(hDib);
  528.     }
  529. }
  530.  
  531.  
  532. static WORD NEAR PASCAL PaletteSize (LPBITMAPINFOHEADER lpbi)
  533. /*
  534.    This function calculates the palette size in bytes. 
  535.  
  536.    Returns: 
  537.  
  538.         Palette size in number of bytes.
  539. */
  540. {
  541.     return DibNumColors(lpbi) * sizeof(RGBQUAD);
  542. }
  543.  
  544.  
  545. static WORD NEAR PASCAL DibNumColors (LPBITMAPINFOHEADER lpbi)
  546. /*
  547.    This function determines the number of colors in the DIB by looking at
  548.     the BitCount filed in the info block.
  549.  
  550.    Returns: 
  551.     
  552.         The number of colors in the DIB.
  553.  
  554. */
  555. {
  556.     int    bits;
  557.  
  558.     if (lpbi->biClrUsed != 0)
  559.         return (WORD)lpbi->biClrUsed;
  560.     bits = lpbi->biBitCount;
  561.  
  562.     switch (bits)
  563.     {
  564.       case 1:
  565.         return 2;
  566.       case 4:
  567.         return 16;
  568.       case 8:
  569.         return 256;
  570.       default:
  571.         /* A 24 bitcount DIB has no color table */
  572.         return 0;
  573.     }
  574. }
  575.  
  576.  
  577. static HANDLE NEAR PASCAL DibCopy( HANDLE hDib )
  578. /*
  579.     This function copies the passed dib and returns a HANDLE to the copy.
  580.  
  581.     Returns:
  582.  
  583.         HANDLE - handle to copied DIB.
  584.         0         - insufficient memory.
  585. */
  586. {
  587.     HANDLE     rv;
  588.     DWORD         size;
  589.     char huge *s;
  590.     char huge *d;
  591.  
  592.     size = GlobalSize(hDib);
  593.     if ((rv = GlobalAlloc(GHND, size)) != NULL)
  594.     {
  595.         d = (char huge *)GlobalLock(rv);
  596.         s = (char huge *)GlobalLock(hDib);
  597.         for(; size > 0; ++s, ++d, --size)
  598.             *d = *s;
  599.  
  600.         GlobalUnlock(rv);
  601.         GlobalUnlock(hDib);
  602.     }
  603.  
  604.     return rv;
  605. }
  606.  
  607.  
  608. static HPALETTE NEAR PASCAL CreateThePal( HANDLE hDib )
  609. /*
  610.     This function creates a palette from the passed DIB - hDib.
  611.  
  612.     Returns:
  613.  
  614.         the HPALETTE if successfull 
  615.         0 - if error
  616.  
  617.     Please NOTE: if the palette is incomplete it will be padded with the color
  618.     white.
  619. */
  620. {
  621.     short                        i;
  622.     short                        NumColors;
  623.     HANDLE                    hLog;
  624.     HPALETTE                    hPal=0;
  625.    LPBITMAPINFOHEADER     lpBi;
  626.     RGBQUAD FAR             *lpOrig;
  627.     LPLOGPALETTE            lpPal;
  628.  
  629.     // Allocate a buffer large enough for a 256 color palette
  630.     if ((hLog = GlobalAlloc(GHND, TOTAL_PALETTE_SIZE)))
  631.     {
  632.  
  633.         lpPal = (LPLOGPALETTE)GlobalLock(hLog);
  634.        lpBi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
  635.  
  636.         lpOrig = (RGBQUAD FAR *)((LPSTR)lpBi + (WORD)lpBi->biSize);
  637.  
  638.         NumColors = DibNumColors(lpBi);
  639.  
  640.         lpPal->palVersion = 0x300;
  641.         lpPal->palNumEntries = 0x100;
  642.  
  643.         /* Copy the palette to the temporary buffer */
  644.         for (i=0; i<NumColors; ++i)
  645.         {
  646.             lpPal->palPalEntry[i].peRed = lpOrig[i].rgbRed;
  647.             lpPal->palPalEntry[i].peGreen = lpOrig[i].rgbGreen;
  648.             lpPal->palPalEntry[i].peBlue = lpOrig[i].rgbBlue;
  649.             lpPal->palPalEntry[i].peFlags = 0;
  650.         }
  651.  
  652.         // Fill in the rest of the palette to white in case it is an incomplete palette
  653.         for( i=NumColors; i<256; ++i)
  654.         {
  655.             lpPal->palPalEntry[i].peFlags = 0;
  656.             lpPal->palPalEntry[i].peRed = COLOR_WHITE;
  657.             lpPal->palPalEntry[i].peGreen = COLOR_WHITE;
  658.             lpPal->palPalEntry[i].peBlue = COLOR_WHITE;
  659.         }
  660.  
  661.         /* Create the palette */
  662.         hPal = CreatePalette(lpPal);
  663.  
  664.         GlobalUnlock(hDib);
  665.         GlobalUnlock(hLog);
  666.         GlobalFree(hLog);
  667.     }
  668.  
  669.     return hPal;
  670. }
  671.