DRAWDIB.C
/******************************************************************************\ 
*       This is a part of the Microsoft Source Code Samples.  
*       Copyright 1993 - 1998 Microsoft Corporation. 
*       All rights reserved.  
*       This source code is only intended as a supplement to  
*       Microsoft Development Tools and/or WinHelp documentation. 
*       See these sources for detailed information regarding the  
*       Microsoft samples programs. 
\******************************************************************************/ 
 
/******************************************************************************* 
 *                                                                             * 
 *  MODULE      : DrawDIB.c                                                    * 
 *                                                                             * 
 *  PURPOSE     : Handles most of the SHOWDIB's DIB drawing and clipboard      * 
 *                operations.                                                  * 
 *                                                                             * 
 *  FUNCTIONS   :                                                              * 
 *                PrintDIB()             -  Sets the current DIB bits to the   * 
 *                                          printer DC.                        * 
 *                                                                             * 
 *                AppPaint()             -  Sets the DIB/bitmap bits on the    * 
 *                                          screen or the given device.        * 
 *                                                                             * 
 *                DrawSelect()           -  Draws selected clip rectangle on   * 
 *                                          the DC/screen.                     * 
 *                                                                             * 
 *                NormalizeRect()        -  Swaps reversed rectangle coords.   * 
 *                                                                             * 
 *                TrackMouse()           -  Draws rubberbanding rectangle and  * 
 *                                          displays it's dimensions.          * 
 *                                                                             * 
 *                BandDIB()              -  Outputs DIB in bands to device.    * 
 *                                                                             * 
 *                SizeWindow()           -  Sizes app. window based on client  * 
 *                                          dimensions and style.              * 
 *                                                                             * 
 *                GetRealClientRect()    -  Calculates client rectangle dimen- * 
 *                                          sions if scrollbars are present.   * 
 *                                                                             * 
 *                SetScrollRanges()      -  Sets global scroll ranges.         * 
 *                                                                             * 
 *                CopyHandle()           -  Makes a copy of memory block.      * 
 *                                                                             * 
 *                CopyPalette()          -  Makes a copy of the GDI logical    * 
 *                                          palette.                           * 
 *                                                                             * 
 *                CopyBitmap()           -  Copies given bitmap to another.    * 
 *                                                                             * 
 *                CropBitmap()           -  Crops a bitmap to the given size.  * 
 *                                                                             * 
 *                RenderFormat()         -  renders currently displayed DIB    * 
 *                                          in CF_BITMAP or CF_DIB format.     * 
 *                                                                             * 
 *                RealizeDibFormat()     -  Realizes the DIB in given format.  * 
 *                                                                             * 
 *                ErrMsg()               -  Pops an error message to user.     * 
 *                                                                             * 
 *                fDialog()              -  Displays a dialog box.             * 
 *                                                                             * 
 *                AppAbout()             -  Shows the About.. dialog box.      * 
 *                                                                             * 
 *******************************************************************************/ 
#include <windows.h> 
#include <io.h> 
#include <stdio.h> 
#include "showdib.h" 
 
MPOINT                ptSize;       /* Stores DIB dimensions                   */ 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   :  PrintDIB(HWND hWnd, HDC hDC, int x, int y, int dx, int dy)* 
 *                                                                          * 
 *  PURPOSE    :  Set the DIB bits to the printer DC.                       * 
 *                                                                          * 
 ****************************************************************************/ 
VOID PrintDIB ( 
    HWND hWnd, 
    HDC hDC, 
    INT x, 
    INT y, 
    INT dx, 
    INT dy) 
 
