Browse Source

If cf_dif is associated with a clip then show a thumbnail of the picture and show the picture in the desciption

git-svn-id: svn://svn.code.sf.net/p/ditto-cp/code/trunk@119 595ec19a-5cb4-439b-94a8-42fb3063c22c
sabrogden 21 years ago
parent
commit
b32542edff
13 changed files with 2212 additions and 284 deletions
  1. 131 0
      DIBAPI.H
  2. 1258 0
      DIBUTIL.CPP
  3. 25 0
      DIBUTIL.H
  4. 47 0
      Misc.cpp
  5. 3 1
      Misc.h
  6. 31 0
      ProcessCopy.cpp
  7. 5 5
      ProcessCopy.h
  8. 206 193
      QListCtrl.cpp
  9. 10 13
      QListCtrl.h
  10. 95 72
      QPasteWnd.cpp
  11. 1 0
      QPasteWnd.h
  12. 332 0
      ToolTipEx.cpp
  13. 68 0
      ToolTipEx.h

+ 131 - 0
DIBAPI.H

@@ -0,0 +1,131 @@
+/*    PortTool v2.2     dibapi.h          */
+
+/*
+ *  dibapi.h
+ *
+ *  ** Win32 Version **
+ *
+ *  Copyright 1991-1998 Microsoft Corporation. All rights reserved
+ *
+ *  Header file for Device-Independent Bitmap (DIB) API.  Provides
+ *  function prototypes and constants for the following functions:
+ *
+ *  BitmapToDIB()        - Creates a DIB from a bitmap
+ *  ChangeBitmapFormat() - Changes a bitmap to a specified DIB format
+ *  ChangeDIBFormat()    - Changes a DIB's BPP and/or compression format
+ *  CopyScreenToBitmap() - Copies entire screen to a standard Bitmap
+ *  CopyScreenToDIB()    - Copies entire screen to a DIB
+ *  CopyWindowToBitmap() - Copies a window to a standard Bitmap
+ *  CopyWindowToDIB()    - Copies a window to a DIB
+ *  CreateDIBPalette()   - Creates a palette from a DIB
+ *  CreateDIB()          - Creates a new DIB
+ *  DestroyDIB()         - Deletes DIB when finished using it
+ *  DIBError()           - Displays message box with error message
+ *  DIBHeight()          - Gets the DIB height
+ *  DIBNumColors()       - Calculates number of colors in the DIB's color table
+ *  DIBToBitmap()        - Creates a bitmap from a DIB
+ *  DIBWidth()           - Gets the DIB width
+ *  FindDIBBits()        - Sets pointer to the DIB bits
+ *  GetSystemPalette()   - Gets the current palette
+ *  LoadDIB()            - Loads a DIB from a file
+ *  PaintBitmap()        - Displays standard bitmap in the specified DC
+ *  PaintDIB()           - Displays DIB in the specified DC
+ *  PalEntriesOnDevice() - Gets the number of palette entries
+ *  PaletteSize()        - Calculates the buffer size required by a palette
+ *  PrintDIB()           - Prints the specified DIB
+ *  PrintScreen()        - Prints the entire screen
+ *  PrintWindow()        - Prints all or part of a window
+ *  SaveDIB()            - Saves the specified dib in a file
+ *
+ * See the file DIBAPI.TXT for more information about these functions.
+ *
+ */
+
+
+/* Handle to a DIB */
+#define HDIB HANDLE
+
+
+/* Print Area selection */
+#define PW_WINDOW        1
+#define PW_CLIENT        2
+
+
+/* Print Options selection */
+#define PW_BESTFIT       1
+#define PW_STRETCHTOPAGE 2
+#define PW_SCALE         3
+
+/* DIB Macros*/
+
+// WIDTHBYTES performs DWORD-aligning of DIB scanlines.  The "bits"
+// parameter is the bit count for the scanline (biWidth * biBitCount),
+// and this macro returns the number of DWORD-aligned bytes needed 
+// to hold those bits.
+
+#ifndef __AMVIDEO__
+#define WIDTHBYTES(bits)    (((bits) + 31) / 32 * 4)
+#endif
+
+/* Error constants */
+enum {
+      ERR_MIN = 0,                     // All error #s >= this value
+      ERR_NOT_DIB = 0,                 // Tried to load a file, NOT a DIB!
+      ERR_MEMORY,                      // Not enough memory!
+      ERR_READ,                        // Error reading file!
+      ERR_LOCK,                        // Error on a GlobalLock()!
+      ERR_OPEN,                        // Error opening a file!
+      ERR_CREATEPAL,                   // Error creating palette.
+      ERR_GETDC,                       // Couldn't get a DC.
+      ERR_CREATEDDB,                   // Error create a DDB.
+      ERR_STRETCHBLT,                  // StretchBlt() returned failure.
+      ERR_STRETCHDIBITS,               // StretchDIBits() returned failure.
+      ERR_SETDIBITSTODEVICE,           // SetDIBitsToDevice() failed.
+      ERR_STARTDOC,                    // Error calling StartDoc().
+      ERR_NOGDIMODULE,                 // Couldn't find GDI module in memory.
+      ERR_SETABORTPROC,                // Error calling SetAbortProc().
+      ERR_STARTPAGE,                   // Error calling StartPage().
+      ERR_NEWFRAME,                    // Error calling NEWFRAME escape.
+      ERR_ENDPAGE,                     // Error calling EndPage().
+      ERR_ENDDOC,                      // Error calling EndDoc().
+      ERR_SETDIBITS,                   // Error calling SetDIBits().
+      ERR_FILENOTFOUND,                // Error opening file in GetDib()
+      ERR_INVALIDHANDLE,               // Invalid Handle
+      ERR_DIBFUNCTION,                 // Error on call to DIB function
+      ERR_MAX                          // All error #s < this value
+     };
+
+
+
+/* Function prototypes */
+
+HDIB BitmapToDIB (HBITMAP hBitmap, HPALETTE hPal);
+HDIB ChangeBitmapFormat (HBITMAP	hBitmap,
+                                   WORD     wBitCount,
+                                   DWORD    dwCompression,
+                                   HPALETTE hPal);
+HDIB ChangeDIBFormat (HDIB hDIB, WORD wBitCount,
+                                DWORD dwCompression);
+HBITMAP CopyScreenToBitmap (LPRECT);
+HDIB CopyScreenToDIB (LPRECT);
+HBITMAP CopyWindowToBitmap (HWND, WORD);
+HDIB CopyWindowToDIB (HWND, WORD);
+HPALETTE CreateDIBPalette (HDIB);
+HDIB CreateDIB(DWORD, DWORD, WORD);
+WORD DestroyDIB (HDIB);
+void DIBError (int ErrNo);
+DWORD DIBHeight (LPSTR lpDIB);
+WORD DIBNumColors (LPSTR lpDIB);
+HBITMAP DIBToBitmap (HDIB hDIB, HPALETTE hPal);
+DWORD DIBWidth (LPSTR lpDIB);
+LPSTR FindDIBBits (LPSTR lpDIB);
+HPALETTE GetSystemPalette (void);
+HDIB LoadDIB (LPSTR);
+BOOL PaintBitmap (HDC, LPRECT, HBITMAP, LPRECT, HPALETTE);
+BOOL PaintDIB (HDC, LPRECT, HDIB, LPRECT, HPALETTE);
+int PalEntriesOnDevice (HDC hDC);
+WORD PaletteSize (LPSTR lpDIB);
+WORD PrintDIB (HDIB, WORD, WORD, WORD, LPSTR);
+WORD PrintScreen (LPRECT, WORD, WORD, WORD, LPSTR);
+WORD PrintWindow (HWND, WORD, WORD, WORD, WORD, LPSTR);
+WORD SaveDIB (HDIB, LPSTR);

+ 1258 - 0
DIBUTIL.CPP

