Annotation of mstools/ole20/samples/bttncur/bttncur.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * BTTNCUR.C
        !             3:  * Buttons & Cursors Version 1.1, March 1993
        !             4:  *
        !             5:  * Public functions to generate different states of toolbar buttons from
        !             6:  * a single bitmap.  States are normal, pressed, checked, and disabled.
        !             7:  *
        !             8:  * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,
        !             9:  * as applied to redistribution of this source code in source form
        !            10:  * License is granted to use of compiled code in shipped binaries.
        !            11:  */
        !            12: 
        !            13: #ifdef WIN32
        !            14: #define _INC_OLE
        !            15: #define __RPC_H__
        !            16: #endif
        !            17: 
        !            18: 
        !            19: #define STRICT
        !            20: #include <windows.h>
        !            21: #include <memory.h>
        !            22: #include "bttncur.h"
        !            23: #include "bttncuri.h"
        !            24: 
        !            25: 
        !            26: 
        !            27: //Display sensitive information
        !            28: TOOLDISPLAYDATA     tdd;
        !            29: 
        !            30: //Library instance
        !            31: HINSTANCE           ghInst;
        !            32: 
        !            33: 
        !            34: //Cache GDI objects to speed drawing.
        !            35: HDC     hDCGlyphs    = NULL;
        !            36: HDC     hDCMono      = NULL;
        !            37: HBRUSH  hBrushDither = NULL;
        !            38: 
        !            39: //Standard images to use in case caller doesn't provide them
        !            40: HBITMAP rghBmpStandardImages[3];
        !            41: 
        !            42: //Standard button colors.
        !            43: const COLORREF crStandard[4]={ RGB(0, 0, 0)          //STDCOLOR_BLACK
        !            44:                              , RGB(128, 128, 128)    //STDCOLOR_DKGRAY
        !            45:                              , RGB(192, 192, 192)    //STDCOLOR_LTGRAY
        !            46:                              , RGB(255, 255, 255)};  //STDCOLOR_WHITE
        !            47: 
        !            48: 
        !            49: /*
        !            50:  * Mapping from image identifier to button type (command/attribute).
        !            51:  * Version 1.00 of this DLL has no attribute images defined, so
        !            52:  * the code will only support three states for each command
        !            53:  * button.  Any state is, however, valid for an application
        !            54:  * defined image.
        !            55:  */
        !            56: 
        !            57: UINT mpButtonType[TOOLIMAGE_MAX-TOOLIMAGE_MIN+1]=
        !            58:         {
        !            59:         BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND,
        !            60:         BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND,
        !            61:         BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND
        !            62:         };
        !            63: 
        !            64: 
        !            65: 
        !            66: 
        !            67: /*
        !            68:  * LibMain
        !            69:  *
        !            70:  * Purpose:
        !            71:  *  DLL-specific entry point called from LibEntry.  Initializes
        !            72:  *  global variables and loads standard image bitmaps.
        !            73:  *
        !            74:  * Parameters:
        !            75:  *  hInstance       HANDLE instance of the DLL.
        !            76:  *  wDataSeg        WORD segment selector of the DLL's data segment.
        !            77:  *  wHeapSize       WORD byte count of the heap.
        !            78:  *  lpCmdLine       LPSTR to command line used to start the module.
        !            79:  *
        !            80:  * Return Value:
        !            81:  *  HANDLE          Instance handle of the DLL.
        !            82:  */
        !            83: 
        !            84: BOOL xxxLibMain(HINSTANCE hInstance)
        !            85:        {
        !            86:         int i;
        !            87: 
        !            88:     ghInst=hInstance;
        !            89: 
        !            90:         tdd.uDPI     =96;
        !            91:     tdd.cyBar    =CYBUTTONBAR96;
        !            92:     tdd.cxButton =TOOLBUTTON_STD96WIDTH;
        !            93:     tdd.cyButton =TOOLBUTTON_STD96HEIGHT;
        !            94:     tdd.cxImage  =TOOLBUTTON_STD96IMAGEWIDTH;
        !            95:     tdd.cyImage  =TOOLBUTTON_STD96IMAGEHEIGHT;
        !            96:     tdd.uIDImages=IDB_STANDARDIMAGES96;
        !            97: 
        !            98:     for (i=0; i < 3; i++)
        !            99:         {
        !           100:         rghBmpStandardImages[i]=LoadBitmap(hInstance
        !           101:             , MAKEINTRESOURCE(IDB_STANDARDIMAGESMIN+i));
        !           102: 
        !           103:         if (NULL==rghBmpStandardImages[i])
        !           104:             return FALSE;
        !           105:         }
        !           106: 
        !           107: 
        !           108:     //Perform global initialization.
        !           109:     if (ToolButtonInit())
        !           110:         {
        !           111:         CursorsCache(hInstance);
        !           112: 
        !           113: 
        !           114:         return TRUE;
        !           115:         }
        !           116: 
        !           117:     return FALSE;
        !           118: 
        !           119:        }
        !           120: 
        !           121: #ifdef WIN32
        !           122: 
        !           123: extern  BOOL WINAPI _CRT_INIT(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved);
        !           124: extern  _cexit(void);
        !           125: void FAR PASCAL WEP(int);
        !           126:                                       
        !           127: extern  BOOL __stdcall LibMain
        !           128: (                       
        !           129:     HINSTANCE hInstance,                    
        !           130:     ULONG        Reason,                    
        !           131:     PCONTEXT  Context                 
        !           132: )
        !           133: {
        !           134:     OutputDebugString("bttncur LibMain:  bttncur.dll loaded\r\n");
        !           135: 
        !           136:     UNREFERENCED_PARAMETER(Context);
        !           137: 
        !           138:     if (Reason == DLL_PROCESS_DETACH) {
        !           139: 
        !           140:         _CRT_INIT(hInstance,Reason,NULL);
        !           141:         WEP(0);
        !           142:         return TRUE;
        !           143:     }
        !           144:     else if (Reason != DLL_PROCESS_ATTACH)
        !           145:         return TRUE;
        !           146: 
        !           147:     if (!_CRT_INIT(hInstance,Reason,NULL))
        !           148:          return FALSE;
        !           149: 
        !           150:         return xxxLibMain(hInstance);
        !           151: 
        !           152: }
        !           153: 
        !           154: #else
        !           155: 
        !           156: HANDLE FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg
        !           157:                           , WORD cbHeapSize, LPSTR lpCmdLine)
        !           158:     {
        !           159: 
        !           160:         //Perform global initialization.
        !           161:     if (xxxLibMain(hInstance))
        !           162:         if (0!=cbHeapSize)
        !           163:             UnlockData(0);
        !           164: 
        !           165:     return hInstance;
        !           166: 
        !           167:     }
        !           168: 
        !           169: #endif
        !           170: 
        !           171: 
        !           172: /*
        !           173:  * WEP
        !           174:  *
        !           175:  * Purpose:
        !           176:  *  Required DLL Exit function.  Does nothing.
        !           177:  *
        !           178:  * Parameters:
        !           179:  *  bSystemExit     BOOL indicating if the system is being shut
        !           180:  *                  down or the DLL has just been unloaded.
        !           181:  *
        !           182:  * Return Value:
        !           183:  *  void
        !           184:  *
        !           185:  */
        !           186: 
        !           187: void FAR PASCAL WEP(int bSystemExit)
        !           188:     {
        !           189:     /*
        !           190:      * **Developers:  Note that WEP is called AFTER Windows does any
        !           191:      *                automatic task cleanup.  You may see warnings for
        !           192:      *                that two DCs, a bitmap, and a brush, were not
        !           193:      *                deleted before task termination.  THIS IS NOT A
        !           194:      *                PROBLEM WITH THIS CODE AND IT IS NOT A BUG.  This
        !           195:      *                WEP function is properly called and performs the
        !           196:      *                cleanup as appropriate.  The fact that Windows is
        !           197:      *                calling WEP after checking task cleanup is not
        !           198:      *                something we can control.  Just to prove it, the
        !           199:      *                OutputDebugStrings in this and ToolButtonFree
        !           200:      *                show that the code is exercised.
        !           201:      */
        !           202: 
        !           203:    #ifdef DEBUG
        !           204:     OutputDebugString("WEP Entry\r\n");
        !           205:    #endif
        !           206: 
        !           207:     CursorsFree();
        !           208:     ToolButtonFree();
        !           209: 
        !           210:    #ifdef DEBUG
        !           211:     OutputDebugString("WEP Exit\r\n");
        !           212:    #endif
        !           213:     return;
        !           214:     }
        !           215: 
        !           216: 
        !           217: 
        !           218: 
        !           219: 
        !           220: /*
        !           221:  * UIToolConfigureForDisplay
        !           222:  * Public API
        !           223:  *
        !           224:  * Purpose:
        !           225:  *  Initializes the library to scale button images for the display type.
        !           226:  *  Without calling this function the library defaults to 96 DPI (VGA).
        !           227:  *  By calling this function an application acknowledges that it must
        !           228:  *  use the data returned from this function to configure itself for
        !           229:  *  the display.
        !           230:  *
        !           231:  * Parameters:
        !           232:  *  lpDD            LPTOOLDISPLAYDATA to fill with the display-sensitive
        !           233:  *                  size values.
        !           234:  *
        !           235:  * Return Value:
        !           236:  *  BOOL            TRUE if the sizes were obtained, FALSE otherwise.
        !           237:  */
        !           238: 
        !           239: BOOL WINAPI UIToolConfigureForDisplay(LPTOOLDISPLAYDATA lpDD)
        !           240:     {
        !           241:     int         cy;
        !           242:     HDC         hDC;
        !           243: 
        !           244: 
        !           245:     if (NULL==lpDD || IsBadWritePtr(lpDD, sizeof(TOOLDISPLAYDATA)))
        !           246:         return FALSE;
        !           247: 
        !           248:     /*
        !           249:      * Determine the aspect ratio of the display we're currently
        !           250:      * running on and calculate the necessary information.
        !           251:      *
        !           252:      * By retrieving the logical Y extent of the display driver, you
        !           253:      * only have limited possibilities:
        !           254:      *      LOGPIXELSY      Display
        !           255:      *      ----------------------------------------
        !           256:      *         48             CGA    (unsupported)
        !           257:      *         72             EGA
        !           258:      *         96             VGA
        !           259:      *        120             8514/a (i.e. HiRes VGA)
        !           260:      */
        !           261: 
        !           262:     hDC=GetDC(NULL);
        !           263: 
        !           264:     if (NULL==hDC)
        !           265:         return FALSE;
        !           266: 
        !           267:     cy=GetDeviceCaps(hDC, LOGPIXELSY);
        !           268:     ReleaseDC(NULL, hDC);
        !           269: 
        !           270:     /*
        !           271:      * Instead of single comparisons, check ranges instead, so in case
        !           272:      * we get something funky, we'll act reasonable.
        !           273:      */
        !           274:     if (72 >=cy)
        !           275:         {
        !           276:         lpDD->uDPI     =72;
        !           277:         lpDD->cyBar    =CYBUTTONBAR72;
        !           278:         lpDD->cxButton =TOOLBUTTON_STD72WIDTH;
        !           279:         lpDD->cyButton =TOOLBUTTON_STD72HEIGHT;
        !           280:         lpDD->cxImage  =TOOLBUTTON_STD72IMAGEWIDTH;
        !           281:         lpDD->cyImage  =TOOLBUTTON_STD72IMAGEHEIGHT;
        !           282:         lpDD->uIDImages=IDB_STANDARDIMAGES72;
        !           283:         }
        !           284:     else
        !           285:         {
        !           286:         if (72 < cy && 120 > cy)
        !           287:             {
        !           288:             lpDD->uDPI     =96;
        !           289:             lpDD->cyBar    =CYBUTTONBAR96;
        !           290:             lpDD->cxButton =TOOLBUTTON_STD96WIDTH;
        !           291:             lpDD->cyButton =TOOLBUTTON_STD96HEIGHT;
        !           292:             lpDD->cxImage  =TOOLBUTTON_STD96IMAGEWIDTH;
        !           293:             lpDD->cyImage  =TOOLBUTTON_STD96IMAGEHEIGHT;
        !           294:             lpDD->uIDImages=IDB_STANDARDIMAGES96;
        !           295:             }
        !           296:         else
        !           297:             {
        !           298:             lpDD->uDPI     =120;
        !           299:             lpDD->cyBar    =CYBUTTONBAR120;
        !           300:             lpDD->cxButton =TOOLBUTTON_STD120WIDTH;
        !           301:             lpDD->cyButton =TOOLBUTTON_STD120HEIGHT;
        !           302:             lpDD->cxImage  =TOOLBUTTON_STD120IMAGEWIDTH;
        !           303:             lpDD->cyImage  =TOOLBUTTON_STD120IMAGEHEIGHT;
        !           304:             lpDD->uIDImages=IDB_STANDARDIMAGES120;
        !           305:             }
        !           306:         }
        !           307: 
        !           308:     return TRUE;
        !           309:     }
        !           310: 
        !           311: 
        !           312: 
        !           313: 
        !           314: 
        !           315: 
        !           316: 
        !           317: 
        !           318: /*
        !           319:  * ToolButtonInit
        !           320:  * Internal
        !           321:  *
        !           322:  * Purpose:
        !           323:  *  Initializes GDI objects for drawing images through UIToolButtonDraw.
        !           324:  *  If the function fails, the function has already performed proper
        !           325:  *  cleanup.
        !           326:  *
        !           327:  * Parameters:
        !           328:  *  None
        !           329:  *
        !           330:  * Return Value:
        !           331:  *  BOOL            TRUE if initialization succeeded.  FALSE otherwise.
        !           332:  */
        !           333: 
        !           334: static BOOL ToolButtonInit(void)
        !           335:     {
        !           336:     COLORREF        rgbHi;
        !           337: 
        !           338:     //DC for BitBltting the image (the glyph)
        !           339:     hDCGlyphs=CreateCompatibleDC(NULL);
        !           340: 
        !           341:     //Create a monochrome DC and a brush for doing pattern dithering.
        !           342:     hDCMono=CreateCompatibleDC(NULL);
        !           343: 
        !           344:     //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white.
        !           345:     if (0x0300 < (UINT)GetVersion())
        !           346:         rgbHi=GetSysColor(COLOR_BTNHIGHLIGHT);
        !           347:     else
        !           348:         rgbHi=crStandard[STDCOLOR_WHITE];
        !           349: 
        !           350:     hBrushDither=HBrushDitherCreate(GetSysColor(COLOR_BTNFACE), rgbHi);
        !           351: 
        !           352:     if (NULL==hDCGlyphs || NULL==hDCMono || NULL==hBrushDither)
        !           353:         {
        !           354:         //On failure, cleanup whatever might have been allocated.
        !           355:         ToolButtonFree();
        !           356:         return FALSE;
        !           357:         }
        !           358: 
        !           359:     return TRUE;
        !           360:     }
        !           361: 
        !           362: 
        !           363: 
        !           364: 
        !           365: 
        !           366: /*
        !           367:  * ToolButtonFree
        !           368:  * Internal
        !           369:  *
        !           370:  * Purpose:
        !           371:  *  Free all GDI allocations made during initialization.  Note that the
        !           372:  *  DEBUG output included here shows that WEP is called and cleanup actually
        !           373:  *  occurs.  However, if you watch debug output in DBWIN or on a terminal,
        !           374:  *  the debugging version of Windows does automatic app cleanup before WEP
        !           375:  *  is called, leading some to believe that this code is buggy.  The
        !           376:  *  debug output below shows that we do perform all necessary cleanup.
        !           377:  *
        !           378:  * Parameters:
        !           379:  *  None
        !           380:  *
        !           381:  * Return Value:
        !           382:  *  None
        !           383:  */
        !           384: 
        !           385: static void ToolButtonFree(void)
        !           386:     {
        !           387:     UINT        i;
        !           388: 
        !           389:     if (NULL!=hDCMono)
        !           390:         DeleteDC(hDCMono);
        !           391:     hDCMono=NULL;
        !           392: 
        !           393: 
        !           394:     if (NULL!=hDCGlyphs)
        !           395:         DeleteDC(hDCGlyphs);
        !           396:     hDCGlyphs=NULL;
        !           397: 
        !           398:     if (NULL!=hBrushDither)
        !           399:         DeleteObject(hBrushDither);
        !           400:     hBrushDither=NULL;
        !           401: 
        !           402:     for (i=0; i < 3; i++)
        !           403:         {
        !           404:         if (NULL!=rghBmpStandardImages[i])
        !           405:             DeleteObject(rghBmpStandardImages[i]);
        !           406:         rghBmpStandardImages[i]=NULL;
        !           407:         }
        !           408: 
        !           409:     return;
        !           410:     }
        !           411: 
        !           412: 
        !           413: 
        !           414: 
        !           415: 
        !           416: /*
        !           417:  * HBrushDitherCreate
        !           418:  * Internal
        !           419:  *
        !           420:  * Purpose:
        !           421:  *  Creates and returns a handle to a pattern brush created from
        !           422:  *  an 8*8 monochrome pattern bitmap.  We use the button face and
        !           423:  *  highlight colors to indicate the resulting colors of a PatBlt
        !           424:  *  using this brush.
        !           425:  *
        !           426:  * Parameters:
        !           427:  *  rgbFace         COLORREF of the button face color.
        !           428:  *  rgbHilight      COLORREF of the button highlight color.
        !           429:  *
        !           430:  * Return Value:
        !           431:  *  HBITMAP         Handle to the dither bitmap.
        !           432:  */
        !           433: 
        !           434: static HBRUSH HBrushDitherCreate(COLORREF rgbFace, COLORREF rgbHilight)
        !           435:     {
        !           436:     struct  //BITMAPINFO with 16 colors
        !           437:         {
        !           438:         BITMAPINFOHEADER    bmiHeader;
        !           439:         RGBQUAD             bmiColors[16];
        !           440:         } bmi;
        !           441: 
        !           442:     HBRUSH          hBrush=NULL;
        !           443:     DWORD           patGray[8];
        !           444:     HDC             hDC;
        !           445:     HBITMAP         hBmp;
        !           446:     static COLORREF rgbFaceOld   =0xFFFFFFFF;  //Initially an impossible color
        !           447:     static COLORREF rgbHilightOld=0xFFFFFFFF;  //so at first we always create
        !           448: 
        !           449:     /*
        !           450:      * If the colors haven't changed from last time, just return the
        !           451:      * existing brush.
        !           452:      */
        !           453:     if (rgbFace==rgbFaceOld && rgbHilight==rgbHilightOld)
        !           454:         return hBrushDither;
        !           455: 
        !           456:     rgbFaceOld=rgbFace;
        !           457:     rgbHilightOld=rgbHilight;
        !           458: 
        !           459:     /*
        !           460:      * We're going to create an 8*8 brush for PatBlt using the
        !           461:      * button face color and button highlight color.  We use this
        !           462:      * brush to affect the pressed state and the disabled state.
        !           463:      */
        !           464:     bmi.bmiHeader.biSize         = sizeof(BITMAPINFOHEADER);
        !           465:     bmi.bmiHeader.biWidth        = 8;
        !           466:     bmi.bmiHeader.biHeight       = 8;
        !           467:     bmi.bmiHeader.biPlanes       = 1;
        !           468:     bmi.bmiHeader.biBitCount     = 1;
        !           469:     bmi.bmiHeader.biCompression  = BI_RGB;
        !           470:     bmi.bmiHeader.biSizeImage    = 0;
        !           471:     bmi.bmiHeader.biXPelsPerMeter= 0;
        !           472:     bmi.bmiHeader.biYPelsPerMeter= 0;
        !           473:     bmi.bmiHeader.biClrUsed      = 0;
        !           474:     bmi.bmiHeader.biClrImportant = 0;
        !           475: 
        !           476:     bmi.bmiColors[0].rgbBlue     = GetBValue(rgbFace);
        !           477:     bmi.bmiColors[0].rgbGreen    = GetGValue(rgbFace);
        !           478:     bmi.bmiColors[0].rgbRed      = GetRValue(rgbFace);
        !           479:     bmi.bmiColors[0].rgbReserved = 0;
        !           480: 
        !           481:     bmi.bmiColors[1].rgbBlue     = GetBValue(rgbHilight);
        !           482:     bmi.bmiColors[1].rgbGreen    = GetGValue(rgbHilight);
        !           483:     bmi.bmiColors[1].rgbRed      = GetRValue(rgbHilight);
        !           484:     bmi.bmiColors[1].rgbReserved = 0;
        !           485: 
        !           486:     //Create the byte array for CreateDIBitmap.
        !           487:     patGray[6]=patGray[4]=patGray[2]=patGray[0]=0x5555AAAAL;
        !           488:     patGray[7]=patGray[5]=patGray[3]=patGray[1]=0xAAAA5555L;
        !           489: 
        !           490:     //Create the bitmap
        !           491:     hDC=GetDC(NULL);
        !           492:     hBmp=CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT, patGray
        !           493:                         , (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
        !           494:     ReleaseDC(NULL, hDC);
        !           495: 
        !           496:     //Create the brush from the bitmap
        !           497:     if (NULL!=hBmp)
        !           498:         {
        !           499:         hBrush=CreatePatternBrush(hBmp);
        !           500:         DeleteObject(hBmp);
        !           501:         }
        !           502: 
        !           503:     /*
        !           504:      * If we could recreate a brush, clean up and make it the current
        !           505:      * pattern.  Otherwise the best we can do it return the old one,
        !           506:      * which will be colored wrong, but at least it works.
        !           507:      */
        !           508:     if (NULL!=hBrush)
        !           509:         {
        !           510:         if (NULL!=hBrushDither)
        !           511:             DeleteObject(hBrushDither);
        !           512: 
        !           513:         hBrushDither=hBrush;
        !           514:         }
        !           515: 
        !           516:     return hBrushDither;
        !           517:     }
        !           518: 
        !           519: 
        !           520: 
        !           521: 
        !           522: 
        !           523: /*
        !           524:  * UIToolButtonDraw
        !           525:  * Public API
        !           526:  *
        !           527:  * Purpose:
        !           528:  *  Draws the complete image of a toolbar-style button with a given
        !           529:  *  image in the center and in a specific state.  The button is drawn
        !           530:  *  on a specified hDC at a given location, so this function is useful
        !           531:  *  on standard owner-draw buttons as well as on toolbar controls that
        !           532:  *  have only one window but show images of multiple buttons.
        !           533:  *
        !           534:  * Parameters:
        !           535:  *  hDC             HDC on which to draw.
        !           536:  *  x, y            int coordinates at which to draw.
        !           537:  *  dx, dy          int dimensions of the *button*, not necessarily the image.
        !           538:  *  hBmp            HBITMAP from which to draw the image.
        !           539:  *  bmx, bmy        int dimensions of each bitmap in hBmp.  If hBmp is NULL
        !           540:  *                  then these are forced to the standard sizes.
        !           541:  *  iImage          int index to the image to draw in the button
        !           542:  *  uStateIn        UINT containing the state index for the button and the
        !           543:  *                  color control bits.
        !           544:  *
        !           545:  * Return Value:
        !           546:  *  BOOL            TRUE if drawing succeeded, FALSE otherwise meaning that
        !           547:  *                  hDC is NULL or hBmp is NULL and iImage is not a valid
        !           548:  *                  index for a standard image.
        !           549:  */
        !           550: 
        !           551: BOOL WINAPI UIToolButtonDraw(HDC hDC, int x, int y, int dx, int dy
        !           552:     , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn)
        !           553:     {
        !           554:     return UIToolButtonDrawTDD(hDC, x, y, dx, dy, hBmp, bmx, bmy, iImage
        !           555:         , uStateIn, &tdd);
        !           556:     }
        !           557: 
        !           558: 
        !           559: 
        !           560: 
        !           561: 
        !           562: 
        !           563: /*
        !           564:  * UIToolButtonDrawTDD
        !           565:  * Public API
        !           566:  *
        !           567:  * Purpose:
        !           568:  *  Draws the complete image of a toolbar-style button with a given
        !           569:  *  image in the center and in a specific state.  The button is drawn
        !           570:  *  on a specified hDC at a given location, so this function is useful
        !           571:  *  on standard owner-draw buttons as well as on toolbar controls that
        !           572:  *  have only one window but show images of multiple buttons.
        !           573:  *
        !           574:  *  This is the same as UIToolButtonDraw but adds the pTDD configuration
        !           575:  *  structure.  UIToolButtonDraw calls us with that pointing to the
        !           576:  *  default 96dpi structure.
        !           577:  *
        !           578:  * Parameters:
        !           579:  *  hDC             HDC on which to draw.
        !           580:  *  x, y            int coordinates at which to draw.
        !           581:  *  dx, dy          int dimensions of the *button*, not necessarily the image.
        !           582:  *  hBmp            HBITMAP from which to draw the image.
        !           583:  *  bmx, bmy        int dimensions of each bitmap in hBmp.  If hBmp is NULL
        !           584:  *                  then these are forced to the standard sizes.
        !           585:  *  iImage          int index to the image to draw in the button
        !           586:  *  uStateIn        UINT containing the state index for the button and the
        !           587:  *                  color control bits.
        !           588:  *  pTDD            LPTOOLDISPLAYDATA containing display configuration.
        !           589:  *                  Can be NULL if hBmp is non-NULL.
        !           590:  *
        !           591:  * Return Value:
        !           592:  *  BOOL            TRUE if drawing succeeded, FALSE otherwise meaning that
        !           593:  *                  hDC is NULL or hBmp is NULL and iImage is not a valid
        !           594:  *                  index for a standard image.
        !           595:  */
        !           596: 
        !           597: BOOL WINAPI UIToolButtonDrawTDD(HDC hDC, int x, int y, int dx, int dy
        !           598:     , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn
        !           599:     , LPTOOLDISPLAYDATA pTDD)
        !           600:     {
        !           601:     static COLORREF crSys[5];  //Avoid stack arrays in DLLs: use static
        !           602:     UINT            uState=(UINT)LOBYTE((WORD)uStateIn);
        !           603:     UINT            uColors=(UINT)HIBYTE((WORD)uStateIn & PRESERVE_ALL);
        !           604:     int             xOffsetGlyph, yOffsetGlyph;
        !           605:     int             i, iSaveDC;
        !           606:     HDC             hMemDC;
        !           607:     HGDIOBJ         hObj;
        !           608:     HBRUSH          hBR;
        !           609:     HBITMAP         hBmpT;
        !           610:     HBITMAP         hBmpMono;
        !           611:     HBITMAP         hBmpMonoOrg;
        !           612:     HBITMAP         hBmpSave=NULL;
        !           613: 
        !           614:     if (NULL==hDC)
        !           615:         return FALSE;
        !           616: 
        !           617:     /*
        !           618:      * If we're given no image bitmap, then use the standard and validate the
        !           619:      * image index.  We also enforce the standard bitmap size and the size of
        !           620:      * the button (as requested by User Interface designers).
        !           621:      */
        !           622:     if (NULL==hBmp && !(uState & BUTTONGROUP_BLANK))
        !           623:         {
        !           624:         hBmp=rghBmpStandardImages[pTDD->uIDImages-IDB_STANDARDIMAGESMIN];
        !           625: 
        !           626:         bmx=pTDD->cxImage;            //Force bitmap dimensions
        !           627:         bmy=pTDD->cyImage;
        !           628: 
        !           629:         dx=pTDD->cxButton;            //Force button dimensions
        !           630:         dy=pTDD->cyButton;
        !           631: 
        !           632:         if (iImage > TOOLIMAGE_MAX)
        !           633:             return FALSE;
        !           634: 
        !           635:         /*
        !           636:          * If we are using a standard command button, verify that the state
        !           637:          * does not contain the LIGHTFACE group which only applies to
        !           638:          * attribute buttons.
        !           639:          */
        !           640:         if (BUTTONTYPE_COMMAND==mpButtonType[iImage]
        !           641:             && (uState & BUTTONGROUP_LIGHTFACE))
        !           642:             return FALSE;
        !           643:         }
        !           644: 
        !           645:     //Create a dithered bitmap.
        !           646:     hBmpMono=CreateBitmap(dx-2, dy-2, 1, 1, NULL);
        !           647: 
        !           648:     if (NULL==hBmpMono)
        !           649:         return FALSE;
        !           650: 
        !           651:     hBmpMonoOrg=(HBITMAP)SelectObject(hDCMono,  hBmpMono);
        !           652: 
        !           653: 
        !           654:     //Save the DC state before we munge on it.
        !           655:     iSaveDC=SaveDC(hDC);
        !           656: 
        !           657:     /*
        !           658:      * Draw a button sans image.  This also fills crSys with the system
        !           659:      * colors for us which has space for five colors.  We don't use the
        !           660:      * fifth, the frame color, in this function.
        !           661:      */
        !           662:     DrawBlankButton(hDC, x, y, dx, dy, (BOOL)(uState & BUTTONGROUP_DOWN), crSys);
        !           663: 
        !           664:     //Shift coordinates to account for the button's border
        !           665:     x++;
        !           666:     y++;
        !           667:     dx-=2;
        !           668:     dy-=2;
        !           669: 
        !           670:     /*
        !           671:      * Determine the offset necessary to center the image but also reflect
        !           672:      * the pushed-in state, which means just adding 1 to the up state.
        !           673:      */
        !           674:     i=(uState & BUTTONGROUP_DOWN) ? 1 : 0;
        !           675:     xOffsetGlyph=((dx-bmx) >> 1)+i;
        !           676:     yOffsetGlyph=((dy-bmy) >> 1)+i;
        !           677: 
        !           678: 
        !           679:     //Select the given image bitmap into the glyph DC before calling MaskCreate
        !           680:     if (NULL!=hBmp)
        !           681:         hBmpSave=(HBITMAP)SelectObject(hDCGlyphs, hBmp);
        !           682: 
        !           683: 
        !           684:     /*
        !           685:      * Draw the face on the button.  If we have an up or [mouse]down
        !           686:      * button then we can just draw it as-is.  For indeterminate,
        !           687:      * disabled, or down disabled we have to gray the image and possibly
        !           688:      * add a white shadow to it (disabled/down disabled).
        !           689:      *
        !           690:      * Also note that for the intermediate state we first draw the normal
        !           691:      * up state, then proceed to add disabling looking highlights.
        !           692:      */
        !           693: 
        !           694:     //Up, mouse down, down, indeterminate
        !           695:     if ((uState & BUTTONGROUP_ACTIVE) && !(uState & BUTTONGROUP_BLANK))
        !           696:         {
        !           697:         BOOL            fColorsSame=TRUE;
        !           698: 
        !           699:         /*
        !           700:          * In here we pay close attention to the system colors.  Where
        !           701:          * the source image is black, we paint COLOR_BTNTEXT.  Where
        !           702:          * light gray, we paint COLOR_BTNFACE.  Where dark gray we paint
        !           703:          * COLOR_BTNSHADOW, and where white we paint COLOR_BTNHILIGHT.
        !           704:          *
        !           705:          * The uColors variable contains flags to prevent color
        !           706:          * conversion.  To do a little optimization, we just do a
        !           707:          * single BitBlt if we're preserving all colors or if no colors
        !           708:          * are different than the standards, which is by far the most
        !           709:          * common case.  Otherwise, cycle through the four colors we can
        !           710:          * convert and do a BitBlt that converts it to the system color.
        !           711:          */
        !           712: 
        !           713:         //See what colors are different.
        !           714:         for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++)
        !           715:             fColorsSame &= (crSys[i]==crStandard[i]);
        !           716: 
        !           717:         if (PRESERVE_ALL==uColors || fColorsSame)
        !           718:             {
        !           719:             BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, bmx, bmy
        !           720:                    , hDCGlyphs, iImage*bmx, 0, SRCCOPY);
        !           721:             }
        !           722:         else
        !           723:             {
        !           724:             /*
        !           725:              * Cycle through hard-coded colors and create a mask that has all
        !           726:              * regions of that color in white and all other regions black.
        !           727:              * Then we select a pattern brush of the color to convert to:
        !           728:              * if we aren't converting the color then we use a brush of
        !           729:              * the standard hard-coded color, otherwise we use the actual
        !           730:              * system color.  The ROP_DSPDxax means that anything that's
        !           731:              * 1's in the mask get the pattern, anything that's 0 is unchanged
        !           732:              * in the destination.
        !           733:              *
        !           734:              * To prevent too many Blts to the screen, we use an intermediate
        !           735:              * bitmap and DC.
        !           736:              */
        !           737: 
        !           738:             hMemDC=CreateCompatibleDC(hDC);
        !           739: 
        !           740:             //Make sure conversion of monochrome to color stays B&W
        !           741:             SetTextColor(hMemDC, 0L);                     //0's in mono -> 0
        !           742:             SetBkColor(hMemDC, (COLORREF)0x00FFFFFF);     //1's in mono -> 1
        !           743: 
        !           744:             hBmpT=CreateCompatibleBitmap(hDC, bmx, bmy);
        !           745:             SelectObject(hMemDC, hBmpT);
        !           746: 
        !           747:             //Copy the unmodified bitmap to the temporary bitmap
        !           748:             BitBlt(hMemDC, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);
        !           749: 
        !           750:             for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++)
        !           751:                 {
        !           752:                 //Convert pixels of the color to convert to 1's in the mask
        !           753:                 SetBkColor(hDCGlyphs, crStandard[i]);
        !           754:                 BitBlt(hDCMono, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);
        !           755: 
        !           756:                 //Preserve or modify the color depending on the flag.
        !           757:                 hBR=CreateSolidBrush((uColors & (1 << i))
        !           758:                                      ? crStandard[i] : crSys[i]);
        !           759: 
        !           760:                 if (NULL!=hBR)
        !           761:                     {
        !           762:                     hObj=SelectObject(hMemDC, hBR);
        !           763: 
        !           764:                     if (NULL!=hObj)
        !           765:                         {
        !           766:                         BitBlt(hMemDC, 0, 0, dx-1, dy-1, hDCMono, 0, 0, ROP_DSPDxax);
        !           767:                         SelectObject(hMemDC, hObj);
        !           768:                         }
        !           769: 
        !           770:                     DeleteObject(hBR);
        !           771:                     }
        !           772:                 }
        !           773: 
        !           774:             //Now put the final version on the display and clean up
        !           775:             BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, dx-1, dy-1
        !           776:                    , hMemDC, 0, 0, SRCCOPY);
        !           777: 
        !           778:             DeleteDC(hMemDC);
        !           779:             DeleteObject(hBmpT);
        !           780: 
        !           781:             }
        !           782:         }
        !           783: 
        !           784: 
        !           785:     //Disabled and indeterminate states (unless we're blank)
        !           786:     if ((uState & BUTTONGROUP_DISABLED || ATTRIBUTEBUTTON_INDETERMINATE==uState)
        !           787:         && !(uState & BUTTONGROUP_BLANK))
        !           788:         {
        !           789:         //Grayed state (up or down, no difference)
        !           790:         MaskCreate(iImage, dx, dy, bmx, bmy, xOffsetGlyph, yOffsetGlyph, 0);
        !           791: 
        !           792:         //Make sure conversion of monochrome to color stays B&W
        !           793:         SetTextColor(hDC, 0L);                     //0's in mono -> 0
        !           794:         SetBkColor(hDC, (COLORREF)0x00FFFFFF);     //1's in mono -> 1
        !           795: 
        !           796:         //If we're disabled, up or down, draw the highlighted shadow.
        !           797:         if (uState & BUTTONGROUP_DISABLED)
        !           798:             {
        !           799:             hBR=CreateSolidBrush(crSys[SYSCOLOR_HILIGHT]);
        !           800: 
        !           801:             if (NULL!=hBR)
        !           802:                 {
        !           803:                 hObj=SelectObject(hDC, hBR);
        !           804: 
        !           805:                 if (NULL!=hObj)
        !           806:                     {
        !           807:                     //Draw hilight color where we have 0's in the mask
        !           808:                     BitBlt(hDC, x+1, y+1, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax);
        !           809:                     SelectObject(hDC, hObj);
        !           810:                     }
        !           811:                 DeleteObject(hBR);
        !           812:                 }
        !           813:             }
        !           814: 
        !           815:         //Draw the gray image.
        !           816:         hBR=CreateSolidBrush(crSys[SYSCOLOR_SHADOW]);
        !           817: 
        !           818:         if (NULL!=hBR)
        !           819:             {
        !           820:             hObj=SelectObject(hDC, hBR);
        !           821: 
        !           822:             if (NULL!=hObj)
        !           823:                 {
        !           824:                 //Draw the shadow color where we have 0's in the mask
        !           825:                 BitBlt(hDC, x, y, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax);
        !           826:                 SelectObject(hDC, hObj);
        !           827:                 }
        !           828: 
        !           829:             DeleteObject(hBR);
        !           830:             }
        !           831:         }
        !           832: 
        !           833:     //If the button is selected do the dither brush avoiding the glyph
        !           834:     if (uState & BUTTONGROUP_LIGHTFACE)
        !           835:         {
        !           836:         HBRUSH      hBRDither;
        !           837: 
        !           838:         /*
        !           839:          * Get the dither brush.  This function will recreate it if
        !           840:          * necessary or return the global one if the colors already match.
        !           841:          */
        !           842:         hBRDither=HBrushDitherCreate(crSys[SYSCOLOR_FACE], crSys[SYSCOLOR_HILIGHT]);
        !           843:         hObj=SelectObject(hDC, hBRDither);
        !           844: 
        !           845:         if (NULL!=hObj)
        !           846:             {
        !           847:             /*
        !           848:              * The mask we create now determines where the dithering
        !           849:              * ends up.  In the down disabled state, we have to preserve
        !           850:              * the highlighted shadow, so the mask we create must have
        !           851:              * two masks of the original glyph, one of them offset by
        !           852:              * one pixel in both x & y.  For the indeterminate state,
        !           853:              * we have to mask all highlighted areas.  The state passed
        !           854:              * to MaskCreate matters here (we've used zero before).
        !           855:              */
        !           856:             MaskCreate(iImage, dx, dy, bmx, bmy
        !           857:                        , xOffsetGlyph-1, yOffsetGlyph-1, uState);
        !           858: 
        !           859:             //Convert monochrome masks to B&W color bitmap in the BitBlt.
        !           860:             SetTextColor(hDC, 0L);
        !           861:             SetBkColor(hDC, (COLORREF)0x00FFFFFF);
        !           862: 
        !           863:             /*
        !           864:              * Only draw the dither brush where the mask is 1's.  For
        !           865:              * the indeterminate state we have to not overdraw the
        !           866:              * shadow highlight so we use dx-3, dy-3 instead of dx-1
        !           867:              * and dy-1.  We do this whether or not we're blank.
        !           868:              */
        !           869:             i=(ATTRIBUTEBUTTON_INDETERMINATE==uState
        !           870:                || BLANKBUTTON_INDETERMINATE==uState) ? 3 : 1;
        !           871: 
        !           872:             BitBlt(hDC, x+1, y+1, dx-i, dy-i, hDCMono, 0, 0, ROP_DSPDxax);
        !           873:             SelectObject(hDC, hObj);
        !           874:             }
        !           875: 
        !           876:         //DO NOT delete hBRDither!  It's a reference to a shared global.
        !           877:         }
        !           878: 
        !           879:     //Cleanup hDCGlyphs:  Must do AFTER calling MaskCreate
        !           880:     if (NULL!=hBmpSave)
        !           881:         SelectObject(hDCGlyphs, hBmpSave);
        !           882: 
        !           883:     SelectObject(hDCMono,   hBmpMonoOrg);
        !           884:     DeleteObject(hBmpMono);
        !           885: 
        !           886:     //Restore everything in the DC.
        !           887:     RestoreDC(hDC, iSaveDC);
        !           888:     return TRUE;
        !           889:     }
        !           890: 
        !           891: 
        !           892: 
        !           893: 
        !           894: 
        !           895: 
        !           896: /*
        !           897:  * DrawBlankButton
        !           898:  *
        !           899:  * Purpose:
        !           900:  *  Draws a button with no face using the current system colors in either
        !           901:  *  an up or down state.
        !           902:  *
        !           903:  * Parameters:
        !           904:  *  hDC             HDC on which to draw
        !           905:  *  x, y            int coordinates where we start drawing
        !           906:  *  dx,dy           int size of the button
        !           907:  *  fDown           BOOL indicating the up or down state of the button
        !           908:  *  pcr             COLORREF FAR * to five colors in which we store text,
        !           909:  *                  shadow, face, highlight, and frame colors.  This is
        !           910:  *                  a matter of convenience for the caller, since we have
        !           911:  *                  to load these colors anyway we might as well send them
        !           912:  *                  back.
        !           913:  *
        !           914:  * Return Value:
        !           915:  *  None
        !           916:  */
        !           917: 
        !           918: static void DrawBlankButton(HDC hDC, int x, int y, int dx, int dy
        !           919:     , BOOL fDown, COLORREF FAR *pcr)
        !           920:     {
        !           921:     //Get the current system colors for buttons.
        !           922:     pcr[0]=GetSysColor(COLOR_BTNTEXT);
        !           923:     pcr[1]=GetSysColor(COLOR_BTNSHADOW);
        !           924:     pcr[2]=GetSysColor(COLOR_BTNFACE);
        !           925: 
        !           926:     //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white.
        !           927:     if (0x0300 < (UINT)GetVersion())
        !           928:         pcr[3]=GetSysColor(COLOR_BTNHIGHLIGHT);
        !           929:     else
        !           930:         pcr[3]=crStandard[STDCOLOR_WHITE];
        !           931: 
        !           932:     pcr[4]=GetSysColor(COLOR_WINDOWFRAME);
        !           933: 
        !           934:     //Draw the border around the button.
        !           935:     PatB(hDC, x+1,    y,      dx-2, 1,    pcr[4]);
        !           936:     PatB(hDC, x+1,    y+dy-1, dx-2, 1,    pcr[4]);
        !           937:     PatB(hDC, x,      y+1,    1,    dy-2, pcr[4]);
        !           938:     PatB(hDC, x+dx-1, y+1,    1,    dy-2, pcr[4]);
        !           939: 
        !           940:     //Shift coordinates to account for the border we just drew
        !           941:     x++;
        !           942:     y++;
        !           943:     dx-=2;
        !           944:     dy-=2;
        !           945: 
        !           946:     //Paint the interior grey as a default.
        !           947:     PatB(hDC, x, y, dx, dy, pcr[2]);
        !           948: 
        !           949:     /*
        !           950:      * Draw shadows and highlights.  The DOWN grouping that contains
        !           951:      * down, mouse down, and down disabled are drawn depressed.  Up,
        !           952:      * indeterminate, and disabled are drawn up.
        !           953:      */
        !           954: 
        !           955:     if (fDown)
        !           956:         {
        !           957:         PatB(hDC, x, y, 1,  dy, pcr[1]);
        !           958:         PatB(hDC, x, y, dx, 1,  pcr[1]);
        !           959:         }
        !           960:     else
        !           961:         {
        !           962:         //Normal button look.
        !           963:         PatB(hDC, x, y, 1,    dy-1, pcr[3]);
        !           964:         PatB(hDC, x, y, dx-1, 1,    pcr[3]);
        !           965: 
        !           966:         PatB(hDC, x+dx-1, y,      1,  dy, pcr[1]);
        !           967:         PatB(hDC, x,      y+dy-1, dx, 1,  pcr[1]);
        !           968: 
        !           969:         PatB(hDC, x+1+dx-3, y+1,    1,    dy-2, pcr[1]);
        !           970:         PatB(hDC, x+1,      y+dy-2, dx-2, 1,    pcr[1]);
        !           971:         }
        !           972: 
        !           973:     return;
        !           974:     }
        !           975: 
        !           976: 
        !           977: 
        !           978: 
        !           979: 
        !           980: 
        !           981: /*
        !           982:  * PatB
        !           983:  * Internal
        !           984:  *
        !           985:  * Purpose:
        !           986:  *  A more convenient PatBlt operation for drawing button borders and
        !           987:  *  highlights.
        !           988:  *
        !           989:  * Parameters:
        !           990:  *  hDC             HDC on which to paint.
        !           991:  *  x, y            int coordinates at which to paint.
        !           992:  *  dx, dy          int dimensions of rectangle to paint.
        !           993:  *  rgb             COLORREF to use as the background color.
        !           994:  *
        !           995:  * Return Value:
        !           996:  *  None
        !           997:  */
        !           998: 
        !           999: static void PatB(HDC hDC, int x, int y, int dx, int dy, COLORREF rgb)
        !          1000:     {
        !          1001:     RECT        rc;
        !          1002: 
        !          1003:     SetBkColor(hDC, rgb);
        !          1004:     SetRect(&rc, x, y, x+dx, y+dy);
        !          1005:     ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
        !          1006:     }
        !          1007: 
        !          1008: 
        !          1009: 
        !          1010: 
        !          1011: /*
        !          1012:  * MaskCreate
        !          1013:  * Internal
        !          1014:  *
        !          1015:  * Purpose:
        !          1016:  *  Creates a monochrome mask bitmap of the given image at the given offset
        !          1017:  *  in the global hDCMono.  Anywhere in the image that you have the light
        !          1018:  *  gray (STDCOLOR_LTGRAY) or the white highlight (STDCOLOR_WHITE) you get
        !          1019:  *  get 1's.  All other pixels are 0's
        !          1020:  *
        !          1021:  * Parameters:
        !          1022:  *  iImage          UINT index of the image for which to create a mask.
        !          1023:  *  dx, dy          int dimensions of the button.
        !          1024:  *  bmx, bmy        int dimensions of the bitmap to use.
        !          1025:  *  xOffset         int offset for x inside hDCMono where we paint.
        !          1026:  *  yOffset         int offset for y inside hDCMono where we paint.
        !          1027:  *  uState          UINT state of the image.  Special cases are made
        !          1028:  *                  for ATTRIBUTEBUTTON_DOWNDISABLED and
        !          1029:  *                  ATTRIBUTEBUTTON_INDETERMINATE.  In any case where you
        !          1030:  *                  do not want a special case, pass zero here, regardless
        !          1031:  *                  of the true button state.
        !          1032:  *
        !          1033:  * Return Value:
        !          1034:  *  None
        !          1035:  */
        !          1036: 
        !          1037: static void MaskCreate(UINT iImage, int dx, int dy, int bmx, int bmy
        !          1038:     ,int xOffset, int yOffset, UINT uState)
        !          1039:     {
        !          1040:     //Initalize whole area with zeros
        !          1041:     PatBlt(hDCMono, 0, 0, dx, dy, WHITENESS);
        !          1042: 
        !          1043:     if (uState & BUTTONGROUP_BLANK)
        !          1044:         return;
        !          1045: 
        !          1046:     //Convert face colored pixels to 1's. all others to black.
        !          1047:     SetBkColor(hDCGlyphs, crStandard[STDCOLOR_LTGRAY]);
        !          1048:     BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);
        !          1049: 
        !          1050:     //In the indeterminate state, don't turn highlight's to 1's. Leave black.
        !          1051:     if (ATTRIBUTEBUTTON_INDETERMINATE!=uState)
        !          1052:         {
        !          1053:         //Convert highlight colored pixels to 1's and OR them with the previous.
        !          1054:         SetBkColor(hDCGlyphs, crStandard[STDCOLOR_WHITE]);
        !          1055:         BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCPAINT);
        !          1056:         }
        !          1057: 
        !          1058:     /*
        !          1059:      * For the down disabled state, AND this same mask with itself at an
        !          1060:      * offset of 1, which accounts for the highlight shadow.
        !          1061:      */
        !          1062:     if (ATTRIBUTEBUTTON_DOWNDISABLED==uState)
        !          1063:         BitBlt(hDCMono, 1, 1, dx-1, dy-1, hDCMono,  0, 0, SRCAND);
        !          1064: 
        !          1065:     return;
        !          1066:     }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.