{ 
    BITMAPINFOHEADER bi; 
    INT dibX,  dibY; 
    INT dibDX, dibDY; 
 
    if (!bLegitDraw) 
        return; 
 
    DibInfo (hbiCurrent, &bi); 
 
    if (IsRectEmpty (&rcClip)){ 
        dibX  = 0; 
        dibY  = 0; 
        dibDX = (INT)bi.biWidth; 
        dibDY = (INT)bi.biHeight; 
    } 
    else{ 
        dibX  = rcClip.left; 
        dibY  = (INT)bi.biHeight - 1 - rcClip.bottom; 
        dibDX = rcClip.right  - rcClip.left; 
        dibDY = rcClip.bottom - rcClip.top; 
    } 
 
    if (hdibCurrent){ 
        /* Stretch the DIB to printer DC */ 
        StretchDibBlt ( hDC, 
                        x, 
                        y, 
                        dx, 
                        dy, 
                        hdibCurrent, 
                        dibX, 
                        dibY, 
                        dibDX, 
                        dibDY, 
                        SRCCOPY); 
    } 
    else if (achFileName[0]) { 
 
        SetMapMode (hDC, MM_ANISOTROPIC); 
        (VOID)SetViewportOrgEx (hDC, x, y, NULL); 
        (VOID)SetViewportExtEx (hDC, dx, dy, NULL); 
 
        BandDIB (hWnd, hDC, 0, 0); 
    } 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   :  AppPaint(HWND hWnd, HDC hDC, int x, int y)                * 
 *                                                                          * 
 *  PURPOSE    :  Sets the DIB/bitmap bits on the screen or the given device* 
 *                                                                          * 
 ****************************************************************************/ 
VOID AppPaint ( 
    HWND hWnd, 
    HDC hDC, 
    INT x, 
    INT y) 
{ 
    HPALETTE hpalT; 
    BITMAPINFOHEADER bi; 
//    LPBITMAPINFOHEADER lpbi; 
 
    (VOID)SetWindowOrgEx (hDC, x, y, NULL); 
    SetBkMode (hDC, wTransparent); 
 
    if (bLegitDraw) { 
                hpalT = SelectPalette (hDC, hpalCurrent, FALSE); 
                RealizePalette (hDC); 
 
        if (hbmCurrent && !bDIBToDevice) { 
            DrawBitmap (hDC, 0, 0, hbmCurrent, SRCCOPY); 
        } 
        else if (hdibCurrent) { 
            DibInfo (hdibCurrent, &bi); 
            DibBlt (hDC, 
                    0, 
                    0, 
                    (INT)bi.biWidth, 
                    (INT)bi.biHeight, 
                    hdibCurrent, 
                    0, 
                    0, 
                    SRCCOPY); 
        } 
        else if (achFileName[0]) { 
            BandDIB (hWnd, hDC, 0, 0); 
        } 
 
        SelectPalette(hDC,hpalT,FALSE); 
    } 
 
    DrawSelect(hDC, TRUE); 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   :  DrawSelect(HDC hdc, BOOL fDraw)                           * 
 *                                                                          * 
 *  PURPOSE    :  Draws the selected clip rectangle with its dimensions on  * 
 *                the DC/screen                                             * 
 *                                                                          * 
 ****************************************************************************/ 
VOID DrawSelect( 
    HDC hdc, 
    BOOL fDraw) 
{ 
    CHAR  sz[80]; 
    INT   x,y,len,dx,dy; 
    HDC   hdcBits; 
    HBITMAP hbm; 
 
    if (!IsRectEmpty (&rcClip)) { 
 
        /* If a rectangular clip region has been selected, draw it */ 
        PatBlt(hdc, rcClip.left,    rcClip.top,        rcClip.right-rcClip.left, 1,  DSTINVERT); 
        PatBlt(hdc, rcClip.left,    rcClip.bottom, 1, -(rcClip.bottom-rcClip.top),   DSTINVERT); 
        PatBlt(hdc, rcClip.right-1, rcClip.top, 1,   rcClip.bottom-rcClip.top,   DSTINVERT); 
        PatBlt(hdc, rcClip.right,   rcClip.bottom-1, -(rcClip.right-rcClip.left), 1, DSTINVERT); 
 
        /* Format the dimensions string ...*/ 
        sprintf( sz, 
                  "%dx%d", 
                  rcClip.right  - rcClip.left, 
                  rcClip.bottom - rcClip.top ); 
     len = lstrlen(sz); 
 
        /* ... and center it in the rectangle */ 
        { SIZE size; 
        (VOID)GetTextExtentPoint(hdc, sz, len, &size); 
        dx = size.cx; dy = size.cy; 
        } 
        x  =  (rcClip.right  + rcClip.left - dx) / 2; 
        y  =  (rcClip.bottom + rcClip.top  - dy) / 2; 
 
        hdcBits = CreateCompatibleDC (hdc); 
        SetTextColor (hdcBits, 0xFFFFFFL); 
        SetBkColor (hdcBits, 0x000000L); 
 
        /* Output the text to the DC */ 
        /*if (hbm = +++CreateBitmap - Not Recommended(use CreateDIBitmap)+++ (dx, dy, 1, 1, NULL)){*/ 
        if (hbm = CreateBitmap(dx, dy, 1, 1, NULL)){ 
            hbm = SelectObject (hdcBits, hbm); 
            ExtTextOut (hdcBits, 0, 0, 0, NULL, sz, len, NULL); 
            BitBlt (hdc, x, y, dx, dy, hdcBits, 0, 0, SRCINVERT); 
            hbm = SelectObject (hdcBits, hbm); 
            DeleteObject (hbm); 
        } 
        DeleteDC (hdcBits); 
        UNREFERENCED_PARAMETER(fDraw); 
    } 
} 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : NormalizeRect(RECT *prc)                                   * 
 *                                                                          * 
 *  PURPOSE    : If the rectangle coordinates are reversed, swaps them      * 
 *                                                                          * 
 ****************************************************************************/ 
VOID PASCAL NormalizeRect (RECT *prc) 
{ 
    if (prc->right < prc->left) 
        SWAP(prc->right,prc->left); 
    if (prc->bottom < prc->top) 
        SWAP(prc->bottom,prc->top); 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : TrackMouse(HWND hwnd, POINT pt)                            * 
 *                                                                          * 
 *  PURPOSE    : Draws a rubberbanding rectangle and displays it's          * 
 *               dimensions till the mouse button is released               * 
 *                                                                          * 
 ****************************************************************************/ 
VOID TrackMouse ( 
    HWND hwnd, 
    MPOINT pt) 
{ 
//    MPOINT ptBase; 
    HDC   hdc; 
    MSG   msg; 
    MPOINT ptOrigin; 
    RECT  rcClient; 
 
    hdc = GetDC(hwnd); 
    SetCapture(hwnd); 
 
    GetClientRect(hwnd,&rcClient); 
 
    /* Get mouse coordinates relative to origin of DIB */ 
    ptOrigin.x = (short int)GetScrollPos(hwnd,SB_HORZ); 
    ptOrigin.y = (short int)GetScrollPos(hwnd,SB_VERT); 
 
    pt.x += ptOrigin.x; 
    pt.y += ptOrigin.y; 
 
    /* Display the coordinates */ 
    (VOID)SetWindowOrgEx(hdc, ptOrigin.x, ptOrigin.y, NULL); 
    DrawSelect(hdc,FALSE); 
 
    /* Initialize clip rectangle to the point */ 
    rcClip.left   = pt.x; 
    rcClip.top    = pt.y; 
    rcClip.right  = pt.x; 
    rcClip.bottom = pt.y; 
 
    /* Eat mouse messages until a WM_LBUTTONUP is encountered. Meanwhile 
     * continue to draw a rubberbanding rectangle and display it's dimensions 
     */ 
    for (;;){ 
        WaitMessage(); 
        if (PeekMessage(&msg,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE)){ 
            DrawSelect(hdc,FALSE); 
 
            rcClip.left   = pt.x; 
            rcClip.top    = pt.y; 
            rcClip.right  = LOWORD(msg.lParam) + ptOrigin.x; 
            rcClip.bottom = HIWORD(msg.lParam) + ptOrigin.y; 
 
            NormalizeRect(&rcClip); 
            DrawSelect(hdc,TRUE); 
 
            if (msg.message == WM_LBUTTONUP) 
                break; 
        } 
        else 
            continue; 
    } 
 
    ReleaseCapture(); 
    ReleaseDC(hwnd,hdc); 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : BandDIB(HWND hWnd, HDC hDC, int x, int y)                  * 
 *                                                                          * 
 *  PURPOSE    : Outputs the DIB in bands to a device or the screen, using  * 
 *               the maximum possible band size.                            * 
 *                                                                          * 
 ****************************************************************************/ 
VOID BandDIB ( 
    HWND hWnd, 
    HDC hDC, 
    INT x, 
    INT y) 
{ 
    HBITMAP            hBitmap, hOld ; 
    HDC                hMemDC ; 
    LPSTR              pBuf; 
    LPBITMAPINFOHEADER lpbi; 
    WORD               wRead, wActualPosition, wScansLeft  ; 
    DWORD              dwMapSize; 
    DWORD              dwScans; 
    WORD               wBitmapHeight; 
    RECT               Rect; 
    HANDLE             hBuf; 
    BOOL               bSuccess = FALSE; 
    INT                nBandSize; 
    HPALETTE           hOldMemPal; 
    HPALETTE           hOldPal; 
    HFILE              fh; 
    OFSTRUCT           of; 
    CHAR               lpBuffer[128]; 
 
    /* Open the map file and get the information out */ 
    fh = OpenFile(achFileName, (LPOFSTRUCT)&of, (UINT)OF_READ); 
 
    if (fh == -1) 
        return; 
    lpbi = (VOID FAR *)GlobalLock(hbiCurrent); 
    if (!lpbi){ 
        _lclose(fh); 
        return; 
    } 
 
    /* Compute scan size in bytes */ 
    dwScans = WIDTHBYTES((DWORD)lpbi->biWidth * lpbi->biBitCount); 
 
    wBitmapHeight = (WORD)lpbi->biHeight ; 
    wScansLeft    = (WORD)lpbi->biHeight ; 
 
    hMemDC = NULL; 
    for ( nBandSize = wScansLeft; 
          (WORD)nBandSize >= MINBAND || (WORD)nBandSize == wScansLeft; 
          nBandSize -= BANDINCREMENT) { 
 
        /* Attempt to maximize band size by trying to allocate a buffer 
         * for the given band size. If allocation fails, try again with the 
         * smaller band size. 
         */ 
        hBuf = GlobalAlloc (GMEM_FIXED | GMEM_ZEROINIT, dwScans * nBandSize) ; 
        if (!hBuf) 
            continue; 
 
        /* Show success and exit loop if we're going to set bits to device. */ 
        if (bDIBToDevice) { 
            (int)hMemDC = 1; 
            break; 
        } 
        else { 
            /* Create a device-dependent bitmap to hold the bits */ 
            hBitmap = CreateCompatibleBitmap (hDC, 
                                              (WORD)lpbi->biWidth, 
                                              nBandSize); 
            if (!hBitmap) { 
                /* Try again for the next smaller band size */ 
                GlobalFree (hBuf); 
                continue; 
            } 
 
            /* Create a memory context for the bitmap */ 
            if (!(hMemDC = CreateCompatibleDC (hDC))) { 
                GlobalFree (hBuf); 
                DeleteObject (hBitmap); 
                continue; 
            } else 
                /* Success in creating a DC */ 
                break; 
        } 
    } 
    if (!hMemDC) { 
 
        /* We failed allocation , so give error message and quit */ 
        if (GetFocus () == hWnd) { 
            LoadString(hInst, IDS_NOMEM, lpBuffer, sizeof(lpBuffer)); 
            ErrMsg (lpBuffer); 
            ValidateRect (hWnd, (LPRECT) (NULL)); 
        } else 
            MessageBeep(0); 
 
        GlobalUnlock(hbiCurrent); 
        _lclose(fh); 
        return; 
    } 
    pBuf = GlobalLock (hBuf); 
 
    /* Calculate number of bytes to be transferred */ 
    dwMapSize = dwScans * nBandSize ; 
 
    /* Manipulate palette appropriately */ 
    if (!bDIBToDevice) 
        hOldMemPal = SelectPalette (hMemDC, hpalCurrent, 0) ; 
 
    /* Now get to the start of the map in the file */ 
    _llseek(fh, dwOffset, (UINT)SEEK_SET); 
 
    /* we are now all set to start off */ 
    wActualPosition = wScansLeft ; 
 
    Rect.left  = 0; 
    Rect.right = (WORD)lpbi->biWidth; 
 
    hOldPal = SelectPalette(hDC, hpalCurrent, 0); 
    RealizePalette(hDC); 
 
    do { 
        /* Read in nBandSize scans or whatever is left */ 
        if (wScansLeft > (WORD)nBandSize) 
            wRead = (WORD)nBandSize ; 
        else 
            wRead = wScansLeft ; 
 
        Rect.bottom = wActualPosition; 
        wActualPosition -= wRead ; 
        Rect.top = wActualPosition; 
 
        dwMapSize = ((DWORD) wRead) * dwScans ; 
 
        /* Now read in the map to the global buffer */ 
        if (RectVisible (hDC, &Rect)) { 
            lread(fh, (LPSTR)pBuf, dwMapSize); 
 
            if (bDIBToDevice) { 
                if (wRead != (WORD)SetDIBitsToDevice (hDC, x, y, 
                                                (WORD)lpbi->biWidth, 
                                                wBitmapHeight, 
                                                0, 
                                                0, 
                                                wBitmapHeight - wScansLeft, 
                                                wRead, 
                                                pBuf, 
                                                (LPBITMAPINFO)lpbi, 
                                                fPalColors ? 
                                                DIB_PAL_COLORS : 
                                                DIB_RGB_COLORS)){ 
                    LoadString(hInst, IDS_CANTDRAWSCANS, lpBuffer, sizeof(lpBuffer)); 
                    ErrMsg(lpBuffer); 
                    GlobalUnlock(hBuf); 
                    GlobalFree(hBuf); 
                    GlobalUnlock(hbiCurrent); 
                    _lclose(fh); 
                    return; 
                } 
            } else { 
                lpbi->biHeight = wRead ; 
 
                /* Set the DIB bits to a device-dependent format */ 
                if (lpbi->biHeight != (int)SetDIBits (hMemDC, 
                                                       hBitmap, 
                                                       0, 
                                                       (WORD)lpbi->biHeight, 
                                                       pBuf, 
                                                       (LPBITMAPINFO)lpbi, 
                                                       (DWORD) (fPalColors ? 
                                                       DIB_PAL_COLORS : 
                                                       DIB_RGB_COLORS))){ 
                    LoadString(hInst, IDS_CANTDRAWSCANS, lpBuffer, sizeof(lpBuffer)); 
                    ErrMsg(lpBuffer); 
                    GlobalUnlock (hBuf); 
                    GlobalFree (hBuf); 
                    GlobalUnlock(hbiCurrent); 
                    _lclose(fh); 
                    return; 
                } 
 
                /* Blt own map onto the screen, remembering the point to start */ 
                hOld = SelectObject (hMemDC, hBitmap) ; 
                if (!BitBlt (hDC, 0, wActualPosition, 
                             (WORD)lpbi->biWidth, 
                             (WORD)lpbi->biHeight, 
                             hMemDC, 0, 0, SRCCOPY)){ 
                    LoadString(hInst, IDS_CANTDRAWMAP, lpBuffer, sizeof(lpBuffer)); 
                    ErrMsg (lpBuffer); 
                    GlobalUnlock (hBuf); 
                    GlobalFree (hBuf); 
                    GlobalUnlock(hbiCurrent); 
                    _lclose(fh); 
                    return; 
                } 
                SelectObject (hMemDC, hOld) ; 
 
                /* Restore the value of bitmap height */ 
                lpbi->biHeight = wBitmapHeight ; 
            } 
        } 
        else { 
            /* This chunk is not visible, seek over the data in the file */ 
            _llseek(fh, dwMapSize, (UINT)SEEK_CUR); 
        } 
        wScansLeft -= wRead ; 
    } while (wScansLeft > 0 ) ; 
 
    /* Delete the objects just created above */ 
    GlobalUnlock (hBuf); 
    GlobalFree (hBuf); 
    SelectPalette (hDC, hOldPal, 0); 
 
    /* Set success flag */ 
    bSuccess = TRUE; 
 
    if (!bDIBToDevice) { 
        SelectPalette (hMemDC, hOldMemPal, 0); 
        DeleteDC (hMemDC) ; 
        DeleteObject (hBitmap) ; 
    } 
    GlobalUnlock(hbiCurrent); 
 
    /* Close the file */ 
    _lclose(fh); 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : SizeWindow(HWND hWnd)                                      * 
 *                                                                          * 
 *  PURPOSE    : Sizes the app. window based on client dimensions (DIB      * 
 *               dimensions) and style. Sets the caption text.              * 
 *                                                                          * 
 ****************************************************************************/ 
VOID SizeWindow (HWND hWnd) 
{ 
    CHAR  *pstr; 
    CHAR  Name[60]; 
    RECT  Rectangle; 
    RECT  rectClient; 
//    INT   dx,dy; 
//    MPOINT pt; 
    BITMAPINFOHEADER bi; 
 
    /* Get information about current DIB */ 
    DibInfo(hbiCurrent,&bi); 
 
    /* Extract the filename from the full pathname */ 
    pstr = achFileName + lstrlen(achFileName); 
    while ( (pstr > achFileName) && (*pstr != '\\') && (*pstr != ':') ) 
    pstr = CharPrev(achFileName, pstr); 
 
    if(pstr != achFileName) 
            pstr++; 
 
    /* Format filename along with the DIB attributes */ 
    sprintf (Name, 
              "%s (%s %dx%dx%d%s)", 
              szAppName, 
              pstr, 
              (WORD)bi.biWidth, 
              (WORD)bi.biHeight, 
              (WORD)bi.biBitCount, 
              bi.biCompression == BI_RGB  ? " RGB" : 
              bi.biCompression == BI_RLE8 ? " RLE8" : " RLE4" ); 
 
    /* Show formatted text in the caption bar */ 
    SetWindowText (hWnd, Name); 
 
    /* Store the size in ptSize, so the scroll bars will work. */ 
    ptSize.x = (WORD)bi.biWidth; 
    ptSize.y = (WORD)bi.biHeight; 
 
    if (IsZoomed (hWnd)) 
        SetScrollRanges (hWnd); 
    else { 
        Rectangle.left   = 0; 
        Rectangle.top    = 0; 
        Rectangle.right  = (WORD)bi.biWidth; 
        Rectangle.bottom = (WORD)bi.biHeight; 
 
        /* Compute the size of the window rectangle based on the given 
         * client rectangle size and the window style, then size the 
         * window. 
         */ 
        AdjustWindowRect (&Rectangle, dwStyle, TRUE); 
        SetWindowPos (hWnd, (HWND)NULL, 0, 0, 
                      Rectangle.right  - Rectangle.left + 1, 
                      Rectangle.bottom - Rectangle.top + 1, 
                      SWP_NOMOVE | SWP_NOZORDER); 
        GetClientRect( hWnd, &rectClient ); 
        // Correct for small bitmap that causes multiline menu 
        if (rectClient.bottom < Rectangle.bottom) { 
            Rectangle.bottom += (Rectangle.bottom - rectClient.bottom); 
            SetWindowPos (hWnd, (HWND)NULL, 0, 0, 
                      Rectangle.right  - Rectangle.left + 1, 
                      Rectangle.bottom - Rectangle.top + 1, 
                      SWP_NOMOVE | SWP_NOZORDER); 
        } 
    } 
 
    InvalidateRect(hWnd,NULL,TRUE); 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : GetRealClientRect(HWND hwnd, LPRECT lprc)                  * 
 *                                                                          * 
 *  PURPOSE    : Calculates the client rectangle taking scrollbars into     * 
 *               consideration.                                             * 
 *                                                                          * 
 ****************************************************************************/ 
VOID GetRealClientRect ( 
    HWND hwnd, 
    PRECT lprc) 
{ 
    DWORD dwStyle; 
 
    dwStyle = GetWindowLong (hwnd, GWL_STYLE); 
    GetClientRect (hwnd,lprc); 
 
    if (dwStyle & WS_HSCROLL) 
        lprc->bottom += GetSystemMetrics (SM_CYHSCROLL); 
 
    if (dwStyle & WS_VSCROLL) 
        lprc->right  += GetSystemMetrics (SM_CXVSCROLL); 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : SetScrollRanges(hwnd)                                      * 
 *                                                                          * 
 *  PURPOSE    :                                                            * 
 *                                                                          * 
 ****************************************************************************/ 
VOID SetScrollRanges(HWND hwnd) 
{ 
    RECT       rc; 
    INT        iRangeH, iRangeV, i; 
    static INT iSem = 0; 
 
    if (!iSem){ 
        iSem++; 
        GetRealClientRect (hwnd, &rc); 
 
        for (i = 0; i < 2; i++){ 
            iRangeV = ptSize.y - rc.bottom; 
            iRangeH = ptSize.x - rc.right; 
 
            if (iRangeH < 0) iRangeH = 0; 
            if (iRangeV < 0) iRangeV = 0; 
 
            if (GetScrollPos ( hwnd, 
                               SB_VERT) > iRangeV || 
                               GetScrollPos (hwnd, SB_HORZ) > iRangeH) 
                InvalidateRect (hwnd, NULL, TRUE); 
 
            SetScrollRange (hwnd, SB_VERT, 0, iRangeV, TRUE); 
            SetScrollRange (hwnd, SB_HORZ, 0, iRangeH, TRUE); 
 
            GetClientRect (hwnd, &rc); 
        } 
        iSem--; 
    } 
} 
 
/*********** THE FOLLOWING FUNCTIONS ARE FOR CLIPBOARD SUPPORT **************/ 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : CopyHandle (HANDLE h)                                      * 
 *                                                                          * 
 *  PURPOSE    : Makes a copy of the given global memory block.             * 
 *                                                                          * 
 *  RETURNS    : A handle to the new block.                                 * 
 *                                                                          * 
 ****************************************************************************/ 
HANDLE CopyHandle (HANDLE h) 
{ 
    BYTE *lpCopy; 
    BYTE *lp; 
    HANDLE hCopy; 
    DWORD  dwLen; 
 
    dwLen = GlobalSize (h); 
    if (hCopy = GlobalAlloc (GHND, dwLen)) { 
 
        lpCopy = (BYTE *)GlobalLock (hCopy); 
        lp     = (BYTE *)GlobalLock (h); 
        while (dwLen--) *lpCopy++ = *lp++; 
        GlobalUnlock (hCopy); 
        GlobalUnlock (h); 
    } 
    return hCopy; 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : CopyPalette(HPALETTE hpal)                                 * 
 *                                                                          * 
 *  PURPOSE    : Makes a copy of a GDI logical palette                      * 
 *                                                                          * 
 *  RETURNS    : A handle to the new palette.                               * 
 *                                                                          * 
 ****************************************************************************/ 
HPALETTE CopyPalette (HPALETTE hpal) 
{ 
    PLOGPALETTE ppal; 
    WORD        nNumEntries; 
 
    if (!hpal) 
        return NULL; 
 
    GetObject(hpal,sizeof(INT),(LPSTR)&nNumEntries); 
 
    if (nNumEntries == 0) 
return NULL; 
 
    ppal = (PLOGPALETTE)LocalAlloc(LPTR,sizeof(LOGPALETTE) + 
                nNumEntries * sizeof(PALETTEENTRY)); 
 
    if (!ppal) 
        return NULL; 
 
    ppal->palVersion    = PALVERSION; 
    ppal->palNumEntries = nNumEntries; 
 
    GetPaletteEntries(hpal,0,nNumEntries,(LPPALETTEENTRY)ppal->palPalEntry); 
 
    hpal = CreatePalette(ppal); 
 
    LocalFree((HANDLE)ppal); 
    return hpal; 
} 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : CopyBitmap (HBITMAP hbm)                                   * 
 *                                                                          * 
 *  PURPOSE    : Copies the given bitmap to another.                        * 
 *                                                                          * 
 *  RETURNS    : A handle to the new bitmap.                                * 
 *                                                                          * 
 ****************************************************************************/ 
HBITMAP CopyBitmap (HBITMAP hbm) 
{ 
    BITMAP  bm; 
    RECT    rc; 
 
    if (!hbm) 
         return NULL; 
 
    GetObject (hbm, sizeof(BITMAP), (LPSTR)&bm); 
    rc.left   = 0; 
    rc.top    = 0; 
    rc.right  = bm.bmWidth; 
    rc.bottom = bm.bmHeight; 
 
    return CropBitmap (hbm, &rc); 
} 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   :  CropBitmap (hbm,lprect)                                   * 
 *                                                                          * 
 *  PURPOSE    :  Crops a bitmap to a new size specified by the lprect      * 
 *                parameter.                                                * 
 *                                                                          * 
 *  RETURNS    :  A handle to the new bitmap.                               * 
 *                                                                          * 
 ****************************************************************************/ 
HBITMAP CropBitmap ( 
    HBITMAP hbm, 
    PRECT prc) 
{ 
    HDC     hMemDCsrc; 
    HDC     hMemDCdst; 
    HDC     hdc; 
    HBITMAP hNewBm; 
    BITMAP  bm; 
    INT     dx,dy; 
 
    if (!hbm) 
         return NULL; 
 
    hdc = GetDC (NULL); 
    hMemDCsrc = CreateCompatibleDC (hdc); 
    hMemDCdst = CreateCompatibleDC (hdc); 
 
    GetObject (hbm, sizeof(BITMAP), (LPSTR)&bm); 
    dx = prc->right  - prc->left; 
    dy = prc->bottom - prc->top; 
 
    /*hNewBm = +++CreateBitmap - Not Recommended(use CreateDIBitmap)+++ (dx, dy, bm.bmPlanes, bm.bmBitsPixel, NULL);*/ 
    hNewBm = CreateBitmap(dx, dy, bm.bmPlanes, bm.bmBitsPixel, NULL); 
    if (hNewBm){ 
        SelectObject (hMemDCsrc, hbm); 
        SelectObject (hMemDCdst, hNewBm); 
 
        BitBlt (hMemDCdst, 
                0, 
                0, 
                dx, 
                dy, 
                hMemDCsrc, 
                prc->left, 
                prc->top, 
                SRCCOPY); 
    } 
 
    ReleaseDC (NULL,hdc); 
    DeleteDC (hMemDCsrc); 
    DeleteDC (hMemDCdst); 
    return hNewBm; 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : RenderFormat(int cf)                                       * 
 *                                                                          * 
 *  PURPOSE    : Renders the currently displayed DIB in CF_DIB or           * 
 *               CF_BITMAP format.The bitmap is clipped to the current      * 
 *               rcClip.                                                    * 
 *                                                                          * 
 *  RETURNS    : A handle to the DIB                                        * 
 *                                                                          * 
 ****************************************************************************/ 
HANDLE RenderFormat (INT cf) 
{ 
    HANDLE  h = NULL; 
    HBITMAP hbm; 
 
    if (!bLegitDraw) 
        return NULL; 
 
    switch (cf){ 
        case CF_BITMAP: 
            if (hbmCurrent && !IsRectEmpty (&rcClip)) 
                h = CropBitmap (hbmCurrent, &rcClip); 
            else{ 
                if (hbmCurrent) 
                    h = CopyBitmap (hbmCurrent); 
                else if (hdibCurrent) 
                    h = BitmapFromDib (hdibCurrent, hpalCurrent); 
                else if (achFileName[0] && (hdibCurrent = OpenDIB (achFileName))) 
                    h = BitmapFromDib (hdibCurrent, hpalCurrent); 
                else 
                    h = NULL; 
 
                if (h && !IsRectEmpty (&rcClip)){ 
                    hbm = CropBitmap (h,&rcClip); 
                    DeleteObject (h); 
                    h = hbm; 
                } 
            } 
            break; 
 
        case CF_DIB: 
            if (!IsRectEmpty (&rcClip)){ 
                if (hbm = RenderFormat (CF_BITMAP)){ 
                    h = DibFromBitmap (hbm, BI_RGB, 0, hpalCurrent); 
                    DeleteObject (hbm); 
                } 
            } 
            else{ 
                if (!hdibCurrent && hbmCurrent) 
                    h = DibFromBitmap (hbmCurrent, BI_RGB, 0, hpalCurrent); 
                else if (hdibCurrent) 
                    h = CopyHandle (hdibCurrent); 
                else if (achFileName[0]) 
                    h = OpenDIB (achFileName); 
                else 
                    h = NULL; 
            } 
            break; 
 
        case CF_PALETTE: 
            if (hpalCurrent) 
                h = CopyPalette (hpalCurrent); 
            break; 
    } 
    return h; 
} 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   :  RealizeDibFormat(DWORD biStyle, WORD biBits)              * 
 *                                                                          * 
 *  PURPOSE    :  Realize the current DIB in the specifed format            * 
 *                This function is used to get a specific format of CF_DIB  * 
 *                                                                          * 
 *                    biStyle     DIB format      RGB or RLE                * 
 *                    biBits      Bits per pixel  1,4,8,24                  * 
 *                                                                          * 
 *  RETURNS    :  A handle to the created DIB.                              * 
 *                                                                          * 
 ****************************************************************************/ 
HANDLE RealizeDibFormat ( 
    DWORD biStyle, 
    WORD biBits) 
{ 
    BITMAPINFOHEADER bi; 
 
    if (!bLegitDraw) 
        return NULL; 
 
    DibInfo (hbiCurrent, &bi); 
 
    /*  Do we have the requested format already? */ 
    if (bi.biCompression == biStyle && bi.biBitCount == biBits){ 
        if (!hdibCurrent) 
            hdibCurrent = RenderFormat (CF_DIB); 
    } 
    else{ 
        if (!hbmCurrent) 
            hbmCurrent = RenderFormat (CF_BITMAP); 
 
        if (hbmCurrent){ 
            if (hdibCurrent) 
                GlobalFree (hdibCurrent); 
 
            hdibCurrent = DibFromBitmap (hbmCurrent, biStyle, biBits, hpalCurrent); 
        } 
    } 
 
    return hdibCurrent; 
} 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : ErrMsg (PSTR sz,...)                                       * 
 *                                                                          * 
 *  PURPOSE    : Opens a Message box with a error message in it.The user can* 
 *               select the OK button to continue                           * 
 *                                                                          * 
 *  RETURNS    : FALSE to indicate an error has occured.                    * 
 *                                                                          * 
 ****************************************************************************/ 
INT ErrMsg (PSTR sz,...) 
{ 
    CHAR ach[128]; 
    va_list args;  
 
    va_start(args, sz);  
 
    wvsprintf (ach, sz, args);   /* Format the string */ 
    MessageBox (NULL, ach, NULL, MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL); 
    return FALSE; 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : fDialog(int id,HWND hwnd,FARPROC fpfn)                     * 
 *                                                                          * 
 *  PURPOSE    : This function displays a dialog box                        * 
 *                                                                          * 
 *  RETURNS    : The exit code.                                             * 
 *                                                                          * 
 ****************************************************************************/ 
BOOL fDialog ( 
    INT id, 
    HWND hwnd, 
    FARPROC fpfn) 
{ 
    BOOL        f; 
    HANDLE      hInst; 
 
    hInst = (HANDLE)GetWindowLong (hwnd, GWL_HINSTANCE); 
    fpfn  = MakeProcInstance (fpfn, hInst); 
    f = DialogBox (hInst, MAKEINTRESOURCE(id), hwnd, (DLGPROC)fpfn); 
    FreeProcInstance (fpfn); 
    return f; 
} 
 
/**************************************************************************** 
 *                                                                          * 
 *  FUNCTION   : AppAbout( hDlg, uiMessage, wParam, lParam )                * 
 *                                                                          * 
 *  PURPOSE    : Dialog function for the About... dialog box                * 
 *                                                                          * 
 ****************************************************************************/ 
BOOL APIENTRY AppAbout( 
    HWND         hDlg, 
    UINT         uiMessage, 
    UINT         wParam, 
    LONG         lParam) 
{ 
    switch (uiMessage) { 
        case WM_COMMAND: 
            if (LOWORD(wParam) == IDOK) 
                EndDialog (hDlg, TRUE); 
            break; 
 
        case WM_INITDIALOG: 
            return TRUE; 
    } 
    return FALSE; 
        UNREFERENCED_PARAMETER(lParam); 
}