@@ -0,0 +1,1258 @@
+//**********************************************************************
+//
+//  dibutil.c
+//
+//  Source file for Device-Independent Bitmap (DIB) API.  Provides
+//  the following functions:
+//
+//  CreateDIB()         - Creates new DIB
+//  FindDIBBits()       - Sets pointer to the DIB bits
+//  DIBWidth()          - Gets the width of the DIB
+//  DIBHeight()         - Gets the height of the DIB
+//  PaletteSize()       - Calculates the buffer size required by a palette
+//  DIBNumColors()      - Calculates number of colors in the DIB's color table
+//  CreateDIBPalette()  - Creates a palette from a DIB
+//  DIBToBitmap()       - Creates a bitmap from a DIB
+//  BitmapToDIB()       - Creates a DIB from a bitmap
+//  PalEntriesOnDevice()- Gets the number of palette entries of a device
+//  GetSystemPalette()  - Returns a handle to the current system palette
+//  AllocRoomForDIB()   - Allocates memory for a DIB
+//  ChangeDIBFormat()   - Changes a DIB's BPP and/or compression format
+//  ChangeBitmapFormat()- Changes a bitmap to a DIB with specified BPP and
+//                        compression format
+//
+// Written by Microsoft Product Support Services, Developer Support.
+// Copyright 1991-1998 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#define     STRICT      // enable strict type checking
+
+#include "stdafx.h"
+#include <assert.h>
+#include "dibapi.h"
+#include "dibutil.h"
+#include <stdio.h>
+
+
+/*************************************************************************
+ *
+ * CreateDIB()
+ *
+ * Parameters:
+ *
+ * DWORD dwWidth    - Width for new bitmap, in pixels
+ * DWORD dwHeight   - Height for new bitmap 
+ * WORD  wBitCount  - Bit Count for new DIB (1, 4, 8, or 24)
+ *
+ * Return Value:
+ *
+ * HDIB             - Handle to new DIB
+ *
+ * Description:
+ *
+ * This function allocates memory for and initializes a new DIB by
+ * filling in the BITMAPINFOHEADER, allocating memory for the color
+ * table, and allocating memory for the bitmap bits.  As with all
+ * HDIBs, the header, colortable and bits are all in one contiguous
+ * memory block.  This function is similar to the CreateBitmap() 
+ * Windows API.
+ *
+ * The colortable and bitmap bits are left uninitialized (zeroed) in the
+ * returned HDIB.
+ *
+ *
+ ************************************************************************/
+
+HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount)
+{
+    BITMAPINFOHEADER    bi;             // bitmap header
+    LPBITMAPINFOHEADER  lpbi;           // pointer to BITMAPINFOHEADER
+    DWORD               dwLen;          // size of memory block
+    HDIB                hDIB;
+    DWORD               dwBytesPerLine; // Number of bytes per scanline
+
+
+    // Make sure bits per pixel is valid
+
+    if (wBitCount <= 1)
+        wBitCount = 1;
+    else if (wBitCount <= 4)
+        wBitCount = 4;
+    else if (wBitCount <= 8)
+        wBitCount = 8;
+    else if (wBitCount <= 24)
+        wBitCount = 24;
+    else
+        wBitCount = 4;  // set default value to 4 if parameter is bogus
+
+    // initialize BITMAPINFOHEADER
+
+    bi.biSize = sizeof(BITMAPINFOHEADER);
+    bi.biWidth = dwWidth;         // fill in width from parameter
+    bi.biHeight = dwHeight;       // fill in height from parameter
+    bi.biPlanes = 1;              // must be 1
+    bi.biBitCount = wBitCount;    // from parameter
+    bi.biCompression = BI_RGB;    
+    bi.biSizeImage = 0;           // 0's here mean "default"
+    bi.biXPelsPerMeter = 0;
+    bi.biYPelsPerMeter = 0;
+    bi.biClrUsed = 0;
+    bi.biClrImportant = 0;
+
+    // calculate size of memory block required to store the DIB.  This
+    // block should be big enough to hold the BITMAPINFOHEADER, the color
+    // table, and the bits
+
+    dwBytesPerLine = WIDTHBYTES(wBitCount * dwWidth);
+    dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + (dwBytesPerLine * dwHeight);
+
+    // alloc memory block to store our bitmap
+
+    hDIB = GlobalAlloc(GHND, dwLen);
+
+    // major bummer if we couldn't get memory block
+
+    if (!hDIB)
+        return NULL;
+
+    // lock memory and get pointer to it
+
+    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
+
+    // use our bitmap info structure to fill in first part of
+    // our DIB with the BITMAPINFOHEADER
+
+    *lpbi = bi;
+
+    // Since we don't know what the colortable and bits should contain,
+    // just leave these blank.  Unlock the DIB and return the HDIB.
+
+    GlobalUnlock(hDIB);
+
+    //return handle to the DIB
+
+    return hDIB;
+}
+
+
+/*************************************************************************
+ *
+ * FindDIBBits()
+ *
+ * Parameter:
+ *
+ * LPSTR lpDIB      - pointer to packed-DIB memory block
+ *
+ * Return Value:
+ *
+ * LPSTR            - pointer to the DIB bits
+ *
+ * Description:
+ *
+ * This function calculates the address of the DIB's bits and returns a
+ * pointer to the DIB bits.
+ *
+ ************************************************************************/
+
+LPSTR FindDIBBits(LPSTR lpDIB)
+{
+   return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB));
+}
+
+
+/*************************************************************************
+ *
+ * DIBWidth()
+ *
+ * Parameter:
+ *
+ * LPSTR lpDIB      - pointer to packed-DIB memory block
+ *
+ * Return Value:
+ *
+ * DWORD            - width of the DIB
+ *
+ * Description:
+ *
+ * This function gets the width of the DIB from the BITMAPINFOHEADER
+ * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
+ * width field if it is an OS/2-style DIB.
+ *
+ ************************************************************************/
+
+
+DWORD DIBWidth(LPSTR lpDIB)
+{
+    LPBITMAPINFOHEADER   lpbmi;  // pointer to a Win 3.0-style DIB
+    LPBITMAPCOREHEADER   lpbmc;  // pointer to an OS/2-style DIB
+
+    // point to the header (whether Win 3.0 and OS/2)
+
+    lpbmi = (LPBITMAPINFOHEADER)lpDIB;
+    lpbmc = (LPBITMAPCOREHEADER)lpDIB;
+
+    // return the DIB width if it is a Win 3.0 DIB
+
+    if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
+        return lpbmi->biWidth;
+    else  // it is an OS/2 DIB, so return its width
+        return (DWORD)lpbmc->bcWidth;
+}
+
+
+/*************************************************************************
+ *
+ * DIBHeight()
+ *
+ * Parameter:
+ *
+ * LPSTR lpDIB      - pointer to packed-DIB memory block
+ *
+ * Return Value:
+ *
+ * DWORD            - height of the DIB
+ *
+ * Description:
+ *
+ * This function gets the height of the DIB from the BITMAPINFOHEADER
+ * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
+ * height field if it is an OS/2-style DIB.
+ *
+ ************************************************************************/
+
+DWORD DIBHeight(LPSTR lpDIB)
+{
+   LPBITMAPINFOHEADER   lpbmi;  // pointer to a Win 3.0-style DIB
+   LPBITMAPCOREHEADER   lpbmc;  // pointer to an OS/2-style DIB
+
+   // point to the header (whether OS/2 or Win 3.0
+
+   lpbmi = (LPBITMAPINFOHEADER)lpDIB;
+   lpbmc = (LPBITMAPCOREHEADER)lpDIB;
+
+    // return the DIB height if it is a Win 3.0 DIB
+    if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
+        return lpbmi->biHeight;
+    else  // it is an OS/2 DIB, so return its height
+        return (DWORD)lpbmc->bcHeight;
+}
+
+
+/*************************************************************************
+ *
+ * PaletteSize()
+ *
+ * Parameter:
+ *
+ * LPSTR lpDIB      - pointer to packed-DIB memory block
+ *
+ * Return Value:
+ *
+ * WORD             - size of the color palette of the DIB
+ *
+ * Description:
+ *
+ * This function gets the size required to store the DIB's palette by
+ * multiplying the number of colors by the size of an RGBQUAD (for a
+ * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2-
+ * style DIB).
+ *
+ ************************************************************************/
+
+WORD PaletteSize(LPSTR lpDIB)
+{
+    // calculate the size required by the palette
+    if (IS_WIN30_DIB (lpDIB))
+        return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
+    else
+        return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
+}
+
+
+/*************************************************************************
+ *
+ * DIBNumColors()
+ *
+ * Parameter:
+ *
+ * LPSTR lpDIB      - pointer to packed-DIB memory block
+ *
+ * Return Value:
+ *
+ * WORD             - number of colors in the color table
+ *
+ * Description:
+ *
+ * This function calculates the number of colors in the DIB's color table
+ * by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style
+ * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
+ * if 24, no colors in color table.
+ *
+ ************************************************************************/
+
+WORD DIBNumColors(LPSTR lpDIB)
+{
+    WORD wBitCount;  // DIB bit count
+
+    // If this is a Windows-style DIB, the number of colors in the
+    // color table can be less than the number of bits per pixel
+    // allows for (i.e. lpbi->biClrUsed can be set to some value).
+    // If this is the case, return the appropriate value.
+    
+
+    if (IS_WIN30_DIB(lpDIB))
+    {
+        DWORD dwClrUsed;
+
+        dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
+        if (dwClrUsed)
+
+        return (WORD)dwClrUsed;
+    }
+
+    // Calculate the number of colors in the color table based on
+    // the number of bits per pixel for the DIB.
+    
+    if (IS_WIN30_DIB(lpDIB))
+        wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
+    else
+        wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
+
+    // return number of colors based on bits per pixel
+
+    switch (wBitCount)
+    {
+        case 1:
+            return 2;
+
+        case 4:
+            return 16;
+
+        case 8:
+            return 256;
+
+        default:
+            return 0;
+    }
+}
+
+
+/*************************************************************************
+ *
+ * CreateDIBPalette()
+ *
+ * Parameter:
+ *
+ * HDIB hDIB        - specifies the DIB
+ *
+ * Return Value:
+ *
+ * HPALETTE         - specifies the palette
+ *
+ * Description:
+ *
+ * This function creates a palette from a DIB by allocating memory for the
+ * logical palette, reading and storing the colors from the DIB's color table
+ * into the logical palette, creating a palette from this logical palette,
+ * and then returning the palette's handle. This allows the DIB to be
+ * displayed using the best possible colors (important for DIBs with 256 or
+ * more colors).
+ *
+ ************************************************************************/
+
+HPALETTE CreateDIBPalette(HDIB hDIB)
+{
+    LPLOGPALETTE        lpPal;          // pointer to a logical palette
+    HANDLE              hLogPal;        // handle to a logical palette
+    HPALETTE            hPal = NULL;    // handle to a palette
+    int                 i, wNumColors;  // loop index, number of colors in color table
+    LPSTR               lpbi;           // pointer to packed-DIB
+    LPBITMAPINFO        lpbmi;          // pointer to BITMAPINFO structure (Win3.0)
+    LPBITMAPCOREINFO    lpbmc;          // pointer to BITMAPCOREINFO structure (OS/2)
+    BOOL                bWinStyleDIB;   // Win3.0 DIB?
+
+    // if handle to DIB is invalid, return NULL
+
+    if (!hDIB)
+        return NULL;
+
+    // lock DIB memory block and get a pointer to it
+
+    lpbi = (LPSTR)GlobalLock(hDIB);
+
+    // get pointer to BITMAPINFO (Win 3.0)
+
+    lpbmi = (LPBITMAPINFO)lpbi;
+
+    // get pointer to BITMAPCOREINFO (OS/2 1.x)
+
+    lpbmc = (LPBITMAPCOREINFO)lpbi;
+
+    // get the number of colors in the DIB 
+
+    wNumColors = DIBNumColors(lpbi);
+
+    // is this a Win 3.0 DIB?
+
+    bWinStyleDIB = IS_WIN30_DIB(lpbi);
+    if (wNumColors)
+    {
+        // allocate memory block for logical palette
+
+        hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) +
+                sizeof(PALETTEENTRY) * wNumColors);
+
+        // if not enough memory, clean up and return NULL
+
+        if (!hLogPal)
+        {
+            GlobalUnlock(hDIB);
+            return NULL;
+        }
+
+        // lock memory block and get pointer to it
+
+        lpPal = (LPLOGPALETTE)GlobalLock(hLogPal);
+
+        // set version and number of palette entries
+
+        lpPal->palVersion = PALVERSION;
+        lpPal->palNumEntries = wNumColors;
+
+        // store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB)
+        // into palette
+        
+        for (i = 0; i < wNumColors; i++)
+        {
+            if (bWinStyleDIB)
+            {
+                lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
+                lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
+                lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
+                lpPal->palPalEntry[i].peFlags = 0;
+            }
+            else
+            {
+                lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
+                lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
+                lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
+                lpPal->palPalEntry[i].peFlags = 0;
+            }
+        }
+
+        // create the palette and get handle to it
+
+        hPal = CreatePalette(lpPal);
+
+        // if error getting handle to palette, clean up and return NULL
+
+        if (!hPal)
+        {
+            GlobalUnlock(hLogPal);
+            GlobalFree(hLogPal);
+            return NULL;
+        }
+    }
+
+    // clean up 
+
+    GlobalUnlock(hLogPal);
+    GlobalFree(hLogPal);
+    GlobalUnlock(hDIB);
+
+    // return handle to DIB's palette
+    return hPal;
+}
+
+
+/*************************************************************************
+ *
+ * DIBToBitmap()
+ *
+ * Parameters:
+ *
+ * HDIB hDIB        - specifies the DIB to convert
+ *
+ * HPALETTE hPal    - specifies the palette to use with the bitmap
+ *
+ * Return Value:
+ *
+ * HBITMAP          - identifies the device-dependent bitmap
+ *
+ * Description:
+ *
+ * This function creates a bitmap from a DIB using the specified palette.
+ * If no palette is specified, default is used.
+ *
+ * NOTE:
+ *
+ * The bitmap returned from this funciton is always a bitmap compatible
+ * with the screen (e.g. same bits/pixel and color planes) rather than
+ * a bitmap with the same attributes as the DIB.  This behavior is by
+ * design, and occurs because this function calls CreateDIBitmap to
+ * do its work, and CreateDIBitmap always creates a bitmap compatible
+ * with the hDC parameter passed in (because it in turn calls
+ * CreateCompatibleBitmap).
+ *
+ * So for instance, if your DIB is a monochrome DIB and you call this
+ * function, you will not get back a monochrome HBITMAP -- you will
+ * get an HBITMAP compatible with the screen DC, but with only 2
+ * colors used in the bitmap.
+ *
+ * If your application requires a monochrome HBITMAP returned for a
+ * monochrome DIB, use the function SetDIBits().
+ *
+ * Also, the DIBpassed in to the function is not destroyed on exit. This
+ * must be done later, once it is no longer needed.
+ *
+ ************************************************************************/
+
+HBITMAP DIBToBitmap(HDIB hDIB, HPALETTE hPal)
+{
+    LPSTR       lpDIBHdr, lpDIBBits;  // pointer to DIB header, pointer to DIB bits
+    HBITMAP     hBitmap;            // handle to device-dependent bitmap
+    HDC         hDC;                    // handle to DC
+    HPALETTE    hOldPal = NULL;    // handle to a palette
+
+    // if invalid handle, return NULL 
+
+    if (!hDIB)
+        return NULL;
+
+    // lock memory block and get a pointer to it
+
+    lpDIBHdr = (LPSTR)GlobalLock(hDIB);
+
+    // get a pointer to the DIB bits
+
+    lpDIBBits = FindDIBBits(lpDIBHdr);
+
+    // get a DC 
+
+    hDC = GetDC(NULL);
+    if (!hDC)
+    {
+        // clean up and return NULL
+
+        GlobalUnlock(hDIB);
+        return NULL;
+    }
+
+    // select and realize palette
+
+    if (hPal)
+        hOldPal = SelectPalette(hDC, hPal, FALSE);
+
+    RealizePalette(hDC);
+
+    // create bitmap from DIB info. and bits
+    hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT,
+            lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
+
+    // restore previous palette
+    if (hOldPal)
+        SelectPalette(hDC, hOldPal, FALSE);
+
+    // clean up
+    ReleaseDC(NULL, hDC);
+    GlobalUnlock(hDIB);
+
+    // return handle to the bitmap
+    return hBitmap;
+}
+
+
+/*************************************************************************
+ *
+ * BitmapToDIB()
+ *
+ * Parameters:
+ *
+ * HBITMAP hBitmap  - specifies the bitmap to convert
+ *
+ * HPALETTE hPal    - specifies the palette to use with the bitmap
+ *
+ * Return Value:
+ *
+ * HDIB             - identifies the device-dependent bitmap
+ *
+ * Description:
+ *
+ * This function creates a DIB from a bitmap using the specified palette.
+ *
+ ************************************************************************/
+
+HDIB BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal)
+{
+    BITMAP              bm;         // bitmap structure
+    BITMAPINFOHEADER    bi;         // bitmap header
+    LPBITMAPINFOHEADER  lpbi;       // pointer to BITMAPINFOHEADER
+    DWORD               dwLen;      // size of memory block
+    HANDLE              hDIB, h;    // handle to DIB, temp handle
+    HDC                 hDC;        // handle to DC
+    WORD                biBits;     // bits per pixel
+
+    // check if bitmap handle is valid
+
+    if (!hBitmap)
+        return NULL;
+
+    // fill in BITMAP structure, return NULL if it didn't work
+
+    if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm))
+        return NULL;
+
+    // if no palette is specified, use default palette
+
+    if (hPal == NULL)
+        hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
+
+    // calculate bits per pixel
+
+    biBits = bm.bmPlanes * bm.bmBitsPixel;
+
+    // make sure bits per pixel is valid
+
+    if (biBits <= 1)
+        biBits = 1;
+    else if (biBits <= 4)
+        biBits = 4;
+    else if (biBits <= 8)
+        biBits = 8;
+    else // if greater than 8-bit, force to 24-bit
+        biBits = 24;
+
+    // initialize BITMAPINFOHEADER
+
+    bi.biSize = sizeof(BITMAPINFOHEADER);
+    bi.biWidth = bm.bmWidth;
+    bi.biHeight = bm.bmHeight;
+    bi.biPlanes = 1;
+    bi.biBitCount = biBits;
+    bi.biCompression = BI_RGB;
+    bi.biSizeImage = 0;
+    bi.biXPelsPerMeter = 0;
+    bi.biYPelsPerMeter = 0;
+    bi.biClrUsed = 0;
+    bi.biClrImportant = 0;
+
+    // calculate size of memory block required to store BITMAPINFO
+
+    dwLen = bi.biSize + PaletteSize((LPSTR)&bi);
+
+    // get a DC
+
+    hDC = GetDC(NULL);
+
+    // select and realize our palette
+
+    hPal = SelectPalette(hDC, hPal, FALSE);
+    RealizePalette(hDC);
+
+    // alloc memory block to store our bitmap
+
+    hDIB = GlobalAlloc(GHND, dwLen);
+
+    // if we couldn't get memory block
+
+    if (!hDIB)
+    {
+      // clean up and return NULL
+
+      SelectPalette(hDC, hPal, TRUE);
+      RealizePalette(hDC);
+      ReleaseDC(NULL, hDC);
+      return NULL;
+    }
+
+    // lock memory and get pointer to it
+
+    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
+
+    /// use our bitmap info. to fill BITMAPINFOHEADER
+
+    *lpbi = bi;
+
+    // call GetDIBits with a NULL lpBits param, so it will calculate the
+    // biSizeImage field for us    
+
+    GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
+        DIB_RGB_COLORS);
+
+    // get the info. returned by GetDIBits and unlock memory block
+
+    bi = *lpbi;
+    GlobalUnlock(hDIB);
+
+    // if the driver did not fill in the biSizeImage field, make one up 
+    if (bi.biSizeImage == 0)
+        bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
+
+    // realloc the buffer big enough to hold all the bits
+
+    dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage;
+
+    if (h = GlobalReAlloc(hDIB, dwLen, 0))
+        hDIB = h;
+    else
+    {
+        // clean up and return NULL
+
+        GlobalFree(hDIB);
+        hDIB = NULL;
+        SelectPalette(hDC, hPal, TRUE);
+        RealizePalette(hDC);
+        ReleaseDC(NULL, hDC);
+        return NULL;
+    }
+
+    // lock memory block and get pointer to it */
+
+    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
+
+    // call GetDIBits with a NON-NULL lpBits param, and actualy get the
+    // bits this time
+
+    if (GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, (LPSTR)lpbi +
+            (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
+            DIB_RGB_COLORS) == 0)
+    {
+        // clean up and return NULL
+
+        GlobalUnlock(hDIB);
+        hDIB = NULL;
+        SelectPalette(hDC, hPal, TRUE);
+        RealizePalette(hDC);
+        ReleaseDC(NULL, hDC);
+        return NULL;
+    }
+
+    bi = *lpbi;
+
+    // clean up 
+    GlobalUnlock(hDIB);
+    SelectPalette(hDC, hPal, TRUE);
+    RealizePalette(hDC);
+    ReleaseDC(NULL, hDC);
+
+    // return handle to the DIB
+    return hDIB;
+}
+
+
+/*************************************************************************
+ *
+ * PalEntriesOnDevice()
+ *
+ * Parameter:
+ *
+ * HDC hDC          - device context
+ *
+ * Return Value:
+ *
+ * int              - number of palette entries on device
+ *
+ * Description:
+ *
+ * This function gets the number of palette entries on the specified device
+ *
+ ************************************************************************/
+
+int PalEntriesOnDevice(HDC hDC)
+{
+    int nColors;  // number of colors
+
+    // Find out the number of colors on this device.
+    
+    nColors = (1 << (GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)));
+
+    assert(nColors);
+    return nColors;
+}
+
+
+/*************************************************************************
+ *
+ * GetSystemPalette()
+ *
+ * Parameters:
+ *
+ * None
+ *
+ * Return Value:
+ *
+ * HPALETTE         - handle to a copy of the current system palette
+ *
+ * Description:
+ *
+ * This function returns a handle to a palette which represents the system
+ * palette.  The system RGB values are copied into our logical palette using
+ * the GetSystemPaletteEntries function.  
+ *
+ ************************************************************************/
+
+HPALETTE GetSystemPalette(void)
+{
+    HDC hDC;                // handle to a DC
+    static HPALETTE hPal = NULL;   // handle to a palette
+    HANDLE hLogPal;         // handle to a logical palette
+    LPLOGPALETTE lpLogPal;  // pointer to a logical palette
+    int nColors;            // number of colors
+
+    // Find out how many palette entries we want.
+
+    hDC = GetDC(NULL);
+
+    if (!hDC)
+        return NULL;
+
+    nColors = PalEntriesOnDevice(hDC);   // Number of palette entries
+
+    // Allocate room for the palette and lock it.
+
+    hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors *
+            sizeof(PALETTEENTRY));
+
+    // if we didn't get a logical palette, return NULL
+
+    if (!hLogPal)
+        return NULL;
+
+    // get a pointer to the logical palette
+
+    lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal);
+
+    // set some important fields
+
+    lpLogPal->palVersion = PALVERSION;
+    lpLogPal->palNumEntries = nColors;
+
+    // Copy the current system palette into our logical palette
+
+    GetSystemPaletteEntries(hDC, 0, nColors,
+            (LPPALETTEENTRY)(lpLogPal->palPalEntry));
+
+    // Go ahead and create the palette.  Once it's created,
+    // we no longer need the LOGPALETTE, so free it.    
+
+    hPal = CreatePalette(lpLogPal);
+
+    // clean up
+
+    GlobalUnlock(hLogPal);
+    GlobalFree(hLogPal);
+    ReleaseDC(NULL, hDC);
+
+    return hPal;
+}
+
+
+/*************************************************************************
+ *
+ * AllocRoomForDIB()
+ *
+ * Parameters:
+ *
+ * BITMAPINFOHEADER - bitmap info header stucture
+ *
+ * HBITMAP          - handle to the bitmap
+ *
+ * Return Value:
+ *
+ * HDIB             - handle to memory block
+ *
+ * Description:
+ *
+ *  This routine takes a BITMAPINOHEADER, and returns a handle to global
+ *  memory which can contain a DIB with that header.  It also initializes
+ *  the header portion of the global memory.  GetDIBits() is used to determine
+ *  the amount of room for the DIB's bits.  The total amount of memory
+ *  needed = sizeof(BITMAPINFOHEADER) + size of color table + size of bits.
+ *
+ ************************************************************************/
+
+HANDLE AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap)
+{
+    DWORD               dwLen;
+    HANDLE              hDIB;
+    HDC                 hDC;
+    LPBITMAPINFOHEADER  lpbi;
+    HANDLE              hTemp;
+
+    // Figure out the size needed to hold the BITMAPINFO structure
+    // (which includes the BITMAPINFOHEADER and the color table).
+
+    dwLen = bi.biSize + PaletteSize((LPSTR) &bi);
+    hDIB  = GlobalAlloc(GHND,dwLen);
+
+    // Check that DIB handle is valid
+
+    if (!hDIB)
+        return NULL;
+
+    // Set up the BITMAPINFOHEADER in the newly allocated global memory,
+    // then call GetDIBits() with lpBits = NULL to have it fill in the
+    // biSizeImage field for us.
+
+    lpbi  = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
+    *lpbi = bi;
+
+    hDC   = GetDC(NULL);
+
+    GetDIBits(hDC, hBitmap, 0, (UINT) bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
+            DIB_RGB_COLORS);
+    ReleaseDC(NULL, hDC);
+
+    // If the driver did not fill in the biSizeImage field,
+    // fill it in -- NOTE: this is a bug in the driver!
+    
+    if (lpbi->biSizeImage == 0)
+        lpbi->biSizeImage = WIDTHBYTES((DWORD)lpbi->biWidth *
+                lpbi->biBitCount) * lpbi->biHeight;
+
+    // Get the size of the memory block we need
+
+    dwLen = lpbi->biSize + PaletteSize((LPSTR) &bi) + lpbi->biSizeImage;
+
+    // Unlock the memory block
+
+    GlobalUnlock(hDIB);
+
+    // ReAlloc the buffer big enough to hold all the bits 
+
+    if (hTemp = GlobalReAlloc(hDIB,dwLen,0))
+        return hTemp;
+    else
+    {
+        // Else free memory block and return failure
+
+        GlobalFree(hDIB);
+        return NULL;
+    }
+}
+
+
+/*************************************************************************
+ *
+ * ChangeDIBFormat()
+ *
+ * Parameter:
+ *
+ * HDIB             - handle to packed-DIB in memory
+ *
+ * WORD             - desired bits per pixel
+ *
+ * DWORD            - desired compression format
+ *
+ * Return Value:
+ *
+ * HDIB             - handle to the new DIB if successful, else NULL
+ *
+ * Description:
+ *
+ * This function will convert the bits per pixel and/or the compression
+ * format of the specified DIB. Note: If the conversion was unsuccessful,
+ * we return NULL. The original DIB is left alone. Don't use code like the
+ * following:
+ *
+ *    hMyDIB = ChangeDIBFormat(hMyDIB, 8, BI_RLE4);
+ *
+ * The conversion will fail, but hMyDIB will now be NULL and the original
+ * DIB will now hang around in memory. We could have returned the old
+ * DIB, but we wanted to allow the programmer to check whether this
+ * conversion succeeded or failed.
+ *
+ ************************************************************************/
+
+HDIB ChangeDIBFormat(HDIB hDIB, WORD wBitCount, DWORD dwCompression)
+{
+    HDC                hDC;             // Handle to DC
+    HBITMAP            hBitmap;         // Handle to bitmap
+    BITMAP             Bitmap;          // BITMAP data structure
+    BITMAPINFOHEADER   bi;              // Bitmap info header
+    LPBITMAPINFOHEADER lpbi;            // Pointer to bitmap info
+    HDIB               hNewDIB = NULL;  // Handle to new DIB
+    HPALETTE           hPal, hOldPal;   // Handle to palette, prev pal
+    WORD               DIBBPP, NewBPP;  // DIB bits per pixel, new bpp
+    DWORD              DIBComp, NewComp;// DIB compression, new compression
+
+    // Check for a valid DIB handle
+
+    if (!hDIB)
+        return NULL;
+
+    // Get the old DIB's bits per pixel and compression format
+
+    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
+    DIBBPP = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
+    DIBComp = ((LPBITMAPINFOHEADER)lpbi)->biCompression;
+    GlobalUnlock(hDIB);
+
+    // Validate wBitCount and dwCompression
+    // They must match correctly (i.e., BI_RLE4 and 4 BPP or
+    // BI_RLE8 and 8BPP, etc.) or we return failure
+    if (wBitCount == 0)
+    {
+        NewBPP = DIBBPP;
+        if ((dwCompression == BI_RLE4 && NewBPP == 4) ||
+                (dwCompression == BI_RLE8 && NewBPP == 8) ||
+                (dwCompression == BI_RGB))
+            NewComp = dwCompression;
+        else
+            return NULL;
+    }
+    else if (wBitCount == 1 && dwCompression == BI_RGB)
+    {
+        NewBPP = wBitCount;
+        NewComp = BI_RGB;
+    }
+    else if (wBitCount == 4)
+    {
+        NewBPP = wBitCount;
+        if (dwCompression == BI_RGB || dwCompression == BI_RLE4)
+            NewComp = dwCompression;
+        else
+            return NULL;
+    }
+    else if (wBitCount == 8)
+    {
+        NewBPP = wBitCount;
+        if (dwCompression == BI_RGB || dwCompression == BI_RLE8)
+            NewComp = dwCompression;
+        else
+            return NULL;
+    }
+    else if (wBitCount == 24 && dwCompression == BI_RGB)
+    {
+        NewBPP = wBitCount;
+        NewComp = BI_RGB;
+    }
+    else
+        return NULL;
+
+    // Save the old DIB's palette
+
+    hPal = CreateDIBPalette(hDIB);
+    if (!hPal)
+        return NULL;
+
+    // Convert old DIB to a bitmap
+
+    hBitmap = DIBToBitmap(hDIB, hPal);
+    if (!hBitmap)
+    {
+        DeleteObject(hPal);
+        return NULL;
+    }
+
+    // Get info about the bitmap
+    GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
+
+    // Fill in the BITMAPINFOHEADER appropriately
+
+    bi.biSize               = sizeof(BITMAPINFOHEADER);
+    bi.biWidth              = Bitmap.bmWidth;
+    bi.biHeight             = Bitmap.bmHeight;
+    bi.biPlanes             = 1;
+    bi.biBitCount           = NewBPP;
+    bi.biCompression        = NewComp;
+    bi.biSizeImage          = 0;
+    bi.biXPelsPerMeter      = 0;
+    bi.biYPelsPerMeter      = 0;
+    bi.biClrUsed            = 0;
+    bi.biClrImportant       = 0;
+
+    // Go allocate room for the new DIB
+
+    hNewDIB = AllocRoomForDIB(bi, hBitmap);
+    if (!hNewDIB)
+        return NULL;
+
+    // Get a pointer to the new DIB
+
+    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB);
+
+    // Get a DC and select/realize our palette in it
+
+    hDC  = GetDC(NULL);
+    hOldPal = SelectPalette(hDC, hPal, FALSE);
+    RealizePalette(hDC);
+
+    // Call GetDIBits and get the new DIB bits
+
+    if (!GetDIBits(hDC, hBitmap, 0, (UINT) lpbi->biHeight,
+            (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi),
+            (LPBITMAPINFO)lpbi, DIB_RGB_COLORS))
+    {
+        GlobalUnlock(hNewDIB);
+        GlobalFree(hNewDIB);
+        hNewDIB = NULL;
+    }
+
+    // Clean up and return
+
+    SelectPalette(hDC, hOldPal, TRUE);
+    RealizePalette(hDC);
+    ReleaseDC(NULL, hDC);
+
+    // Unlock the new DIB's memory block
+    if (hNewDIB)
+        GlobalUnlock(hNewDIB);
+
+    DeleteObject(hBitmap);
+    DeleteObject(hPal);
+
+    return hNewDIB;
+}
+
+
+/*************************************************************************
+ *
+ * ChangeBitmapFormat()
+ *
+ * Parameter:
+ *
+ * HBITMAP          - handle to a bitmap
+ *
+ * WORD             - desired bits per pixel
+ *
+ * DWORD            - desired compression format
+ *
+ * HPALETTE         - handle to palette
+ *
+ * Return Value:
+ *
+ * HDIB             - handle to the new DIB if successful, else NULL
+ *
+ * Description:
+ *
+ * This function will convert a bitmap to the specified bits per pixel
+ * and compression format. The bitmap and it's palette will remain
+ * after calling this function.
+ *
+ ************************************************************************/
+
+HDIB ChangeBitmapFormat(HBITMAP hBitmap, WORD wBitCount, DWORD dwCompression,
+        HPALETTE hPal)
+{
+    HDC                hDC;          // Screen DC
+    HDIB               hNewDIB=NULL; // Handle to new DIB
+    BITMAP             Bitmap;       // BITMAP data structure
+    BITMAPINFOHEADER   bi;           // Bitmap info. header
+    LPBITMAPINFOHEADER lpbi;         // Pointer to bitmap header
+    HPALETTE           hOldPal=NULL; // Handle to palette
+    WORD               NewBPP;       // New bits per pixel
+    DWORD              NewComp;      // New compression format
+
+    // Check for a valid bitmap handle
+
+    if (!hBitmap)
+        return NULL;
+
+    // Validate wBitCount and dwCompression
+    // They must match correctly (i.e., BI_RLE4 and 4 BPP or
+    // BI_RLE8 and 8BPP, etc.) or we return failure
+    
+    if (wBitCount == 0)
+    {
+        NewComp = dwCompression;
+        if (NewComp == BI_RLE4)
+            NewBPP = 4;
+        else if (NewComp == BI_RLE8)
+            NewBPP = 8;
+        else // Not enough info */
+            return NULL;
+    }
+    else if (wBitCount == 1 && dwCompression == BI_RGB)
+    {
+        NewBPP = wBitCount;
+        NewComp = BI_RGB;
+    }
+    else if (wBitCount == 4)
+    {
+        NewBPP = wBitCount;
+        if (dwCompression == BI_RGB || dwCompression == BI_RLE4)
+            NewComp = dwCompression;
+        else
+            return NULL;
+    }
+    else if (wBitCount == 8)
+    {
+        NewBPP = wBitCount;
+        if (dwCompression == BI_RGB || dwCompression == BI_RLE8)
+            NewComp = dwCompression;
+        else
+            return NULL;
+    }
+    else if (wBitCount == 24 && dwCompression == BI_RGB)
+    {
+        NewBPP = wBitCount;
+        NewComp = BI_RGB;
+    }
+    else
+        return NULL;
+
+    // Get info about the bitmap
+
+    GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
+
+    // Fill in the BITMAPINFOHEADER appropriately
+
+    bi.biSize               = sizeof(BITMAPINFOHEADER);
+    bi.biWidth              = Bitmap.bmWidth;
+    bi.biHeight             = Bitmap.bmHeight;
+    bi.biPlanes             = 1;
+    bi.biBitCount           = NewBPP;
+    bi.biCompression        = NewComp;
+    bi.biSizeImage          = 0;
+    bi.biXPelsPerMeter      = 0;
+    bi.biYPelsPerMeter      = 0;
+    bi.biClrUsed            = 0;
+    bi.biClrImportant       = 0;
+
+    // Go allocate room for the new DIB
+
+    hNewDIB = AllocRoomForDIB(bi, hBitmap);
+    if (!hNewDIB)
+        return NULL;
+
+    // Get a pointer to the new DIB
+
+    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB);
+
+    // If we have a palette, get a DC and select/realize it
+
+    if (hPal)
+    {
+        hDC  = GetDC(NULL);
+        hOldPal = SelectPalette(hDC, hPal, FALSE);
+        RealizePalette(hDC);
+    }
+
+    // Call GetDIBits and get the new DIB bits
+
+    if (!GetDIBits(hDC, hBitmap, 0, (UINT) lpbi->biHeight, (LPSTR)lpbi +
+            (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
+            DIB_RGB_COLORS))
+    {
+        GlobalUnlock(hNewDIB);
+        GlobalFree(hNewDIB);
+        hNewDIB = NULL;
+    }
+
+    // Clean up and return
+
+    if (hOldPal)
+    {
+        SelectPalette(hDC, hOldPal, TRUE);
+        RealizePalette(hDC);
+        ReleaseDC(NULL, hDC);
+    }
+
+    // Unlock the new DIB's memory block
+
+    if (hNewDIB)
+        GlobalUnlock(hNewDIB);
+
+    return hNewDIB;
+}

