home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lzwsrc.zip / IMGVIEW.CPP next >
C/C++ Source or Header  |  1996-09-05  |  25KB  |  928 lines

  1. //***************************************************************************
  2. //
  3. //  ImgView.cpp
  4. //
  5. //  REQUIRED NOTICE: This utility contains LZW technology of the Unisys
  6. //  Corporation covered by U.S. Patent No. 4,588,302 and foreign counter-
  7. //  parts. No permission is granted by Unisys for the sale, lease, transfer,
  8. //  or distribution of any products containing LZW capability including
  9. //  products derived from this utility. Software or firmware derived from
  10. //  this PC Magazine utility containing GIF and TIFF-LZW capability may be
  11. //  used solely for the personal non-commercial and not-for-profit purposes
  12. //  of the developer and may not be distributed to others for any purpose.
  13. //  Information about LZW licensing may be obtained from:
  14. //
  15. //    Welch Licensing Department
  16. //    Unisys Corporation
  17. //    M/SC2SW1
  18. //    Township Line & Union Meeting Roads
  19. //    Blue Bell, PA 19424
  20. //
  21. //***************************************************************************
  22.  
  23. #include <windows.h>
  24. #include <commctrl.h>
  25. #include <initguid.h>
  26. #include <shlobj.h>
  27. #include <stdlib.h>
  28. #include "\Lead\Include\L_bitmap.h"
  29. #include "Password.h"
  30. #include "Resource.h"
  31. #include "ImgView.h"
  32.  
  33. /////////////////////////////////////////////////////////////////////////////
  34. // Global variables
  35.  
  36. UINT            g_cRefThisDll = 0;          // Reference count for this DLL
  37. HINSTANCE       g_hInstance = NULL;         // Instance handle for this DLL
  38. BITMAPHANDLE    g_hBitmap;                  // Bitmap handle (LEAD format)
  39. HPALETTE        g_hPalette = NULL;          // Palette handle
  40.  
  41. char g_szKey[] = "Software\\PC Magazine\\ImgView\\V1.0";
  42. char g_szMainWndClassName[] = "MainWndClass";
  43. char g_szViewWndClassName[] = "ViewWndClass";
  44. char g_szValueName[] = "StatusBarPref";
  45.  
  46. /////////////////////////////////////////////////////////////////////////////
  47. // DLL entry point
  48.  
  49. extern "C" BOOL WINAPI DllMain (HINSTANCE hInstance, ULONG ulReason,
  50.     LPVOID lpReserved)
  51. {
  52.     if (ulReason == DLL_PROCESS_ATTACH) {
  53.         g_hInstance = hInstance;
  54.         g_hBitmap.Flags.Allocated = FALSE;
  55.     }
  56.     return TRUE;
  57. }
  58.  
  59. /////////////////////////////////////////////////////////////////////////////
  60. // Exported functions
  61.  
  62. STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppv)
  63. {
  64.     *ppv = NULL; 
  65.     if (rclsid != CLSID_FileViewer)
  66.         return CLASS_E_CLASSNOTAVAILABLE;
  67.  
  68.     CClassFactory* pClassFactory = new CClassFactory;
  69.  
  70.     if (pClassFactory == NULL)
  71.         return E_OUTOFMEMORY;
  72.  
  73.     HRESULT hr = pClassFactory->QueryInterface (riid, ppv);
  74.  
  75.     if (FAILED (hr))
  76.         delete pClassFactory;
  77.  
  78.     return hr;
  79. }
  80.  
  81. STDAPI DllCanUnloadNow ()
  82. {
  83.     return (g_cRefThisDll == 0) ? S_OK : S_FALSE;
  84. }
  85.  
  86. /////////////////////////////////////////////////////////////////////////////
  87. // CClassFactory member functions
  88.  
  89. CClassFactory::CClassFactory ()
  90. {
  91.     m_cRef = 0;
  92.     g_cRefThisDll++;
  93. }
  94.  
  95. CClassFactory::~CClassFactory ()
  96. {
  97.     g_cRefThisDll--;
  98. }
  99.  
  100. HRESULT CClassFactory::QueryInterface (REFIID riid, LPVOID* ppv)
  101. {
  102.     *ppv = NULL;
  103.     HRESULT hr = E_NOINTERFACE;
  104.  
  105.     if (riid == IID_IUnknown)
  106.         *ppv = (LPUNKNOWN) this;
  107.     else if (riid == IID_IClassFactory)
  108.         *ppv = (LPCLASSFACTORY) this;
  109.  
  110.     if (*ppv != NULL) {
  111.         ((LPUNKNOWN) *ppv)->AddRef ();
  112.         hr = NOERROR;
  113.     }
  114.     return hr;
  115. }
  116.  
  117. ULONG CClassFactory::AddRef ()
  118. {
  119.     return ++m_cRef;
  120. }
  121.  
  122. ULONG CClassFactory::Release ()
  123. {
  124.     ULONG cRef = --m_cRef;
  125.     if (m_cRef == 0)
  126.         delete this;
  127.     return cRef;
  128. }
  129.  
  130. HRESULT CClassFactory::CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,
  131.     LPVOID* ppv)
  132. {
  133.     *ppv = NULL;
  134.     if (pUnkOuter != NULL)
  135.         return CLASS_E_NOAGGREGATION;
  136.  
  137.     CFileViewer* pFileViewer = new CFileViewer;
  138.  
  139.     if (pFileViewer == NULL)
  140.         return E_OUTOFMEMORY;
  141.  
  142.     HRESULT hr = pFileViewer->QueryInterface (riid, ppv);
  143.  
  144.     if (FAILED (hr))
  145.         delete pFileViewer;
  146.  
  147.     return hr;
  148. }
  149.  
  150. HRESULT CClassFactory::LockServer (BOOL fLock)
  151. {
  152.     return E_NOTIMPL;
  153. }
  154.  
  155. /////////////////////////////////////////////////////////////////////////////
  156. // CFileViewer member functions
  157.  
  158. CFileViewer::CFileViewer ()
  159. {
  160.     m_cRef = 0;
  161.     g_cRefThisDll++;
  162.     m_bShowInitializeCalled = FALSE;
  163.     m_szFile[0] = 0;
  164. }
  165.  
  166. CFileViewer::~CFileViewer ()
  167. {
  168.     g_cRefThisDll--;
  169. }
  170.  
  171. HRESULT CFileViewer::QueryInterface (REFIID riid, LPVOID* ppv)
  172. {
  173.     *ppv = NULL;
  174.     HRESULT hr = E_NOINTERFACE;
  175.  
  176.     if (riid == IID_IUnknown)
  177.         *ppv = (LPUNKNOWN) this;
  178.     else if (riid == IID_IPersistFile)
  179.         *ppv = (LPPERSISTFILE) this;
  180.     else if (riid == IID_IFileViewer)
  181.         *ppv = (LPFILEVIEWER) this;
  182.  
  183.     if (*ppv != NULL) {
  184.         ((LPUNKNOWN) *ppv)->AddRef ();
  185.         hr = NOERROR;
  186.     }
  187.     return hr;
  188. }
  189.  
  190. ULONG CFileViewer::AddRef ()
  191. {
  192.     return ++m_cRef;
  193. }
  194.  
  195. ULONG CFileViewer::Release ()
  196. {
  197.     ULONG cRef = --m_cRef;
  198.     if (m_cRef == 0)
  199.         delete this;
  200.     return cRef;
  201. }
  202.  
  203. HRESULT CFileViewer::Load (LPCOLESTR pszFile, DWORD dwMode)
  204. {
  205.     wcstombs (m_szFile, pszFile, sizeof (m_szFile));
  206.     return NOERROR;
  207. }
  208.  
  209. HRESULT CFileViewer::GetCurFile (LPOLESTR* ppszFile)
  210. {
  211.     return E_NOTIMPL;
  212. }
  213.  
  214. HRESULT CFileViewer::GetClassID (LPCLSID lpClsID)
  215. {
  216.     *lpClsID = CLSID_FileViewer;
  217.     return NOERROR;
  218. }
  219.  
  220. HRESULT CFileViewer::IsDirty ()
  221. {
  222.     return S_FALSE; // Can't get dirty if the file can't be edited
  223. }
  224.  
  225. HRESULT CFileViewer::Save (LPCOLESTR pszFile, BOOL fRemember)
  226. {
  227.     return E_NOTIMPL;
  228. }
  229.  
  230. HRESULT CFileViewer::SaveCompleted (LPCOLESTR pszFile)
  231. {
  232.     return E_NOTIMPL;
  233. }
  234.  
  235. HRESULT CFileViewer::PrintTo (LPSTR pszDriver, BOOL fSuppressUI)
  236. {
  237.     return E_NOTIMPL;
  238. }
  239.  
  240. HRESULT CFileViewer::ShowInitialize (LPFILEVIEWERSITE lpfsi)
  241. {
  242.     //
  243.     // Unlock GIF and TIFF-LZW support in LEADTOOLS.
  244.     //
  245.     L_UnlockSupport (L_SUPPORT_GIFLZW, LEADTOOLS_GIFKEY);
  246.     L_UnlockSupport (L_SUPPORT_TIFLZW, LEADTOOLS_TIFKEY);
  247.  
  248.     //
  249.     // Load the image.
  250.     //
  251.     if (!LoadImage (m_szFile))
  252.         return E_FAIL;
  253.  
  254.     //
  255.     // Create the file viewer window.
  256.     //
  257.     WNDCLASS wc;
  258.     wc.style = 0;
  259.     wc.lpfnWndProc = (WNDPROC) MainWndProc;
  260.     wc.cbClsExtra = 0;
  261.     wc.cbWndExtra = 0;
  262.     wc.hInstance = g_hInstance;
  263.     wc.hIcon = LoadIcon (NULL, IDI_WINLOGO);
  264.     wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  265.     wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  266.     wc.lpszMenuName = MAKEINTRESOURCE (IDR_MENU);
  267.     wc.lpszClassName = g_szMainWndClassName;
  268.  
  269.     RegisterClass (&wc);
  270.  
  271.     char szWndTitle[MAX_PATH + 16];
  272.     GetFileTitle (m_szFile, szWndTitle, sizeof (szWndTitle));
  273.     lstrcat (szWndTitle, " - Quick View");
  274.  
  275.     m_hWnd = CreateWindow (g_szMainWndClassName, szWndTitle,
  276.         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  277.         CW_USEDEFAULT, HWND_DESKTOP, NULL, g_hInstance, NULL);
  278.  
  279.     if (m_hWnd == NULL) {
  280.         UnregisterClass (g_szMainWndClassName, g_hInstance);
  281.         L_FreeBitmap (&g_hBitmap);
  282.         return E_OUTOFMEMORY;
  283.     }
  284.  
  285.     SetWindowLong (m_hWnd, (int) this, GWL_USERDATA);
  286.  
  287.     //
  288.     // Size the window to fit the image.
  289.     //
  290.     SizeWindowToImage (m_hWnd, &g_hBitmap);
  291.  
  292.     //
  293.     // Set the flag indicating ShowInitialize was called, and exit.
  294.     //
  295.     m_bShowInitializeCalled = TRUE;
  296.     return NOERROR;
  297. }
  298.  
  299. HRESULT CFileViewer::Show (LPFVSHOWINFO pvsi)
  300. {
  301.     //
  302.     // Fail the call if ShowInitialize wasn't called first.
  303.     //
  304.     if (!m_bShowInitializeCalled)
  305.         return E_UNEXPECTED;
  306.  
  307.     //
  308.     // Display the window on the screen.
  309.     //
  310.     ShowWindow (m_hWnd, pvsi->iShow);
  311.  
  312.     //
  313.     // Forward messages to the window.
  314.     //
  315.     MSG msg;
  316.     while (GetMessage (&msg, NULL, 0, 0)) {
  317.         TranslateMessage (&msg);
  318.         DispatchMessage (&msg);
  319.     }
  320.  
  321.     //
  322.     // Clean up and return.
  323.     //
  324.     UnregisterClass (g_szMainWndClassName, g_hInstance);
  325.     UnregisterClass (g_szViewWndClassName, g_hInstance);
  326.  
  327.     L_FreeBitmap (&g_hBitmap);
  328.  
  329.     if (g_hPalette != NULL) {
  330.         DeleteObject (g_hPalette);
  331.         g_hPalette = NULL;
  332.     }
  333.     return NOERROR;
  334. }
  335.  
  336. BOOL CFileViewer::LoadImage (LPSTR pszFile)
  337. {
  338.     FILEINFO fi;
  339.     if (L_FileInfo (pszFile, &fi) != SUCCESS)
  340.         return FALSE;
  341.  
  342.     if ((fi.Format != FILE_JFIF) &&
  343.         (fi.Format != FILE_PCD)  &&
  344.         (fi.Format != FILE_PCX)  &&
  345.         (fi.Format != FILE_PNG)  &&
  346.         (fi.Format != FILE_TGA)  &&
  347.         (fi.Format != FILE_TIF)  &&
  348.         (fi.Format != FILE_JTIF) &&
  349.         (fi.Format != FILE_GIF))
  350.         return FALSE; // Unsupported file format
  351.  
  352.     BITMAPHANDLE hBitmap;
  353.     L_LoadBitmap (pszFile, &hBitmap, 0, ORDER_BGR);
  354.  
  355.     if (!hBitmap.Flags.Allocated)
  356.         return FALSE;
  357.  
  358.     if (!g_hBitmap.Flags.Allocated)
  359.         L_FreeBitmap (&g_hBitmap);
  360.     g_hBitmap = hBitmap;
  361.  
  362.     if (g_hPalette != NULL)
  363.         DeleteObject (g_hPalette);
  364.  
  365.     HDC hdc = GetDC (NULL);
  366.     g_hPalette = L_CreatePaintPalette (hdc, &g_hBitmap);
  367.     ReleaseDC (NULL, hdc);
  368.  
  369.     lstrcpy (m_szFile, pszFile);
  370.     return TRUE;
  371. }
  372.  
  373. /////////////////////////////////////////////////////////////////////////////
  374. // Window procedures and helper functions
  375.  
  376. LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam,
  377.     LPARAM lParam)
  378. {
  379.     HDROP hDrop;
  380.     char szFile[MAX_PATH];
  381.     CFileViewer* pViewer;
  382.     static HWND hWndStatusBar;
  383.     static HWND hWndView;
  384.  
  385.     switch (msg) {
  386.  
  387.     case WM_CREATE:
  388.         //
  389.         // Create a status bar at the bottom of the window.
  390.         //
  391.         InitCommonControls ();
  392.         hWndStatusBar = CreateStatusWindow (WS_CHILD | WS_VISIBLE, "Ready",
  393.             hwnd, ID_STATUS_BAR);
  394.  
  395.         if (hWndStatusBar == NULL)
  396.             return -1;
  397.  
  398.         //
  399.         // Hide the status bar if the user prefers it hidden.
  400.         //
  401.         if (PreferStatusBarHidden ()) {
  402.             ShowWindow (hWndStatusBar, SW_HIDE);
  403.             CheckMenuItem (GetMenu (hwnd), IDM_STATUS, MF_UNCHECKED);
  404.         }
  405.  
  406.         //
  407.         // Fill the visible portion of the window's client area with a view.
  408.         //
  409.         WNDCLASS wc;
  410.         wc.style = 0;
  411.         wc.lpfnWndProc = (WNDPROC) ViewWndProc;
  412.         wc.cbClsExtra = 0;
  413.         wc.cbWndExtra = 0;
  414.         wc.hInstance = g_hInstance;
  415.         wc.hIcon = NULL;
  416.         wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  417.         wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
  418.         wc.lpszMenuName = NULL;
  419.         wc.lpszClassName = g_szViewWndClassName;
  420.  
  421.         RegisterClass (&wc);
  422.  
  423.         hWndView = CreateWindowEx (WS_EX_CLIENTEDGE, g_szViewWndClassName,
  424.             NULL, WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, 0, 0, 0, 0,
  425.             hwnd, (HMENU) ID_VIEW, g_hInstance, NULL);
  426.  
  427.         if (hWndView == NULL) {
  428.             UnregisterClass (g_szViewWndClassName, g_hInstance);
  429.             return -1;
  430.         }
  431.  
  432.         //
  433.         // Register this window to accept dropped files.
  434.         //
  435.         DragAcceptFiles (hwnd, TRUE);
  436.         return 0;
  437.  
  438.     case WM_SIZE:
  439.         //
  440.         // When the main window is resized, resize its children, too.
  441.         //
  442.         if ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)) {
  443.             SendMessage (hWndStatusBar, WM_SIZE, wParam, lParam);
  444.             ResizeView (hWndView, hWndStatusBar, (int) LOWORD (lParam),
  445.                 (int) HIWORD (lParam));
  446.         }
  447.         return 0;
  448.  
  449.     case WM_PALETTECHANGED:
  450.         //
  451.         // Realize the logical palette if g_hPalette is non-NULL and
  452.         // the window handle in wParam is not our own.
  453.         //
  454.         if (hwnd == (HWND) wParam)
  455.             return FALSE;
  456.  
  457.         // Fall through to the WM_QUERYNEWPALETTE handler...
  458.  
  459.     case WM_QUERYNEWPALETTE:
  460.         //
  461.         // Realize the logical palette if g_hPalette is non-NULL.
  462.         //
  463.         if (g_hPalette != NULL) {
  464.             HDC hdc;
  465.             hdc = GetDC (hwnd);
  466.             SelectPalette (hdc, g_hPalette, FALSE);
  467.  
  468.             UINT nColors;
  469.             if (nColors = RealizePalette (hdc))
  470.                 InvalidateRect (hwnd, NULL, FALSE);
  471.  
  472.             ReleaseDC (hwnd, hdc);
  473.             return nColors ? TRUE : FALSE;
  474.         }
  475.         break;
  476.  
  477.     case WM_COMMAND:
  478.         switch (LOWORD (wParam)) {
  479.  
  480.         case IDM_COPY:
  481.             //
  482.             // Copy the image to the clipboard.
  483.             //
  484.             L_CopyToClipboard (hwnd, &g_hBitmap);
  485.             return 0;
  486.  
  487.         case IDM_STATUS:
  488.             //
  489.             // Toggle the status bar on or off.
  490.             //
  491.             if (IsWindowVisible (hWndStatusBar)) { // Hide it
  492.                 ShowWindow (hWndStatusBar, SW_HIDE);
  493.                 CheckMenuItem (GetMenu (hwnd), IDM_STATUS, MF_UNCHECKED);
  494.                 RecordStatusBarPreference (FALSE);
  495.             }
  496.             else { // Make it visible
  497.                 ShowWindow (hWndStatusBar, SW_SHOW);
  498.                 CheckMenuItem (GetMenu (hwnd), IDM_STATUS, MF_CHECKED);
  499.                 RecordStatusBarPreference (TRUE);
  500.             }
  501.  
  502.             RECT rect;
  503.             GetClientRect (hwnd, &rect);
  504.             ResizeView (hWndView, hWndStatusBar, rect.right - rect.left,
  505.                 rect.bottom - rect.top);
  506.             return 0;
  507.  
  508.         case IDM_ABOUT:
  509.             //
  510.             // Display the viewer's About box.
  511.             //
  512.             DialogBox (g_hInstance, MAKEINTRESOURCE (IDD_ABOUTDLG), hwnd,
  513.                 (DLGPROC) AboutDlgProc);
  514.             return 0;
  515.  
  516.         case IDM_EXIT:
  517.             //
  518.             // Close the window.
  519.             //
  520.             PostMessage (hwnd, WM_CLOSE, 0, 0);
  521.             return 0;
  522.         }
  523.         break;
  524.  
  525.     case WM_MENUSELECT:
  526.         //
  527.         // Display help text for menu commands.
  528.         //
  529.         UINT nItem, nFlags;
  530.         nItem = LOWORD (wParam);
  531.         nFlags = HIWORD (wParam);
  532.         char szText[64];
  533.  
  534.         if ((nFlags == 0xFFFF) && (lParam == 0))
  535.             SendMessage (hWndStatusBar, SB_SETTEXT, 0, (LPARAM) "Ready");
  536.         else if (LoadString (g_hInstance, nItem, szText, sizeof (szText)))
  537.             SendMessage (hWndStatusBar, SB_SETTEXT, 0, (LPARAM) szText);
  538.         else
  539.             SendMessage (hWndStatusBar, SB_SETTEXT, 0, (LPARAM) "");
  540.  
  541.         return 0;
  542.  
  543.     case WM_DROPFILES:
  544.         //
  545.         // Display an image dropped over the window.
  546.         //
  547.         hDrop = (HDROP) wParam;
  548.         DragQueryFile (hDrop, 0, szFile, sizeof (szFile));
  549.  
  550.         pViewer = (CFileViewer*) GetWindowLong (hwnd, GWL_USERDATA);
  551.         if (pViewer->LoadImage (szFile)) {
  552.             RECT rect;
  553.             GetClientRect (hWndView, &rect);
  554.             SendMessage (hWndView, WM_SIZE, SIZE_RESTORED,
  555.                 MAKELPARAM (rect.right, rect.bottom));
  556.             InvalidateRect (hWndView, NULL, TRUE);
  557.         }
  558.  
  559.         DragFinish (hDrop);
  560.         return 0;
  561.  
  562.     case WM_DESTROY:
  563.         //
  564.         // Post a WM_QUIT message to the window to end the message loop.
  565.         //
  566.         PostQuitMessage (0);
  567.         return 0;
  568.     }
  569.     return DefWindowProc (hwnd, msg, wParam, lParam);
  570. }
  571.  
  572. LRESULT CALLBACK ViewWndProc (HWND hwnd, UINT msg, WPARAM wParam,
  573.     LPARAM lParam)
  574. {
  575.     SCROLLINFO si;
  576.     int nMaxPos, nDelta;
  577.  
  578.     switch (msg) {
  579.  
  580.     case WM_SIZE:
  581.         //
  582.         // Adjust the scroll bars when the view size changes.
  583.         //
  584.         int cx, cy;
  585.         cx = LOWORD (lParam);
  586.         cy = HIWORD (lParam);
  587.  
  588.         BOOL bRepaintAll;
  589.         bRepaintAll = FALSE;
  590.  
  591.         int nMax, nPos, nPage;
  592.         nMax = nPos = nPage = 0;
  593.         if (cx < g_hBitmap.Width) {
  594.             nPage = cx;
  595.             nMax = g_hBitmap.Width - 1;
  596.             nPos = min (GetScrollPos (hwnd, SB_HORZ), nMax - nPage + 1);
  597.         }
  598.  
  599.         if (nPos != GetScrollPos (hwnd, SB_HORZ))
  600.             bRepaintAll = TRUE;
  601.  
  602.         si.cbSize = sizeof (si);
  603.         si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS | SIF_DISABLENOSCROLL;
  604.         si.nMin = 0;
  605.         si.nMax = nMax;
  606.         si.nPos = nPos;
  607.         si.nPage = nPage;
  608.  
  609.         SetScrollInfo (hwnd, SB_HORZ, &si, TRUE);
  610.  
  611.         nMax = nPos = nPage = 0;
  612.         if (cy < g_hBitmap.Height) {
  613.             nPage = cy;
  614.             nMax = g_hBitmap.Height - 1;
  615.             nPos = min (GetScrollPos (hwnd, SB_VERT), nMax - nPage + 1);
  616.         }
  617.  
  618.         if (nPos != GetScrollPos (hwnd, SB_VERT))
  619.             bRepaintAll = TRUE;
  620.  
  621.         si.cbSize = sizeof (si);
  622.         si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS | SIF_DISABLENOSCROLL;
  623.         si.nMin = 0;
  624.         si.nMax = nMax;
  625.         si.nPos = nPos;
  626.         si.nPage = nPage;
  627.  
  628.         SetScrollInfo (hwnd, SB_VERT, &si, TRUE);
  629.  
  630.         if (bRepaintAll)
  631.             InvalidateRect (hwnd, NULL, FALSE);
  632.  
  633.         return 0;
  634.  
  635.     case WM_HSCROLL:
  636.         //
  637.         // Scroll the image horizontally.
  638.         //
  639.         si.cbSize = sizeof (si);
  640.         si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  641.         GetScrollInfo (hwnd, SB_HORZ, &si);
  642.  
  643.         nMaxPos = si.nMax - si.nPage + 1;
  644.         nDelta = 0;
  645.  
  646.         switch (LOWORD (wParam)) {
  647.  
  648.         case SB_LINELEFT:
  649.             if (si.nPos > 0)
  650.                 nDelta = -(min (4, si.nPos));
  651.             break;
  652.  
  653.         case SB_PAGELEFT:
  654.             if (si.nPos > 0)
  655.                 nDelta = -(min (((int) si.nPage * 10) / 9, si.nPos));
  656.             break;
  657.  
  658.         case SB_THUMBTRACK:
  659.             nDelta = (int) HIWORD (wParam) - si.nPos;
  660.             break;
  661.  
  662.         case SB_PAGERIGHT:
  663.             if (si.nPos < nMaxPos)
  664.                 nDelta = min (((int) si.nPage * 10) / 9, nMaxPos - si.nPos);
  665.             break;
  666.  
  667.         case SB_LINERIGHT:
  668.             if (si.nPos < nMaxPos)
  669.                 nDelta = min (4, nMaxPos - si.nPos);
  670.             break;
  671.         }
  672.  
  673.         if (nDelta) {
  674.             SetScrollPos (hwnd, SB_HORZ, si.nPos + nDelta, TRUE);
  675.             ScrollWindow (hwnd, -nDelta, 0, NULL, NULL);
  676.             UpdateWindow (hwnd);
  677.         }
  678.         return 0;
  679.  
  680.     case WM_VSCROLL:
  681.         //
  682.         // Scroll the image vertically.
  683.         //
  684.         si.cbSize = sizeof (si);
  685.         si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  686.         GetScrollInfo (hwnd, SB_VERT, &si);
  687.  
  688.         nMaxPos = si.nMax - si.nPage + 1;
  689.         nDelta = 0;
  690.  
  691.         switch (LOWORD (wParam)) {
  692.  
  693.         case SB_LINEUP:
  694.             if (si.nPos > 0)
  695.                 nDelta = -(min (4, si.nPos));
  696.             break;
  697.  
  698.         case SB_PAGEUP:
  699.             if (si.nPos > 0)
  700.                 nDelta = -(min (((int) si.nPage * 10) / 9, si.nPos));
  701.             break;
  702.  
  703.         case SB_THUMBTRACK:
  704.             nDelta = (int) HIWORD (wParam) - si.nPos;
  705.             break;
  706.  
  707.         case SB_PAGEDOWN:
  708.             if (si.nPos < nMaxPos)
  709.                 nDelta = min (((int) si.nPage * 10) / 9, nMaxPos - si.nPos);
  710.             break;
  711.  
  712.         case SB_LINEDOWN:
  713.             if (si.nPos < nMaxPos)
  714.                 nDelta = min (4, nMaxPos - si.nPos);
  715.             break;
  716.         }
  717.  
  718.         if (nDelta) {
  719.             SetScrollPos (hwnd, SB_VERT, si.nPos + nDelta, TRUE);
  720.             ScrollWindow (hwnd, 0, -nDelta, NULL, NULL);
  721.             UpdateWindow (hwnd);
  722.         }
  723.         return 0;
  724.  
  725.     case WM_PAINT:
  726.         //
  727.         // Draw the image.
  728.         //
  729.         int nHorzPos, nVertPos;
  730.         nHorzPos = GetScrollPos (hwnd, SB_HORZ);
  731.         nVertPos = GetScrollPos (hwnd, SB_VERT);
  732.  
  733.         RECT rect;
  734.         SetRect (&rect, -nHorzPos, -nVertPos, g_hBitmap.Width - nHorzPos,
  735.             g_hBitmap.Height - nVertPos);
  736.  
  737.         HDC hdc;
  738.         PAINTSTRUCT ps;
  739.         hdc = BeginPaint (hwnd, &ps);
  740.  
  741.         HPALETTE hOldPalette;
  742.         if (g_hPalette != NULL) {
  743.             hOldPalette = SelectPalette (hdc, g_hPalette, FALSE);
  744.             RealizePalette (hdc);
  745.         }
  746.  
  747.         L_PaintDC (hdc, &g_hBitmap, NULL, NULL, &rect, &ps.rcPaint, SRCCOPY);
  748.  
  749.         if (g_hPalette != NULL)
  750.             SelectPalette (hdc, hOldPalette, FALSE);
  751.  
  752.         EndPaint (hwnd, &ps);
  753.         return 0;
  754.     }
  755.     return DefWindowProc (hwnd, msg, wParam, lParam);
  756. }
  757.  
  758. void SizeWindowToImage (HWND hWndMain, BITMAPHANDLE* pBitmap)
  759. {
  760.     HWND hWndView = GetDlgItem (hWndMain, ID_VIEW);
  761.     HWND hWndStatusBar = GetDlgItem (hWndMain, ID_STATUS_BAR);
  762.  
  763.     //
  764.     // Calculate the size of the view window.
  765.     //
  766.     RECT rect;
  767.     SetRect (&rect, 0, 0,
  768.         pBitmap->Width + GetSystemMetrics (SM_CXVSCROLL),
  769.         pBitmap->Height + GetSystemMetrics (SM_CYHSCROLL));
  770.  
  771.     AdjustWindowRectEx (&rect, (DWORD) GetWindowLong (hWndView, GWL_STYLE),
  772.         FALSE, (DWORD) GetWindowLong (hWndView, GWL_EXSTYLE));
  773.  
  774.     //
  775.     // Then calculate the size of the main window.
  776.     //
  777.     AdjustWindowRectEx (&rect, (DWORD) GetWindowLong (hWndMain, GWL_STYLE),
  778.         TRUE, (DWORD) GetWindowLong (hWndMain, GWL_EXSTYLE));
  779.  
  780.     MENUITEMINFO mii;
  781.     mii.cbSize = sizeof (mii);
  782.     mii.fMask = MIIM_STATE;
  783.  
  784.     GetMenuItemInfo (GetMenu (hWndMain), IDM_STATUS, FALSE, &mii);
  785.  
  786.     if (mii.fState & MFS_CHECKED) {
  787.         RECT rectStatusBar;
  788.         GetWindowRect (hWndStatusBar, &rectStatusBar);
  789.         rect.bottom += (rectStatusBar.bottom - rectStatusBar.top);
  790.     }
  791.  
  792.     //
  793.     // Adjust the window size.
  794.     //
  795.     int nMaxWidth = (GetSystemMetrics (SM_CXSCREEN) * 9) / 10;
  796.     int nMaxHeight = (GetSystemMetrics (SM_CYSCREEN) * 9) / 10;
  797.  
  798.     int nWidth = max (160, rect.right - rect.left);
  799.     int nHeight = max (120, rect.bottom - rect.top);
  800.  
  801.     if ((nWidth <= nMaxWidth) && (nHeight <= nMaxHeight))
  802.         SetWindowPos (hWndMain, NULL, 0, 0, nWidth, nHeight,
  803.             SWP_NOZORDER | SWP_NOMOVE);
  804. }
  805.  
  806. void ResizeView (HWND hWndView, HWND hWndStatusBar, int cx, int cy)
  807. {
  808.     if (hWndView != NULL) {
  809.         if (IsWindowVisible (hWndStatusBar)) {
  810.             RECT rect;
  811.             GetWindowRect (hWndStatusBar, &rect);
  812.             cy = cy - (rect.bottom - rect.top);
  813.             if (cy < 0)
  814.                 cy = 0;
  815.         }
  816.         SetWindowPos (hWndView, NULL, 0, 0, cx, cy,
  817.             SWP_NOMOVE | SWP_NOZORDER);
  818.     }
  819. }
  820.  
  821. void RecordStatusBarPreference (BOOL bVisible)
  822. {
  823.     HKEY hKey;
  824.  
  825.     if (RegCreateKeyEx (HKEY_CURRENT_USER, g_szKey, 0, NULL,
  826.         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) ==
  827.         ERROR_SUCCESS) {
  828.  
  829.         DWORD dwVal = bVisible ? 1 : 0;
  830.         RegSetValueEx (hKey, g_szValueName, 0, REG_DWORD, (PBYTE) &dwVal,
  831.             sizeof (dwVal));
  832.         RegCloseKey (hKey);
  833.     }
  834. }
  835.  
  836. BOOL PreferStatusBarHidden ()
  837. {
  838.     HKEY hKey;
  839.     BOOL bResult = FALSE;
  840.  
  841.     if (RegOpenKeyEx (HKEY_CURRENT_USER, g_szKey, 0, KEY_QUERY_VALUE,
  842.         &hKey) == ERROR_SUCCESS) {
  843.  
  844.         DWORD dwVal;
  845.         DWORD dwSize = sizeof (dwVal);
  846.         if (RegQueryValueEx (hKey, g_szValueName, NULL, NULL, (PBYTE) &dwVal,
  847.             &dwSize) == ERROR_SUCCESS)
  848.             bResult = dwVal ? FALSE : TRUE;
  849.  
  850.         RegCloseKey (hKey);
  851.     }
  852.     return bResult;
  853. }
  854.  
  855. /////////////////////////////////////////////////////////////////////////////
  856. // Dialog procedures
  857.  
  858. BOOL CALLBACK AboutDlgProc (HWND hwnd, UINT uMessage, WPARAM wParam,
  859.     LPARAM lParam)
  860. {
  861.     static HFONT hFont;
  862.     static HBRUSH hBrush;
  863.  
  864.     switch (uMessage) {
  865.     
  866.     case WM_INITDIALOG:
  867.         //
  868.         // Enlarge the program title for visual effect and create a
  869.         // custom background brush.
  870.         //
  871.         LOGFONT lf;
  872.         GetObject ((HFONT) SendMessage (hwnd, WM_GETFONT, 0, 0),
  873.             sizeof (lf), &lf);
  874.  
  875.         lf.lfHeight = lf.lfHeight * 3;
  876.         lf.lfWidth = lf.lfWidth * 3;
  877.         lf.lfWeight = FW_BOLD;
  878.         lf.lfItalic = 1;
  879.         lstrcpy (lf.lfFaceName, "Arial");
  880.  
  881.         hFont = CreateFontIndirect (&lf);
  882.         if (hFont != NULL)
  883.             SendDlgItemMessage (hwnd, IDC_TITLE, WM_SETFONT,
  884.                 (WPARAM) hFont, 0);
  885.  
  886.         hBrush = CreateSolidBrush (GetSysColor (COLOR_3DFACE));
  887.         return TRUE;
  888.  
  889.     case WM_CTLCOLORSTATIC:
  890.         //
  891.         // Change the program title's text color to red.
  892.         //
  893.         SetBkColor ((HDC) wParam, GetSysColor (COLOR_3DFACE));
  894.         if (GetDlgCtrlID ((HWND) lParam) == IDC_TITLE)
  895.             SetTextColor ((HDC) wParam, RGB (255, 0, 0));
  896.         return (BOOL) hBrush;
  897.  
  898.     case WM_COMMAND:
  899.         //
  900.         // Process messages from the controls.
  901.         //
  902.         UINT nID;
  903.         nID = (UINT) LOWORD (wParam);
  904.  
  905.         switch (nID) {
  906.  
  907.         case IDOK:
  908.             EndDialog (hwnd, IDOK);
  909.             return TRUE;
  910.  
  911.         case IDCANCEL:
  912.             EndDialog (hwnd, IDCANCEL);
  913.             return TRUE;
  914.         }
  915.         break;
  916.  
  917.     case WM_DESTROY:
  918.         //
  919.         // Clean up and exit.
  920.         //
  921.         if (hFont != NULL)
  922.             DeleteObject (hFont);
  923.         DeleteObject (hBrush);
  924.         return TRUE;
  925.     }
  926.     return FALSE;
  927. }
  928.