home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic 5 Developer's Kit / vb5 dev kit.iso / dev / imglib12 / tstapp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-20  |  72.8 KB  |  2,478 lines

  1. /****************************************************************************
  2.     Copyright (c) 1994, 1995 by SimSoft
  3.     PROGRAM: testapp.c
  4.     PURPOSE: Test program to exercise the functionality of ImgLib
  5.  
  6.     Revision History:
  7.     Nov  6, 94  Beta release
  8.     Dec 18, 94  Release 1.0
  9.     Feb 19, 95  Release 1.1:  Added support for file saving, scrolling, sizing
  10.                               printing
  11.     Mar 25, 95  Release 1.2:  Removed references to unsupported image types.
  12.                               Added clipdoard operations by utilizing ClipDIB
  13.                               Added the "Zoom x5" feature.
  14.                               Simplified palette handling.
  15. ****************************************************************************/
  16.  
  17. #include <windows.h>
  18. #include <commdlg.h>
  19. #ifndef WIN32
  20. #include <print.h>
  21. #endif
  22. #include <malloc.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include "tstapp.h"
  26. #include "imglib.h"
  27. #ifdef USE_WING
  28. #include <wing.h>
  29. typedef HDC (WINGAPI *WINGCREATEDC) (void);
  30. typedef HBITMAP (WINGAPI *WINGCREATEBITMAP) (HDC, BITMAPINFO const FAR *, void FAR *FAR *);
  31. typedef BOOL (WINGAPI *WINGSTRETCHBLT) (HDC, int, int, int, int, HDC, int, int, int, int);
  32.  
  33. WINGSTRETCHBLT fpWinGStretchBlt;
  34. WINGCREATEBITMAP fpWinGCreateBitmap;
  35. WINGCREATEDC fpWinGCreateDC;
  36. #endif
  37.  
  38. #ifdef WIN32
  39. #define huge
  40. #define CONTROL_ID(w) (LOWORD (w))
  41. #define allocmem(s) (malloc (s))
  42. #define freemem(p) (free (p))
  43. #define copymem(d, s, c) (memcpy (d, s, c))
  44. #else
  45. #define CONTROL_ID(w) (w)
  46. #define allocmem(s) (GlobalLock (GlobalAlloc (GHND, (DWORD)s)))
  47. #define freemem(p) (GlobalFree (LOWORD (GlobalHandle (HIWORD (p)))))
  48. #define copymem(d, s, c) (hmemcpy (d, s, c))
  49. #endif
  50.  
  51. typedef char huge * HPSTR;
  52.  
  53. #define WINDOW_NAME "ImgLib Test App"
  54. #define MENU_POSITION_ROTATE      5
  55. #define MENU_POSITION_MIRROR      6
  56. #define MENU_POSITION_TC_OPT      0
  57.  
  58. static HWND       hwndMain;
  59. static HINSTANCE  hInst;
  60. static char       szBuffer[256];
  61. static HINSTANCE  hWinGInst;
  62. static HACCEL     hAccel;
  63. static LPVOID     lpDIB1, lpDIB2, lpDIBDisplay;
  64. static HPALETTE   hPalette;
  65. static LPPRINTDLG pPrintDlgStruct;
  66. static BOOL       bHalftoneImgLib, bFillPage;
  67. static unsigned int uPrintCopies = 1;
  68. static RECT       rcSelection;
  69. static POINT      ptAnchor;
  70. static BOOL       bDrawSelection, bPasting;
  71. static HDC        hdcWinG;
  72. static HBITMAP    hbmpWinG, hbmpWinGOld;
  73.  
  74. static BOOL       InitApplication (HANDLE);
  75. static BOOL       InitInstance (HANDLE, int);
  76. LRESULT CALLBACK  MainWndProc (HWND, UINT, WPARAM, LPARAM);
  77. BOOL CALLBACK     AboutProc (HWND, UINT, WPARAM, LPARAM);
  78. BOOL CALLBACK     FileTypeProc (HWND, UINT, WPARAM, LPARAM);
  79. BOOL CALLBACK     BrightnessProc (HWND, UINT, WPARAM, LPARAM);
  80. BOOL CALLBACK     PrintProc (HWND, UINT, WPARAM, LPARAM);
  81. static BOOL       GetOpenFile (LPSTR);
  82. static BOOL       GetSaveFile (LPSTR);
  83. LPVOID            CreateDisplayDIB (HWND, LPVOID*, HPALETTE *);
  84. static void       UpdateWindowTitle (LPSTR, BOOL);
  85. static void       ResizeWindowToDIB (HWND, LPVOID);
  86. static void       HandleVerticalScroll (WPARAM, LPARAM);
  87. static void       HandleHorizontalScroll (WPARAM, LPARAM);
  88. static void       HandleWindowSizing (LPVOID, WPARAM, LPARAM);
  89. static void       HandlePrinting (LPVOID);
  90. static void       HandleMenuPopup (WPARAM, LPARAM);
  91. static void       InitializePrintStruct (void);
  92. static void       HandleLButtonDown (WPARAM, LPARAM);
  93. static void       HandleLButtonUp (WPARAM, LPARAM);
  94. static void       HandleMouseMove (WPARAM, LPARAM);
  95. static void       HandleRButtonDown (WPARAM, LPARAM);
  96. static void       HandleCharacter (WPARAM, LPARAM);
  97. static void       HandlePasting (WPARAM, LPARAM);
  98. static void       HandleCopying (WPARAM, LPARAM);
  99. static void       HandleZoomin (WPARAM, LPARAM);
  100. static void       DrawSelectionBox (void);
  101. static void       EraseSelectionBox (void);
  102. static void       ProcessNewDIB (LPVOID);
  103. static LRESULT    HandlePaintingAndUpdates (UINT, WPARAM, LPARAM);
  104. #ifdef USE_WING
  105. static void       InitializeWinG (void);
  106. static void       UpdateWinGBitmap (LPVOID);
  107. #endif
  108.  
  109. /****************************************************************************
  110.     FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  111.     PURPOSE: calls initialization function, processes message loop
  112. ****************************************************************************/
  113.  
  114. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  115. MSG               msg;
  116.  
  117.   hInst = hInstance;
  118.  
  119.   if (!hPrevInstance)
  120.   {
  121.     if (!InitApplication (hInstance))
  122.       return (FALSE);
  123.   }
  124.   if (!InitInstance (hInstance, nCmdShow))
  125.     return (FALSE);
  126.   
  127.   while (GetMessage (&msg, NULL, 0, 0xffff))
  128.   {
  129.     if (!TranslateAccelerator (hwndMain, hAccel, &msg))
  130.     {
  131.       TranslateMessage (&msg);
  132.       DispatchMessage (&msg);
  133.     }
  134.   }
  135.   return (0);
  136. }
  137.  
  138.  
  139. /****************************************************************************
  140.     FUNCTION: InitApplication(HANDLE)
  141.     PURPOSE: Initializes window data and registers window class
  142. ****************************************************************************/
  143.  
  144. BOOL InitApplication (HANDLE hInstance)
  145. {
  146. WNDCLASS          wc;
  147.  
  148.   wc.style = 0;
  149.   wc.lpfnWndProc = MainWndProc;
  150.   wc.cbClsExtra = 0;
  151.   wc.cbWndExtra = 0;
  152.   wc.hInstance = hInstance;
  153.   wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
  154.   wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  155.   wc.hbrBackground = GetStockObject (WHITE_BRUSH);
  156.   wc.lpszMenuName = "tstappmenu";
  157.   wc.lpszClassName = "Test App";
  158.   
  159.   return (RegisterClass (&wc));
  160. }
  161.  
  162.  
  163. /****************************************************************************
  164.     FUNCTION:  InitInstance(HANDLE, int)
  165.     PURPOSE:  Saves instance handle and creates main window
  166. ****************************************************************************/
  167.  
  168. BOOL InitInstance (HANDLE hInstance, int nCmdShow)
  169. {
  170. UINT              uErrMode;
  171. HMENU             hMenu;
  172. HDC               hDC;
  173.  
  174.   hAccel = LoadAccelerators (hInstance, "tstappaccel");
  175.  
  176.   if (!hAccel)
  177.     return (FALSE);
  178.  
  179.   /*
  180.    * Just use default size and location.  It's easier to size an already
  181.    * created window for the specific client area size.
  182.    */
  183.    
  184.   hwndMain = CreateWindow ("Test App", WINDOW_NAME,
  185.         WS_OVERLAPPEDWINDOW,
  186.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  187.         NULL, NULL, hInstance, NULL);
  188.  
  189.   if (!hwndMain)
  190.     return (FALSE);
  191.  
  192.   ShowWindow (hwndMain, nCmdShow);
  193.   UpdateWindow (hwndMain);
  194.   hDC = GetDC (hwndMain);
  195.  
  196.   if (GetDeviceCaps (hDC, RASTERCAPS) & RC_PALETTE)
  197.   {
  198.     uErrMode = SetErrorMode (SEM_NOOPENFILEERRORBOX);
  199. #ifdef WIN32
  200.     hWinGInst = LoadLibrary ("wing32.dll");
  201. #else
  202.     hWinGInst = LoadLibrary ("wing.dll");
  203.   
  204.     if (hWinGInst < HINSTANCE_ERROR)
  205.       hWinGInst = 0;
  206. #endif
  207.     SetErrorMode (uErrMode);
  208.   }
  209.   else
  210.     hWinGInst = NULL;
  211.   
  212.   ReleaseDC (hwndMain, hDC);
  213.   hMenu = GetMenu (hwndMain);
  214.  
  215. #ifdef USE_WING
  216.   if (hWinGInst)
  217.   {
  218.     InitializeWinG ();
  219.     CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_WING, MF_BYCOMMAND | MF_CHECKED);
  220.     CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_IMGLIB, MF_BYCOMMAND | MF_UNCHECKED);
  221.   }
  222.   else
  223. #endif
  224.     EnableMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_WING, MF_BYCOMMAND | MF_GRAYED);
  225.   
  226.   return (TRUE);
  227. }
  228.  
  229. /****************************************************************************
  230.     FUNCTION: MainWndProc(HWND, UINT, WPARAM, LPARAM)
  231.     PURPOSE:  Processes messages
  232. ****************************************************************************/
  233.  
  234. LRESULT CALLBACK MainWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  235. {
  236. int               iCount, iBrightness;
  237. static char       szFileName[260], szOldTitle[256];
  238. LPVOID            lpDIBNew;
  239. HMENU             hMenu;
  240. DWORD             dwStartTime;
  241. static short      nFileType;
  242. PRINTDLG          PrintDlgStruct;
  243.  
  244.   switch (message)
  245.   {
  246.     case WM_QUERYNEWPALETTE:
  247.     case WM_PALETTECHANGED:
  248.     case WM_PAINT:
  249.       
  250.       return (HandlePaintingAndUpdates (message, wParam, lParam));
  251.       break;
  252.  
  253.     case WM_CHAR:
  254.       
  255.       HandleCharacter (wParam, lParam);
  256.       break;
  257.  
  258.     case WM_LBUTTONDOWN:
  259.       
  260.       HandleLButtonDown (wParam, lParam);
  261.       break;
  262.  
  263.     case WM_RBUTTONDOWN:
  264.       
  265.       HandleRButtonDown (wParam, lParam);
  266.       break;
  267.  
  268.     case WM_LBUTTONUP:
  269.       
  270.       HandleLButtonUp (wParam, lParam);
  271.       break;
  272.  
  273.     case WM_MOUSEMOVE:
  274.       
  275.       HandleMouseMove (wParam, lParam);
  276.       break;
  277.  
  278.     case WM_INITMENUPOPUP:
  279.  
  280.       HandleMenuPopup (wParam, lParam);
  281.       break;
  282.  
  283.     case WM_VSCROLL:
  284.  
  285.       HandleVerticalScroll (wParam, lParam);
  286.       break;
  287.  
  288.     case WM_HSCROLL:
  289.  
  290.       HandleHorizontalScroll (wParam, lParam);
  291.       break;
  292.  
  293.     case WM_SIZE:
  294.  
  295.       HandleWindowSizing (lpDIBDisplay, wParam, lParam);
  296.       break;
  297.  
  298.     case WM_COMMAND:
  299.  
  300.       switch (CONTROL_ID (wParam))
  301.       {
  302.         case ID_FILE_PRINT:
  303.  
  304.           if (lpDIB1)
  305.             HandlePrinting (lpDIB1);
  306.           break;
  307.  
  308.         case ID_FILE_PRINT_SETUP:
  309.  
  310.           if (!pPrintDlgStruct)
  311.             InitializePrintStruct ();
  312.  
  313.           if (!pPrintDlgStruct)
  314.             break;
  315.  
  316.           PrintDlgStruct = *pPrintDlgStruct;
  317.           PrintDlgStruct.hwndOwner = hWnd;
  318.           PrintDlgStruct.Flags = PD_PRINTSETUP;
  319.           
  320.           if (PrintDlg (&PrintDlgStruct) == TRUE)
  321.             *pPrintDlgStruct = PrintDlgStruct;
  322.           break;
  323.  
  324.         case ID_FILE_SAVE:
  325.  
  326.           if (lpDIB1)
  327.           {
  328.             if (GetSaveFile (szFileName) == FALSE)
  329.               break;
  330.  
  331.             if (DialogBoxParam (hInst, "IDD_FILETYPE", hWnd, FileTypeProc, (LPARAM)(LPINT)&nFileType) != TRUE)
  332.               break;
  333.  
  334.             UpdateWindowTitle (szFileName, TRUE);
  335.  
  336.             if (WriteDIBToFile (lpDIB1, szFileName, nFileType) == FALSE)
  337.             {
  338.               switch (GetLastImgLibError ())
  339.               {
  340.                 case ERROR_WRITE_ACCESS_DENIED:
  341.                   wsprintf ((LPSTR)szBuffer, (LPSTR)"Error writing to file \"%s\"", (LPSTR)szFileName);
  342.                   break;
  343.                 case ERROR_INVALID_POINTER:
  344.                   wsprintf ((LPSTR)szBuffer, (LPSTR)"Error accessing one of the pointer parameters", (LPSTR)szFileName);
  345.                   break;
  346.                 case ERROR_INCOMPATIBLE_IMAGE:
  347.                   wsprintf ((LPSTR)szBuffer, (LPSTR)"Image format incompatible with the selected file type", (LPSTR)szFileName);
  348.                   break;
  349.               }
  350.               MessageBox (NULL, szBuffer, "Save Error", MB_TASKMODAL | MB_ICONSTOP | MB_OK);
  351.             }
  352.           }
  353.           break;
  354.  
  355.         case ID_FILE_OPEN:
  356.         
  357.           if (GetOpenFile (szFileName) == FALSE)
  358.             break;
  359.  
  360.           SetCursor (LoadCursor (NULL, IDC_WAIT));
  361.           lpDIBNew = ReadFileIntoDIB (szFileName);
  362.           
  363.           if (lpDIBNew)
  364.           {
  365.             bDrawSelection = FALSE;
  366.             UpdateWindowTitle (szFileName, TRUE);
  367.             ProcessNewDIB (lpDIBNew);;
  368.           }
  369.           SetCursor (LoadCursor (NULL, IDC_ARROW));
  370.  
  371.           if (!lpDIBNew)
  372.           {
  373.             switch (GetLastImgLibError ())
  374.             {
  375.               case ERROR_UNSUPPORTED_IMAGE:
  376.                 MessageBox (hWnd, "Unsupported image type", WINDOW_NAME, MB_OK | MB_ICONSTOP);
  377.                 break;
  378.               case ERROR_NO_MEMORY:
  379.                 MessageBox (hWnd, "Out of memory reading image", WINDOW_NAME, MB_OK | MB_ICONSTOP);
  380.                 break;
  381.               case ERROR_INVALID_POINTER:
  382.                 MessageBox (hWnd, "Access violation", WINDOW_NAME, MB_OK | MB_ICONSTOP);
  383.                 break;
  384.             }
  385.           }
  386.           break;
  387.  
  388.         case ID_OPTIONS_TIME:
  389.         
  390.           if (GetOpenFile (szFileName) == FALSE)
  391.             break;
  392.  
  393.           SetCursor (LoadCursor (NULL, IDC_WAIT));
  394.           GetWindowText (hWnd, szOldTitle, sizeof (szOldTitle));
  395.           dwStartTime = GetTickCount ();
  396.  
  397.           for (iCount = 0;iCount < 10;iCount++)
  398.           {
  399.             wsprintf ((LPSTR)szBuffer, (LPSTR)"Testing image loading speed \"%s\" -- %d", (LPSTR)szFileName, iCount);
  400.             UpdateWindowTitle (szBuffer, FALSE);
  401.             lpDIBNew = ReadFileIntoDIB (szFileName);
  402.  
  403.             if (lpDIBNew)
  404.             {
  405.               DIBFree (lpDIBNew);
  406.             }
  407.             else
  408.             {
  409.               break;
  410.             }
  411.           }
  412.           SetWindowText (hWnd, szOldTitle);
  413.           SetCursor (LoadCursor (NULL, IDC_ARROW));
  414.           
  415.           if (iCount == 10)
  416.             wsprintf ((LPSTR)szBuffer, (LPSTR)"File \"%s\" loaded 10 times in %ld milliseconds", (LPSTR)szFileName, GetTickCount () - dwStartTime);
  417.           else
  418.             wsprintf ((LPSTR)szBuffer, (LPSTR)"File \"%s\" failed to load 10 times", (LPSTR)szFileName);
  419.  
  420.           MessageBox (hWnd, szBuffer, "ImgLib Timing Results", MB_OK);
  421.           break;
  422.  
  423.         case ID_FILE_EXIT:
  424.  
  425.           DestroyWindow (hWnd);
  426.           break;
  427.  
  428.         case ID_EDIT_UNDO:
  429.  
  430.           if (lpDIB1 && lpDIB2)
  431.           {
  432.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  433.  
  434.             if (lpDIBDisplay && lpDIBDisplay != lpDIB1)
  435.               DIBFree (lpDIBDisplay);
  436.  
  437.             lpDIBNew = lpDIB2;
  438.             lpDIB2 = lpDIB1;
  439.             lpDIB1 = lpDIBNew;
  440.  
  441.             if (hPalette)
  442.             {
  443.               DeleteObject (hPalette);
  444.               hPalette = NULL;
  445.             }
  446.             
  447.             lpDIBDisplay = CreateDisplayDIB (hWnd, &lpDIB1, &hPalette);
  448.             bDrawSelection = FALSE;
  449.             ResizeWindowToDIB (hWnd, lpDIBDisplay);
  450.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  451.           }
  452.           break;
  453.  
  454.         case ID_EDIT_PASTE:
  455.  
  456.           HandlePasting (wParam, lParam);
  457.           break;
  458.  
  459.         case ID_EDIT_COPY:
  460.  
  461.           HandleCopying (wParam, lParam);
  462.           break;
  463.  
  464.         case ID_EDIT_ZOOM:
  465.  
  466.           HandleZoomin (wParam, lParam);
  467.           break;
  468.  
  469.         case ID_EDIT_EMPTY:
  470.  
  471.           if (OpenClipboard (hWnd))
  472.           {
  473.             EmptyClipboard ();
  474.             CloseClipboard ();
  475.           }
  476.           break;
  477.  
  478.         case ID_PROCESS_BRIGHTNESS:
  479.  
  480.           if (lpDIB1)
  481.           {
  482.             iBrightness = DialogBox (hInst, "IDD_BRIGHTNESS", hWnd, BrightnessProc);
  483.  
  484.             if (iBrightness)
  485.             {
  486.               SetCursor (LoadCursor (NULL, IDC_WAIT));
  487.               lpDIBNew = BrightenDIB (lpDIB1, (short)iBrightness);
  488.               ProcessNewDIB (lpDIBNew);
  489.               SetCursor (LoadCursor (NULL, IDC_ARROW));
  490.             }
  491.           }
  492.           break;
  493.  
  494.         case ID_PROCESS_SMOOTH:
  495.  
  496.           if (lpDIB1)
  497.           {
  498.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  499.             lpDIBNew = SmoothDIB (lpDIB1, 1);
  500.             ProcessNewDIB (lpDIBNew);
  501.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  502.           }
  503.           break;
  504.  
  505.         case ID_PROCESS_HALFTONE:
  506.  
  507.           if (lpDIB1)
  508.           {
  509.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  510.             lpDIBNew = HalftoneDIB (lpDIB1);
  511.             ProcessNewDIB (lpDIBNew);
  512.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  513.           }
  514.           break;
  515.  
  516.         case ID_PROCESS_GRAY:
  517.  
  518.           if (lpDIB1)
  519.           {
  520.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  521.             lpDIBNew = GrayDIB (lpDIB1);
  522.             ProcessNewDIB (lpDIBNew);
  523.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  524.           }
  525.           break;
  526.  
  527.         case ID_PROCESS_EXPAND:
  528.  
  529.           if (lpDIB1)
  530.           {
  531.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  532.             lpDIBNew = ExpandToTrueDIB (lpDIB1);
  533.             ProcessNewDIB (lpDIBNew);
  534.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  535.           }
  536.           break;
  537.  
  538.         case ID_PROCESS_ROT90:
  539.         case ID_PROCESS_ROT180:
  540.         case ID_PROCESS_ROT270:
  541.  
  542.           if (lpDIB1)
  543.           {
  544.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  545.  
  546.             switch (CONTROL_ID (wParam))
  547.             {
  548.               case ID_PROCESS_ROT90:
  549.  
  550.                 lpDIBNew = RotateDIB (lpDIB1, 90);
  551.                 break;
  552.               case ID_PROCESS_ROT180:
  553.  
  554.                 lpDIBNew = RotateDIB (lpDIB1, 180);
  555.                 break;
  556.               case ID_PROCESS_ROT270:
  557.  
  558.                 lpDIBNew = RotateDIB (lpDIB1, 270);
  559.                 break;
  560.             }
  561.             ProcessNewDIB (lpDIBNew);
  562.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  563.           }
  564.           break;
  565.  
  566.         case ID_PROCESS_MIRRORH:
  567.         case ID_PROCESS_MIRRORV:
  568.  
  569.           if (lpDIB1)
  570.           {
  571.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  572.  
  573.             switch (CONTROL_ID (wParam))
  574.             {
  575.               case ID_PROCESS_MIRRORH:
  576.  
  577.                 lpDIBNew = MirrorDIB (lpDIB1, FALSE);
  578.                 break;
  579.               case ID_PROCESS_MIRRORV:
  580.  
  581.                 lpDIBNew = MirrorDIB (lpDIB1, TRUE);
  582.                 break;
  583.             }
  584.             ProcessNewDIB (lpDIBNew);
  585.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  586.           }
  587.           break;
  588.  
  589.         case ID_OPTIONS_TC_DISPLAY_GDI:
  590.  
  591.           hMenu = GetMenu (hWnd);
  592.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_GDI, MF_BYCOMMAND | MF_CHECKED);
  593.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_WING, MF_BYCOMMAND | MF_UNCHECKED);
  594.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_IMGLIB, MF_BYCOMMAND | MF_UNCHECKED);
  595.  
  596.           if (lpDIB1)
  597.           {
  598.             if (lpDIBDisplay && lpDIBDisplay != lpDIB1)
  599.               DIBFree (lpDIBDisplay);
  600.  
  601.             lpDIBDisplay = CreateDisplayDIB (hWnd, &lpDIB1, &hPalette);
  602.             InvalidateRect (hWnd, (LPRECT) (NULL), FALSE);
  603.           }
  604.           break;
  605.  
  606.         case ID_OPTIONS_TC_DISPLAY_WING:
  607.  
  608.           hMenu = GetMenu (hWnd);
  609.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_GDI, MF_BYCOMMAND | MF_UNCHECKED);
  610.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_WING, MF_BYCOMMAND | MF_CHECKED);
  611.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_IMGLIB, MF_BYCOMMAND | MF_UNCHECKED);
  612.  
  613.           if (lpDIB1)
  614.           {
  615.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  616.  
  617.             if (lpDIBDisplay && lpDIBDisplay != lpDIB1)
  618.               DIBFree (lpDIBDisplay);
  619.  
  620.             lpDIBDisplay = CreateDisplayDIB (hWnd, &lpDIB1, &hPalette);
  621.             InvalidateRect (hWnd, (LPRECT) (NULL), FALSE);
  622.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  623.           }
  624.           break;
  625.  
  626.         case ID_OPTIONS_TC_DISPLAY_IMGLIB:
  627.  
  628.           hMenu = GetMenu (hWnd);
  629.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_GDI, MF_BYCOMMAND | MF_UNCHECKED);
  630.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_WING, MF_BYCOMMAND | MF_UNCHECKED);
  631.           CheckMenuItem (hMenu, ID_OPTIONS_TC_DISPLAY_IMGLIB, MF_BYCOMMAND | MF_CHECKED);
  632.  
  633.           if (lpDIB1)
  634.           {
  635.             SetCursor (LoadCursor (NULL, IDC_WAIT));
  636.  
  637.             if (lpDIBDisplay && lpDIBDisplay != lpDIB1)
  638.               DIBFree (lpDIBDisplay);
  639.  
  640.             lpDIBDisplay = CreateDisplayDIB (hWnd, &lpDIB1, &hPalette);
  641.             InvalidateRect (hWnd, (LPRECT) (NULL), FALSE);
  642.             SetCursor (LoadCursor (NULL, IDC_ARROW));
  643.           }
  644.           break;
  645.  
  646.         case ID_OPTIONS_RETAIN_TC:
  647.  
  648.           hMenu = GetMenu (hWnd);
  649.           if (GetMenuState (hMenu, ID_OPTIONS_RETAIN_TC, MF_BYCOMMAND) & MF_CHECKED)
  650.           {
  651.             CheckMenuItem (hMenu, ID_OPTIONS_RETAIN_TC, MF_BYCOMMAND | MF_UNCHECKED);
  652.  
  653.             if (lpDIBDisplay && lpDIB1 != lpDIBDisplay)
  654.             {
  655.               DIBFree (lpDIB1);
  656.               lpDIB1 = lpDIBDisplay;
  657.             }
  658.           }
  659.           else
  660.           {
  661.             CheckMenuItem (hMenu, ID_OPTIONS_RETAIN_TC, MF_BYCOMMAND | MF_CHECKED);
  662.           }
  663.  
  664.           break;
  665.  
  666.         case ID_HELP_ABOUT:
  667.  
  668.           DialogBox (hInst, "IDD_ABOUT_DIALOG", hWnd, AboutProc);
  669.           break;
  670.  
  671.         default:
  672.           return (DefWindowProc (hWnd, message, wParam, lParam));
  673.       }
  674.       break;
  675.  
  676.     case WM_DESTROY:
  677.  
  678.       if (lpDIB1)
  679.         DIBFree (lpDIB1);
  680.  
  681.       if (lpDIB2)
  682.         DIBFree (lpDIB2);
  683.  
  684.       if (lpDIBDisplay && lpDIBDisplay != lpDIB1)
  685.         DIBFree (lpDIBDisplay);
  686.  
  687.       if (hPalette)
  688.       {
  689.         DeleteObject (hPalette);
  690.         hPalette = NULL;
  691.       }
  692.  
  693.       if (hWinGInst)
  694.       {
  695.         if (hbmpWinG)
  696.         {
  697.           SelectObject (hdcWinG, hbmpWinGOld);
  698.           DeleteObject (hbmpWinG);
  699.         }
  700.         DeleteDC (hdcWinG);
  701.         FreeLibrary (hWinGInst);
  702.       }
  703.       PostQuitMessage(0);
  704.       break;
  705.  
  706.     default:
  707.       return (DefWindowProc (hWnd, message, wParam, lParam));
  708.   }
  709.   return (0);
  710. }
  711.  
  712. /****************************************************************************
  713.     FUNCTION: AboutProc(HWND, UINT, WPARAM, LPARAM)
  714.     PURPOSE:  Processes messages for the About dialog
  715. ****************************************************************************/
  716.  
  717. BOOL CALLBACK AboutProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  718. {
  719. HWND              hwndStatic;
  720. char              szImgLibVer[512];
  721.  
  722.   switch (message)
  723.   {
  724.     case WM_INITDIALOG:
  725.  
  726.       hwndStatic = GetDlgItem (hDlg, IDC_ABOUT_STRING);
  727.       GetImgLibVersion (szImgLibVer, sizeof (szImgLibVer));
  728.       SetWindowText (hwndStatic, szImgLibVer);
  729.       return (TRUE);
  730.  
  731.     case WM_COMMAND:
  732.       if (CONTROL_ID (wParam) == IDOK)
  733.       {
  734.         EndDialog(hDlg, TRUE);
  735.         return (TRUE);
  736.       }
  737.       break;
  738.   }
  739.   return (FALSE);
  740. }
  741.  
  742. /****************************************************************************
  743.     FUNCTION: BrightnessProc(HWND, UINT, WPARAM, LPARAM)
  744.     PURPOSE:  Processes messages for the Brightness Control dialog
  745. ****************************************************************************/
  746.  
  747. BOOL CALLBACK BrightnessProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  748. {
  749. HWND              hwndStatic, hwndScroll;
  750. char              szMessage[32];
  751. int               iScrollCode, iNewPos;
  752. static LPVOID     lpDIBSave;
  753. LPVOID            lpDIBNew;
  754. HBITMAP           hbmpTemp;
  755.  
  756.   switch (message)
  757.   {
  758.     case WM_INITDIALOG:
  759.  
  760.       lpDIBSave = lpDIBDisplay;
  761.       hwndScroll = GetDlgItem (hDlg, IDC_BRIGHTNESS_SCROLLBAR);
  762.       SetScrollRange (hwndScroll, SB_CTL, 50, 150, TRUE);
  763.       SetScrollPos (hwndScroll, SB_CTL, 100, TRUE);
  764.       return (TRUE);
  765.  
  766.     case WM_HSCROLL:
  767.  
  768. #ifdef WIN32
  769.       iScrollCode = (int) LOWORD (wParam);
  770.       iNewPos = (int) HIWORD (wParam);
  771. #else
  772.       iScrollCode = (int) wParam;
  773.       iNewPos = (int) LOWORD (lParam);
  774. #endif
  775.       
  776.       hwndScroll = GetDlgItem (hDlg, IDC_BRIGHTNESS_SCROLLBAR);
  777.  
  778.       switch (iScrollCode)
  779.       {
  780.         case SB_ENDSCROLL:
  781.           iNewPos = GetScrollPos (hwndScroll, SB_CTL);
  782.           lpDIBNew = BrightenDIB (lpDIBSave, (short) iNewPos);
  783.  
  784.           if (lpDIBNew)
  785.           {
  786.             if (lpDIBDisplay != lpDIBSave)
  787.               DIBFree (lpDIBDisplay);
  788.  
  789.             lpDIBDisplay = lpDIBNew;
  790.             InvalidateRect (hwndMain, NULL, FALSE);
  791.             
  792.             /*
  793.              * WinG will not change the palette (as it uses a dithered palette
  794.              * which works with all colors.)  For that reason we force the
  795.              * slow standard GDI repaint.  This code will not have any side
  796.              * effects on non-WinG displays.
  797.              */
  798.             hbmpTemp = hbmpWinG;
  799.             hbmpWinG = NULL;
  800.             UpdateWindow (hwndMain);
  801.             hbmpWinG = hbmpTemp;
  802.           }
  803.           break;
  804.     
  805.         case SB_LINEDOWN:
  806.           iNewPos = GetScrollPos (hwndScroll, SB_CTL) + 1;
  807.           break;
  808.  
  809.         case SB_LINEUP:
  810.           iNewPos = GetScrollPos (hwndScroll, SB_CTL) - 1;
  811.           break;
  812.         case SB_PAGEDOWN:
  813.           iNewPos = GetScrollPos (hwndScroll, SB_CTL) + 10;
  814.           break;
  815.  
  816.         case SB_PAGEUP:
  817.           iNewPos = GetScrollPos (hwndScroll, SB_CTL) - 10;
  818.           break;
  819.       }
  820.  
  821.       if (iNewPos < 50)
  822.         iNewPos = 50;
  823.  
  824.       if (iNewPos > 150)
  825.         iNewPos = 150;
  826.  
  827.       wsprintf ((LPSTR)szMessage, (LPSTR)"%d %%", iNewPos);
  828.       hwndStatic = GetDlgItem (hDlg, IDC_BRIGHTNESS_PERCENTAGE);
  829.       SetWindowText (hwndStatic, szMessage);
  830.       SetScrollPos (hwndScroll, SB_CTL, iNewPos, TRUE);
  831.       return (TRUE);
  832.  
  833.     case WM_COMMAND:
  834.  
  835.       switch (CONTROL_ID (wParam))
  836.       {
  837.         case IDOK:
  838.           hwndScroll = GetDlgItem (hDlg, IDC_BRIGHTNESS_SCROLLBAR);
  839.           iNewPos = GetScrollPos (hwndScroll, SB_CTL);
  840.           
  841.           if (lpDIBDisplay != lpDIBSave)
  842.           {
  843.             DIBFree (lpDIBDisplay);
  844.             lpDIBDisplay = lpDIBSave;
  845.           }
  846.           EndDialog(hDlg, iNewPos);
  847.           return (TRUE);
  848.         case IDCANCEL:
  849.           
  850.           if (lpDIBDisplay != lpDIBSave)
  851.           {
  852.             DIBFree (lpDIBDisplay);
  853.             lpDIBDisplay = lpDIBSave;
  854.             InvalidateRect (hwndMain, NULL, FALSE);
  855.           }
  856.           EndDialog(hDlg, FALSE);
  857.           return (TRUE);
  858.       }
  859.       break;
  860.   }
  861.   return (FALSE);
  862. }
  863.  
  864. /****************************************************************************
  865.     FUNCTION: FileTypeProc(HWND, UINT, WPARAM, LPARAM)
  866.     PURPOSE:  Processes messages for the FileType dialog
  867. ****************************************************************************/
  868.  
  869. BOOL CALLBACK FileTypeProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  870. {
  871. static short      *pnFileType;
  872. int               iCtrl;
  873.  
  874.   switch (message)
  875.   {
  876.     case WM_INITDIALOG:
  877.  
  878.       pnFileType = (short *)lParam;
  879.  
  880.       switch (*pnFileType)
  881.       {
  882.         case FILETYPE_BMP:
  883.           iCtrl = IDC_IT_BMP;
  884.           break;
  885.         case FILETYPE_TIFF_DEFAULT:
  886.           iCtrl = IDC_IT_TIFF;
  887.           break;
  888.         case FILETYPE_TIFF_NO_COMPRESSION:
  889.           iCtrl = IDC_IT_TIFF_NOCOMP;
  890.           break;
  891.         case FILETYPE_TIFF_HUFFMAN:
  892.           iCtrl = IDC_IT_TIFF_HUFFMAN;
  893.           break;
  894.         case FILETYPE_TIFF_PACKBITS:
  895.           iCtrl = IDC_IT_TIFF_PACKBITS;
  896.           break;
  897.         case FILETYPE_TIFF_G3:
  898.           iCtrl = IDC_IT_TIFF_G3;
  899.           break;
  900.         case FILETYPE_TIFF_G4:
  901.           iCtrl = IDC_IT_TIFF_G4;
  902.           break;
  903.         default:
  904.           iCtrl = IDC_IT_BMP;
  905.           break;
  906.       }
  907.       CheckRadioButton (hDlg, IDC_IT_BMP, IDC_IT_TIFF_G4, iCtrl);
  908.       return (TRUE);
  909.  
  910.     case WM_COMMAND:
  911.  
  912.       if (CONTROL_ID (wParam) == IDOK)
  913.       {
  914.         if (IsDlgButtonChecked (hDlg, IDC_IT_BMP))
  915.           *pnFileType = FILETYPE_BMP;
  916.         else if (IsDlgButtonChecked (hDlg, IDC_IT_TIFF))
  917.           *pnFileType = FILETYPE_TIFF_DEFAULT;
  918.         else if (IsDlgButtonChecked (hDlg, IDC_IT_TIFF_NOCOMP))
  919.           *pnFileType = FILETYPE_TIFF_NO_COMPRESSION;
  920.         else if (IsDlgButtonChecked (hDlg, IDC_IT_TIFF_HUFFMAN))
  921.           *pnFileType = FILETYPE_TIFF_HUFFMAN;
  922.         else if (IsDlgButtonChecked (hDlg, IDC_IT_TIFF_PACKBITS))
  923.           *pnFileType = FILETYPE_TIFF_PACKBITS;
  924.         else if (IsDlgButtonChecked (hDlg, IDC_IT_TIFF_G3))
  925.           *pnFileType = FILETYPE_TIFF_G3;
  926.         else if (IsDlgButtonChecked (hDlg, IDC_IT_TIFF_G4))
  927.           *pnFileType = FILETYPE_TIFF_G4;
  928.         EndDialog(hDlg, TRUE);
  929.         return (TRUE);
  930.       }
  931.       else if (CONTROL_ID (wParam) == IDCANCEL)
  932.       {
  933.         EndDialog(hDlg, FALSE);
  934.         return (TRUE);
  935.       }
  936.       break;
  937.   }
  938.   return (FALSE);
  939. }
  940.  
  941. /****************************************************************************
  942.     FUNCTION: PrintProc(HWND, UINT, WPARAM, LPARAM)
  943.     PURPOSE:  Processes messages for the Print dialog
  944. ****************************************************************************/
  945.  
  946. BOOL CALLBACK PrintProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  947. {
  948. static LPBITMAPINFOHEADER pBmi;
  949. HWND              hwndCtl;
  950. LPDEVNAMES        pDevNames, pDevNamesNew;
  951. LPDEVMODE         pDevMode, pDevModeNew;
  952. char              szBuffer[256];
  953. static PRINTDLG   PrintDlgStruct;
  954. unsigned int      uCopyCount;
  955. BOOL              bConvertOK;
  956. HANDLE            hDevModeNew, hDevNamesNew;
  957.  
  958.   switch (message)
  959.   {
  960.     case WM_INITDIALOG:
  961.  
  962.       PrintDlgStruct = *pPrintDlgStruct;
  963.       SetDlgItemInt (hDlg, IDC_COPY_COUNT, uPrintCopies, FALSE);
  964.       pBmi = (LPBITMAPINFOHEADER) lParam;
  965.       pDevNames = (LPDEVNAMES)GlobalLock (pPrintDlgStruct->hDevNames);
  966.       pDevMode = (LPDEVMODE)GlobalLock (pPrintDlgStruct->hDevMode);
  967.  
  968.       /*
  969.        * Make copies of the DEVNAMES and DEVMODE structures
  970.        */
  971.       hDevNamesNew = GlobalAlloc (GMEM_MOVEABLE, GlobalSize (pPrintDlgStruct->hDevNames));
  972.       pDevNamesNew = (LPDEVNAMES) GlobalLock (hDevNamesNew);
  973.       hDevModeNew = GlobalAlloc (GMEM_MOVEABLE, GlobalSize (pPrintDlgStruct->hDevMode));
  974.       pDevModeNew = (LPDEVMODE) GlobalLock (hDevModeNew);
  975.       copymem (pDevModeNew, pDevMode, GlobalSize (hDevModeNew));
  976.       copymem (pDevNamesNew, pDevNames, GlobalSize (hDevNamesNew));
  977.       GlobalUnlock (pPrintDlgStruct->hDevNames);
  978.       GlobalUnlock (pPrintDlgStruct->hDevMode);
  979.       PrintDlgStruct.hDevMode = hDevModeNew;
  980.       PrintDlgStruct.hDevNames = hDevNamesNew;
  981.  
  982.       if (pBmi->biPlanes * pBmi->biBitCount == 1 || pDevModeNew->dmColor == DMCOLOR_COLOR)   // monochrome bitmap or color printer
  983.       {
  984.         hwndCtl = GetDlgItem (hDlg, IDC_HALFTONE_GROUP);
  985.         EnableWindow (hwndCtl, FALSE);
  986.         hwndCtl = GetDlgItem (hDlg, IDC_METHOD_GDI);
  987.         EnableWindow (hwndCtl, FALSE);
  988.         hwndCtl = GetDlgItem (hDlg, IDC_METHOD_IMGLIB);
  989.         EnableWindow (hwndCtl, FALSE);
  990.       }
  991.       else
  992.       {
  993.         if (bHalftoneImgLib)
  994.           CheckRadioButton (hDlg, IDC_METHOD_GDI, IDC_METHOD_IMGLIB, IDC_METHOD_IMGLIB);
  995.         else
  996.           CheckRadioButton (hDlg, IDC_METHOD_GDI, IDC_METHOD_IMGLIB, IDC_METHOD_GDI);
  997.       }
  998.       if (bFillPage)
  999.         CheckDlgButton (hDlg, IDC_FILL_PAGE, TRUE);
  1000.  
  1001.       wsprintf ((LPSTR)szBuffer, (LPSTR)"%s on %s", (LPSTR)pDevNamesNew + pDevNamesNew->wDeviceOffset, (LPSTR)pDevNamesNew + pDevNamesNew->wOutputOffset);
  1002.       SetDlgItemText (hDlg, IDC_PRINTERNAME, szBuffer);
  1003.       GlobalUnlock (hDevNamesNew);
  1004.       GlobalUnlock (hDevModeNew);
  1005.       return (TRUE);
  1006.  
  1007.     case WM_COMMAND:
  1008.  
  1009.       switch (CONTROL_ID (wParam))
  1010.       {
  1011.         case IDC_SETUP_PRINTER:
  1012.  
  1013.           PrintDlgStruct.hwndOwner = hDlg;
  1014.           PrintDlgStruct.Flags = PD_PRINTSETUP;
  1015.           if (PrintDlg (&PrintDlgStruct))
  1016.           {
  1017.             pDevModeNew = (LPDEVMODE) GlobalLock (PrintDlgStruct.hDevMode);
  1018.             if (pBmi->biPlanes * pBmi->biBitCount == 1 || pDevModeNew->dmColor == DMCOLOR_COLOR)   // monochrome bitmap or color printer
  1019.             {
  1020.               hwndCtl = GetDlgItem (hDlg, IDC_HALFTONE_GROUP);
  1021.               EnableWindow (hwndCtl, FALSE);
  1022.               hwndCtl = GetDlgItem (hDlg, IDC_METHOD_GDI);
  1023.               EnableWindow (hwndCtl, FALSE);
  1024.               hwndCtl = GetDlgItem (hDlg, IDC_METHOD_IMGLIB);
  1025.               EnableWindow (hwndCtl, FALSE);
  1026.             }
  1027.             else
  1028.             {
  1029.               hwndCtl = GetDlgItem (hDlg, IDC_HALFTONE_GROUP);
  1030.               EnableWindow (hwndCtl, TRUE);
  1031.               hwndCtl = GetDlgItem (hDlg, IDC_METHOD_GDI);
  1032.               EnableWindow (hwndCtl, TRUE);
  1033.               hwndCtl = GetDlgItem (hDlg, IDC_METHOD_IMGLIB);
  1034.               EnableWindow (hwndCtl, TRUE);
  1035.             }
  1036.             GlobalUnlock (PrintDlgStruct.hDevMode);
  1037.           }
  1038.           return (TRUE);
  1039.  
  1040.         case IDOK:
  1041.  
  1042.           uCopyCount = GetDlgItemInt (hDlg, IDC_COPY_COUNT, &bConvertOK, FALSE);
  1043.  
  1044.           if (!bConvertOK || uCopyCount < 1 || uCopyCount > 100)
  1045.           {
  1046.             MessageBox (hDlg, "Invalid value.  Please enter a number between 1 and 100", "Print", MB_ICONSTOP | MB_OK);
  1047.             SetFocus (GetDlgItem (hDlg, IDC_COPY_COUNT));
  1048.             return (TRUE);
  1049.           }
  1050.           uPrintCopies = uCopyCount;
  1051.           bFillPage = IsDlgButtonChecked (hDlg, IDC_FILL_PAGE);
  1052.           bHalftoneImgLib = IsDlgButtonChecked (hDlg, IDC_METHOD_IMGLIB);
  1053.           GlobalFree (pPrintDlgStruct->hDevNames);
  1054.           GlobalFree (pPrintDlgStruct->hDevMode);
  1055.           *pPrintDlgStruct = PrintDlgStruct;
  1056.           EndDialog (hDlg, TRUE);
  1057.           return (TRUE);
  1058.  
  1059.         case IDCANCEL:
  1060.  
  1061.           GlobalFree (PrintDlgStruct.hDevNames);
  1062.           GlobalFree (PrintDlgStruct.hDevMode);
  1063.           EndDialog (hDlg, FALSE);
  1064.           return (TRUE);
  1065.       }
  1066.       break;
  1067.   }
  1068.   return (FALSE);
  1069. }
  1070.  
  1071. /*************************************************************************
  1072.   Function:  GetOpenFile (LPSTR. WORD)
  1073.    Purpose:  Prompts user for a filename through the use of a Windows
  1074.              FileOpen common dialog box.
  1075.    Returns:  TRUE if a filename is selected.
  1076.              FALSE if no filename is selected.
  1077.   Comments:  Filename is put into the string passed to the routine.
  1078.              If a filename is not selected, NULL is returned.
  1079. *************************************************************************/
  1080.  
  1081. BOOL GetOpenFile (LPSTR szFileName)
  1082. {
  1083. OPENFILENAME   of;
  1084. DWORD          flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
  1085. static char    szTitle[30];         // Dialog Box title
  1086. static char    szTemplate[20];      // Dialog Box template
  1087. static char    szFile[256];         // File name
  1088. static char    szFileTitle[256];    // Title
  1089. static char    szDrive[5];          // Drive
  1090. static char    szDir[256];          // Directory
  1091. char szFilter[] =                   // Filter
  1092.   "Pictures\0*.bmp;*.jpg;*.tga;*.pcd;*.pcx;*.tif\0All Files\0*.*\0";
  1093. LPSTR          pFile;
  1094.  
  1095.    szFile[0] = '\0';
  1096.    of.lStructSize       = sizeof (OPENFILENAME);
  1097.    of.hwndOwner         = hwndMain;
  1098.    of.hInstance         = hInst;
  1099.    of.lpstrFilter       = szFilter;
  1100.    of.lpstrCustomFilter = NULL;
  1101.    of.nMaxCustFilter    = 0L;
  1102.    of.nFilterIndex      = 1L;
  1103.    of.lpstrFile         = szFile;
  1104.    of.nMaxFile          = sizeof (szFile);
  1105.    of.lpstrFileTitle    = szFileTitle;
  1106.    of.nMaxFileTitle     = sizeof (szFileTitle);
  1107.    of.lpstrInitialDir   = szDir;
  1108.    of.lpstrTitle        = "Open a new test bitmap file";
  1109.    of.Flags             = flags;
  1110.    of.nFileOffset       = 0;
  1111.    of.nFileExtension    = 0;
  1112.    of.lpstrDefExt       = NULL;
  1113.    of.lCustData         = 0;
  1114.    of.lpfnHook          = NULL;
  1115.    of.lpTemplateName    = NULL;
  1116.  
  1117.   if (GetOpenFileName (&of))
  1118.   {
  1119.     lstrcpy (szFileName, of.lpstrFile);
  1120.     lstrcpy (szDir, of.lpstrFile);
  1121.     pFile = strrchr (szDir, '\\');
  1122.  
  1123.     if (pFile)
  1124.       *pFile = 0;
  1125.  
  1126.     return TRUE;
  1127.   }
  1128.   else
  1129.     return FALSE;
  1130. }
  1131.  
  1132. /*************************************************************************
  1133.   Function:  GetSaveFile (LPSTR. WORD)
  1134.    Purpose:  Prompts user for a filename through the use of a Windows
  1135.              FileOpen common dialog box.
  1136.    Returns:  TRUE if a filename is selected.
  1137.              FALSE if no filename is selected.
  1138.   Comments:  Filename is put into the string passed to the routine.
  1139.              If a filename is not selected, NULL is returned.
  1140. *************************************************************************/
  1141.  
  1142. BOOL GetSaveFile (LPSTR szFileName)
  1143. {
  1144. OPENFILENAME   of;
  1145. DWORD          flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
  1146. static char    szTitle[30];         // Dialog Box title
  1147. static char    szTemplate[20];      // Dialog Box template
  1148. static char    szFile[256];         // File name
  1149. static char    szFileTitle[256];    // Title
  1150. static char    szDrive[5];          // Drive
  1151. static char    szDir[256];          // Directory
  1152. char szFilter[] =                   // Filter
  1153.   "Windows Pictures\0*.bmp;*.tif\0All Files\0*.*\0";
  1154. LPSTR          pFile;
  1155.  
  1156.    szFile[0] = '\0';
  1157.    of.lStructSize       = sizeof (OPENFILENAME);
  1158.    of.hwndOwner         = GetFocus ();
  1159.    of.hInstance         = hInst;
  1160.    of.lpstrFilter       = szFilter;
  1161.    of.lpstrCustomFilter = NULL;
  1162.    of.nMaxCustFilter    = 0L;
  1163.    of.nFilterIndex      = 1L;
  1164.    of.lpstrFile         = szFile;
  1165.    of.nMaxFile          = sizeof (szFile);
  1166.    of.lpstrFileTitle    = szFileTitle;
  1167.    of.nMaxFileTitle     = sizeof (szFileTitle);
  1168.    of.lpstrInitialDir   = szDir;
  1169.    of.lpstrTitle        = "Save the image in a bitmap file";
  1170.    of.Flags             = flags;
  1171.    of.nFileOffset       = 0;
  1172.    of.nFileExtension    = 0;
  1173.    of.lpstrDefExt       = "*.bmp";
  1174.    of.lCustData         = 0;
  1175.    of.lpfnHook          = NULL;
  1176.    of.lpTemplateName    = NULL;
  1177.  
  1178.   if (GetSaveFileName (&of))
  1179.   {
  1180.     lstrcpy (szFileName, of.lpstrFile);
  1181.     lstrcpy (szDir, of.lpstrFile);
  1182.     pFile = strrchr (szDir, '\\');
  1183.  
  1184.     if (pFile)
  1185.       *pFile = 0;
  1186.  
  1187.     return TRUE;
  1188.   }
  1189.   else
  1190.     return FALSE;
  1191. }
  1192.  
  1193. /*************************************************************************
  1194.   Function:  CreateDisplayDIB()
  1195.    Purpose:  Creates a DIB suitable for the display based on user-selected options.
  1196.    Returns:  a new DIB pointer
  1197. *************************************************************************/
  1198.  
  1199. LPVOID CreateDisplayDIB (HWND hwnd, LPVOID *lpDIB, HPALETTE *phPal)
  1200. {
  1201. HMENU             hMenu;
  1202. LPBITMAPINFO      pBitmapInfo;
  1203. UINT              uState;
  1204. LPVOID            lpDIBDisplay;
  1205. long              lColors;
  1206. int               iPixelBits, iPlanes;
  1207. HDC               hDC;
  1208.  
  1209.   hDC = GetDC (hwnd);
  1210.   iPixelBits = GetDeviceCaps (hDC, BITSPIXEL);
  1211.   iPlanes = GetDeviceCaps (hDC, PLANES);
  1212.   ReleaseDC (hwnd, hDC);
  1213.  
  1214.   if (iPixelBits * iPlanes > 8)
  1215.   {
  1216.     /*
  1217.      * No color reduction on true color (or high color) displays
  1218.      */
  1219.     *phPal = NULL;
  1220.     return (*lpDIB);
  1221.   }
  1222.   pBitmapInfo = (LPBITMAPINFO) *lpDIB;
  1223.   hMenu = GetMenu (hwnd);
  1224.   uState = GetMenuState (hMenu, ID_OPTIONS_TC_DISPLAY_GDI, MF_BYCOMMAND);
  1225.  
  1226.   if (uState & MF_CHECKED || pBitmapInfo->bmiHeader.biClrUsed)
  1227.   {
  1228.     lpDIBDisplay = *lpDIB;
  1229.     
  1230.     if (pBitmapInfo->bmiHeader.biClrUsed > 2)
  1231.       *phPal = CreateDIBPalette (lpDIBDisplay);
  1232.     else
  1233.       *phPal = NULL;
  1234.   }
  1235.   else
  1236.   {
  1237.     uState = GetMenuState (hMenu, ID_OPTIONS_TC_DISPLAY_WING, MF_BYCOMMAND);
  1238.  
  1239.     if (uState & MF_CHECKED && hWinGInst)
  1240.     {
  1241.       lpDIBDisplay = WinGHalftoneDIB (*lpDIB, phPal);
  1242.     }
  1243.     else
  1244.     {
  1245.       lColors = 1 << iPixelBits * iPlanes;
  1246.       lpDIBDisplay = ReduceDIB (*lpDIB, lColors, TRUE);
  1247.       *phPal = CreateDIBPalette (lpDIBDisplay);
  1248.     }
  1249.  
  1250.     if (lpDIBDisplay && lpDIBDisplay != *lpDIB)
  1251.     {
  1252.       if (!(GetMenuState (hMenu, ID_OPTIONS_RETAIN_TC, MF_BYCOMMAND) & MF_CHECKED))
  1253.       {
  1254.         DIBFree (*lpDIB);
  1255.         *lpDIB = lpDIBDisplay;
  1256.       }
  1257.     }
  1258.   }
  1259. #ifdef USE_WING
  1260.   /*
  1261.    * Use WinG for displaying if available
  1262.    */
  1263.  
  1264.   if (hWinGInst)
  1265.     UpdateWinGBitmap (lpDIBDisplay);
  1266. #endif
  1267.   return (lpDIBDisplay);
  1268. }
  1269.  
  1270. /*************************************************************************
  1271.   Function:  UpdateWindowTitle ()
  1272.    Purpose:  Updates the window title with the name of the file displayed.
  1273.    Returns:  none
  1274. *************************************************************************/
  1275.  
  1276. static void UpdateWindowTitle (LPSTR pszFilePath, BOOL bStripPath)
  1277. {
  1278. static char       szWindowName[260];
  1279. char              szFileName[260];
  1280. char              *pszFileName = NULL;
  1281.  
  1282.   if (pszFilePath && *pszFilePath)
  1283.   {
  1284.     /*
  1285.      * Make local copy because in 16-bit world strrchr can only operate on
  1286.      * near pointers.
  1287.      */
  1288.     lstrcpy (szFileName, pszFilePath);
  1289.  
  1290.     if (bStripPath)
  1291.       pszFileName = strrchr (szFileName, '\\');
  1292.  
  1293.     /*
  1294.      * If found the last path delimiter, skip over it.
  1295.      */
  1296.     if (pszFileName)
  1297.       pszFileName++;
  1298.     else
  1299.       pszFileName = szFileName;
  1300.  
  1301.     wsprintf ((LPSTR)szWindowName, (LPSTR)"%s -- %s", (LPSTR)WINDOW_NAME, (LPSTR)pszFileName);
  1302.   }
  1303.   else
  1304.     wsprintf ((LPSTR)szWindowName, (LPSTR)"%s", (LPSTR)WINDOW_NAME);
  1305.  
  1306.   SetWindowText (hwndMain, szWindowName);
  1307. }
  1308.  
  1309. /*************************************************************************
  1310.   Function:  ResizeWindowToDIB ()
  1311.    Purpose:  Updates the window size to fit the given device-independent DIB
  1312.    Returns:  none
  1313. *************************************************************************/
  1314.  
  1315. static void ResizeWindowToDIB (HWND hwnd, LPVOID pDIB)
  1316. {
  1317. int               iWidth, iHeight, iXOverhead, iYOverhead;
  1318. int               iScreenWidth, iScreenHeight, iXPos, iYPos;
  1319. int               iHScrollRange, iVScrollRange;
  1320. LPBITMAPINFOHEADER pBmi = (LPBITMAPINFOHEADER)pDIB;
  1321. HDC               hDC;
  1322. RECT              rect;
  1323. BOOL              bHScroll, bVScroll;
  1324. DWORD             dwStyle;
  1325.  
  1326.   bHScroll = bVScroll = FALSE;
  1327.   GetWindowRect (hwnd, &rect);
  1328.   iXPos = rect.left;
  1329.  
  1330.   if (iXPos < 0)
  1331.     iXPos = 0;
  1332.  
  1333.   iYPos = rect.top;
  1334.  
  1335.   if (iYPos < 0)
  1336.     iYPos = 0;
  1337.  
  1338.   hDC = GetDC (hwnd);
  1339.   iScreenWidth = GetDeviceCaps (hDC, HORZRES);
  1340.   iScreenHeight = GetDeviceCaps (hDC, VERTRES);
  1341.   ReleaseDC (hwnd, hDC);
  1342.   iWidth = (int)pBmi->biWidth;
  1343.   iHeight = (int)pBmi->biHeight;
  1344.   iXOverhead = GetSystemMetrics (SM_CXFRAME) * 2;
  1345.   iYOverhead = GetSystemMetrics (SM_CYFRAME) * 2 + GetSystemMetrics (SM_CYCAPTION) + GetSystemMetrics (SM_CYMENU);
  1346.  
  1347.   if (iWidth + iXOverhead + iXPos > iScreenWidth)
  1348.   {
  1349.     iXPos = iScreenWidth - iWidth - iXOverhead;
  1350.  
  1351.     if (iXPos < 0)
  1352.     {
  1353.       iHScrollRange = -iXPos;
  1354.       iXPos = 0;
  1355.       bHScroll = TRUE;
  1356.     }
  1357.   }
  1358.   if (iHeight + iYOverhead + iYPos > iScreenHeight)
  1359.   {
  1360.     iYPos = iScreenHeight - iHeight - iYOverhead;
  1361.  
  1362.     if (iYPos < 0)
  1363.     {
  1364.       iVScrollRange = -iYPos;
  1365.       iYPos = 0;
  1366.       bVScroll = TRUE;
  1367.     }
  1368.   }
  1369.   dwStyle = GetWindowLong (hwnd, GWL_STYLE);
  1370.  
  1371.   if (bHScroll)
  1372.   {
  1373.     ShowScrollBar (hwndMain, SB_HORZ, TRUE);
  1374.     /*
  1375.      * Having the vertical scrollbar will "steal" some more pixels
  1376.      * from the client area.  Check and adjust for it here.
  1377.      */
  1378.     if (bVScroll)
  1379.       iHScrollRange += GetSystemMetrics (SM_CXVSCROLL);
  1380.   }
  1381.   else
  1382.   {
  1383.     /*
  1384.      * Remove the scrollbar
  1385.      */
  1386.     if (dwStyle & WS_HSCROLL)
  1387.     {
  1388.       SetScrollPos (hwnd, SB_HORZ, 0, TRUE);
  1389.       ShowScrollBar (hwndMain, SB_HORZ, FALSE);
  1390.     }
  1391.   }
  1392.   if (bVScroll)
  1393.   {
  1394.     ShowScrollBar (hwndMain, SB_VERT, TRUE);
  1395.     /*
  1396.      * Having the horizontal scrollbar will "steal" some more pixels
  1397.      * from the client area.  Check and adjust for it here.
  1398.      */
  1399.     if (bHScroll)
  1400.       iVScrollRange += GetSystemMetrics (SM_CYHSCROLL);
  1401.   }
  1402.   else
  1403.   {
  1404.     /*
  1405.      * Remove the scrollbar
  1406.      */
  1407.     if (dwStyle & WS_VSCROLL)
  1408.     {
  1409.       SetScrollPos (hwnd, SB_VERT, 0, TRUE);
  1410.       ShowScrollBar (hwndMain, SB_VERT, FALSE);
  1411.     }
  1412.   }
  1413.   
  1414.   /*
  1415.    * Having done all this checking, the following call may still cause the
  1416.    * addition of scrollbars in rare circumstances like the menu bar becoming
  1417.    * 2-line.
  1418.    */
  1419.   SetWindowPos (hwnd, HWND_TOP, iXPos, iYPos, min (iXOverhead + iWidth, iScreenWidth),
  1420.                 min (iYOverhead + iHeight, iScreenHeight),
  1421.                 SWP_NOACTIVATE | SWP_NOZORDER);
  1422.   if (bHScroll)
  1423.     SetScrollRange (hwnd, SB_HORZ, 0, iHScrollRange, TRUE);
  1424.   if (bVScroll)
  1425.     SetScrollRange (hwnd, SB_VERT, 0, iVScrollRange, TRUE);
  1426.  
  1427.   InvalidateRect (hwnd, (LPRECT) (NULL), FALSE);
  1428. }
  1429.  
  1430. /*************************************************************************
  1431.   Function:  HandleVerticalScroll ()
  1432.    Purpose:  Process the vertical scrollbar operations.
  1433.    Returns:  none
  1434. *************************************************************************/
  1435.  
  1436. static void HandleVerticalScroll (WPARAM wParam, LPARAM lParam)
  1437. {
  1438. int               nScrollCode, iNewPos, iVScroll, iHScroll;
  1439. int               iCurrPos, iMinScroll, iMaxScroll, iClientHeight;
  1440. RECT              rect;
  1441.  
  1442.   UpdateWindow (hwndMain);
  1443.  
  1444. #ifdef WIN32
  1445.   nScrollCode = (int) LOWORD (wParam);
  1446.   iNewPos = (int) HIWORD (wParam);
  1447. #else
  1448.   nScrollCode = (int) wParam;
  1449.   iNewPos = (int) LOWORD (lParam);
  1450. #endif
  1451.  
  1452.   GetClientRect (hwndMain, &rect);
  1453.   iClientHeight = rect.bottom;
  1454.   iHScroll = iVScroll = 0;
  1455.   GetScrollRange (hwndMain, SB_VERT, &iMinScroll, &iMaxScroll);
  1456.   iCurrPos = GetScrollPos (hwndMain, SB_VERT);
  1457.  
  1458.   switch (nScrollCode)
  1459.   {
  1460.     case SB_BOTTOM:
  1461.       
  1462.       iVScroll = iMaxScroll - iCurrPos;
  1463.       break;
  1464.  
  1465.     case SB_PAGEDOWN:
  1466.  
  1467.       if (iCurrPos + iClientHeight <= iMaxScroll)
  1468.         iVScroll = -iClientHeight;
  1469.       else
  1470.         iVScroll = - (iMaxScroll - iCurrPos);
  1471.  
  1472.       break;
  1473.  
  1474.     case SB_PAGEUP:
  1475.  
  1476.       if (iCurrPos - iClientHeight >= 0)
  1477.         iVScroll = iClientHeight;
  1478.       else
  1479.         iVScroll = iCurrPos;
  1480.  
  1481.       break;
  1482.  
  1483.     case SB_THUMBTRACK:
  1484.     case SB_THUMBPOSITION:
  1485.       iVScroll = GetScrollPos (hwndMain, SB_VERT) - iNewPos;
  1486.       break;
  1487.   
  1488.     case SB_LINEDOWN:
  1489.  
  1490.       iVScroll = -1;
  1491.       break;
  1492.  
  1493.     case SB_LINEUP:
  1494.  
  1495.       iVScroll = 1;
  1496.       break;
  1497.  
  1498.     case SB_ENDSCROLL:
  1499.  
  1500.       return;
  1501.   }
  1502.   if (iCurrPos - iVScroll > iMaxScroll)
  1503.     iVScroll = iCurrPos - iMaxScroll;
  1504.  
  1505.   if (iCurrPos - iVScroll < iMinScroll)
  1506.     iVScroll = iCurrPos - iMinScroll;
  1507.  
  1508.   if (!iVScroll)
  1509.     return;
  1510.  
  1511.   ScrollWindow (hwndMain, iHScroll, iVScroll, NULL, &rect);
  1512.   SetScrollPos (hwndMain, SB_VERT, iCurrPos - iVScroll, TRUE);
  1513. }
  1514.  
  1515. /*************************************************************************
  1516.   Function:  HandleHorizontalScroll ()
  1517.    Purpose:  Process the horozontal scrollbar operations.
  1518.    Returns:  none
  1519. *************************************************************************/
  1520.  
  1521. static void HandleHorizontalScroll (WPARAM wParam, LPARAM lParam)
  1522. {
  1523. int               nScrollCode, iNewPos, iVScroll, iHScroll;
  1524. int               iCurrPos, iMinScroll, iMaxScroll, iClientWidth;
  1525. RECT              rect;
  1526.  
  1527.   UpdateWindow (hwndMain);
  1528.  
  1529. #ifdef WIN32
  1530.   nScrollCode = (int) LOWORD (wParam);
  1531.   iNewPos = (int) HIWORD (wParam);
  1532. #else
  1533.   nScrollCode = (int) wParam;
  1534.   iNewPos = (int) LOWORD (lParam);
  1535. #endif
  1536.  
  1537.   GetClientRect (hwndMain, &rect);
  1538.   iClientWidth = rect.right;
  1539.   iHScroll = iVScroll = 0;
  1540.   GetScrollRange (hwndMain, SB_HORZ, &iMinScroll, &iMaxScroll);
  1541.   iCurrPos = GetScrollPos (hwndMain, SB_HORZ);
  1542.  
  1543.   switch (nScrollCode)
  1544.   {
  1545.     case SB_BOTTOM:
  1546.       
  1547.       iHScroll = iMaxScroll - iCurrPos;
  1548.       break;
  1549.  
  1550.     case SB_PAGEDOWN:
  1551.  
  1552.       if (iCurrPos + iClientWidth <= iMaxScroll)
  1553.         iHScroll = -iClientWidth;
  1554.       else
  1555.         iHScroll = - (iMaxScroll - iCurrPos);
  1556.  
  1557.       break;
  1558.  
  1559.     case SB_PAGEUP:
  1560.  
  1561.       if (iCurrPos - iClientWidth >= 0)
  1562.         iHScroll = iClientWidth;
  1563.       else
  1564.         iHScroll = iCurrPos;
  1565.  
  1566.       break;
  1567.  
  1568.     case SB_THUMBTRACK:
  1569.     case SB_THUMBPOSITION:
  1570.       iHScroll = GetScrollPos (hwndMain, SB_HORZ) - iNewPos;
  1571.       break;
  1572.   
  1573.     case SB_LINEDOWN:
  1574.  
  1575.       iHScroll = -1;
  1576.       break;
  1577.  
  1578.     case SB_LINEUP:
  1579.  
  1580.       iHScroll = 1;
  1581.       break;
  1582.  
  1583.     case SB_ENDSCROLL:
  1584.  
  1585.       return;
  1586.   }
  1587.   if (iCurrPos - iHScroll > iMaxScroll)
  1588.     iHScroll = iCurrPos - iMaxScroll;
  1589.  
  1590.   if (iCurrPos - iHScroll < iMinScroll)
  1591.     iHScroll = iCurrPos - iMinScroll;
  1592.  
  1593.   if (!iHScroll)
  1594.     return;
  1595.  
  1596.   ScrollWindow (hwndMain, iHScroll, iVScroll, NULL, &rect);
  1597.   SetScrollPos (hwndMain, SB_HORZ, iCurrPos - iHScroll, TRUE);
  1598. }
  1599.  
  1600. /*************************************************************************
  1601.   Function:  HandleWindowSizing ()
  1602.    Purpose:  Process the WM_SIZE messages.
  1603.    Returns:  none
  1604. *************************************************************************/
  1605.  
  1606. static void HandleWindowSizing (LPVOID pDIB, WPARAM wParam, LPARAM lParam)
  1607. {
  1608. LPBITMAPINFOHEADER pBmi = (LPBITMAPINFOHEADER)pDIB;
  1609. BOOL              bHScroll, bVScroll;
  1610. DWORD             dwStyle;
  1611. int               iNewWidth, iNewHeight;
  1612. int               iHScrollRange, iVScrollRange;
  1613. int               iPos;
  1614. static BOOL       bSizing;
  1615.  
  1616.   /*
  1617.    * Prevent resizing from infinitely recursing.  This may be caused by having
  1618.    * to add or take away a scrollbar which in turn causes another WM_SIZE
  1619.    * message to be generated as the client area is affected by the scrollbars.
  1620.    */
  1621.   if (bSizing)
  1622.     return;
  1623.   if (!pBmi)
  1624.     return;
  1625.   if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE || wParam == SIZE_MAXSHOW)
  1626.     return;
  1627.  
  1628.   bSizing = TRUE;
  1629.   bHScroll = bVScroll = FALSE;
  1630.   iHScrollRange = iVScrollRange = 0;
  1631.   dwStyle = GetWindowLong (hwndMain, GWL_STYLE);
  1632.   iNewWidth = (int) LOWORD (lParam);
  1633.   iNewHeight = (int) HIWORD (lParam);
  1634.  
  1635.   if (dwStyle & WS_HSCROLL)
  1636.     iNewHeight += GetSystemMetrics (SM_CYHSCROLL);
  1637.  
  1638.   if (dwStyle & WS_VSCROLL)
  1639.     iNewWidth += GetSystemMetrics (SM_CXVSCROLL);
  1640.  
  1641.   /*
  1642.    * The following code determines if the scrollbars are required.
  1643.    * Adding a scrollbar "steals" pixels from client area, so the affected
  1644.    * dimension must be rechecked for a need of scrollbar.
  1645.    */
  1646.   if (pBmi->biWidth > iNewWidth)
  1647.   {
  1648.     bHScroll = TRUE;
  1649.     iHScrollRange = (int)pBmi->biWidth - iNewWidth;
  1650.     iNewHeight -= GetSystemMetrics (SM_CYHSCROLL);
  1651.   }
  1652.  
  1653.   if (pBmi->biHeight > iNewHeight)
  1654.   {
  1655.     bVScroll = TRUE;
  1656.     iVScrollRange = (int)pBmi->biHeight - iNewHeight;
  1657.     iNewWidth -= GetSystemMetrics (SM_CXVSCROLL);
  1658.  
  1659.     /*
  1660.      * Recheck the width to see if a horizontal scrollbar may be ncecessary.
  1661.      */
  1662.     if (pBmi->biWidth > iNewWidth && !bHScroll)
  1663.     {
  1664.       bHScroll = TRUE;
  1665.       iHScrollRange = (int)pBmi->biWidth - iNewWidth;
  1666.       iNewHeight -= GetSystemMetrics (SM_CYHSCROLL);
  1667.       iVScrollRange += GetSystemMetrics (SM_CYHSCROLL);
  1668.     }
  1669.   }
  1670.  
  1671.   if (!bHScroll && (dwStyle & WS_HSCROLL))
  1672.   {
  1673.     /*
  1674.      * Remove the scrollbar
  1675.      */
  1676.     SetScrollPos (hwndMain, SB_HORZ, 0, TRUE);
  1677.     ShowScrollBar (hwndMain, SB_HORZ, FALSE);
  1678.   }
  1679.   if (!bVScroll && (dwStyle & WS_VSCROLL))
  1680.   {
  1681.     /*
  1682.      * Remove the scrollbar
  1683.      */
  1684.     SetScrollPos (hwndMain, SB_VERT, 0, TRUE);
  1685.     ShowScrollBar (hwndMain, SB_VERT, FALSE);
  1686.   }
  1687.   /*
  1688.    * Update the scrollbar positions and ranges
  1689.    */
  1690.   if (bHScroll)
  1691.   {
  1692.     ShowScrollBar (hwndMain, SB_HORZ, TRUE);
  1693.     iPos = GetScrollPos (hwndMain, SB_HORZ);
  1694.  
  1695.     if (iPos > iHScrollRange)
  1696.     {
  1697.       InvalidateRect (hwndMain, NULL, FALSE);
  1698.       SetScrollPos (hwndMain, SB_HORZ, iHScrollRange, TRUE);
  1699.     }
  1700.     SetScrollRange (hwndMain, SB_HORZ, 0, iHScrollRange, TRUE);
  1701.   }
  1702.   if (bVScroll)
  1703.   {
  1704.     ShowScrollBar (hwndMain, SB_VERT, TRUE);
  1705.     iPos = GetScrollPos (hwndMain, SB_VERT);
  1706.  
  1707.     if (iPos > iVScrollRange)
  1708.     {
  1709.       InvalidateRect (hwndMain, NULL, FALSE);
  1710.       SetScrollPos (hwndMain, SB_VERT, iVScrollRange, TRUE);
  1711.     }
  1712.     SetScrollRange (hwndMain, SB_VERT, 0, iVScrollRange, TRUE);
  1713.   }
  1714.   bSizing = FALSE;
  1715. }
  1716.  
  1717. /*************************************************************************
  1718.   Function:  HandlePrinting ()
  1719.    Purpose:  Process the File/Print request.
  1720.    Returns:  none
  1721. *************************************************************************/
  1722.  
  1723. static void HandlePrinting (LPVOID lpDIB)
  1724. {
  1725. HDC               hDC;
  1726. LPDEVNAMES        pDevNames;
  1727. LPDEVMODE         pDevMode;
  1728. LPVOID            lpDIBPrint = NULL;
  1729. LPBITMAPINFOHEADER pBih;
  1730. LPBITMAPINFO      pBmi;
  1731. char              szTitle[128];
  1732. DOCINFO           DocInfo;
  1733. int               iXMargin, iYMargin, iWidth, iHeight;
  1734.  
  1735.   if (!pPrintDlgStruct)
  1736.   {
  1737.     InitializePrintStruct ();
  1738.  
  1739.     if (!pPrintDlgStruct)
  1740.       return;
  1741.   }
  1742.   if (!DialogBoxParam (hInst, "IDD_PRINT", hwndMain, PrintProc, (LPARAM)lpDIB))
  1743.     return;
  1744.  
  1745.   SetCursor (LoadCursor (NULL, IDC_WAIT));
  1746.   pDevNames = (LPDEVNAMES)GlobalLock (pPrintDlgStruct->hDevNames);
  1747.   pDevMode = (LPDEVMODE)GlobalLock (pPrintDlgStruct->hDevMode);
  1748.   pDevMode->dmCopies = uPrintCopies;
  1749.   hDC = CreateDC ((LPCSTR)pDevNames + pDevNames->wDriverOffset, (LPCSTR)pDevNames + pDevNames->wDeviceOffset,
  1750.                   (LPCSTR)pDevNames + pDevNames->wOutputOffset, pDevMode);
  1751.  
  1752.   if (bHalftoneImgLib)
  1753.   {
  1754.     lpDIBPrint = HalftoneDIB (lpDIB);
  1755.     pBih = (LPBITMAPINFOHEADER) lpDIBPrint;
  1756.   }
  1757.   else
  1758.   {
  1759.     pBih = (LPBITMAPINFOHEADER) lpDIB;
  1760.   }
  1761.   iXMargin = GetDeviceCaps (hDC, HORZRES) / 20;
  1762.   iYMargin = GetDeviceCaps (hDC, VERTRES) / 20;
  1763.  
  1764.   if (bFillPage)
  1765.   {
  1766.     iWidth = GetDeviceCaps (hDC, HORZRES) - iXMargin * 2;
  1767.     iHeight = GetDeviceCaps (hDC, VERTRES) - iYMargin * 2;
  1768.  
  1769.     if (iWidth / pBih->biWidth > iHeight / pBih->biHeight)
  1770.       iWidth = (int)pBih->biWidth * iHeight / (int)pBih->biHeight;
  1771.     else
  1772.       iHeight = (int)pBih->biHeight * iWidth / (int)pBih->biWidth;
  1773.   }
  1774.   else
  1775.   {
  1776.     iWidth = (int)pBih->biWidth;
  1777.     iHeight = (int)pBih->biHeight;
  1778.  
  1779.     /*
  1780.      * ImgLib halftonning increases the image size 4 times.  To make the
  1781.      * output look the same size, size the output the same for GDI.
  1782.      */
  1783.     if (!bHalftoneImgLib)
  1784.     {
  1785.       iWidth *= 4;
  1786.       iHeight *= 4;
  1787.     }
  1788.   }
  1789.   pBmi = (LPBITMAPINFO)pBih;
  1790.   GetWindowText (hwndMain, szTitle, sizeof (szTitle));
  1791.   DocInfo.cbSize = sizeof (DocInfo);
  1792.   DocInfo.lpszDocName = szTitle;
  1793.   DocInfo.lpszOutput = NULL;
  1794.   StartDoc (hDC, &DocInfo);
  1795.   StartPage (hDC);
  1796.   StretchDIBits (hDC, iXMargin, iYMargin, iWidth, iHeight, 0, 0, (int)pBih->biWidth,
  1797.                                  (int)pBih->biHeight, (HPSTR)&pBmi->bmiColors[pBih->biClrUsed], pBmi,
  1798.                                  DIB_RGB_COLORS, SRCCOPY);
  1799.   EndPage (hDC);
  1800.   EndDoc (hDC);
  1801.   DeleteDC (hDC);
  1802.  
  1803.   if (lpDIBPrint)
  1804.     DIBFree (lpDIBPrint);
  1805.  
  1806.   GlobalUnlock (pPrintDlgStruct->hDevNames);
  1807.   GlobalUnlock (pPrintDlgStruct->hDevMode);
  1808.   SetCursor (LoadCursor (NULL, IDC_ARROW));
  1809. }
  1810.  
  1811. /*************************************************************************
  1812.   Function:  InitializePrintStruct ()
  1813.    Purpose:  Initialize the printing structure with default printer information.
  1814.    Returns:  none
  1815. *************************************************************************/
  1816.  
  1817. static void InitializePrintStruct (void)
  1818. {
  1819.   if (pPrintDlgStruct)
  1820.     freemem (pPrintDlgStruct);
  1821.  
  1822.   pPrintDlgStruct = (LPPRINTDLG)allocmem (sizeof (PRINTDLG));
  1823.  
  1824.   if (pPrintDlgStruct)
  1825.   {
  1826. #ifdef WIN32
  1827.     memset (pPrintDlgStruct, 0, sizeof (PRINTDLG));
  1828. #else
  1829.     _fmemset (pPrintDlgStruct, 0, sizeof (PRINTDLG));
  1830. #endif
  1831.     pPrintDlgStruct->lStructSize = sizeof (PRINTDLG);
  1832.     pPrintDlgStruct->hwndOwner = hwndMain;
  1833.     pPrintDlgStruct->Flags = PD_PRINTSETUP | PD_RETURNDEFAULT;
  1834.  
  1835.     if (PrintDlg (pPrintDlgStruct) == FALSE)
  1836.     {
  1837.       freemem (pPrintDlgStruct);
  1838.       pPrintDlgStruct = NULL;
  1839.       MessageBox (hwndMain, "Error getting the default printer information", WINDOW_NAME, MB_OK | MB_ICONSTOP);
  1840.       return;
  1841.     }
  1842.   }
  1843. }
  1844.  
  1845. /*************************************************************************
  1846.   Function:  HandleMenuPopup ()
  1847.    Purpose:  Prepare a menu for display based on the current application state
  1848.    Returns:  none
  1849. *************************************************************************/
  1850.  
  1851. static void HandleMenuPopup (WPARAM wParam, LPARAM lParam)
  1852. {
  1853. HMENU             hMenuParent, hMenuPopup;
  1854. UINT              uIndex;
  1855. BOOL              bSystemMenu;
  1856. HDC               hDC;
  1857. LPBITMAPINFOHEADER pBmi;
  1858.  
  1859.   bSystemMenu = HIWORD (lParam);
  1860.  
  1861.   if (bSystemMenu)
  1862.     return;
  1863.  
  1864.   hMenuParent = GetMenu (hwndMain);
  1865.   hMenuPopup = (HMENU)wParam;
  1866.   uIndex = LOWORD (lParam);
  1867.  
  1868.   if (hMenuPopup == GetSubMenu (hMenuParent, 0))
  1869.   {
  1870.     if (lpDIBDisplay)
  1871.     {
  1872.       EnableMenuItem (hMenuPopup, ID_FILE_SAVE, MF_BYCOMMAND | MF_ENABLED);
  1873.       EnableMenuItem (hMenuPopup, ID_FILE_PRINT, MF_BYCOMMAND | MF_ENABLED);
  1874.     }
  1875.     else
  1876.     {
  1877.       EnableMenuItem (hMenuPopup, ID_FILE_SAVE, MF_BYCOMMAND | MF_GRAYED);
  1878.       EnableMenuItem (hMenuPopup, ID_FILE_PRINT, MF_BYCOMMAND | MF_GRAYED);
  1879.     }
  1880.   }
  1881.   else if (hMenuPopup == GetSubMenu (hMenuParent, 1))
  1882.   {
  1883.     if (lpDIB1 && lpDIB2)
  1884.       EnableMenuItem (hMenuPopup, ID_EDIT_UNDO, MF_BYCOMMAND | MF_ENABLED);
  1885.     else
  1886.       EnableMenuItem (hMenuPopup, ID_EDIT_UNDO, MF_BYCOMMAND | MF_GRAYED);
  1887.  
  1888.     if (lpDIB1)
  1889.       EnableMenuItem (hMenuPopup, ID_EDIT_COPY, MF_BYCOMMAND | MF_ENABLED);
  1890.     else
  1891.       EnableMenuItem (hMenuPopup, ID_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
  1892.  
  1893.     if (IsClipboardFormatAvailable (CF_BITMAP) || IsClipboardFormatAvailable (CF_DIB))
  1894.       EnableMenuItem (hMenuPopup, ID_EDIT_PASTE, MF_BYCOMMAND | MF_ENABLED);
  1895.     else
  1896.       EnableMenuItem (hMenuPopup, ID_EDIT_PASTE, MF_BYCOMMAND | MF_GRAYED);
  1897.  
  1898.     if (bDrawSelection)
  1899.       EnableMenuItem (hMenuPopup, ID_EDIT_ZOOM, MF_BYCOMMAND | MF_ENABLED);
  1900.     else
  1901.       EnableMenuItem (hMenuPopup, ID_EDIT_ZOOM, MF_BYCOMMAND | MF_GRAYED);
  1902.   }
  1903.   else if (hMenuPopup == GetSubMenu (hMenuParent, 2))
  1904.   {
  1905.     if (lpDIB1)
  1906.     {
  1907.       pBmi = (LPBITMAPINFOHEADER) lpDIBDisplay;
  1908.       
  1909.       /*
  1910.        * Disallow controlling brightness of monochrome bitmaps
  1911.        */
  1912.       if (pBmi->biPlanes * pBmi->biBitCount > 1)
  1913.         EnableMenuItem (hMenuPopup, ID_PROCESS_BRIGHTNESS, MF_BYCOMMAND | MF_ENABLED);
  1914.       else
  1915.         EnableMenuItem (hMenuPopup, ID_PROCESS_BRIGHTNESS, MF_BYCOMMAND | MF_GRAYED);
  1916.  
  1917.       EnableMenuItem (hMenuPopup, ID_PROCESS_SMOOTH, MF_BYCOMMAND | MF_ENABLED);
  1918.       EnableMenuItem (hMenuPopup, ID_PROCESS_HALFTONE, MF_BYCOMMAND | MF_ENABLED);
  1919.       EnableMenuItem (hMenuPopup, ID_PROCESS_GRAY, MF_BYCOMMAND | MF_ENABLED);
  1920.  
  1921.       if (pBmi->biPlanes * pBmi->biBitCount <= 8)
  1922.         EnableMenuItem (hMenuPopup, ID_PROCESS_EXPAND, MF_BYCOMMAND | MF_ENABLED);
  1923.       else
  1924.         EnableMenuItem (hMenuPopup, ID_PROCESS_EXPAND, MF_BYCOMMAND | MF_GRAYED);
  1925.  
  1926.       EnableMenuItem (hMenuPopup, MENU_POSITION_ROTATE, MF_BYPOSITION | MF_ENABLED);
  1927.       EnableMenuItem (hMenuPopup, MENU_POSITION_MIRROR, MF_BYPOSITION | MF_ENABLED);
  1928.     }
  1929.     else
  1930.     {
  1931.       EnableMenuItem (hMenuPopup, ID_PROCESS_BRIGHTNESS, MF_BYCOMMAND | MF_GRAYED);
  1932.       EnableMenuItem (hMenuPopup, ID_PROCESS_SMOOTH, MF_BYCOMMAND | MF_GRAYED);
  1933.       EnableMenuItem (hMenuPopup, ID_PROCESS_HALFTONE, MF_BYCOMMAND | MF_GRAYED);
  1934.       EnableMenuItem (hMenuPopup, ID_PROCESS_GRAY, MF_BYCOMMAND | MF_GRAYED);
  1935.       EnableMenuItem (hMenuPopup, ID_PROCESS_EXPAND, MF_BYCOMMAND | MF_GRAYED);
  1936.       EnableMenuItem (hMenuPopup, MENU_POSITION_ROTATE, MF_BYPOSITION | MF_GRAYED);
  1937.       EnableMenuItem (hMenuPopup, MENU_POSITION_MIRROR, MF_BYPOSITION | MF_GRAYED);
  1938.     }
  1939.   }
  1940.   else if (hMenuPopup == GetSubMenu (hMenuParent, 3))
  1941.   {
  1942.     hDC = GetDC (NULL);
  1943.  
  1944.     if (GetDeviceCaps (hDC, BITSPIXEL) > 8)
  1945.       EnableMenuItem (hMenuPopup, MENU_POSITION_TC_OPT, MF_BYPOSITION | MF_GRAYED);
  1946.     else
  1947.       EnableMenuItem (hMenuPopup, MENU_POSITION_TC_OPT, MF_BYPOSITION | MF_ENABLED);
  1948.  
  1949.     ReleaseDC (NULL, hDC);
  1950.   }
  1951. }
  1952.  
  1953. /*************************************************************************
  1954.   Function:  HandleLButtonDown ()
  1955.    Purpose:  Process the WM_LBUTTONDOWN message
  1956.    Returns:  none
  1957. *************************************************************************/
  1958. static void HandleLButtonDown (WPARAM wParam, LPARAM lParam)
  1959. {
  1960.   SetCapture (hwndMain);
  1961.  
  1962.   if (!bPasting)
  1963.   {
  1964.     if (bDrawSelection)
  1965.       EraseSelectionBox ();
  1966.     else
  1967.       bDrawSelection = TRUE;
  1968.  
  1969.     ptAnchor.x = rcSelection.left = rcSelection.right = LOWORD (lParam);
  1970.     ptAnchor.y = rcSelection.top = rcSelection.bottom = HIWORD (lParam);
  1971.     DrawSelectionBox ();
  1972.   }
  1973. }
  1974.  
  1975. /*************************************************************************
  1976.   Function:  HandleLButtonUp ()
  1977.    Purpose:  Process the WM_LBUTTONUP message
  1978.    Returns:  none
  1979. *************************************************************************/
  1980. static void HandleLButtonUp (WPARAM wParam, LPARAM lParam)
  1981. {
  1982. HANDLE            hDIB;
  1983. LPBITMAPINFOHEADER pBih;
  1984. HBITMAP           hBitmap;
  1985. HPALETTE          hPalTemp;
  1986. LPVOID            lpDIBNew, lpDIBTemp;
  1987.  
  1988.   if (bPasting)
  1989.   {
  1990.     if (OpenClipboard (hwndMain))
  1991.     {
  1992.       SetCursor (LoadCursor (NULL, IDC_WAIT));
  1993.  
  1994.       if (IsClipboardFormatAvailable (CF_DIB))
  1995.       {
  1996.         hDIB = GetClipboardData (CF_DIB);
  1997.         pBih = (LPBITMAPINFOHEADER)GlobalLock (hDIB);
  1998.         lpDIBNew = MergeDIB (lpDIB1, pBih, rcSelection.left, rcSelection.top);
  1999.         GlobalUnlock (hDIB);
  2000.       }
  2001.       else if (IsClipboardFormatAvailable (CF_BITMAP))
  2002.       {
  2003.         hBitmap = GetClipboardData (CF_BITMAP);
  2004.         hPalTemp = GetClipboardData (CF_PALETTE);
  2005.         lpDIBTemp = DDBToDIB (hBitmap, hPalTemp);
  2006.  
  2007.         if (lpDIBTemp)
  2008.         {
  2009.           lpDIBNew = MergeDIB (lpDIB1, lpDIBTemp, rcSelection.left, rcSelection.top);
  2010.           DIBFree (lpDIBTemp);
  2011.         }
  2012.       }
  2013.       else
  2014.       {
  2015.         CloseClipboard ();
  2016.         return;
  2017.       }
  2018.       CloseClipboard ();
  2019.       EraseSelectionBox ();
  2020.       bDrawSelection = FALSE;
  2021.       ProcessNewDIB (lpDIBNew);
  2022.       SetCursor (LoadCursor (NULL, IDC_ARROW));
  2023.     }
  2024.     bPasting = FALSE;
  2025.   }
  2026.   else
  2027.   {
  2028.     if (rcSelection.right - rcSelection.left < 5 || rcSelection.bottom - rcSelection.top < 5)
  2029.     {
  2030.       EraseSelectionBox ();
  2031.       bDrawSelection = FALSE;
  2032.     }
  2033.   }
  2034.   ReleaseCapture ();
  2035. }
  2036.  
  2037. /*************************************************************************
  2038.   Function:  HandleRButtonDown ()
  2039.    Purpose:  Process the WM_RBUTTONDOWN message
  2040.    Returns:  none
  2041. *************************************************************************/
  2042. static void HandleRButtonDown (WPARAM wParam, LPARAM lParam)
  2043. {
  2044.   if (GetCapture () == hwndMain)
  2045.   {
  2046.     EraseSelectionBox ();
  2047.     bDrawSelection = FALSE;
  2048.     bPasting = FALSE;
  2049.     ReleaseCapture ();
  2050.   }
  2051. }
  2052.  
  2053. /*************************************************************************
  2054.   Function:  HandleMouseMove ()
  2055.    Purpose:  Process the WM_MOUSEMOVE message
  2056.    Returns:  none
  2057. *************************************************************************/
  2058. static void HandleMouseMove (WPARAM wParam, LPARAM lParam)
  2059. {
  2060. LONG              lX, lY, ldx, ldy;
  2061.  
  2062.   if (GetCapture () == hwndMain)
  2063.   {
  2064.     EraseSelectionBox ();
  2065.     lX = LOWORD (lParam);
  2066.     lY = HIWORD (lParam);
  2067.  
  2068.     if (lX < 0)
  2069.       lX = 0;
  2070.  
  2071.     if (lY < 0)
  2072.       lY = 0;
  2073.     
  2074.     if (bPasting)
  2075.     {
  2076.       ldx = lX - rcSelection.left;
  2077.       ldy = lY - rcSelection.top;
  2078.       OffsetRect (&rcSelection, (int)ldx, (int)ldy);
  2079.     }
  2080.     else
  2081.     {
  2082.       if (lX > ptAnchor.x)
  2083.       {
  2084.         rcSelection.right = (int)lX;
  2085.         rcSelection.left = ptAnchor.x;
  2086.       }
  2087.       else
  2088.       {
  2089.         rcSelection.left = (int)lX;
  2090.         rcSelection.right = ptAnchor.x;
  2091.       }
  2092.  
  2093.       if (lY > ptAnchor.y)
  2094.       {
  2095.         rcSelection.bottom = (int)lY;
  2096.         rcSelection.top = ptAnchor.y;
  2097.       }
  2098.       else
  2099.       {
  2100.         rcSelection.top = (int)lY;
  2101.         rcSelection.bottom = ptAnchor.y;
  2102.       }
  2103.     }
  2104.     DrawSelectionBox ();
  2105.   }
  2106. }
  2107.  
  2108. /*************************************************************************
  2109.   Function:  HandleCharacter ()
  2110.    Purpose:  Process the WM_CHAR message
  2111.    Returns:  none
  2112. *************************************************************************/
  2113. static void HandleCharacter (WPARAM wParam, LPARAM lParam)
  2114. {
  2115.   if (GetCapture () == hwndMain && wParam == VK_ESCAPE)
  2116.   {
  2117.     EraseSelectionBox ();
  2118.     bDrawSelection = FALSE;
  2119.     bPasting = FALSE;
  2120.     ReleaseCapture ();
  2121.   }
  2122. }
  2123.  
  2124. /*************************************************************************
  2125.   Function:  HandlePasting ()
  2126.    Purpose:  Process the clipdoard paste
  2127.    Returns:  none
  2128. *************************************************************************/
  2129. static void HandlePasting (WPARAM wParam, LPARAM lParam)
  2130. {
  2131. HANDLE            hDIB;
  2132. LPBITMAPINFOHEADER pBih;
  2133. long              lWidth, lHeight;
  2134. HBITMAP           hBitmap;
  2135. BITMAP            bm;
  2136. POINT             ptCursor;
  2137. LPVOID            lpDIBNew;
  2138. HPALETTE          hPalTemp;
  2139.  
  2140.   if (OpenClipboard (hwndMain))
  2141.   {
  2142.     if (lpDIB1)
  2143.     {
  2144.       if (IsClipboardFormatAvailable (CF_DIB))
  2145.       {
  2146.         hDIB = GetClipboardData (CF_DIB);
  2147.         pBih = (LPBITMAPINFOHEADER)GlobalLock (hDIB);
  2148.         lWidth = pBih->biWidth;
  2149.         lHeight = pBih->biHeight;
  2150.         GlobalUnlock (hDIB);
  2151.       }
  2152.       else if (IsClipboardFormatAvailable (CF_BITMAP))
  2153.       {
  2154.         hBitmap = GetClipboardData (CF_BITMAP);
  2155.         GetObject (hBitmap, sizeof (bm), &bm);
  2156.         lWidth = bm.bmWidth;
  2157.         lHeight = bm.bmHeight;
  2158.       }
  2159.       else
  2160.       {
  2161.         CloseClipboard ();
  2162.         return;
  2163.       }
  2164.       GetCursorPos (&ptCursor);
  2165.       ScreenToClient (hwndMain, &ptCursor);
  2166.       rcSelection.left = ptCursor.x;
  2167.       rcSelection.top = ptCursor.y;
  2168.       rcSelection.right = ptCursor.x + (int)lWidth;
  2169.       rcSelection.bottom = ptCursor.y + (int)lHeight;
  2170.       bDrawSelection = TRUE;
  2171.       bPasting = TRUE;
  2172.       DrawSelectionBox ();
  2173.       SetCapture (hwndMain);
  2174.     }
  2175.     else
  2176.     {
  2177.       if (IsClipboardFormatAvailable (CF_DIB))
  2178.       {
  2179.         hDIB = GetClipboardData (CF_DIB);
  2180.         pBih = (LPBITMAPINFOHEADER)GlobalLock (hDIB);
  2181.         lpDIBNew = CopyDIB (pBih);
  2182.         GlobalUnlock (hDIB);
  2183.       }
  2184.       else if (IsClipboardFormatAvailable (CF_BITMAP))
  2185.       {
  2186.         hBitmap = GetClipboardData (CF_BITMAP);
  2187.         hPalTemp = GetClipboardData (CF_PALETTE);
  2188.         lpDIBNew = DDBToDIB (hBitmap, hPalTemp);
  2189.       }
  2190.       else
  2191.       {
  2192.         CloseClipboard ();
  2193.         return;
  2194.       }
  2195.       ProcessNewDIB (lpDIBNew);
  2196.     }
  2197.     CloseClipboard ();
  2198.   }
  2199. }
  2200.  
  2201. /*************************************************************************
  2202.   Function:  HandleCopying ()
  2203.    Purpose:  Process the clipdoard copy
  2204.    Returns:  none
  2205. *************************************************************************/
  2206. static void HandleCopying (WPARAM wParam, LPARAM lParam)
  2207. {
  2208. LPVOID            lpDIBTemp, lpDIB;
  2209. DWORD             dwSize;
  2210. HANDLE            hDIB;
  2211.  
  2212.   if (lpDIB1)
  2213.   {
  2214.     if (OpenClipboard (hwndMain))
  2215.     {
  2216.       if (bDrawSelection)
  2217.       {
  2218.         EraseSelectionBox ();
  2219.         bDrawSelection = FALSE;
  2220.         lpDIBTemp = ClipDIB (lpDIB1, rcSelection.left, rcSelection.top, rcSelection.right - rcSelection.left + 1, rcSelection.bottom - rcSelection.top + 1);
  2221.       }
  2222.       else
  2223.         lpDIBTemp = lpDIB1;
  2224.  
  2225.       if (lpDIBTemp)
  2226.       {
  2227.         dwSize = GetDIBSize (lpDIBTemp);
  2228.         hDIB = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, dwSize);
  2229.         lpDIB = GlobalLock (hDIB);
  2230.  
  2231.         if (lpDIB)
  2232.         {
  2233.           copymem (lpDIB, lpDIBTemp, dwSize);
  2234.           GlobalUnlock (hDIB);
  2235.           EmptyClipboard ();
  2236.           SetClipboardData (CF_DIB, hDIB);
  2237.         }
  2238.         
  2239.         if (bDrawSelection)
  2240.           DIBFree (lpDIBTemp);
  2241.       }
  2242.       CloseClipboard ();
  2243.     }
  2244.   }
  2245. }
  2246.  
  2247. /*************************************************************************
  2248.   Function:  HandleZoomin ()
  2249.    Purpose:  Process the zoomin procedure
  2250.    Returns:  none
  2251. *************************************************************************/
  2252. static void HandleZoomin (WPARAM wParam, LPARAM lParam)
  2253. {
  2254. LPVOID            lpDIBTemp, lpDIBNew;
  2255.  
  2256.   if (lpDIB1 && bDrawSelection)
  2257.   {
  2258.     SetCursor (LoadCursor (NULL, IDC_WAIT));
  2259.     EraseSelectionBox ();
  2260.     bDrawSelection = FALSE;
  2261.     lpDIBTemp = ClipDIB (lpDIB1, rcSelection.left, rcSelection.top, rcSelection.right - rcSelection.left + 1, rcSelection.bottom - rcSelection.top + 1);
  2262.  
  2263.     if (lpDIBTemp)
  2264.     {
  2265.       lpDIBNew = ZoomDIB (lpDIBTemp, 500, 500);
  2266.       DIBFree (lpDIBTemp);
  2267.       
  2268.       if (lpDIBNew)
  2269.         ProcessNewDIB (lpDIBNew);
  2270.     }
  2271.     SetCursor (LoadCursor (NULL, IDC_ARROW));
  2272.   }
  2273. }
  2274.  
  2275. /*************************************************************************
  2276.   Function:  DrawSelectionBox ()
  2277.    Purpose:  Draw the selection
  2278.    Returns:  none
  2279. *************************************************************************/
  2280. static void DrawSelectionBox (void)
  2281. {
  2282. HDC               hDC;
  2283.   
  2284.   UpdateWindow (hwndMain);
  2285.   hDC = GetDC (hwndMain);
  2286.  
  2287.   if (hDC)
  2288.   {
  2289.     SetROP2 (hDC, R2_XORPEN);
  2290.     SelectObject (hDC, GetStockObject (WHITE_PEN));
  2291.     SelectObject (hDC, GetStockObject (HOLLOW_BRUSH));
  2292.     Rectangle (hDC, rcSelection.left, rcSelection.top, rcSelection.right, rcSelection.bottom);
  2293.     ReleaseDC (hwndMain, hDC);
  2294.   }
  2295. }
  2296.  
  2297. /*************************************************************************
  2298.   Function:  EraseSelectionBox ()
  2299.    Purpose:  Erase the selection
  2300.    Returns:  none
  2301. *************************************************************************/
  2302. static void EraseSelectionBox (void)
  2303. {
  2304.   if (bDrawSelection)
  2305.     DrawSelectionBox ();
  2306. }
  2307.  
  2308. /*************************************************************************
  2309.   Function:  ProcessNewDIB ()
  2310.    Purpose:  Set up to display a newly loaded/created DIB
  2311.    Returns:  none
  2312. *************************************************************************/
  2313. static void       ProcessNewDIB (LPVOID lpDIBNew)
  2314. {
  2315.   if (lpDIBNew && lpDIBNew != lpDIB1)
  2316.   {
  2317.     if (lpDIBDisplay && lpDIBDisplay != lpDIB1)
  2318.       DIBFree (lpDIBDisplay);
  2319.  
  2320.     if (lpDIB2)
  2321.       DIBFree (lpDIB2);
  2322.  
  2323.     lpDIB2 = lpDIB1;
  2324.     lpDIB1 = lpDIBNew;
  2325.  
  2326.     if (hPalette)
  2327.     {
  2328.       DeleteObject (hPalette);
  2329.       hPalette = NULL;
  2330.     }
  2331.     lpDIBDisplay = CreateDisplayDIB (hwndMain, &lpDIB1, &hPalette);
  2332.  
  2333.     if (lpDIBDisplay)
  2334.       ResizeWindowToDIB (hwndMain, lpDIBDisplay);
  2335.   }
  2336. }
  2337.  
  2338. /*************************************************************************
  2339.   Function:  HandlePaintingAndUpdates ()
  2340.    Purpose:  Process image painting and palette management
  2341.    Returns:  none
  2342. *************************************************************************/
  2343. static LRESULT HandlePaintingAndUpdates (UINT message, WPARAM wParam, LPARAM lParam)
  2344. {
  2345. RECT              rcClient;
  2346. HPALETTE          hPalOld;
  2347. HDC               hDC;
  2348. int               iCount, iXPos, iYPos, iYStart;
  2349. PAINTSTRUCT       PaintStruct;
  2350. HPSTR             hpBits;
  2351. LPBITMAPINFO      pBitmapInfo;
  2352.  
  2353.   switch (message)
  2354.   {
  2355.     case WM_QUERYNEWPALETTE:
  2356.  
  2357.     /*
  2358.      * If palette realization causes a palette change,
  2359.      * we need to do a full redraw.
  2360.      */
  2361.     if (hPalette && wParam != (UINT)hwndMain)
  2362.     {
  2363.       hDC = GetDC (hwndMain);
  2364.       hPalOld = SelectPalette (hDC, hPalette, FALSE);
  2365.       iCount = RealizePalette (hDC);
  2366.       InvalidateRect (hwndMain, (LPRECT) (NULL), FALSE);
  2367.       UpdateWindow (hwndMain);
  2368.       SelectPalette (hDC, hPalOld, 0);
  2369.       ReleaseDC (hwndMain, hDC);
  2370.       return TRUE;
  2371.     }
  2372.     break;
  2373.  
  2374.     case WM_PALETTECHANGED:
  2375.  
  2376.       if (hPalette && wParam != (UINT)hwndMain)
  2377.         InvalidateRect (hwndMain, (LPRECT) (NULL), FALSE);
  2378.  
  2379.       break;
  2380.  
  2381.     case WM_PAINT:
  2382.       
  2383.       hDC = BeginPaint (hwndMain, &PaintStruct);
  2384.  
  2385.       if (lpDIBDisplay)
  2386.       {
  2387.         if (hPalette)
  2388.         {
  2389.           hPalOld = SelectPalette (hDC, hPalette, FALSE);
  2390.           RealizePalette (hDC);
  2391.         }
  2392.  
  2393.         GetClientRect (hwndMain, &rcClient);
  2394.         iXPos = GetScrollPos (hwndMain, SB_HORZ);
  2395.         iYPos = GetScrollPos (hwndMain, SB_VERT);
  2396.         pBitmapInfo = (LPBITMAPINFO) lpDIBDisplay;
  2397. #ifdef USE_WING
  2398.         if (hWinGInst && hbmpWinG)
  2399.         {
  2400.           fpWinGStretchBlt (hDC, 0, 0, rcClient.right, rcClient.bottom, hdcWinG, iXPos, iYPos,
  2401.                             rcClient.right, rcClient.bottom);
  2402.         }
  2403.         else
  2404. #endif
  2405.         {
  2406.           iYStart = (int)pBitmapInfo->bmiHeader.biHeight - rcClient.bottom - iYPos;
  2407.           hpBits = (HPSTR)&pBitmapInfo->bmiColors[pBitmapInfo->bmiHeader.biClrUsed];
  2408.           StretchDIBits (hDC, 0, 0, rcClient.right, rcClient.bottom, iXPos, iYStart,
  2409.                          rcClient.right, rcClient.bottom, hpBits, pBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  2410.         }
  2411.         if (hPalette)
  2412.           SelectPalette (hDC, hPalOld, FALSE);
  2413.       }
  2414.  
  2415.       if (bDrawSelection)
  2416.         DrawSelectionBox ();
  2417.  
  2418.       EndPaint (hwndMain, &PaintStruct);
  2419.       break;
  2420.   }
  2421.   return (0);
  2422. }
  2423.  
  2424. #ifdef USE_WING
  2425.  
  2426. /*************************************************************************
  2427.   Function:  InitializeWinG ()
  2428.    Purpose:  Initializes WinG
  2429.    Returns:  none
  2430. *************************************************************************/
  2431. static void InitializeWinG ()
  2432. {
  2433.   fpWinGCreateDC = (WINGCREATEDC) GetProcAddress (hWinGInst, "WinGCreateDC");
  2434.   fpWinGCreateBitmap = (WINGCREATEBITMAP) GetProcAddress (hWinGInst, "WinGCreateBitmap");
  2435.   fpWinGStretchBlt = (WINGSTRETCHBLT) GetProcAddress (hWinGInst, "WinGStretchBlt");
  2436.   hdcWinG = fpWinGCreateDC ();
  2437. }
  2438.  
  2439. /*************************************************************************
  2440.   Function:  UpdateWinGBitmap ()
  2441.    Purpose:  Updates WinG bitmap used to draw DIBs
  2442.    Returns:  none
  2443. *************************************************************************/
  2444. static void UpdateWinGBitmap (LPVOID lpDIB)
  2445. {
  2446. LPBITMAPINFO      pBiDIB = (LPBITMAPINFO) lpDIB;
  2447. HPALETTE          hpalTemp, hpalOld;
  2448. HPSTR             hpBits;
  2449.  
  2450.   if (hbmpWinG)
  2451.   {
  2452.     SelectObject (hdcWinG, hbmpWinGOld);
  2453.     DeleteObject (hbmpWinG);
  2454.   }
  2455.  
  2456.   /*
  2457.    * Create a new bitmap and put it in WinG DC for quick repaints.  WinG
  2458.    * deals with 8-bit-per-pixel bitmaps only.
  2459.    */
  2460.   hbmpWinG = fpWinGCreateBitmap (hdcWinG, pBiDIB, NULL);
  2461.   
  2462.   if (hbmpWinG)
  2463.   {
  2464.     hbmpWinGOld = SelectObject (hdcWinG, hbmpWinG);
  2465.     hpalTemp = CreateDIBPalette (lpDIB);
  2466.     hpalOld = SelectPalette (hdcWinG, hpalTemp, FALSE);
  2467.     RealizePalette (hdcWinG);
  2468.     hpBits = (HPSTR)&pBiDIB->bmiColors[pBiDIB->bmiHeader.biClrUsed];
  2469.     StretchDIBits (hdcWinG, 0, 0, (int)pBiDIB->bmiHeader.biWidth, (int)pBiDIB->bmiHeader.biHeight, 0, 0,
  2470.                    (int)pBiDIB->bmiHeader.biWidth, (int)pBiDIB->bmiHeader.biHeight, hpBits, pBiDIB, DIB_RGB_COLORS, SRCCOPY);
  2471.     SelectPalette (hdcWinG, hpalOld, FALSE);
  2472.     DeleteObject (hpalTemp);
  2473.   }
  2474. }
  2475.  
  2476. #endif
  2477.