+ 25 - 0
DIBUTIL.H

@@ -0,0 +1,25 @@
+/*    PortTool v2.2     dibutil.h          */
+
+/*
+ *  dibutil.h
+ *
+ *  Copyright 1991-1998 Microsoft Corporation. All rights reserved.
+ *
+ *  Header file for Device-Independent Bitmap (DIB) API.  Provides
+ *  function prototypes and constants for the following functions:
+ *
+ *  AllocRoomForDIB()   - Allocates memory for a DIB
+ *
+ */
+
+
+/* DIB constants */
+#define PALVERSION   0x300
+
+/* DIB macros */
+#define IS_WIN30_DIB(lpbi)  ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
+#define RECTWIDTH(lpRect)     ((lpRect)->right - (lpRect)->left)
+#define RECTHEIGHT(lpRect)    ((lpRect)->bottom - (lpRect)->top)
+
+/* function prototypes */
+HANDLE          AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap);

+ 47 - 0
Misc.cpp

@@ -23,6 +23,53 @@ int GetCBitmapHeight(const CBitmap & cbm)
 	return bm.bmHeight;
 } 
 
+BOOL GetCBitmap(void	*pClip2, CDC *pDC, CBitmap *pBitMap, int nMaxHeight)
+{
+	LPBITMAPINFO	lpBI ;
+	void*           pDIBBits;
+	BOOL bRet = FALSE;
+
+	CClipFormat		*pClip = (CClipFormat *)pClip2;
+
+	switch(pClip->m_cfType)
+	{
+	case CF_DIB:
+	{
+		lpBI = (LPBITMAPINFO)GlobalLock(pClip->m_hgData);
+		if(lpBI)
+		{
+			pDIBBits = (void*)(lpBI->bmiColors + sizeof(RGBQUAD));
+
+			int nHeight = min(nMaxHeight, lpBI->bmiHeader.biHeight);
+			int nWidth = (nHeight * lpBI->bmiHeader.biWidth) / lpBI->bmiHeader.biHeight;
+			
+			if(pBitMap)
+			{
+				pBitMap->CreateCompatibleBitmap(pDC, nWidth, nHeight);
+
+				CDC MemDc;
+				MemDc.CreateCompatibleDC(pDC);
+
+				CBitmap* oldBitmap = MemDc.SelectObject(pBitMap);	
+			
+				::StretchDIBits(MemDc.m_hDC,
+					0, 0, 
+					nWidth, nHeight,
+					0, 0, lpBI->bmiHeader.biWidth, 
+					lpBI->bmiHeader.biHeight,
+					pDIBBits, lpBI, DIB_PAL_COLORS, SRCCOPY);
+
+				MemDc.SelectObject(oldBitmap);
+
+				bRet = TRUE;
+			}
+		}
+	}
+	}
+
+	return bRet;
+}
+
 CString GetIPAddress()
 {
 	WORD wVersionRequested;

+ 3 - 1
Misc.h

@@ -9,6 +9,7 @@
 #define ONE_MINUTE				60000
 
 #define DELETE_PTR(ptr) {  if(ptr) {delete ptr; ptr = NULL;}  }
+#define IS_WIN30_DIB(lpbi)  ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
 
 #include "DatabaseUtilities.h"
 
@@ -40,7 +41,8 @@ void SetThreadName(DWORD dwThreadID, LPCTSTR szThreadName);
 
 int GetCBitmapWidth(const CBitmap & cbm);
 int GetCBitmapHeight(const CBitmap & cbm); 
-
+BOOL GetCBitmap(void *pClip2, CDC *pDC, CBitmap *pBitMap, int nMaxHeight);
+HANDLE BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal);
 
 void LogSendRecieveInfo(CString cs);
 

