home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows (5th Edition) / Programming Windows, 5th ed. - Companion CD (097-0002183)(1999).iso / Chap16 / Dibble / Dibble.c next >
Encoding:
C/C++ Source or Header  |  1998-10-09  |  33.7 KB  |  972 lines

  1. /*----------------------------------------
  2.    DIBBLE.C -- Bitmap and Palette Program
  3.                (c) Charles Petzold, 1998
  4.   ----------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include "dibhelp.h"
  8. #include "dibpal.h"
  9. #include "dibconv.h"
  10. #include "resource.h"
  11.  
  12. #define WM_USER_SETSCROLLS    (WM_USER + 1)
  13. #define WM_USER_DELETEDIB     (WM_USER + 2)
  14. #define WM_USER_DELETEPAL     (WM_USER + 3)
  15. #define WM_USER_CREATEPAL     (WM_USER + 4)
  16.  
  17. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
  18.  
  19. TCHAR szAppName[] = TEXT ("Dibble") ;
  20.  
  21. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  22.                     PSTR szCmdLine, int iCmdShow)
  23. {
  24.      HACCEL   hAccel ;
  25.      HWND     hwnd ;
  26.      MSG      msg ;
  27.      WNDCLASS wndclass ;
  28.  
  29.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  30.      wndclass.lpfnWndProc   = WndProc ;
  31.      wndclass.cbClsExtra    = 0 ;
  32.      wndclass.cbWndExtra    = 0 ;
  33.      wndclass.hInstance     = hInstance ;
  34.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  35.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  36.      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  37.      wndclass.lpszMenuName  = szAppName ;
  38.      wndclass.lpszClassName = szAppName ;
  39.  
  40.      if (!RegisterClass (&wndclass))
  41.      {
  42.           MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
  43.                       szAppName, MB_ICONERROR) ;
  44.           return 0 ;
  45.      }
  46.  
  47.      hwnd = CreateWindow (szAppName, szAppName,
  48.                           WS_OVERLAPPEDWINDOW | WM_VSCROLL | WM_HSCROLL,
  49.                           CW_USEDEFAULT, CW_USEDEFAULT,
  50.                           CW_USEDEFAULT, CW_USEDEFAULT, 
  51.                           NULL, NULL, hInstance, NULL) ;
  52.  
  53.      ShowWindow (hwnd, iCmdShow) ;
  54.      UpdateWindow (hwnd) ;
  55.  
  56.      hAccel = LoadAccelerators (hInstance, szAppName) ;
  57.  
  58.      while (GetMessage (&msg, NULL, 0, 0))
  59.      {
  60.           if (!TranslateAccelerator (hwnd, hAccel, &msg))
  61.           {
  62.                TranslateMessage (&msg) ;
  63.                DispatchMessage (&msg) ;
  64.           }
  65.      }
  66.      return msg.wParam ;
  67. }
  68.  
  69. /*-------------------------------------------------------------
  70.    DisplayDib: Displays or prints DIB actual size or stretched 
  71.                depending on menu selection
  72.   -------------------------------------------------------------*/
  73.  
  74. int DisplayDib (HDC hdc, HBITMAP hBitmap, int x, int y, 
  75.                 int cxClient, int cyClient, 
  76.                 WORD wShow, BOOL fHalftonePalette)
  77. {
  78.      BITMAP bitmap ;
  79.      HDC    hdcMem ; 
  80.      int    cxBitmap, cyBitmap, iReturn ;
  81.  
  82.      GetObject (hBitmap, sizeof (BITMAP), &bitmap) ;
  83.      cxBitmap = bitmap.bmWidth ;
  84.      cyBitmap = bitmap.bmHeight ;
  85.  
  86.      SaveDC (hdc) ;
  87.  
  88.      if (fHalftonePalette)
  89.           SetStretchBltMode (hdc, HALFTONE) ;
  90.      else
  91.           SetStretchBltMode (hdc, COLORONCOLOR) ;
  92.  
  93.      hdcMem = CreateCompatibleDC (hdc) ;
  94.      SelectObject (hdcMem, hBitmap) ;
  95.  
  96.      switch (wShow)
  97.      {
  98.      case IDM_SHOW_NORMAL:
  99.           if (fHalftonePalette)
  100.                iReturn = StretchBlt (hdc,    0, 0, 
  101.                                              min (cxClient, cxBitmap - x), 
  102.                                              min (cyClient, cyBitmap - y), 
  103.                                      hdcMem, x, y, 
  104.                                              min (cxClient, cxBitmap - x), 
  105.                                              min (cyClient, cyBitmap - y), 
  106.                                      SRCCOPY);
  107.           else
  108.                iReturn = BitBlt (hdc,    0, 0, 
  109.                                          min (cxClient, cxBitmap - x), 
  110.                                          min (cyClient, cyBitmap - y),
  111.                                  hdcMem, x, y, SRCCOPY) ;
  112.           break ;
  113.                
  114.      case IDM_SHOW_CENTER:
  115.           if (fHalftonePalette)
  116.                iReturn = StretchBlt (hdc, (cxClient - cxBitmap) / 2,
  117.                                           (cyClient - cyBitmap) / 2, 
  118.                                           cxBitmap, cyBitmap,
  119.                                      hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY);
  120.           else
  121.                iReturn = BitBlt (hdc, (cxClient - cxBitmap) / 2,
  122.                                       (cyClient - cyBitmap) / 2, 
  123.                                       cxBitmap, cyBitmap,
  124.                                  hdcMem, 0, 0, SRCCOPY) ;
  125.           break ;
  126.  
  127.      case IDM_SHOW_STRETCH:
  128.           iReturn = StretchBlt (hdc,    0, 0, cxClient, cyClient, 
  129.                                 hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY) ;
  130.           break ;
  131.  
  132.      case IDM_SHOW_ISOSTRETCH:
  133.           SetMapMode (hdc, MM_ISOTROPIC) ;
  134.           SetWindowExtEx (hdc, cxBitmap, cyBitmap, NULL) ;
  135.           SetViewportExtEx (hdc, cxClient, cyClient, NULL) ;
  136.           SetWindowOrgEx (hdc, cxBitmap / 2, cyBitmap / 2, NULL) ;
  137.           SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;
  138.  
  139.           iReturn = StretchBlt (hdc,    0, 0, cxBitmap, cyBitmap, 
  140.                                 hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY) ;
  141.           break ;
  142.      }
  143.      DeleteDC (hdcMem) ;
  144.      RestoreDC (hdc, -1) ;
  145.      return iReturn ;
  146. }
  147.  
  148. /*--------------------------------------------------------------------
  149.    DibFlipHorizontal: Calls non-optimized DibSetPixel and DibGetPixel
  150.   --------------------------------------------------------------------*/
  151.  
  152. HDIB DibFlipHorizontal (HDIB hdibSrc)
  153. {
  154.      HDIB hdibDst ;
  155.      int  cx, cy, x, y ;
  156.  
  157.      if (!DibIsAddressable (hdibSrc))
  158.           return NULL ;
  159.  
  160.      if (NULL == (hdibDst = DibCopy (hdibSrc, FALSE)))
  161.           return NULL ;
  162.  
  163.      cx = DibWidth  (hdibSrc) ;
  164.      cy = DibHeight (hdibSrc) ;
  165.      
  166.      for (x = 0 ; x < cx ; x++)
  167.      for (y = 0 ; y < cy ; y++)
  168.      {
  169.           DibSetPixel (hdibDst, x, cy - 1 - y, DibGetPixel (hdibSrc, x, y)) ;
  170.      }
  171.      return hdibDst ;
  172. }
  173.  
  174. /*---------------------------------------------------------------
  175.    DibRotateRight: Calls optimized DibSetPixelx and DibGetPixelx
  176.   ---------------------------------------------------------------*/
  177.  
  178. HDIB DibRotateRight (HDIB hdibSrc)
  179. {
  180.      HDIB hdibDst ;
  181.      int  cx, cy, x, y ;
  182.  
  183.      if (!DibIsAddressable (hdibSrc))
  184.           return NULL ;
  185.  
  186.      if (NULL == (hdibDst = DibCopy (hdibSrc, TRUE)))
  187.           return NULL ;
  188.  
  189.      cx = DibWidth (hdibSrc) ;
  190.      cy = DibHeight (hdibSrc) ;
  191.  
  192.      switch (DibBitCount (hdibSrc))
  193.      {
  194.      case  1:  
  195.           for (x = 0 ; x < cx ; x++)
  196.           for (y = 0 ; y < cy ; y++)
  197.                DibSetPixel1 (hdibDst, cy - y - 1, x, 
  198.                     DibGetPixel1 (hdibSrc, x, y)) ;
  199.           break ;
  200.  
  201.      case  4:  
  202.           for (x = 0 ; x < cx ; x++)
  203.           for (y = 0 ; y < cy ; y++)
  204.                DibSetPixel4 (hdibDst, cy - y - 1, x, 
  205.                     DibGetPixel4 (hdibSrc, x, y)) ;
  206.           break ;
  207.  
  208.      case  8:
  209.           for (x = 0 ; x < cx ; x++)
  210.           for (y = 0 ; y < cy ; y++)
  211.                DibSetPixel8 (hdibDst, cy - y - 1, x, 
  212.                     DibGetPixel8 (hdibSrc, x, y)) ;
  213.           break ;
  214.  
  215.      case 16:  
  216.           for (x = 0 ; x < cx ; x++)
  217.           for (y = 0 ; y < cy ; y++)
  218.                DibSetPixel16 (hdibDst, cy - y - 1, x, 
  219.                     DibGetPixel16 (hdibSrc, x, y)) ;
  220.           break ;
  221.  
  222.      case 24:
  223.           for (x = 0 ; x < cx ; x++)
  224.           for (y = 0 ; y < cy ; y++)
  225.                DibSetPixel24 (hdibDst, cy - y - 1, x, 
  226.                     DibGetPixel24 (hdibSrc, x, y)) ;
  227.           break ;
  228.  
  229.      case 32:  
  230.           for (x = 0 ; x < cx ; x++)
  231.           for (y = 0 ; y < cy ; y++)
  232.                DibSetPixel32 (hdibDst, cy - y - 1, x, 
  233.                     DibGetPixel32 (hdibSrc, x, y)) ;
  234.           break ;
  235.      }
  236.      return hdibDst ;
  237. }
  238.  
  239. /*----------------------------------------------------------
  240.    PaletteMenu: Uncheck and check menu item on palette menu
  241.   ----------------------------------------------------------*/
  242.  
  243. void PaletteMenu (HMENU hMenu, WORD wItemNew)
  244. {
  245.      static WORD wItem = IDM_PAL_NONE ;
  246.  
  247.      CheckMenuItem (hMenu, wItem, MF_UNCHECKED) ;
  248.      wItem = wItemNew ;
  249.      CheckMenuItem (hMenu, wItem, MF_CHECKED) ;
  250. }
  251.  
  252. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  253. {
  254.      static BOOL         fHalftonePalette ;
  255.      static DOCINFO      di = { sizeof (DOCINFO), TEXT ("Dibble: Printing") } ;
  256.      static HBITMAP      hBitmap ;
  257.      static HDIB         hdib ;
  258.      static HMENU        hMenu ;
  259.      static HPALETTE     hPalette ;
  260.      static int          cxClient, cyClient, iVscroll, iHscroll ;
  261.      static OPENFILENAME ofn ;
  262.      static PRINTDLG     printdlg = { sizeof (PRINTDLG) } ;
  263.      static TCHAR        szFileName [MAX_PATH], szTitleName [MAX_PATH] ;
  264.      static TCHAR        szFilter[] = TEXT ("Bitmap Files (*.BMP)\0*.bmp\0")
  265.                                       TEXT ("All Files (*.*)\0*.*\0\0") ;
  266.      static TCHAR      * szCompression[] = { 
  267.                            TEXT ("BI_RGB"), TEXT ("BI_RLE8"), TEXT ("BI_RLE4"), 
  268.                            TEXT ("BI_BITFIELDS"), TEXT ("Unknown") } ;
  269.      static WORD         wShow = IDM_SHOW_NORMAL ;
  270.      BOOL                fSuccess ;
  271.      BYTE              * pGlobal ;
  272.      HDC                 hdc, hdcPrn ;
  273.      HGLOBAL             hGlobal ;
  274.      HDIB                hdibNew ;
  275.      int                 iEnable, cxPage, cyPage, iConvert ;
  276.      PAINTSTRUCT         ps ;
  277.      SCROLLINFO          si ;
  278.      TCHAR               szBuffer [256] ;
  279.  
  280.      switch (message)
  281.      {
  282.      case WM_CREATE:
  283.          
  284.                // Save the menu handle in a static variable
  285.  
  286.           hMenu = GetMenu (hwnd) ;
  287.  
  288.                // Initialize the OPENFILENAME structure for the File Open
  289.                //   and File Save dialog boxes.
  290.  
  291.           ofn.lStructSize       = sizeof (OPENFILENAME) ;
  292.           ofn.hwndOwner         = hwnd ;
  293.           ofn.hInstance         = NULL ;
  294.           ofn.lpstrFilter       = szFilter ;
  295.           ofn.lpstrCustomFilter = NULL ;
  296.           ofn.nMaxCustFilter    = 0 ;
  297.           ofn.nFilterIndex      = 0 ;
  298.           ofn.lpstrFile         = szFileName ;
  299.           ofn.nMaxFile          = MAX_PATH ;
  300.           ofn.lpstrFileTitle    = szTitleName ;
  301.           ofn.nMaxFileTitle     = MAX_PATH ;
  302.           ofn.lpstrInitialDir   = NULL ;
  303.           ofn.lpstrTitle        = NULL ;
  304.           ofn.Flags             = OFN_OVERWRITEPROMPT ;
  305.           ofn.nFileOffset       = 0 ;
  306.           ofn.nFileExtension    = 0 ;
  307.           ofn.lpstrDefExt       = TEXT ("bmp") ;
  308.           ofn.lCustData         = 0 ;
  309.           ofn.lpfnHook          = NULL ;
  310.           ofn.lpTemplateName    = NULL ;
  311.           return 0 ;
  312.  
  313.      case WM_DISPLAYCHANGE:
  314.           SendMessage (hwnd, WM_USER_DELETEPAL, 0, 0) ;
  315.           SendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;
  316.           return 0 ;
  317.  
  318.      case WM_SIZE:
  319.                // Save the client area width and height in static variables.
  320.  
  321.           cxClient = LOWORD (lParam) ;
  322.           cyClient = HIWORD (lParam) ;
  323.  
  324.           wParam = FALSE ;
  325.                                              // fall through
  326.  
  327.                // WM_USER_SETSCROLLS:  Programmer-defined Message!
  328.                // Set the scroll bars. If the display mode is not normal,
  329.                //   make them invisible. If wParam is TRUE, reset the 
  330.                //   scroll bar position.
  331.  
  332.      case WM_USER_SETSCROLLS:
  333.           if (hdib == NULL || wShow != IDM_SHOW_NORMAL)
  334.           {
  335.                si.cbSize = sizeof (SCROLLINFO) ;
  336.                si.fMask  = SIF_RANGE ;
  337.                si.nMin   = 0 ;
  338.                si.nMax   = 0 ;
  339.                SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ;
  340.                SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ;
  341.           }
  342.           else
  343.           {
  344.                     // First the vertical scroll
  345.  
  346.                si.cbSize = sizeof (SCROLLINFO) ;
  347.                si.fMask  = SIF_ALL ;
  348.  
  349.                GetScrollInfo (hwnd, SB_VERT, &si) ;
  350.                si.nMin  = 0 ;
  351.                si.nMax  = DibHeight (hdib) ;
  352.                si.nPage = cyClient ;
  353.           
  354.                if ((BOOL) wParam)
  355.                     si.nPos = 0 ;
  356.  
  357.                SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ;
  358.                GetScrollInfo (hwnd, SB_VERT, &si) ;
  359.  
  360.                iVscroll = si.nPos ;
  361.  
  362.                     // Then the horizontal scroll
  363.  
  364.                GetScrollInfo (hwnd, SB_HORZ, &si) ;
  365.                si.nMin  = 0 ;
  366.                si.nMax  = DibWidth (hdib) ;
  367.                si.nPage = cxClient ;
  368.           
  369.                if ((BOOL) wParam)
  370.                     si.nPos = 0 ;
  371.  
  372.                SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ;
  373.                GetScrollInfo (hwnd, SB_HORZ, &si) ;
  374.  
  375.                iHscroll = si.nPos ;
  376.           }
  377.           return 0 ;
  378.  
  379.           // WM_VSCROLL: Vertically scroll the DIB
  380.  
  381.      case WM_VSCROLL:
  382.           si.cbSize = sizeof (SCROLLINFO) ;
  383.           si.fMask  = SIF_ALL ;
  384.           GetScrollInfo (hwnd, SB_VERT, &si) ;
  385.           
  386.           iVscroll = si.nPos ;
  387.  
  388.           switch (LOWORD (wParam))
  389.           {
  390.           case SB_LINEUP:      si.nPos -= 1 ;             break ;
  391.           case SB_LINEDOWN:    si.nPos += 1 ;             break ;
  392.           case SB_PAGEUP:      si.nPos -= si.nPage ;      break ;
  393.           case SB_PAGEDOWN:    si.nPos += si.nPage ;      break ;
  394.           case SB_THUMBTRACK:  si.nPos  = si.nTrackPos ;  break ;
  395.           default:                                        break ;
  396.           }
  397.  
  398.           si.fMask = SIF_POS ;
  399.           SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ;
  400.           GetScrollInfo (hwnd, SB_VERT, &si) ;
  401.  
  402.           if (si.nPos != iVscroll)
  403.           {
  404.                ScrollWindow (hwnd, 0, iVscroll - si.nPos, NULL, NULL) ;
  405.                iVscroll = si.nPos ;
  406.                UpdateWindow (hwnd) ;
  407.           }
  408.           return 0 ;
  409.  
  410.           // WM_HSCROLL: Horizontally scroll the DIB
  411.  
  412.      case WM_HSCROLL:
  413.           si.cbSize = sizeof (SCROLLINFO) ;
  414.           si.fMask  = SIF_ALL ;
  415.           GetScrollInfo (hwnd, SB_HORZ, &si) ;
  416.           
  417.           iHscroll = si.nPos ;
  418.  
  419.           switch (LOWORD (wParam))
  420.           {
  421.           case SB_LINELEFT:    si.nPos -= 1 ;             break ;
  422.           case SB_LINERIGHT:   si.nPos += 1 ;             break ;
  423.           case SB_PAGELEFT:    si.nPos -= si.nPage ;      break ;
  424.           case SB_PAGERIGHT:   si.nPos += si.nPage ;      break ;
  425.           case SB_THUMBTRACK:  si.nPos  = si.nTrackPos ;  break ;
  426.           default:                                        break ;
  427.           }
  428.  
  429.           si.fMask = SIF_POS ;
  430.           SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ;
  431.           GetScrollInfo (hwnd, SB_HORZ, &si) ;
  432.  
  433.           if (si.nPos != iHscroll)
  434.           {
  435.                ScrollWindow (hwnd, iHscroll - si.nPos, 0, NULL, NULL) ;
  436.                iHscroll = si.nPos ;
  437.                UpdateWindow (hwnd) ;
  438.           }
  439.           return 0 ;
  440.  
  441.           // WM_INITMENUPOPUP:  Enable or Gray menu items
  442.  
  443.      case WM_INITMENUPOPUP:
  444.           if (hdib)
  445.                iEnable = MF_ENABLED ;
  446.           else
  447.                iEnable = MF_GRAYED ;
  448.  
  449.           EnableMenuItem (hMenu, IDM_FILE_SAVE,       iEnable) ;
  450.           EnableMenuItem (hMenu, IDM_FILE_PRINT,      iEnable) ;
  451.           EnableMenuItem (hMenu, IDM_FILE_PROPERTIES, iEnable) ;
  452.           EnableMenuItem (hMenu, IDM_EDIT_CUT,        iEnable) ;
  453.           EnableMenuItem (hMenu, IDM_EDIT_COPY,       iEnable) ;
  454.           EnableMenuItem (hMenu, IDM_EDIT_DELETE,     iEnable) ;
  455.  
  456.           if (DibIsAddressable (hdib))
  457.                iEnable = MF_ENABLED ;
  458.           else
  459.                iEnable = MF_GRAYED ;
  460.  
  461.           EnableMenuItem (hMenu, IDM_EDIT_ROTATE,    iEnable) ;
  462.           EnableMenuItem (hMenu, IDM_EDIT_FLIP,      iEnable) ;
  463.           EnableMenuItem (hMenu, IDM_CONVERT_01,     iEnable) ;
  464.           EnableMenuItem (hMenu, IDM_CONVERT_04,     iEnable) ;
  465.           EnableMenuItem (hMenu, IDM_CONVERT_08,     iEnable) ;
  466.           EnableMenuItem (hMenu, IDM_CONVERT_16,     iEnable) ;
  467.           EnableMenuItem (hMenu, IDM_CONVERT_24,     iEnable) ;
  468.           EnableMenuItem (hMenu, IDM_CONVERT_32,     iEnable) ;
  469.  
  470.           switch (DibBitCount (hdib))
  471.           {
  472.           case  1: EnableMenuItem (hMenu, IDM_CONVERT_01, MF_GRAYED) ; break ;
  473.           case  4: EnableMenuItem (hMenu, IDM_CONVERT_04, MF_GRAYED) ; break ;
  474.           case  8: EnableMenuItem (hMenu, IDM_CONVERT_08, MF_GRAYED) ; break ;
  475.           case 16: EnableMenuItem (hMenu, IDM_CONVERT_16, MF_GRAYED) ; break ;
  476.           case 24: EnableMenuItem (hMenu, IDM_CONVERT_24, MF_GRAYED) ; break ;
  477.           case 32: EnableMenuItem (hMenu, IDM_CONVERT_32, MF_GRAYED) ; break ;
  478.           }
  479.  
  480.           if (hdib && DibColorSize (hdib) > 0)
  481.                iEnable = MF_ENABLED ;
  482.           else
  483.                iEnable = MF_GRAYED ;
  484.  
  485.           EnableMenuItem (hMenu, IDM_PAL_DIBTABLE,    iEnable) ;
  486.  
  487.           if (DibIsAddressable (hdib) && DibBitCount (hdib) > 8)
  488.                iEnable = MF_ENABLED ;
  489.           else
  490.                iEnable = MF_GRAYED ;
  491.  
  492.           EnableMenuItem (hMenu, IDM_PAL_OPT_POP4,   iEnable) ;
  493.           EnableMenuItem (hMenu, IDM_PAL_OPT_POP5,   iEnable) ;
  494.           EnableMenuItem (hMenu, IDM_PAL_OPT_POP6,   iEnable) ;
  495.           EnableMenuItem (hMenu, IDM_PAL_OPT_MEDCUT, iEnable) ;
  496.  
  497.           EnableMenuItem (hMenu, IDM_EDIT_PASTE, 
  498.                IsClipboardFormatAvailable (CF_DIB) ? MF_ENABLED : MF_GRAYED) ;
  499.  
  500.           return 0 ;
  501.  
  502.           // WM_COMMAND:  Process all menu commands.
  503.  
  504.      case WM_COMMAND:
  505.           iConvert = 0 ;
  506.  
  507.           switch (LOWORD (wParam))
  508.           {
  509.           case IDM_FILE_OPEN:
  510.  
  511.                     // Show the File Open dialog box
  512.  
  513.                if (!GetOpenFileName (&ofn))
  514.                     return 0 ;
  515.                
  516.                     // If there's an existing DIB and palette, delete them
  517.  
  518.                SendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;
  519.                
  520.                     // Load the DIB into memory
  521.  
  522.                SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
  523.                ShowCursor (TRUE) ;
  524.  
  525.                hdib = DibFileLoad (szFileName) ;
  526.  
  527.                ShowCursor (FALSE) ;
  528.                SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
  529.  
  530.                     // Reset the scroll bars
  531.  
  532.                SendMessage (hwnd, WM_USER_SETSCROLLS, TRUE, 0) ;
  533.  
  534.                     // Create the palette and DDB
  535.  
  536.                SendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;
  537.  
  538.                if (!hdib)
  539.                {
  540.                     MessageBox (hwnd, TEXT ("Cannot load DIB file!"), 
  541.                                 szAppName, MB_OK | MB_ICONEXCLAMATION) ;
  542.                }
  543.                InvalidateRect (hwnd, NULL, TRUE) ;
  544.                return 0 ;
  545.  
  546.           case IDM_FILE_SAVE:
  547.  
  548.                     // Show the File Save dialog box
  549.  
  550.                if (!GetSaveFileName (&ofn))
  551.                     return 0 ;
  552.  
  553.                     // Save the DIB to memory
  554.  
  555.                SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
  556.                ShowCursor (TRUE) ;
  557.  
  558.                fSuccess = DibFileSave (hdib, szFileName) ;
  559.  
  560.                ShowCursor (FALSE) ;
  561.                SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
  562.  
  563.                if (!fSuccess)
  564.                     MessageBox (hwnd, TEXT ("Cannot save DIB file!"),
  565.                                 szAppName, MB_OK | MB_ICONEXCLAMATION) ;
  566.                return 0 ;
  567.  
  568.           case IDM_FILE_PRINT:
  569.                if (!hdib)
  570.                     return 0 ;
  571.  
  572.                     // Get printer DC
  573.  
  574.               printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION ;
  575.  
  576.               if (!PrintDlg (&printdlg))
  577.                     return 0 ;
  578.  
  579.                if (NULL == (hdcPrn = printdlg.hDC))
  580.                {
  581.                     MessageBox (hwnd, TEXT ("Cannot obtain Printer DC"),
  582.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  583.                     return 0 ;
  584.                }
  585.                     // Check if the printer can print bitmaps
  586.  
  587.                if (!(RC_BITBLT & GetDeviceCaps (hdcPrn, RASTERCAPS)))
  588.                {
  589.                     DeleteDC (hdcPrn) ;
  590.                     MessageBox (hwnd, TEXT ("Printer cannot print bitmaps"),
  591.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  592.                     return 0 ;
  593.                }
  594.                     // Get size of printable area of page
  595.  
  596.                cxPage = GetDeviceCaps (hdcPrn, HORZRES) ;
  597.                cyPage = GetDeviceCaps (hdcPrn, VERTRES) ;
  598.  
  599.                fSuccess = FALSE ;
  600.  
  601.                     // Send the DIB to the printer
  602.  
  603.                SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
  604.                ShowCursor (TRUE) ;
  605.  
  606.                if ((StartDoc (hdcPrn, &di) > 0) && (StartPage (hdcPrn) > 0))
  607.                {
  608.                     DisplayDib (hdcPrn, DibBitmapHandle (hdib), 0, 0, 
  609.                                 cxPage, cyPage, wShow, FALSE) ;
  610.                     
  611.                     if (EndPage (hdcPrn) > 0)
  612.                     {
  613.                          fSuccess = TRUE ;
  614.                          EndDoc (hdcPrn) ;
  615.                     }
  616.                }
  617.                ShowCursor (FALSE) ;
  618.                SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
  619.  
  620.                DeleteDC (hdcPrn) ;
  621.  
  622.                if (!fSuccess)
  623.                     MessageBox (hwnd, TEXT ("Could not print bitmap"),
  624.                                 szAppName, MB_ICONEXCLAMATION | MB_OK) ;
  625.                return 0 ;
  626.  
  627.           case IDM_FILE_PROPERTIES:
  628.                if (!hdib)
  629.                     return 0 ;
  630.  
  631.                wsprintf (szBuffer, TEXT ("Pixel width:\t%i\n")
  632.                                    TEXT ("Pixel height:\t%i\n")
  633.                                    TEXT ("Bits per pixel:\t%i\n")
  634.                                    TEXT ("Number of colors:\t%i\n")
  635.                                    TEXT ("Compression:\t%s\n"),
  636.                          DibWidth (hdib), DibHeight (hdib),
  637.                          DibBitCount (hdib), DibNumColors (hdib),
  638.                          szCompression [min (3, DibCompression (hdib))]) ;
  639.  
  640.                MessageBox (hwnd, szBuffer, szAppName, 
  641.                            MB_ICONEXCLAMATION | MB_OK) ;
  642.                return 0 ;
  643.  
  644.           case IDM_APP_EXIT:
  645.                SendMessage (hwnd, WM_CLOSE, 0, 0) ;
  646.                return 0 ;
  647.  
  648.           case IDM_EDIT_COPY:
  649.           case IDM_EDIT_CUT:
  650.                if (!(hGlobal = DibCopyToPackedDib (hdib, TRUE)))
  651.                     return 0 ;
  652.  
  653.                OpenClipboard (hwnd) ;
  654.                EmptyClipboard () ;
  655.                SetClipboardData (CF_DIB, hGlobal) ;
  656.                CloseClipboard () ;
  657.  
  658.                if (LOWORD (wParam) == IDM_EDIT_COPY)
  659.                     return 0 ;
  660.                                    // fall through for IDM_EDIT_CUT
  661.           case IDM_EDIT_DELETE:
  662.                SendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;
  663.                InvalidateRect (hwnd, NULL, TRUE) ;
  664.                return 0 ;
  665.  
  666.           case IDM_EDIT_PASTE:
  667.                OpenClipboard (hwnd) ;
  668.  
  669.                hGlobal = GetClipboardData (CF_DIB) ;
  670.                pGlobal = GlobalLock (hGlobal) ;
  671.  
  672.                     // If there's an existing DIB and palette, delete them.
  673.                     // Then convert the packed DIB to an HDIB.
  674.  
  675.                if (pGlobal)
  676.                {
  677.                     SendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;
  678.                     hdib = DibCopyFromPackedDib ((BITMAPINFO *) pGlobal) ;
  679.                     SendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;
  680.                }
  681.  
  682.                GlobalUnlock (hGlobal) ;
  683.                CloseClipboard () ;
  684.  
  685.                     // Reset the scroll bars
  686.  
  687.                SendMessage (hwnd, WM_USER_SETSCROLLS, TRUE, 0) ;
  688.                InvalidateRect (hwnd, NULL, TRUE) ;
  689.                return 0 ;
  690.  
  691.           case IDM_EDIT_ROTATE:
  692.                if (hdibNew = DibRotateRight (hdib))
  693.                {
  694.                     DibDelete (hdib) ;
  695.                     DeleteObject (hBitmap) ;
  696.                     hdib = hdibNew ;
  697.                     hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;
  698.                     SendMessage (hwnd, WM_USER_SETSCROLLS, TRUE, 0) ;
  699.                     InvalidateRect (hwnd, NULL, TRUE) ;
  700.                }
  701.                else
  702.                {
  703.                     MessageBox (hwnd, TEXT ("Not enough memory"),
  704.                                 szAppName, MB_OK | MB_ICONEXCLAMATION) ;
  705.                }
  706.                return 0 ;
  707.  
  708.           case IDM_EDIT_FLIP:
  709.                if (hdibNew = DibFlipHorizontal (hdib))
  710.                {
  711.                     DibDelete (hdib) ;
  712.                     DeleteObject (hBitmap) ;
  713.                     hdib = hdibNew ;
  714.                     hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;
  715.                     InvalidateRect (hwnd, NULL, TRUE) ;
  716.                }
  717.                else
  718.                {
  719.                     MessageBox (hwnd, TEXT ("Not enough memory"),
  720.                                 szAppName, MB_OK | MB_ICONEXCLAMATION) ;
  721.                }
  722.                return 0 ;
  723.  
  724.           case IDM_SHOW_NORMAL:
  725.           case IDM_SHOW_CENTER:
  726.           case IDM_SHOW_STRETCH:
  727.           case IDM_SHOW_ISOSTRETCH:
  728.                CheckMenuItem (hMenu, wShow, MF_UNCHECKED) ;
  729.                wShow = LOWORD (wParam) ;
  730.                CheckMenuItem (hMenu, wShow, MF_CHECKED) ;
  731.  
  732.                SendMessage (hwnd, WM_USER_SETSCROLLS, FALSE, 0) ;
  733.  
  734.                InvalidateRect (hwnd, NULL, TRUE) ;
  735.                return 0 ;
  736.  
  737.           case IDM_CONVERT_32:  iConvert += 8 ;
  738.           case IDM_CONVERT_24:  iConvert += 8 ;   
  739.           case IDM_CONVERT_16:  iConvert += 8 ;
  740.           case IDM_CONVERT_08:  iConvert += 4 ;
  741.           case IDM_CONVERT_04:  iConvert += 3 ;
  742.           case IDM_CONVERT_01:  iConvert += 1 ;
  743.                SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
  744.                ShowCursor (TRUE) ;
  745.  
  746.                hdibNew = DibConvert (hdib, iConvert) ;
  747.  
  748.                ShowCursor (FALSE) ;
  749.                SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
  750.  
  751.                if (hdibNew)
  752.                {
  753.                     SendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;
  754.                     hdib = hdibNew ;
  755.                     SendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;
  756.                     InvalidateRect (hwnd, NULL, TRUE) ;
  757.                }
  758.                else
  759.                {
  760.                     MessageBox (hwnd, TEXT ("Not enough memory"),
  761.                                 szAppName, MB_OK | MB_ICONEXCLAMATION) ;
  762.                }
  763.                return 0 ;
  764.  
  765.           case IDM_APP_ABOUT:
  766.                MessageBox (hwnd, TEXT ("Dibble (c) Charles Petzold, 1998"),
  767.                            szAppName, MB_OK | MB_ICONEXCLAMATION) ;
  768.                return 0 ;
  769.           }
  770.      
  771.                // All the other WM_COMMAND messages are from the palette
  772.                //   items. Any existing palette is deleted, and the cursor
  773.                //   is set to the hourglass.
  774.  
  775.           SendMessage (hwnd, WM_USER_DELETEPAL, 0, 0) ;
  776.           SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
  777.           ShowCursor (TRUE) ;
  778.  
  779.                // Notice that all messages for palette items are ended
  780.                //   with break rather than return. This is to allow 
  781.                //   additional processing later on.
  782.  
  783.           switch (LOWORD (wParam))
  784.           {
  785.           case IDM_PAL_DIBTABLE: 
  786.                hPalette = DibPalDibTable (hdib) ; 
  787.                break ;
  788.  
  789.           case IDM_PAL_HALFTONE: 
  790.                hdc = GetDC (hwnd) ;
  791.  
  792.                if (hPalette = CreateHalftonePalette (hdc))
  793.                     fHalftonePalette = TRUE ;
  794.  
  795.                ReleaseDC (hwnd, hdc) ;
  796.                break ;
  797.  
  798.           case IDM_PAL_ALLPURPOSE: 
  799.                hPalette = DibPalAllPurpose () ; 
  800.                break ;
  801.  
  802.           case IDM_PAL_GRAY2:   hPalette = DibPalUniformGrays (  2) ; break ;
  803.           case IDM_PAL_GRAY3:   hPalette = DibPalUniformGrays (  3) ; break ;
  804.           case IDM_PAL_GRAY4:   hPalette = DibPalUniformGrays (  4) ; break ;
  805.           case IDM_PAL_GRAY8:   hPalette = DibPalUniformGrays (  8) ; break ;
  806.           case IDM_PAL_GRAY16:  hPalette = DibPalUniformGrays ( 16) ; break ;
  807.           case IDM_PAL_GRAY32:  hPalette = DibPalUniformGrays ( 32) ; break ;
  808.           case IDM_PAL_GRAY64:  hPalette = DibPalUniformGrays ( 64) ; break ;
  809.           case IDM_PAL_GRAY128: hPalette = DibPalUniformGrays (128) ; break ;
  810.           case IDM_PAL_GRAY256: hPalette = DibPalUniformGrays (256) ; break ;
  811.  
  812.           case IDM_PAL_RGB222: hPalette = DibPalUniformColors (2,2,2); break;
  813.           case IDM_PAL_RGB333: hPalette = DibPalUniformColors (3,3,3); break;
  814.           case IDM_PAL_RGB444: hPalette = DibPalUniformColors (4,4,4); break;
  815.           case IDM_PAL_RGB555: hPalette = DibPalUniformColors (5,5,5); break;
  816.           case IDM_PAL_RGB666: hPalette = DibPalUniformColors (6,6,6); break;
  817.           case IDM_PAL_RGB775: hPalette = DibPalUniformColors (7,7,5); break;
  818.           case IDM_PAL_RGB757: hPalette = DibPalUniformColors (7,5,7); break;
  819.           case IDM_PAL_RGB577: hPalette = DibPalUniformColors (5,7,7); break;
  820.           case IDM_PAL_RGB884: hPalette = DibPalUniformColors (8,8,4); break;
  821.           case IDM_PAL_RGB848: hPalette = DibPalUniformColors (8,4,8); break;
  822.           case IDM_PAL_RGB488: hPalette = DibPalUniformColors (4,8,8); break;
  823.  
  824.           case IDM_PAL_OPT_POP4:  
  825.                hPalette = DibPalPopularity (hdib, 4) ;
  826.                break ;
  827.  
  828.           case IDM_PAL_OPT_POP5:  
  829.                hPalette = DibPalPopularity (hdib, 5) ;
  830.                break ;
  831.  
  832.           case IDM_PAL_OPT_POP6:  
  833.                hPalette = DibPalPopularity (hdib, 6) ;
  834.                break ;                   
  835.  
  836.           case IDM_PAL_OPT_MEDCUT:
  837.                hPalette = DibPalMedianCut (hdib, 6) ;
  838.                break ;
  839.           }
  840.  
  841.                // After processing Palette items from the menu, the cursor
  842.                //   is restored to an arrow, the menu item is checked, and
  843.                //   the window is invalidated.
  844.  
  845.           hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;
  846.  
  847.           ShowCursor (FALSE) ;
  848.           SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
  849.  
  850.           if (hPalette)
  851.                PaletteMenu (hMenu, (LOWORD (wParam))) ;
  852.  
  853.           InvalidateRect (hwnd, NULL, TRUE) ;
  854.           return 0 ;
  855.  
  856.           // This programmer-defined message deletes an existing DIB 
  857.           //   in preparation for getting a new one.  Invoked during 
  858.           //   File Open command, Edit Paste command, and others.
  859.  
  860.      case WM_USER_DELETEDIB:
  861.           if (hdib)
  862.           {
  863.                DibDelete (hdib) ;
  864.                hdib = NULL ;
  865.           }
  866.           SendMessage (hwnd, WM_USER_DELETEPAL, 0, 0) ;
  867.           return 0 ;
  868.  
  869.           // This programmer-defined message deletes an existing palette
  870.           //   in preparation for defining a new one.
  871.  
  872.      case WM_USER_DELETEPAL:
  873.           if (hPalette)
  874.           {
  875.                DeleteObject (hPalette) ;
  876.                hPalette = NULL ;
  877.                fHalftonePalette = FALSE ;
  878.                PaletteMenu (hMenu, IDM_PAL_NONE) ;
  879.           }
  880.           if (hBitmap)
  881.                DeleteObject (hBitmap) ;
  882.  
  883.           return 0 ;
  884.  
  885.           // Programmers-defined message to create a new palette based on 
  886.           //   a new DIB.  If wParam == TRUE, create a DDB as well.
  887.  
  888.      case WM_USER_CREATEPAL:
  889.           if (hdib)
  890.           {
  891.                hdc = GetDC (hwnd) ;
  892.  
  893.                if (!(RC_PALETTE & GetDeviceCaps (hdc, RASTERCAPS)))
  894.                {
  895.                     PaletteMenu (hMenu, IDM_PAL_NONE) ;
  896.                }
  897.                else if (hPalette = DibPalDibTable (hdib))
  898.                {
  899.                     PaletteMenu (hMenu, IDM_PAL_DIBTABLE) ;
  900.                }
  901.                else if (hPalette = CreateHalftonePalette (hdc))
  902.                {
  903.                     fHalftonePalette = TRUE ;
  904.                     PaletteMenu (hMenu, IDM_PAL_HALFTONE) ;
  905.                }
  906.                ReleaseDC (hwnd, hdc) ;
  907.  
  908.                if ((BOOL) wParam)
  909.                     hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;
  910.           }
  911.           return 0 ;
  912.  
  913.      case WM_PAINT:
  914.           hdc = BeginPaint (hwnd, &ps) ;
  915.  
  916.           if (hPalette)
  917.           {
  918.                SelectPalette (hdc, hPalette, FALSE) ;
  919.                RealizePalette (hdc) ;
  920.           }
  921.           if (hBitmap)
  922.           {
  923.                DisplayDib (hdc, 
  924.                            fHalftonePalette ? DibBitmapHandle (hdib) : hBitmap, 
  925.                            iHscroll, iVscroll, 
  926.                            cxClient, cyClient, 
  927.                            wShow, fHalftonePalette) ;
  928.           }
  929.           EndPaint (hwnd, &ps) ;
  930.           return 0 ;
  931.  
  932.      case WM_QUERYNEWPALETTE:
  933.           if (!hPalette)
  934.                return FALSE ;
  935.  
  936.           hdc = GetDC (hwnd) ;
  937.           SelectPalette (hdc, hPalette, FALSE) ;
  938.           RealizePalette (hdc) ;
  939.           InvalidateRect (hwnd, NULL, TRUE) ;
  940.  
  941.           ReleaseDC (hwnd, hdc) ;
  942.           return TRUE ;
  943.  
  944.      case WM_PALETTECHANGED:
  945.           if (!hPalette || (HWND) wParam == hwnd)
  946.                break ;
  947.  
  948.           hdc = GetDC (hwnd) ;
  949.           SelectPalette (hdc, hPalette, FALSE) ;
  950.           RealizePalette (hdc) ;
  951.           UpdateColors (hdc) ;
  952.  
  953.           ReleaseDC (hwnd, hdc) ;
  954.           break ;
  955.  
  956.      case WM_DESTROY:
  957.           if (hdib)
  958.                DibDelete (hdib) ;
  959.  
  960.           if (hBitmap)
  961.                DeleteObject (hBitmap) ;
  962.  
  963.           if (hPalette)
  964.                DeleteObject (hPalette) ;
  965.  
  966.           PostQuitMessage (0) ;
  967.           return 0 ;
  968.      }
  969.      return DefWindowProc (hwnd, message, wParam, lParam) ;
  970. }
  971.  
  972.