home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / sdk / mapi / win16 / dev / smpcli / bitmap.c next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  16.9 KB  |  660 lines

  1. /*
  2.  -  B I T M A P . C
  3.  -
  4.  *  Purpose:
  5.  *      Bitmap and Listbox support functions for InBox in sample mail client.
  6.  *
  7.  *  Copyright 1993-1995 Microsoft Corporation. All Rights Reserved.
  8.  */
  9.  
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <windows.h>
  13. #include <windowsx.h>
  14. #ifdef WIN32
  15. #include <objerror.h>
  16. #include <objbase.h>
  17. #endif
  18. #ifdef WIN16
  19. #include <compobj.h>
  20. #endif
  21. #include <mapiwin.h>
  22. #include <mapidbg.h>
  23. #include <mapi.h>
  24. #include <mapix.h>
  25. #include "bitmap.h"
  26. #include "client.h"
  27.  
  28.  
  29. /*
  30.  *  globals
  31.  */
  32.  
  33. DWORD   rgbWindowColor = 0xFF000000;    // variables for the current
  34. DWORD   rgbHiliteColor = 0xFF000000;    // system color settings.
  35. DWORD   rgbWindowText  = 0xFF000000;    // on a WM_SYSCOLORCHANGE
  36. DWORD   rgbHiliteText  = 0xFF000000;    // we check to see if we need
  37. DWORD   rgbGrayText    = 0xFF000000;    // to reload our bitmap.
  38. DWORD   rgbDDWindow    = 0xFF000000;    //
  39. DWORD   rgbDDHilite    = 0xFF000000;    // 0xFF000000 is an invalid RGB
  40.  
  41. // an array of integers containing the tab stops, in pixels. The tab 
  42. // stops must be sorted in ascending order; back tabs are not allowed. 
  43.  
  44. int     rgTabs[] = { 2, 28, 135, 292 };
  45. int     dxbmpLB, dybmpLB;   // dx and dy of listbox bmps
  46.  
  47. HDC     hdcMemory = 0;      // hdc to hold listbox bitmaps (for speed)
  48. HBITMAP hbmpOrigMemBmp = 0; // original null bitmap in hdcMemory
  49. HBITMAP hbmpLB = 0;         // cached listbox bitmaps
  50. HFONT   hfontLB = 0;        // hfont of LB
  51. HWND    hwndLB = 0;         // hwnd of LB
  52.  
  53. FONTSTYLE fontStyle = { 8, FW_NORMAL, 0, TEXT("MS Sans Serif") };
  54.  
  55. extern HANDLE hInst;
  56.  
  57.  
  58. /*
  59.  -  DeInitBmps
  60.  -  
  61.  *  Purpose:
  62.  *      cleans up LB hfonts, hdc, and hbmps
  63.  */
  64.  
  65. VOID DeInitBmps(VOID)
  66. {
  67.     DeleteBitmapLB();
  68.     if(hdcMemory)
  69.     {
  70.         DeleteDC(hdcMemory);
  71.         hdcMemory = 0;
  72.     }
  73.  
  74.     if(hfontLB)
  75.     {
  76.         SetWindowFont(hwndLB, GetStockObject(SYSTEM_FONT), FALSE);
  77.         DeleteObject(hfontLB);
  78.         hfontLB = 0;
  79.     }
  80. }
  81.  
  82.  
  83. /*
  84.  -  SetLBFont
  85.  -  
  86.  *  Purpose:
  87.  *      creates a font from the global fontStyle
  88.  *      sets global hfontLB to new font and WM_SETFONTs
  89.  *      the hwndLB to the new font
  90.  */
  91.  
  92. VOID SetLBFont(VOID)
  93. {
  94.     LOGFONT lf;
  95.  
  96.     lf.lfHeight = fontStyle.lfHeight;
  97.     lf.lfWidth = 0;
  98.     lf.lfEscapement = 0;
  99.     lf.lfOrientation = 0;
  100.     lf.lfWeight = fontStyle.lfWeight;
  101.     lf.lfItalic = fontStyle.lfItalic;
  102.     lf.lfUnderline = 0;
  103.     lf.lfStrikeOut = 0;
  104.     lf.lfCharSet = ANSI_CHARSET;
  105.     lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  106.     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  107.     lf.lfQuality = DEFAULT_QUALITY;
  108.     lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
  109.     lstrcpy(lf.lfFaceName, fontStyle.lfFaceName);
  110.  
  111.     hfontLB = CreateFontIndirect(&lf);
  112.     if(hfontLB)
  113.         SetWindowFont(hwndLB, hfontLB, FALSE);        
  114. }
  115.  
  116.  
  117. /*
  118.  -  InitBmps
  119.  -  
  120.  *  Purpose:
  121.  *      inits listbox globals, creates listbox
  122.  *  
  123.  *  Arguments:
  124.  *      HWND    main hwnd of app (parent of LB)
  125.  *  
  126.  *  Returns:
  127.  *      TRUE - success; FALSE - failed
  128.  */
  129.  
  130. BOOL InitBmps(HWND hwnd, int idLB)
  131. {
  132.     HDC     hdcScreen;
  133.     HBITMAP hbmpTemp;
  134.  
  135.     hdcScreen = GetDC(0);
  136.     if(!hdcScreen)
  137.         goto CantInit;
  138.     hdcMemory = CreateCompatibleDC(hdcScreen);
  139.     if(!hdcMemory)
  140.         goto ReleaseScreenDC;
  141.  
  142.     hbmpTemp = CreateCompatibleBitmap(hdcMemory, 1, 1);
  143.     if(!hbmpTemp)
  144.         goto ReleaseMemDC;
  145.     hbmpOrigMemBmp = SelectObject(hdcMemory, hbmpTemp); // get hbmp of NULL
  146.     if(!hbmpOrigMemBmp)                                 // bmp for hdcMemory
  147.         goto ReleaseMemDC;                              // for when we delete
  148.     SelectObject(hdcMemory, hbmpOrigMemBmp);            // it later in life
  149.     DeleteObject(hbmpTemp);
  150.     ReleaseDC(0, hdcScreen);
  151.  
  152.     SetRGBValues();     // set the global RGB values
  153.     LoadBitmapLB();     // load the bmps into hdcMemory
  154.  
  155.     hwndLB = GetDlgItem(hwnd, idLB);
  156.     
  157.     SetLBFont();    // set the font of our listbox
  158.     return TRUE;
  159.  
  160. /* Error recovery exits */
  161. ReleaseMemDC:
  162.     DeleteDC(hdcMemory);
  163.     hdcMemory = 0;
  164.  
  165. ReleaseScreenDC:
  166.     ReleaseDC(0, hdcScreen);
  167.  
  168. CantInit:
  169.     return FALSE;
  170. }
  171.  
  172.  
  173. /*
  174.  -  SetRGBValues
  175.  -  
  176.  *  Purpose:
  177.  *      To set various system colors in static variables.  Called at
  178.  *      init time and when system colors change.
  179.  */
  180.  
  181. VOID SetRGBValues(VOID)
  182. {
  183.     rgbWindowColor = GetSysColor(COLOR_WINDOW);
  184.     rgbHiliteColor = GetSysColor(COLOR_HIGHLIGHT);
  185.     rgbWindowText  = GetSysColor(COLOR_WINDOWTEXT);
  186.     rgbHiliteText  = GetSysColor(COLOR_HIGHLIGHTTEXT);
  187.     rgbGrayText    = GetSysColor(COLOR_GRAYTEXT);
  188. }
  189.  
  190.  
  191. /*
  192.  -  MeasureItem
  193.  -  
  194.  *  Purpose:
  195.  *      called from msg WM_MEASUREITEM: returns max dy of listbox items
  196.  *  
  197.  *  Arguments:
  198.  *      HWND        hwnd of main window
  199.  *      pmis        measureitemstruct from WM_MEASUREITEM call
  200.  */
  201.  
  202. VOID MeasureItem(HANDLE hwnd, LPMEASUREITEMSTRUCT pmis)
  203. {
  204.     HDC        hDC = GetDC(hwnd);
  205.     HANDLE     hFont = hfontLB;
  206.     TEXTMETRIC TM;
  207.  
  208.     if(!hFont)
  209.         hFont = GetStockObject(SYSTEM_FONT);
  210.     hFont = SelectObject(hDC, hFont);
  211.     GetTextMetrics(hDC, &TM);
  212.     SelectObject(hDC, hFont);
  213.     ReleaseDC(hwnd, hDC);
  214.  
  215.     // set the height to be max of (dyfont or dybitmap)
  216.     pmis->itemHeight = max(dybmpLB, TM.tmHeight);
  217. }
  218.  
  219.  
  220. /*
  221.  -  OutTextFormat
  222.  -  
  223.  *  Purpose:
  224.  *      to parse the string in the listbox and draw it accordingly:
  225.  *      first char == chBOLD: line is bold
  226.  *      first char == chUNDERLINE: line is underlined (can follow chBOLD)
  227.  *      char == chTAB: go to next column in rgTabs
  228.  *      '/001#': bitblt that numbered bitmap.
  229.  *      otherwise, outtext the line
  230.  *  
  231.  *  Arguments:
  232.  *      pDI     from DrawItem from WM_DRAWITEM msg
  233.  */
  234.  
  235. VOID OutTextFormat(LPDRAWITEMSTRUCT pDI)
  236. {
  237.     TCHAR   szDateRec[32];
  238.     TCHAR   szItem[256];
  239.     TCHAR   szTemp[4];
  240.     TCHAR   szDots[4] = {"..."};
  241.     TCHAR   *pch;
  242.     INT     nT;
  243.     INT     nTab = 0;           // current tab we is on
  244.     INT     nBmp;               // index of envelope bitmap
  245.     HFONT   hfDef = 0;
  246.     HFONT   hfOld = 0;          // bold or underlined font
  247.     TCHAR   *pchBuff = NULL;
  248.     LPMSGID lpMsgId = (LPMSGID)pDI->itemData;
  249.  
  250.     pch = szItem;
  251.  
  252.     // Format a string from the info in lpMsgNode
  253.     // First, calculate the index to the desired bitmap
  254.     
  255.     nBmp = ((!lpMsgId->fUnRead) * 2) + ((!!lpMsgId->fHasAttach) * 1 );
  256.  
  257.     // Convert our received date and build string
  258.     
  259.     ConvertDateRec (lpMsgId->lpszDateRec, szDateRec);
  260.  
  261.     // Limit our subject size
  262.     
  263.     szTemp[0] = '\0';
  264.     
  265.     if(lpMsgId->lpszSubject && (lstrlen(lpMsgId->lpszSubject) > 32))
  266.     {
  267.         memcpy(szTemp, &lpMsgId->lpszSubject[28], 4);
  268.         memcpy(&lpMsgId->lpszSubject[28], szDots, 4);
  269.     }
  270.     
  271.     wsprintf(szItem, "\001%d\t%s\t%s\t%s", nBmp, 
  272.             (lpMsgId->lpszFrom ? lpMsgId->lpszFrom : ""),
  273.             (lpMsgId->lpszSubject ? lpMsgId->lpszSubject : ""),
  274.             szDateRec);
  275.  
  276.     // erase background
  277.     ExtTextOut(pDI->hDC, 0, 0, ETO_OPAQUE, &pDI->rcItem, NULL, 0, NULL);
  278.  
  279.     // underline or bold this line?  Only check first & second char
  280.     if(*pch == chBOLD || *pch == chUNDERLINE)
  281.     {
  282.         LOGFONT     lf;
  283.  
  284.         hfOld = GetWindowFont(pDI->hwndItem);
  285.         if(!hfOld)
  286.             hfOld = GetStockObject(SYSTEM_FONT);
  287.         GetObject(hfOld, sizeof(lf), &lf);
  288.  
  289.         if(*pch == chBOLD)
  290.         {
  291.             lf.lfWeight = FW_BOLD;
  292.             pch++;
  293.         }
  294.         if(*pch == chUNDERLINE)
  295.         {
  296.             lf.lfUnderline = TRUE;
  297.             pch++;
  298.         }
  299.  
  300.         hfDef = CreateFontIndirect(&lf);
  301.         if(hfDef)
  302.             SelectObject(pDI->hDC, hfDef);
  303.     }
  304.  
  305.     // selected or nonselected bmps?
  306.     nT = (ODS_SELECTED & pDI->itemState) ? (BMWIDTH * NUMBMPS) : 0;
  307.  
  308.     // parse the string
  309.     for(; *pch; pch++)
  310.     {
  311.         TCHAR   *pchT;
  312.         RECT    rc;
  313.  
  314.         if(*pch == chBITMAP)     // do we have a bitmap?
  315.         {
  316.             ++pch;
  317.             // draw the bitmap
  318.             BitBlt(pDI->hDC, pDI->rcItem.left + rgTabs[nTab],
  319.                 pDI->rcItem.top, BMWIDTH, BMHEIGHT, hdcMemory,
  320.                 nT + (int)(*pch - TEXT('0')) * BMWIDTH, 0, SRCCOPY);
  321.             continue;
  322.         }
  323.  
  324.         if(*pch == chTAB)    // move to next tabstop?
  325.         {
  326.             nTab++;
  327.             continue;
  328.         }
  329.  
  330.         pchT = pch;     // find end of the column of text
  331.         while(*pchT && (*pchT != chTAB))
  332.             pchT++;
  333.  
  334.         // set rect to drawtext in
  335.         SetRect(&rc, pDI->rcItem.left + rgTabs[nTab], pDI->rcItem.top, 
  336.             pDI->rcItem.right, pDI->rcItem.bottom);
  337.  
  338.         // draw the text
  339.         ExtTextOut(pDI->hDC, rc.left, rc.top + 1, ETO_OPAQUE | ETO_CLIPPED,
  340.             &rc, pch, pchT - pch, NULL);
  341.         pch = pchT - 1; // move to end of this column
  342.     }
  343.  
  344.     if(hfDef)   // delete underline or bold font if we created it
  345.     {
  346.         SelectObject(pDI->hDC, hfOld);
  347.         DeleteObject(hfDef);
  348.     }
  349.  
  350.     if(szTemp[0] != '\0')
  351.     {
  352.         memcpy(&lpMsgId->lpszSubject[28], szTemp, 4);
  353.     }
  354. }
  355.  
  356.  
  357. /*
  358.  -  DrawItem
  359.  -
  360.  *  Purpose:
  361.  *      Handles WM_DRAWITEM for both drive and directory listboxes.
  362.  *
  363.  *  Parameters:
  364.  *      pDI     LPDRAWITEMSTRUCT passed from the WM_DRAWITEM message.
  365.  */
  366.  
  367. VOID DrawItem(LPDRAWITEMSTRUCT pDI)
  368. {
  369.     COLORREF    crText, crBack;
  370.  
  371.     if((int)pDI->itemID < 0)
  372.         return;
  373.  
  374.     if((ODA_DRAWENTIRE | ODA_SELECT) & pDI->itemAction)
  375.     {
  376.         if(pDI->itemState & ODS_SELECTED)
  377.         {
  378.             // Select the appropriate text colors
  379.             crText = SetTextColor(pDI->hDC, rgbHiliteText);
  380.             crBack = SetBkColor(pDI->hDC, rgbHiliteColor);
  381.         }
  382.  
  383.         // parse and spit out bmps and text
  384.         OutTextFormat(pDI);
  385.  
  386.         // Restore original colors if we changed them above.
  387.         if(pDI->itemState & ODS_SELECTED)
  388.         {
  389.             SetTextColor(pDI->hDC, crText);
  390.             SetBkColor(pDI->hDC,   crBack);
  391.         }
  392.     }
  393.  
  394.     if((ODA_FOCUS & pDI->itemAction) || (ODS_FOCUS & pDI->itemState))
  395.         DrawFocusRect(pDI->hDC, &pDI->rcItem);
  396. }
  397.  
  398.  
  399. /*
  400.  -  ConvertDateRec
  401.  -
  402.  *  Purpose:
  403.  *      To convert the lpszDateReceived field of a message to a
  404.  *      more paletable display format; namely: mm/dd/yy hh:mmAM.
  405.  *
  406.  *  Parameters:
  407.  *      lpszDateRec         - Original format
  408.  *      lpszDateDisplay     - Display format
  409.  */
  410.  
  411. VOID ConvertDateRec (LPSTR lpszDateRec, LPSTR lpszDateDisplay)
  412. {
  413.     char  szDateTmp[32];
  414.     LPSTR lpszYear;
  415.     LPSTR lpszMonth;
  416.     LPSTR lpszDay;
  417.     LPSTR lpszHour;
  418.     LPSTR lpszMinute;
  419.     int nHour;
  420.     static char szFoo[2][3] =
  421.     {"AM", "PM"};
  422.  
  423.     *lpszDateDisplay = 0;
  424.     if (!lpszDateRec || !*lpszDateRec)
  425.         return;
  426.  
  427.     lstrcpy(szDateTmp, lpszDateRec);
  428.  
  429.     lpszYear = strtok (szDateTmp, "/ :");
  430.     lpszMonth = strtok (NULL, "/ :");
  431.     lpszDay = strtok (NULL, "/ :");
  432.     lpszHour = strtok (NULL, "/ :");
  433.     lpszMinute = strtok (NULL, "/ :");
  434.  
  435.     if(lpszHour)
  436.         nHour = atoi (lpszHour);
  437.     else
  438.         nHour = 0;
  439.  
  440.     if (nHour > 12)
  441.         wsprintf (lpszHour, "%d", nHour - 12);
  442.  
  443.     wsprintf (lpszDateDisplay, "%s/%s/%s %s:%s%s", lpszMonth,
  444.         (lpszDay ? lpszDay : ""),
  445.         (lpszYear ? lpszYear : ""),
  446.         (lpszHour ? lpszHour : ""),
  447.         (lpszMinute ? lpszMinute : ""),
  448.         szFoo[(nHour > 11 ? 1 : 0)]);
  449. }
  450.  
  451.  
  452. /*
  453.  *  RgbInvertRgb
  454.  *  
  455.  *  Purpose:
  456.  *      To reverse the byte order of the RGB value (for file format
  457.  *  
  458.  *  Arguments:
  459.  *  
  460.  *  Returns:
  461.  *      New color value (RGB to BGR)
  462.  */
  463.  
  464. #define RgbInvertRgb(_rgbOld) \
  465.     (DWORD)RGB(GetBValue(_rgbOld), GetGValue(_rgbOld), GetRValue(_rgbOld))
  466.  
  467.  
  468. /*
  469.  *  LoadAlterBitmap (mostly stolen from commdlg)
  470.  *  
  471.  *  Purpose:
  472.  *      Loads the IDB_ENVELOPE bitmap and gives all the pixels that are
  473.  *      RGBREPLACE a new color.
  474.  *
  475.  *  Assumption:
  476.  *      This function will work on one bitmap during it's lifetime.
  477.  *      (Due to the fact that it finds RGBREPLACE once and then
  478.  *      operates on that offset whenever called again because under NT,
  479.  *      it appears that the bitmap is cached, so the second time you go
  480.  *      looking for RGBREPLACE, it won't be found.) You could load the
  481.  *      resource, copy it, then modify the copy as a workaround. But I
  482.  *      chose the cheap way out as I will only ever modify one bmp.
  483.  *  
  484.  *  Arguments:
  485.  *      rgbInstead  rgb value to replace defined RGBREPLACE with
  486.  *  
  487.  *  Returns:
  488.  *      NULL - failed or hbmp of new modified bitmap
  489.  */
  490.  
  491. HBITMAP LoadAlterBitmap(DWORD rgbInstead)
  492. {
  493.     HANDLE              hbmp = 0;
  494.     LPBITMAPINFOHEADER  qbihInfo;
  495.     HDC                 hdcScreen;
  496.     HRSRC               hresLoad;
  497.     HGLOBAL             hres;
  498.     LPBYTE              qbBits;
  499.     DWORD               rgbReplace = 0;
  500.     DWORD               *rgdw = NULL;
  501.     DWORD               *lpdw = NULL;
  502.     ULONG               cb = 0;
  503.     
  504.     if (rgbInstead)
  505.         rgbReplace = RGBREPLACE;
  506.  
  507.     // load our listbox bmps resource
  508.     hresLoad = FindResource(hInst, MAKEINTRESOURCE(IDB_ENVELOPE), RT_BITMAP);
  509.     if(hresLoad == 0)
  510.         return 0;
  511.     hres = LoadResource(hInst, hresLoad);
  512.     if(hres == 0)
  513.         return 0;
  514.  
  515.     rgbReplace = RgbInvertRgb(rgbReplace);
  516.     rgbInstead = RgbInvertRgb(rgbInstead);
  517.     qbihInfo = (LPBITMAPINFOHEADER)LockResource(hres);
  518.  
  519.     // Skip over the header structure
  520.     qbBits = (LPBYTE)(qbihInfo + 1);
  521.  
  522.     // Skip the color table entries, if any
  523.     qbBits += (1 << (qbihInfo->biBitCount)) * sizeof(RGBQUAD);
  524.  
  525.     // Copy the resource into writable memory so we can
  526.     // munge the color table to set our background color
  527.     cb = (ULONG)(qbBits - (LPBYTE)qbihInfo) + qbihInfo->biSizeImage;
  528.     rgdw = (DWORD *)GlobalAllocPtr(GMEM_MOVEABLE, cb);
  529.     
  530.     CopyMemory((LPVOID)rgdw, (LPVOID)qbihInfo, cb);
  531.     
  532.     // find the color to replace in the color table
  533.     for(lpdw = (DWORD *)((LPBYTE)rgdw + qbihInfo->biSize); ; lpdw++)
  534.     {
  535.         if(*lpdw == rgbReplace)
  536.             break;
  537.     }
  538.  
  539.     // replace that color value with our new one
  540.     *lpdw = (DWORD)rgbInstead;
  541.  
  542.     // Create a color bitmap compatible with the display device
  543.     hdcScreen = GetDC(0);
  544.     if(hdcScreen != 0)
  545.     {
  546.         hbmp = CreateDIBitmap(hdcScreen, (LPBITMAPINFOHEADER)rgdw, 
  547.                 (LONG)CBM_INIT, qbBits, (LPBITMAPINFO) rgdw, DIB_RGB_COLORS);
  548.         ReleaseDC(0, hdcScreen);
  549.     }
  550.  
  551.     UnlockResource(hres);
  552.     FreeResource(hres);
  553.  
  554.     GlobalFreePtr(rgdw);
  555.     
  556.     return hbmp;
  557. }
  558.  
  559.  
  560. /*
  561.  *  DeleteBitmapLB
  562.  *  
  563.  *  Purpose:
  564.  *      Get rid of hbmpLB, if it exists
  565.  */
  566.  
  567. VOID DeleteBitmapLB(VOID)
  568. {
  569.     if(hbmpOrigMemBmp)
  570.     {
  571.         SelectObject(hdcMemory, hbmpOrigMemBmp);
  572.         if(hbmpLB != 0)
  573.         {
  574.             DeleteObject(hbmpLB);
  575.             hbmpLB = 0;
  576.         }
  577.     }
  578. }
  579.  
  580.  
  581. /*
  582.  *  LoadBitmapLB (mostly stolen from commdlg)
  583.  *  
  584.  *  Purpose:
  585.  *      Creates the listbox bitmap. If an appropriate bitmap
  586.  *      already exists, it just returns immediately.  Otherwise, it
  587.  *      loads the bitmap and creates a larger bitmap with both regular
  588.  *      and highlight colors.
  589.  *
  590.  *  Returns:
  591.  *      TRUE - success; FALSE - failure
  592.  */
  593.  
  594. BOOL LoadBitmapLB(VOID)
  595. {
  596.     BITMAP  bmp;
  597.     HANDLE  hbmp, hbmpOrig;
  598.     HDC     hdcTemp;
  599.     BOOL    bWorked = FALSE;
  600.  
  601.     // check for existing bitmap and validity
  602.     if( (hbmpLB != 0) &&
  603.         (rgbWindowColor == rgbDDWindow) &&
  604.         (rgbHiliteColor == rgbDDHilite))
  605.     {
  606.         if(SelectObject(hdcMemory, hbmpLB))
  607.             return TRUE;
  608.     }
  609.  
  610.     DeleteBitmapLB();
  611.  
  612.     rgbDDWindow = rgbWindowColor;
  613.     rgbDDHilite = rgbHiliteColor;
  614.  
  615.     if(!(hdcTemp = CreateCompatibleDC(hdcMemory)))
  616.         goto LoadExit;
  617.  
  618.     if(!(hbmp = LoadAlterBitmap(rgbWindowColor)))
  619.         goto DeleteTempDC;
  620.  
  621.     GetObject(hbmp, sizeof(BITMAP), (LPBYTE) &bmp);
  622.     dybmpLB = bmp.bmHeight;
  623.     dxbmpLB = bmp.bmWidth;
  624.  
  625.     hbmpOrig = SelectObject(hdcTemp, hbmp);
  626.  
  627.     hbmpLB = CreateDiscardableBitmap(hdcTemp, dxbmpLB*2, dybmpLB);
  628.     if(!hbmpLB)
  629.         goto DeleteTempBmp;
  630.  
  631.     if(!SelectObject(hdcMemory, hbmpLB))
  632.     {
  633.         DeleteBitmapLB();
  634.         goto DeleteTempBmp;
  635.     }
  636.  
  637.     BitBlt(hdcMemory, 0, 0, dxbmpLB, dybmpLB,   // copy unhighlited bmps
  638.            hdcTemp, 0, 0, SRCCOPY);             // into hdcMemory
  639.     SelectObject(hdcTemp, hbmpOrig);
  640.  
  641.     DeleteObject(hbmp);
  642.  
  643.     if(!(hbmp = LoadAlterBitmap(rgbHiliteColor)))
  644.         goto DeleteTempDC;
  645.  
  646.     hbmpOrig = SelectObject(hdcTemp, hbmp);
  647.     BitBlt(hdcMemory, dxbmpLB, 0, dxbmpLB, dybmpLB, // copy highlited bmps
  648.         hdcTemp, 0, 0, SRCCOPY);                    // into hdcMemory
  649.     SelectObject(hdcTemp, hbmpOrig);
  650.  
  651.     bWorked = TRUE;
  652.  
  653. DeleteTempBmp:
  654.     DeleteObject(hbmp);
  655. DeleteTempDC:
  656.     DeleteDC(hdcTemp);
  657. LoadExit:
  658.     return bWorked;
  659. }
  660.