+ 31 - 0
ProcessCopy.cpp

@@ -90,6 +90,37 @@ HGLOBAL COleDataObjectEx::GetGlobalData(CLIPFORMAT cfFormat, LPFORMATETC lpForma
 /*----------------------------------------------------------------------------*\
 CClipFormat - holds the data of one clip format.
 \*----------------------------------------------------------------------------*/
+CClipFormat::CClipFormat(CLIPFORMAT cfType, HGLOBAL hgData)
+{
+	m_cfType = cfType;
+	m_hgData = hgData;
+	bDeleteData = true;
+}
+
+CClipFormat::~CClipFormat() 
+{ 
+	Free(); 
+}
+
+void CClipFormat::Clear()
+{
+	m_cfType = 0;
+	m_hgData = 0;
+}
+
+void CClipFormat::Free()
+{
+	if(bDeleteData)
+	{
+		if(m_hgData)
+		{
+			m_hgData = ::GlobalFree( m_hgData );
+			m_hgData = NULL;
+		}
+	}
+}
+
+
 
 /*----------------------------------------------------------------------------*\
 CClipFormats - holds an array of CClipFormat

+ 5 - 5
ProcessCopy.h

@@ -35,13 +35,13 @@ class CClipFormat
 public:
 	CLIPFORMAT	m_cfType;
     HGLOBAL		m_hgData;
+	bool		bDeleteData;
 
-	CClipFormat( CLIPFORMAT cfType = 0, HGLOBAL hgData = 0 )
-		{ m_cfType = cfType; m_hgData = hgData; }
-	~CClipFormat() { Free(); }
+	CClipFormat(CLIPFORMAT cfType = 0, HGLOBAL hgData = 0);
+	~CClipFormat();
 
-	void Clear() { m_cfType = 0;  m_hgData = 0; }
-	void Free() { if( m_hgData ) m_hgData = ::GlobalFree( m_hgData ); }
+	void Clear();
+	void Free();
 };
 
 /*----------------------------------------------------------------------------*\

+ 206 - 193
QListCtrl.cpp

@@ -5,6 +5,7 @@
 #include "CP_Main.h"
 #include "QListCtrl.h"
 #include "ProcessPaste.h"
+#include "dibapi.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -46,6 +47,7 @@ CQListCtrl::CQListCtrl()
 	
 	m_bShowTextForFirstTenHotKeys = true;
 	m_bStartTop = true;
+	m_pToolTip = NULL;
 }
 
 CQListCtrl::~CQListCtrl()
@@ -101,24 +103,20 @@ int CQListCtrl::GetFirstTenIndex( int num )
 
 BEGIN_MESSAGE_MAP(CQListCtrl, CListCtrl)
 //{{AFX_MSG_MAP(CQListCtrl)
-ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown)
-ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
-ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomdrawList)
-ON_WM_SYSKEYDOWN()
-ON_WM_ERASEBKGND()
-ON_WM_CREATE()
-ON_WM_VSCROLL()
-ON_WM_HSCROLL()
-ON_WM_TIMER()
-ON_WM_WINDOWPOSCHANGED()
-ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnSelectionChange)
-ON_WM_SIZE()
-	ON_WM_KEYDOWN()
-	ON_WM_MOUSEWHEEL()
-	ON_WM_KEYUP()
+	ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown)
+	ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
+	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomdrawList)
+	ON_WM_SYSKEYDOWN()
+	ON_WM_ERASEBKGND()
+	ON_WM_CREATE()
+	ON_WM_VSCROLL()
+	ON_WM_HSCROLL()
+	ON_WM_TIMER()
+	ON_WM_WINDOWPOSCHANGED()
+	ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnSelectionChange)
 	//}}AFX_MSG_MAP
-ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
-ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
+	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
+	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
 ON_WM_KILLFOCUS()
 END_MESSAGE_MAP()
 
@@ -424,6 +422,8 @@ void CQListCtrl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult)
 				strSymbols.Delete(nFlag);
 		}
 		
+		DrawBitMap(nItem, rcText, pDC);
+
 		// draw the symbol box
 		if( strSymbols.GetLength() > 0 )
 		{
@@ -499,6 +499,73 @@ void CQListCtrl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult)
 	}
 }
 
+BOOL CQListCtrl::DrawBitMap(int nItem, CRect &crRect, CDC *pDC)
+{
+	CClipFormat Clip;
+	Clip.m_cfType = CF_DIB;
+	CBitmap Bitmap;
+	bool bAddToMap = false;
+	bool bGetDIB = false;
+
+	long lDatabaseID = GetItemData(nItem);
+
+	if(m_ThumbNails.Lookup(lDatabaseID, Clip) == FALSE)
+	{
+		GetClipData(nItem, Clip);
+			
+		bAddToMap = true;
+	}
+	
+	if(Clip.m_hgData)
+	{
+		if(GetCBitmap(&Clip, pDC, &Bitmap, crRect.Height()))
+		{
+			int nWidth = GetCBitmapWidth(Bitmap);
+			int nHeight = GetCBitmapHeight(Bitmap);
+
+			CDC MemDc;
+			MemDc.CreateCompatibleDC(pDC);
+
+			CBitmap* oldBitmap = MemDc.SelectObject(&Bitmap);
+
+			pDC->BitBlt(crRect.left, crRect.top, nWidth, nHeight, &MemDc, 0, 0, SRCCOPY);
+
+			MemDc.SelectObject(oldBitmap);
+
+			crRect.left += nWidth + 3;
+
+			bGetDIB = true;
+		}
+		else
+		{
+			bAddToMap = false;
+		}
+	}
+
+	if(bAddToMap)
+	{
+		CClipFormat ThumbData(CF_DIB);
+
+		//Convert the bitmap to a DIB to cache the bitmap
+		//caching the bitmap had problems
+		if(bGetDIB)
+		{
+			HPALETTE hPal = NULL;
+
+			ThumbData.m_hgData = BitmapToDIB(Bitmap.operator HBITMAP(), hPal);
+
+			long l = GlobalSize(ThumbData.m_hgData);
+
+			//Map will delete memory in destructor
+			ThumbData.bDeleteData = false;
+		}
+		
+		m_ThumbNails.SetAt(lDatabaseID, ThumbData);
+	}
+
+	return TRUE;
+}
+
 void CQListCtrl::RefreshVisibleRows()
 {
 	int nTopIndex = GetTopIndex();
@@ -638,24 +705,11 @@ int CQListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
 		return -1;
 	
 	EnableToolTips();
-	
-	m_Popup.Init();
 
-	InitializeFlatSB(m_hWnd);
-	FlatSB_EnableScrollBar(m_hWnd, SB_BOTH, ESB_DISABLE_BOTH);
-
-	CWnd* pParent = GetParent();
+	m_pToolTip = new CToolTipEx;
+	m_pToolTip->Create(this);
 	
-	m_SkinVerticleScrollbar.Create(NULL, WS_CHILD|SS_LEFT|SS_NOTIFY|WS_VISIBLE|WS_GROUP,CRect(0,0,0,0), pParent);
-	m_SkinHorizontalScrollbar.Create(NULL, WS_CHILD|SS_LEFT|SS_NOTIFY|WS_VISIBLE|WS_GROUP,CRect(0,0,0,0), pParent);
-	m_SkinVerticleScrollbar.m_pList = this;
-	m_SkinHorizontalScrollbar.m_pList = this;
-
-	PositionScrollBars();
 	
-	//	m_Popup.SetTTWnd( GetToolTips()->m_hWnd );
-	//	m_Popup.m_TI.hwnd = m_hWnd;
-    
 	return 0;
 }
 
@@ -665,100 +719,98 @@ BOOL CQListCtrl::PreTranslateMessage(MSG* pMsg)
 	if(m_Accels.OnMsg(pMsg, dID))
 		if(GetParent()->SendMessage(NM_SELECT_DB_ID, dID, 0) )
 			return TRUE;
+
+	if(m_pToolTip)
+	{
+		if(m_pToolTip->OnMsg(pMsg))
+			return TRUE;
+	}
 		
-		switch(pMsg->message) 
+	switch(pMsg->message) 
+	{
+	case WM_KEYDOWN:
+		WPARAM vk = pMsg->wParam;
+				
+		// if a number key was pressed
+		if( '0' <= vk && vk <= '9' )
 		{
-		case WM_KEYDOWN:
-			WPARAM vk = pMsg->wParam;
+			// if <Ctrl> is required but is absent, then break
+			if( g_Opt.m_bUseCtrlNumAccel && !(GetKeyState(VK_CONTROL) & 0x8000) )
+				break;
 			
-			if(m_Popup.m_bIsShowing)
+			int index = vk - '0';
+			// '0' is actually 10 in the ditto window
+			if( index == 0 )
+				index = 10;
+			// translate num 1-10 into the actual index (based upon m_bStartTop)
+			index = GetFirstTenIndex( index );
+			GetParent()->SendMessage(NM_SELECT_INDEX, index, 0);
+			return TRUE;
+		}
+		
+		switch( vk )
+		{
+		case 'X': // Ctrl-X = Cut (prepare for moving the items into a Group)
+			if(GetKeyState(VK_CONTROL) & 0x8000)
 			{
-				m_Popup.Hide();
+				LoadCopyOrCutToClipboard();		
 				
-				if(vk == VK_ESCAPE)
-					return TRUE;
+				theApp.IC_Cut(); // uses selection
+				return TRUE;
 			}
+			break;
 			
-			// if a number key was pressed
-			if( '0' <= vk && vk <= '9' )
+		case 'C': // Ctrl-C = Copy (prepare for copying the items into a Group)
+			if(GetKeyState(VK_CONTROL) & 0x8000)
 			{
-				// if <Ctrl> is required but is absent, then break
-				if( g_Opt.m_bUseCtrlNumAccel && !(GetKeyState(VK_CONTROL) & 0x8000) )
-					break;
+				LoadCopyOrCutToClipboard();
 				
-				int index = vk - '0';
-				// '0' is actually 10 in the ditto window
-				if( index == 0 )
-					index = 10;
-				// translate num 1-10 into the actual index (based upon m_bStartTop)
-				index = GetFirstTenIndex( index );
-				GetParent()->SendMessage(NM_SELECT_INDEX, index, 0);
+				theApp.IC_Copy(); // uses selection
 				return TRUE;
 			}
+			break;
 			
-			switch( vk )
+		case 'V': // Ctrl-V = Paste (actually performs the copy or move of items into the current Group)
+			if(GetKeyState(VK_CONTROL) & 0x8000)
 			{
-			case 'X': // Ctrl-X = Cut (prepare for moving the items into a Group)
-				if(GetKeyState(VK_CONTROL) & 0x8000)
-				{
-					LoadCopyOrCutToClipboard();		
-					
-					theApp.IC_Cut(); // uses selection
-					return TRUE;
-				}
-				break;
-				
-			case 'C': // Ctrl-C = Copy (prepare for copying the items into a Group)
-				if(GetKeyState(VK_CONTROL) & 0x8000)
-				{
-					LoadCopyOrCutToClipboard();
-					
-					theApp.IC_Copy(); // uses selection
-					return TRUE;
-				}
-				break;
-				
-			case 'V': // Ctrl-V = Paste (actually performs the copy or move of items into the current Group)
-				if(GetKeyState(VK_CONTROL) & 0x8000)
-				{
-					theApp.IC_Paste();
-					return TRUE;
-				}
-				break;
-				
-			case 'A': // Ctrl-A = Select All
-				if(GetKeyState(VK_CONTROL) & 0x8000)
-				{
-					int nCount = GetItemCount();
-					for(int i = 0; i < nCount; i++)
-					{
-						SetSelection(i);
-					}
-					return TRUE;
-				}
-				break;
-				
-			case VK_F3:
-				{
-					ShowFullDescription();
-					return TRUE;
-				}
-			case VK_BACK:
-				theApp.EnterGroupID( theApp.m_GroupParentID );
+				theApp.IC_Paste();
 				return TRUE;
-			case VK_SPACE:
-				if(GetKeyState(VK_CONTROL) & 0x8000)
+			}
+			break;
+			
+		case 'A': // Ctrl-A = Select All
+			if(GetKeyState(VK_CONTROL) & 0x8000)
+			{
+				int nCount = GetItemCount();
+				for(int i = 0; i < nCount; i++)
 				{
-					theApp.ShowPersistent( !g_Opt.m_bShowPersistent );
-					return TRUE;
+					SetSelection(i);
 				}
-				break;
-			} // end switch(vk)
+				return TRUE;
+			}
+			break;
 			
-			break; // end case WM_KEYDOWN
-		} // end switch(pMsg->message)
+		case VK_F3:
+			{
+				ShowFullDescription();
+				return TRUE;
+			}
+		case VK_BACK:
+			theApp.EnterGroupID( theApp.m_GroupParentID );
+			return TRUE;
+		case VK_SPACE:
+			if(GetKeyState(VK_CONTROL) & 0x8000)
+			{
+				theApp.ShowPersistent( !g_Opt.m_bShowPersistent );
+				return TRUE;
+			}
+			break;
+		} // end switch(vk)
+		
+		break; // end case WM_KEYDOWN
+	} // end switch(pMsg->message)
 		
-		return CListCtrl::PreTranslateMessage(pMsg);
+	return CListCtrl::PreTranslateMessage(pMsg);
 }
 
 void CQListCtrl::LoadCopyOrCutToClipboard()
@@ -789,16 +841,46 @@ void CQListCtrl::ShowFullDescription(bool bFromAuto)
 	GetWindowRect(&crWindow);
 	GetItemRect(nItem, rc, LVIR_BOUNDS);
 	ClientToScreen(rc);
+
+	CPoint pt;
 	
 	if(bFromAuto == false)
 	{
-		m_Popup.m_Pos = CPoint(rc.left, rc.bottom);
+		pt = CPoint(rc.left, rc.bottom);
 	}
 	else
-		m_Popup.m_Pos = CPoint((crWindow.left + (crWindow.right - crWindow.left)/2), rc.bottom);
+		pt = CPoint((crWindow.left + (crWindow.right - crWindow.left)/2), rc.bottom);
+
 	CString cs;
 	GetToolTipText(nItem, cs);
-	m_Popup.Show( cs );
+
+	if(m_pToolTip)
+	{
+		CClipFormat Clip;
+		Clip.m_cfType = CF_DIB;
+		static CBitmap *pBitMap = NULL;
+
+		if(GetClipData(nItem, Clip) && Clip.m_hgData)
+		{			
+			pBitMap = new CBitmap;
+			if(pBitMap)
+			{
+				CRect rcItem;
+				GetWindowRect(rcItem);
+				
+				CDC *pDC = GetDC();;
+
+				GetCBitmap(&Clip, pDC, pBitMap, (rcItem.Width() * 2));
+
+				ReleaseDC(pDC);
+
+				m_pToolTip->SetBitmap(pBitMap);
+			}
+		}
+		
+		m_pToolTip->SetToolTipText(cs);
+		m_pToolTip->Show(pt);
+	}
 }
 
 void CQListCtrl::GetToolTipText(int nItem, CString &csText)
@@ -825,6 +907,18 @@ void CQListCtrl::GetToolTipText(int nItem, CString &csText)
 	}
 }
 
+BOOL CQListCtrl::GetClipData(int nItem, CClipFormat &Clip)
+{
+	CWnd* pParent=GetParent();
+	if(pParent && (pParent->GetSafeHwnd() != NULL))
+	{
+		if(GetParent()->SendMessage(NM_GET_CLIP_DATA, nItem, (LPARAM) &Clip))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
 DWORD CQListCtrl::GetItemData(int nItem)
 {
 	if((GetStyle() & LVS_OWNERDATA))
@@ -870,7 +964,7 @@ void CQListCtrl::DestroyAndCreateAccelerator(BOOL bCreate)
 void CQListCtrl::OnKillFocus(CWnd* pNewWnd)
 {
 	CListCtrl::OnKillFocus(pNewWnd);
-	m_Popup.Hide();
+	m_pToolTip->Hide();
 }
 
 BOOL CQListCtrl::SetItemCountEx(int iCount, DWORD dwFlags /* = LVSICF_NOINVALIDATEALL */)
@@ -888,10 +982,6 @@ void CQListCtrl::OnSelectionChange(NMHDR* pNMHDR, LRESULT* pResult)
 	if((pnmv->uNewState == 3) ||
 		(pnmv->uNewState == 1))
 	{
-		if(m_Popup.m_bIsShowing)
-		{
-			m_Popup.Hide();
-		}
 		if(g_Opt.m_bAllwaysShowDescription)
 		{
 			KillTimer(TIMER_SHOW_PROPERTIES);
@@ -913,80 +1003,3 @@ void CQListCtrl::OnTimer(UINT nIDEvent)
 	
 	CListCtrl::OnTimer(nIDEvent);
 }
-
-void CQListCtrl::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) 
-{
-	CListCtrl::OnWindowPosChanged(lpwndpos);
-}
-
-void CQListCtrl::OnSize(UINT nType, int cx, int cy) 
-{
-	if(::IsWindow(m_hWnd))
-		PositionScrollBars();
-	
-	CListCtrl::OnSize(nType, cx, cy);
-}
-
-void CQListCtrl::PositionScrollBars()
-{
-	CWnd* pParent = GetParent();
-	
-	CRect windowRect;
-	GetWindowRect(&windowRect);
-	
-	pParent->ScreenToClient(&windowRect);
-
-	CRect vBar(windowRect.right,
-				windowRect.top,
-				windowRect.right + m_SkinVerticleScrollbar.GetHeight(),
-				windowRect.bottom + m_SkinHorizontalScrollbar.GetHeight() / 1.3);
-
-	CRect hBar(windowRect.left,
-				windowRect.bottom,
-				windowRect.right,
-				windowRect.bottom + m_SkinHorizontalScrollbar.GetHeight());
-	
-	m_SkinVerticleScrollbar.SetWindowPos(NULL,vBar.left,vBar.top,vBar.Width(),vBar.Height(),SWP_NOZORDER);
-	m_SkinHorizontalScrollbar.SetWindowPos(NULL,hBar.left,hBar.top,hBar.Width(),hBar.Height(),SWP_NOZORDER);
-	
-	m_SkinHorizontalScrollbar.UpdateThumbPosition();
-	m_SkinVerticleScrollbar.UpdateThumbPosition();
-}
-
-void CQListCtrl::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint)
-{
-	nWidth -= m_SkinVerticleScrollbar.GetHeight();;
-	nHeight -= m_SkinHorizontalScrollbar.GetHeight();
-
-	CWnd::MoveWindow(x, y, nWidth, nHeight, bRepaint);
-}
-
-void CQListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
-{
-	// TODO: Add your message handler code here and/or call default
-	
-	CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
-
-	m_SkinVerticleScrollbar.UpdateThumbPosition();
-	m_SkinHorizontalScrollbar.UpdateThumbPosition();
-}
-
-BOOL CQListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
-{
-	BOOL bRet = CListCtrl::OnMouseWheel(nFlags, zDelta, pt);
-
-	m_SkinVerticleScrollbar.UpdateThumbPosition();
-	m_SkinHorizontalScrollbar.UpdateThumbPosition();
-
-	return bRet;
-}
-
-void CQListCtrl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
-{
-	// TODO: Add your message handler code here and/or call default
-	
-	CListCtrl::OnKeyUp(nChar, nRepCnt, nFlags);
-
-	m_SkinVerticleScrollbar.UpdateThumbPosition();
-	m_SkinHorizontalScrollbar.UpdateThumbPosition();
-}

+ 10 - 13
QListCtrl.h

@@ -7,8 +7,7 @@
 // QListCtrl.h : header file
 //
 #include "ArrayEx.h"
-#include "SkinHorizontalScrollbar.h"
-#include "SkinVerticleScrollbar.h"
+#include "ToolTipEx.h"
 
 #define NM_SELECT					WM_USER+0x100
 #define NM_RIGHT					WM_USER+0x101
@@ -21,6 +20,8 @@
 #define NM_SELECT_DB_ID		        WM_USER+0x109
 #define NM_SELECT_INDEX		        WM_USER+0x110
 #define NM_GROUP_TREE_MESSAGE       WM_USER+0x111
+#define NM_GET_CLIP_DATA	        WM_USER+0x112
+
 
 //#define NM_LIST_CUT			        WM_USER+0x111
 //#define NM_LIST_COPY		        WM_USER+0x112
@@ -59,8 +60,6 @@ public:
 public:
 	virtual ~CQListCtrl();
 
-	CPopup	m_Popup;
-
 	// The "FirstTen" block is either at the top or the bottom
 	//  of the list based upon m_bStartTop.
 	BOOL	m_bShowTextForFirstTenHotKeys;
@@ -92,13 +91,15 @@ public:
 
 	void ShowFullDescription(bool bFromAuto = false);
 	BOOL SetItemCountEx(int iCount, DWORD dwFlags = LVSICF_NOINVALIDATEALL);
-	void MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);
+
+	void HidePopup()	{ if(m_pToolTip) m_pToolTip->Hide();	}
 
 protected:
 	void SendSelection(int nItem);;
 	void SendSelection(ARRAY &arrItems);
 	void LoadCopyOrCutToClipboard();
-	void PositionScrollBars();
+	BOOL GetClipData(int nItem, CClipFormat &Clip);
+	BOOL DrawBitMap(int nItem, CRect &crRect, CDC *pDC);
 		
 	WCHAR *m_pwchTip;
 	TCHAR *m_pchTip;
@@ -108,8 +109,9 @@ protected:
 	//Accelerator
 	CAccels	m_Accels;
 
-	CSkinVerticleScrollbar m_SkinVerticleScrollbar;
-	CSkinHorizontalScrollbar m_SkinHorizontalScrollbar;
+	CMap<long, long, CClipFormat, CClipFormat> m_ThumbNails;
+
+	CToolTipEx *m_pToolTip;
 	
 	// Generated message map functions
 protected:
@@ -123,12 +125,7 @@ protected:
 	afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
 	afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
 	afx_msg void OnTimer(UINT nIDEvent);
-	afx_msg void OnWindowPosChanged(WINDOWPOS FAR* lpwndpos);
 	afx_msg void OnSelectionChange(NMHDR* pNMHDR, LRESULT* pResult);
-	afx_msg void OnSize(UINT nType, int cx, int cy);
-	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
-	afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
-	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
 	//}}AFX_MSG
 	afx_msg BOOL OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult );
 	DECLARE_MESSAGE_MAP()

+ 95 - 72
QPasteWnd.cpp

@@ -49,48 +49,48 @@ CQPasteWnd::~CQPasteWnd()
 
 BEGIN_MESSAGE_MAP(CQPasteWnd, CWndEx)
 //{{AFX_MSG_MAP(CQPasteWnd)
-ON_WM_CREATE()
-ON_WM_SIZE()
-ON_WM_SETFOCUS()
-ON_WM_ACTIVATE()
-ON_COMMAND(ID_MENU_LINESPERROW_1, OnMenuLinesperrow1)
-ON_COMMAND(ID_MENU_LINESPERROW_2, OnMenuLinesperrow2)
-ON_COMMAND(ID_MENU_LINESPERROW_3, OnMenuLinesperrow3)
-ON_COMMAND(ID_MENU_LINESPERROW_4, OnMenuLinesperrow4)
-ON_COMMAND(ID_MENU_LINESPERROW_5, OnMenuLinesperrow5)
-ON_COMMAND(ID_MENU_TRANSPARENCY_10, OnMenuTransparency10)
-ON_COMMAND(ID_MENU_TRANSPARENCY_15, OnMenuTransparency15)
-ON_COMMAND(ID_MENU_TRANSPARENCY_20, OnMenuTransparency20)
-ON_COMMAND(ID_MENU_TRANSPARENCY_25, OnMenuTransparency25)
-ON_COMMAND(ID_MENU_TRANSPARENCY_30, OnMenuTransparency30)
-ON_COMMAND(ID_MENU_TRANSPARENCY_40, OnMenuTransparency40)
-ON_COMMAND(ID_MENU_TRANSPARENCY_5, OnMenuTransparency5)
-ON_COMMAND(ID_MENU_TRANSPARENCY_NONE, OnMenuTransparencyNone)
-ON_NOTIFY(NM_RCLICK, ID_LIST_HEADER, OnRclickQuickPaste)
-ON_COMMAND(ID_MENU_DELETE, OnMenuDelete)
-ON_COMMAND(ID_MENU_POSITIONING_ATCARET, OnMenuPositioningAtcaret)
-ON_COMMAND(ID_MENU_POSITIONING_ATCURSOR, OnMenuPositioningAtcursor)
-ON_COMMAND(ID_MENU_POSITIONING_ATPREVIOUSPOSITION, OnMenuPositioningAtpreviousposition)
-ON_COMMAND(ID_MENU_OPTIONS, OnMenuOptions)
-ON_BN_CLICKED(ID_CANCEL, OnCancelFilter)
-ON_COMMAND(ID_MENU_EXITPROGRAM, OnMenuExitprogram)
-ON_COMMAND(ID_MENU_TOGGLECONNECTCV, OnMenuToggleConnectCV)
-ON_COMMAND(ID_MENU_PROPERTIES, OnMenuProperties)
-ON_WM_CLOSE()
-ON_NOTIFY(LVN_BEGINDRAG, ID_LIST_HEADER, OnBegindrag)
-ON_WM_SYSKEYDOWN()
-ON_NOTIFY(LVN_GETDISPINFO, ID_LIST_HEADER, GetDispInfo)
-ON_NOTIFY(LVN_ODFINDITEM, ID_LIST_HEADER, OnFindItem)
-ON_COMMAND(ID_MENU_FIRSTTENHOTKEYS_USECTRLNUM, OnMenuFirsttenhotkeysUsectrlnum)
-ON_COMMAND(ID_MENU_FIRSTTENHOTKEYS_SHOWHOTKEYTEXT, OnMenuFirsttenhotkeysShowhotkeytext)
-ON_COMMAND(ID_MENU_QUICKOPTIONS_ALLWAYSSHOWDESCRIPTION, OnMenuQuickoptionsAllwaysshowdescription)
-ON_COMMAND(ID_MENU_QUICKOPTIONS_DOUBLECLICKINGONCAPTION_TOGGLESALWAYSONTOP, OnMenuQuickoptionsDoubleclickingoncaptionTogglesalwaysontop)
-ON_COMMAND(ID_MENU_QUICKOPTIONS_DOUBLECLICKINGONCAPTION_ROLLUPWINDOW, OnMenuQuickoptionsDoubleclickingoncaptionRollupwindow)
-ON_COMMAND(ID_MENU_QUICKOPTIONS_DOUBLECLICKINGONCAPTION_TOGGLESALWAYSSHOWDESCRIPTION, OnMenuQuickoptionsDoubleclickingoncaptionTogglesshowdescription)
-ON_COMMAND(ID_MENU_QUICKOPTIONS_PROMPTFORNEWGROUPNAMES, OnMenuQuickoptionsPromptfornewgroupnames)
-ON_BN_CLICKED(ID_SHOW_GROUPS_BOTTOM, OnShowGroupsBottom)
-ON_BN_CLICKED(ID_SHOW_GROUPS_TOP, OnShowGroupsTop)
-ON_COMMAND(ID_MENU_VIEWGROUPS, OnMenuViewgroups)
+	ON_WM_CREATE()
+	ON_WM_SIZE()
+	ON_WM_SETFOCUS()
+	ON_WM_ACTIVATE()
+	ON_COMMAND(ID_MENU_LINESPERROW_1, OnMenuLinesperrow1)
+	ON_COMMAND(ID_MENU_LINESPERROW_2, OnMenuLinesperrow2)
+	ON_COMMAND(ID_MENU_LINESPERROW_3, OnMenuLinesperrow3)
+	ON_COMMAND(ID_MENU_LINESPERROW_4, OnMenuLinesperrow4)
+	ON_COMMAND(ID_MENU_LINESPERROW_5, OnMenuLinesperrow5)
+	ON_COMMAND(ID_MENU_TRANSPARENCY_10, OnMenuTransparency10)
+	ON_COMMAND(ID_MENU_TRANSPARENCY_15, OnMenuTransparency15)
+	ON_COMMAND(ID_MENU_TRANSPARENCY_20, OnMenuTransparency20)
+	ON_COMMAND(ID_MENU_TRANSPARENCY_25, OnMenuTransparency25)
+	ON_COMMAND(ID_MENU_TRANSPARENCY_30, OnMenuTransparency30)
+	ON_COMMAND(ID_MENU_TRANSPARENCY_40, OnMenuTransparency40)
+	ON_COMMAND(ID_MENU_TRANSPARENCY_5, OnMenuTransparency5)
+	ON_COMMAND(ID_MENU_TRANSPARENCY_NONE, OnMenuTransparencyNone)
+	ON_NOTIFY(NM_RCLICK, ID_LIST_HEADER, OnRclickQuickPaste)
+	ON_COMMAND(ID_MENU_DELETE, OnMenuDelete)
+	ON_COMMAND(ID_MENU_POSITIONING_ATCARET, OnMenuPositioningAtcaret)
+	ON_COMMAND(ID_MENU_POSITIONING_ATCURSOR, OnMenuPositioningAtcursor)
+	ON_COMMAND(ID_MENU_POSITIONING_ATPREVIOUSPOSITION, OnMenuPositioningAtpreviousposition)
+	ON_COMMAND(ID_MENU_OPTIONS, OnMenuOptions)
+	ON_BN_CLICKED(ID_CANCEL, OnCancelFilter)
+	ON_COMMAND(ID_MENU_EXITPROGRAM, OnMenuExitprogram)
+	ON_COMMAND(ID_MENU_TOGGLECONNECTCV, OnMenuToggleConnectCV)
+	ON_COMMAND(ID_MENU_PROPERTIES, OnMenuProperties)
+	ON_WM_CLOSE()
+	ON_NOTIFY(LVN_BEGINDRAG, ID_LIST_HEADER, OnBegindrag)
+	ON_WM_SYSKEYDOWN()
+	ON_NOTIFY(LVN_GETDISPINFO, ID_LIST_HEADER, GetDispInfo)
+	ON_NOTIFY(LVN_ODFINDITEM, ID_LIST_HEADER, OnFindItem)
+	ON_COMMAND(ID_MENU_FIRSTTENHOTKEYS_USECTRLNUM, OnMenuFirsttenhotkeysUsectrlnum)
+	ON_COMMAND(ID_MENU_FIRSTTENHOTKEYS_SHOWHOTKEYTEXT, OnMenuFirsttenhotkeysShowhotkeytext)
+	ON_COMMAND(ID_MENU_QUICKOPTIONS_ALLWAYSSHOWDESCRIPTION, OnMenuQuickoptionsAllwaysshowdescription)
+	ON_COMMAND(ID_MENU_QUICKOPTIONS_DOUBLECLICKINGONCAPTION_TOGGLESALWAYSONTOP, OnMenuQuickoptionsDoubleclickingoncaptionTogglesalwaysontop)
+	ON_COMMAND(ID_MENU_QUICKOPTIONS_DOUBLECLICKINGONCAPTION_ROLLUPWINDOW, OnMenuQuickoptionsDoubleclickingoncaptionRollupwindow)
+	ON_COMMAND(ID_MENU_QUICKOPTIONS_DOUBLECLICKINGONCAPTION_TOGGLESALWAYSSHOWDESCRIPTION, OnMenuQuickoptionsDoubleclickingoncaptionTogglesshowdescription)
+	ON_COMMAND(ID_MENU_QUICKOPTIONS_PROMPTFORNEWGROUPNAMES, OnMenuQuickoptionsPromptfornewgroupnames)
+	ON_BN_CLICKED(ID_SHOW_GROUPS_BOTTOM, OnShowGroupsBottom)
+	ON_BN_CLICKED(ID_SHOW_GROUPS_TOP, OnShowGroupsTop)
+	ON_COMMAND(ID_MENU_VIEWGROUPS, OnMenuViewgroups)
 	ON_COMMAND(ID_MENU_QUICKPROPERTIES_SETTONEVERAUTODELETE, OnMenuQuickpropertiesSettoneverautodelete)
 	ON_COMMAND(ID_MENU_QUICKPROPERTIES_AUTODELETE, OnMenuQuickpropertiesAutodelete)
 	ON_COMMAND(ID_MENU_QUICKPROPERTIES_REMOVEHOTKEY, OnMenuQuickpropertiesRemovehotkey)
@@ -112,31 +112,32 @@ ON_COMMAND(ID_MENU_VIEWGROUPS, OnMenuViewgroups)
 	ON_COMMAND(ID_MENU_SENTTO_PROMPTFORIP, OnMenuSenttoPromptforip)
 	ON_COMMAND(ID_MENU_GROUPS_MOVETOGROUP, OnMenuGroupsMovetogroup)
 	//}}AFX_MSG_MAP
-ON_MESSAGE(NM_SELECT, OnListSelect)
-ON_MESSAGE(NM_END, OnListEnd)
-ON_MESSAGE(CB_SEARCH, OnSearch)
-ON_MESSAGE(NM_DELETE, OnDelete)
-ON_MESSAGE(NM_PROPERTIES, OnProperties)
-ON_NOTIFY(NM_GETTOOLTIPTEXT, ID_LIST_HEADER, OnGetToolTipText)
-ON_MESSAGE(NM_SELECT_DB_ID, OnListSelect_DB_ID)
-ON_MESSAGE(NM_SELECT_INDEX, OnListSelect_Index)
-ON_MESSAGE(WM_REFRESH_VIEW, OnRefreshView)
-ON_WM_NCLBUTTONDBLCLK()
-ON_WM_WINDOWPOSCHANGING()
-ON_COMMAND(ID_VIEWCAPTIONBARON_RIGHT, OnViewcaptionbaronRight)
-ON_COMMAND(ID_VIEWCAPTIONBARON_BOTTOM, OnViewcaptionbaronBottom)
-ON_COMMAND(ID_VIEWCAPTIONBARON_LEFT, OnViewcaptionbaronLeft)
-ON_COMMAND(ID_VIEWCAPTIONBARON_TOP, OnViewcaptionbaronTop)
-ON_COMMAND(ID_MENU_AUTOHIDE, OnMenuAutohide)
-ON_COMMAND(ID_MENU_VIEWFULLDESCRIPTION, OnMenuViewfulldescription)
-ON_COMMAND(ID_MENU_ALLWAYSONTOP, OnMenuAllwaysontop)
-ON_COMMAND(ID_SORT_ASCENDING, OnSortAscending)
-ON_COMMAND(ID_SORT_DESCENDING, OnSortDescending)
-ON_COMMAND(ID_MENU_NEWGROUP, OnMenuNewGroup)
-ON_COMMAND(ID_MENU_NEWGROUPSELECTION, OnMenuNewGroupSelection)
-ON_MESSAGE(NM_GROUP_TREE_MESSAGE, OnGroupTreeMessage)
-ON_COMMAND(ID_BACK_BUTTON, OnBackButton)
-END_MESSAGE_MAP()
+	ON_MESSAGE(NM_SELECT, OnListSelect)
+	ON_MESSAGE(NM_END, OnListEnd)
+	ON_MESSAGE(CB_SEARCH, OnSearch)
+	ON_MESSAGE(NM_DELETE, OnDelete)
+	ON_MESSAGE(NM_PROPERTIES, OnProperties)
+	ON_NOTIFY(NM_GETTOOLTIPTEXT, ID_LIST_HEADER, OnGetToolTipText)
+	ON_MESSAGE(NM_SELECT_DB_ID, OnListSelect_DB_ID)
+	ON_MESSAGE(NM_SELECT_INDEX, OnListSelect_Index)
+	ON_MESSAGE(WM_REFRESH_VIEW, OnRefreshView)
+	ON_WM_NCLBUTTONDBLCLK()
+	ON_WM_WINDOWPOSCHANGING()
+	ON_COMMAND(ID_VIEWCAPTIONBARON_RIGHT, OnViewcaptionbaronRight)
+	ON_COMMAND(ID_VIEWCAPTIONBARON_BOTTOM, OnViewcaptionbaronBottom)
+	ON_COMMAND(ID_VIEWCAPTIONBARON_LEFT, OnViewcaptionbaronLeft)
+	ON_COMMAND(ID_VIEWCAPTIONBARON_TOP, OnViewcaptionbaronTop)
+	ON_COMMAND(ID_MENU_AUTOHIDE, OnMenuAutohide)
+	ON_COMMAND(ID_MENU_VIEWFULLDESCRIPTION, OnMenuViewfulldescription)
+	ON_COMMAND(ID_MENU_ALLWAYSONTOP, OnMenuAllwaysontop)
+	ON_COMMAND(ID_SORT_ASCENDING, OnSortAscending)
+	ON_COMMAND(ID_SORT_DESCENDING, OnSortDescending)
+	ON_COMMAND(ID_MENU_NEWGROUP, OnMenuNewGroup)
+	ON_COMMAND(ID_MENU_NEWGROUPSELECTION, OnMenuNewGroupSelection)
+	ON_MESSAGE(NM_GROUP_TREE_MESSAGE, OnGroupTreeMessage)
+	ON_COMMAND(ID_BACK_BUTTON, OnBackButton)
+	ON_MESSAGE(NM_GET_CLIP_DATA, OnGetClipData)
+	END_MESSAGE_MAP()
 
 
 /////////////////////////////////////////////////////////////////////////////
@@ -747,8 +748,6 @@ void CQPasteWnd::OnRclickQuickPaste(NMHDR* pNMHDR, LRESULT* pResult)
 
 		SetMenuChecks(cmSubMenu);
 		
-		m_lstHeader.m_Popup.Hide();
-		
 		if(pNMHDR == NULL)
 		{
 			int nItem = m_lstHeader.GetCaret();
@@ -1889,9 +1888,8 @@ void CQPasteWnd::OnNcLButtonDblClk(UINT nHitTest, CPoint point)
 void CQPasteWnd::OnWindowPosChanging(WINDOWPOS* lpwndpos)
 {
 	CWndEx::OnWindowPosChanging(lpwndpos);
-	
-	if(m_lstHeader.m_Popup.m_bIsShowing)
-		m_lstHeader.m_Popup.Hide();
+
+	m_lstHeader.HidePopup();
 	
 	CRect rcScreen;
 	
@@ -2007,3 +2005,28 @@ void CQPasteWnd::OnBackButton()
 {
 	theApp.EnterGroupID(theApp.m_GroupParentID);
 }
+
+LRESULT CQPasteWnd::OnGetClipData(LPARAM lParam, WPARAM wParam)
+{
+	BOOL bRet = FALSE;
+	CClipFormat *pClip = (CClipFormat *)wParam;
+	int nItem = (int)lParam;
+	try
+	{
+		m_Recset.SetAbsolutePosition(nItem);
+
+		CDataTable recset;
+		recset.Open("SELECT * FROM Data WHERE lDataID = %d AND strClipBoardFormat = \"%s\"", m_Recset.m_lDataID, GetFormatName(pClip->m_cfType));
+		if(recset.IsEOF() == false)
+		{			
+			pClip->m_hgData = NewGlobal(recset.m_ooData.m_dwDataLength);
+	
+			::CopyToGlobalHH(pClip->m_hgData, recset.m_ooData.m_hData, recset.m_ooData.m_dwDataLength);
+
+			bRet = TRUE;
+		}
+	}
+	CATCHDAO
+
+	return bRet;
+}

+ 1 - 0
QPasteWnd.h

@@ -192,6 +192,7 @@ public:
 	afx_msg void OnMenuNewGroup();
 	afx_msg void OnMenuNewGroupSelection();
 	afx_msg void OnBackButton();
+	afx_msg LRESULT OnGetClipData(LPARAM lParam, WPARAM wParam);
 };
 
 

+ 332 - 0
ToolTipEx.cpp

@@ -0,0 +1,332 @@
+// ToolTipEx.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "cp_main.h"
+#include "ToolTipEx.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#define DELETE_BITMAP	if(m_pBitmap)					\
+						{								\
+							m_pBitmap->DeleteObject();	\
+							DELETE_PTR(m_pBitmap);		\
+						}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CToolTipEx
+
+CToolTipEx::CToolTipEx() :
+	m_dwTextStyle(DT_EXPANDTABS|DT_EXTERNALLEADING|DT_NOPREFIX|DT_WORDBREAK),
+	m_rectMargin(2, 2, 3, 3),
+	m_pBitmap(NULL)
+{
+}
+
+CToolTipEx::~CToolTipEx()
+{
+	DELETE_BITMAP
+	
+	m_Font.DeleteObject();
+}
+
+
+BEGIN_MESSAGE_MAP(CToolTipEx, CWnd)
+	//{{AFX_MSG_MAP(CToolTipEx)
+	ON_WM_PAINT()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CToolTipEx message handlers
+
+BOOL CToolTipEx::Create(CWnd* pParentWnd)
+{    
+    // Get the class name and create the window
+    CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS, 
+                                              LoadCursor(NULL, IDC_ARROW));
+
+    // Create the window - just don't show it yet.
+    if (!CWnd::CreateEx(WS_EX_TOPMOST, szClassName, _T(""), 
+                        WS_POPUP|WS_BORDER, 
+                        0, 0, 10, 10, // size & position updated when needed
+                        pParentWnd->GetSafeHwnd(), 0, NULL))
+	{
+        return FALSE;
+	}
+
+	SetLogFont(GetSystemToolTipFont(), FALSE);
+   
+    return TRUE;
+}
+
+BOOL CToolTipEx::Show(CPoint point)
+{
+	CRect rect = GetBoundsRect();
+
+	CRect rcScreen;
+	int nMonitor = GetMonitorFromRect(&rect);
+	GetMonitorRect(nMonitor, &rcScreen);
+	CRect crRectToScreen(point, CPoint(point.x + rect.right, point.y + rect.bottom));
+		
+	if(crRectToScreen.right > rcScreen.right)
+	{
+		point.x -= (crRectToScreen.right - rcScreen.right);
+		///Add a border
+		point.x -= 2;
+	}
+
+	if(crRectToScreen.bottom > rcScreen.bottom)
+	{
+		point.y -= (crRectToScreen.bottom - rcScreen.bottom);
+		//add a border
+		point.y -= 2;
+	}
+
+
+	ShowWindow(SW_HIDE);
+    SetWindowPos(NULL,
+                 point.x, point.y,
+                 rect.Width(), rect.Height(),
+                 SWP_SHOWWINDOW|SWP_NOCOPYBITS|SWP_NOACTIVATE|SWP_NOZORDER);
+
+	return TRUE;
+}
+
+BOOL CToolTipEx::Hide()
+{
+	DELETE_BITMAP
+
+	ShowWindow(SW_HIDE);
+
+	return TRUE;
+}
+
+void CToolTipEx::OnPaint() 
+{
+	CPaintDC dc(this); // device context for painting
+
+	CRect rect;
+    GetClientRect(rect);
+
+	CBrush  Brush, *pOldBrush;
+	Brush.CreateSolidBrush(GetSysColor(COLOR_INFOBK));
+
+	pOldBrush = dc.SelectObject(&Brush);
+	CFont *pOldFont = dc.SelectObject(&m_Font);
+
+    dc.FillRect(&rect, &Brush);
+
+	// Draw Text
+    dc.SetBkMode(TRANSPARENT);
+    rect.DeflateRect(m_rectMargin);
+
+	if(m_pBitmap)
+	{
+		CDC MemDc;
+		MemDc.CreateCompatibleDC(&dc);
+
+		CBitmap* oldBitmap = MemDc.SelectObject(m_pBitmap);
+
+		int nWidth = GetCBitmapWidth(*m_pBitmap);
+		int nHeight = GetCBitmapHeight(*m_pBitmap);
+		
+		dc.BitBlt(rect.left, rect.top, nWidth, nHeight, &MemDc, 0, 0, SRCCOPY);
+
+		MemDc.SelectObject(oldBitmap);
+
+		rect.top += nHeight;
+	}
+
+    dc.DrawText(m_csText, rect, m_dwTextStyle);
+
+	// Cleanup
+    dc.SelectObject(pOldBrush);
+	dc.SelectObject(pOldFont);
+}
+
+void CToolTipEx::PostNcDestroy() 
+{
+	CWnd::PostNcDestroy();
+
+    delete this;
+}
+
+BOOL CToolTipEx::OnMsg(MSG* pMsg)
+{
+	switch(pMsg->message) 
+	{
+		case WM_WINDOWPOSCHANGING:
+		case WM_LBUTTONDOWN:
+		{
+			//if (!IsCursorInToolTip())
+			Hide();
+			break;
+		}
+		case WM_KEYDOWN:
+		{
+			Hide();
+			WPARAM vk = pMsg->wParam;
+			if(vk == VK_ESCAPE)
+				return TRUE;
+			break;
+		}
+		case WM_LBUTTONDBLCLK:
+		case WM_RBUTTONDOWN :
+		case WM_RBUTTONDBLCLK:
+		case WM_MBUTTONDOWN:
+		case WM_MBUTTONDBLCLK:
+		case WM_NCLBUTTONDOWN:
+		case WM_NCLBUTTONDBLCLK:
+		case WM_NCRBUTTONDOWN:
+		case WM_NCRBUTTONDBLCLK:
+		case WM_NCMBUTTONDOWN:
+		case WM_NCMBUTTONDBLCLK:
+		{
+			Hide();
+			break;
+		}
+	}
+
+	return FALSE;
+}
+
+CRect CToolTipEx::GetBoundsRect()
+{
+    CWindowDC dc(NULL);
+   
+	CFont *pOldFont = (CFont*) dc.SelectObject((CFont*)&m_Font); 
+	
+	int nLineWidth = 0;
+
+	if (nLineWidth == 0)
+    {
+        // Count the number of lines of text
+        int nStart = 0, nNumLines = 0;
+		CString strTextCopy = m_csText;
+        do 
+		{
+            nStart = strTextCopy.Find(_T("\n"));
+
+            // skip found character 
+            if (nStart >= 0)
+                strTextCopy = strTextCopy.Mid(nStart+1);
+
+            nNumLines++;
+        } while (nStart >= 0);
+
+        // Find the widest line
+        for (int i = 0; i < nNumLines; i++)
+        {
+            CString strLine = GetFieldFromString(m_csText, i, _T('\n')) + _T("  ");
+            nLineWidth = max(nLineWidth, dc.GetTextExtent(strLine).cx);
+        }
+    }
+
+    CRect rect(0, 0, max(0,nLineWidth), 0);
+    dc.DrawText(m_csText, rect, DT_CALCRECT | m_dwTextStyle);
+
+	dc.SelectObject(pOldFont);
+	
+    rect.bottom += m_rectMargin.top + m_rectMargin.bottom;
+    rect.right += m_rectMargin.left + m_rectMargin.right + 2;
+
+	if(m_pBitmap)
+	{
+		int nWidth = GetCBitmapWidth(*m_pBitmap);
+		int nHeight = GetCBitmapHeight(*m_pBitmap);
+
+		rect.bottom += nHeight;
+		if((rect.left + nWidth) > rect.right)
+			rect.right = rect.left + nWidth;
+	}
+
+    return rect;
+}
+
+CString CToolTipEx::GetFieldFromString(CString ref, int nIndex, TCHAR ch)
+{
+    CString strReturn;
+    LPCTSTR pstrStart = ref.LockBuffer();
+    LPCTSTR pstrBuffer = pstrStart;
+    int nCurrent = 0;
+    int nStart = 0;
+    int nEnd = 0;
+    int nOldStart = 0;
+
+    while (nCurrent <= nIndex && *pstrBuffer != _T('\0'))
+    {
+        if (*pstrBuffer == ch)
+        {
+            nOldStart = nStart;
+            nStart = nEnd+1;
+            nCurrent++;
+        }
+        nEnd++;
+        pstrBuffer++;
+    }
+
+    // May have reached the end of the string
+    if (*pstrBuffer == _T('\0'))
+    {
+        nOldStart = nStart;
+        nEnd++;
+    }
+
+    ref.UnlockBuffer();
+
+    if (nCurrent < nIndex) 
+    {
+        //TRACE1("Warning: GetStringField - Couldn't find field %d.\n", nIndex);
+        return strReturn;
+    }
+    return ref.Mid(nOldStart, nEnd-nOldStart-1);
+}
+
+LPLOGFONT CToolTipEx::GetSystemToolTipFont()
+{
+    static LOGFONT LogFont;
+
+    NONCLIENTMETRICS ncm;
+    ncm.cbSize = sizeof(NONCLIENTMETRICS);
+    if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0))
+        return FALSE;
+
+    memcpy(&LogFont, &(ncm.lfStatusFont), sizeof(LOGFONT));
+
+    return &LogFont; 
+}
+
+BOOL CToolTipEx::SetLogFont(LPLOGFONT lpLogFont, BOOL bRedraw /*=TRUE*/)
+{
+    ASSERT(lpLogFont);
+    if (!lpLogFont)
+        return FALSE;
+
+	LOGFONT LogFont;
+
+    // Store font as the global default
+    memcpy(&LogFont, lpLogFont, sizeof(LOGFONT));
+
+    // Create the actual font object
+    m_Font.DeleteObject();
+    m_Font.CreateFontIndirect(&LogFont);
+
+    if (bRedraw && ::IsWindow(GetSafeHwnd())) 
+        Invalidate();
+
+    return TRUE;
+}
+
+void CToolTipEx::SetBitmap(CBitmap *pBitmap)
+{
+	DELETE_BITMAP
+
+	m_pBitmap = pBitmap;
+}

+ 68 - 0
ToolTipEx.h

@@ -0,0 +1,68 @@
+#if !defined(AFX_ToolTipEx_H__5796127D_8817_493F_ACA7_8741A6759DD3__INCLUDED_)
+#define AFX_ToolTipEx_H__5796127D_8817_493F_ACA7_8741A6759DD3__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// ToolTipEx.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CToolTipEx window
+
+class CToolTipEx : public CWnd
+{
+// Construction
+public:
+	CToolTipEx();
+
+// Attributes
+public:
+
+// Operations
+public:
+	BOOL OnMsg(MSG* pMsg);
+	BOOL Create(CWnd* pParentWnd);
+	BOOL Show(CPoint point);
+	BOOL Hide();
+	void SetToolTipText(CString csText)	{ m_csText = csText; Invalidate(); }
+	void SetBitmap(CBitmap *pBitmap);
+
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CToolTipEx)
+	protected:
+	virtual void PostNcDestroy();
+	//}}AFX_VIRTUAL
+
+// Implementation
+public:
+	virtual ~CToolTipEx();
+	
+protected:
+	DWORD m_dwTextStyle;
+	CRect m_rectMargin;
+	CString m_csText;
+	CFont m_Font;
+	CBitmap *m_pBitmap;
+
+protected:
+	CString GetFieldFromString(CString ref, int nIndex, TCHAR ch);
+	CRect GetBoundsRect();
+	BOOL SetLogFont(LPLOGFONT lpLogFont, BOOL bRedraw /*=TRUE*/);
+	LPLOGFONT GetSystemToolTipFont();
+
+	// Generated message map functions
+protected:
+	//{{AFX_MSG(CToolTipEx)
+	afx_msg void OnPaint();
+	//}}AFX_MSG
+	DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_ToolTipEx_H__5796127D_8817_493F_ACA7_8741A6759DD3__INCLUDED_)