winmain.cpp
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:131k
源码类别:

压缩解压

开发平台:

MultiPlatform

  1. //******************************************************************************
  2. //
  3. // File:        WINMAIN.CPP
  4. //
  5. // Description: This module contains all the Windows specific code for Pocket
  6. //              UnZip.  It contains the entire user interface.  This code knows
  7. //              almost nothing about the Info-ZIP code.  All Info-ZIP related
  8. //              functions are wrapped by helper functions in INTRFACE.CPP.  The
  9. //              code in this module only calls those wrapper functions and
  10. //              INTRFACE.CPP handles all the details and callbacks of the 
  11. //              Info-ZIP code.
  12. //
  13. // Copyright:   All the source files for Pocket UnZip, except for components
  14. //              written by the Info-ZIP group, are copyrighted 1997 by Steve P.
  15. //              Miller.  The product "Pocket UnZip" itself is property of the
  16. //              author and cannot be altered in any way without written consent
  17. //              from Steve P. Miller.
  18. //
  19. // Disclaimer:  All project files are provided "as is" with no guarantee of
  20. //              their correctness.  The authors are not liable for any outcome
  21. //              that is the result of using this source.  The source for Pocket
  22. //              UnZip has been placed in the public domain to help provide an
  23. //              understanding of its implementation.  You are hereby granted
  24. //              full permission to use this source in any way you wish, except
  25. //              to alter Pocket UnZip itself.  For comments, suggestions, and
  26. //              bug reports, please write to stevemil@pobox.com.
  27. //
  28. // Functions:   WinMain
  29. //              InitializeApplication
  30. //              ShutdownApplication
  31. //              RegisterUnzip
  32. //              BuildImageList
  33. //              WndProc
  34. //              OnCreate
  35. //              OnFileOpen
  36. //              OnActionView
  37. //              OnActionSelectAll
  38. //              OnViewExpandedView
  39. //              OnHelp
  40. //              OnGetDispInfo
  41. //              OnDeleteItem
  42. //              OnItemChanged
  43. //              Sort
  44. //              CompareFunc
  45. //              SetCaptionText
  46. //              DrawBanner
  47. //              AddDeleteColumns
  48. //              ResizeColumns
  49. //              GetZipErrorString
  50. //              AddFileToListView
  51. //              EnableAllMenuItems
  52. //              CheckAllMenuItems
  53. //              CenterWindow
  54. //              AddTextToEdit
  55. //              FormatValue
  56. //              BuildAttributesString
  57. //              BuildTypeString
  58. //              GetFileFromPath
  59. //              ForwardSlashesToBackSlashesA
  60. //              ForwardSlashesToBackSlashesW
  61. //              DeleteDirectory(LPTSTR szPath);
  62. //              RegWriteKey
  63. //              RegReadKey
  64. //              WriteOptionString
  65. //              WriteOptionInt
  66. //              GetOptionString
  67. //              GetOptionInt
  68. //              DisableEditing
  69. //              EditSubclassProc
  70. //              GetMenuString
  71. //              InitializeMRU
  72. //              AddFileToMRU
  73. //              RemoveFileFromMRU
  74. //              ActivateMRU
  75. //              ReadZipFileList
  76. //              DlgProcProperties
  77. //              MergeValues
  78. //              CheckThreeStateBox
  79. //              ExtractOrTestFiles
  80. //              DlgProcExtractOrTest
  81. //              FolderBrowser
  82. //              DlgProcBrowser
  83. //              SubclassSaveAsDlg
  84. //              DlgProcExtractProgress
  85. //              DlgProcViewProgress
  86. //              UpdateProgress
  87. //              PromptToReplace
  88. //              DlgProcReplace
  89. //              DlgProcPassword
  90. //              DlgProcViewAssociation
  91. //              DlgProcComment
  92. //              DlgProcAbout
  93. //
  94. //
  95. // Date      Name          History
  96. // --------  ------------  -----------------------------------------------------
  97. // 02/01/97  Steve Miller  Created (Version 1.0 using Info-ZIP UnZip 5.30)
  98. //
  99. //******************************************************************************
  100. extern "C" {
  101. #define __WINMAIN_CPP__
  102. #define UNZIP_INTERNAL
  103. #include "unzip.h"
  104. #include "version.h"   // Only needed by consts.h (VERSION_DATE & VersionDate)
  105. #include "consts.h"    // Only include once - defines constant string messages.
  106. #include "crypt.h"     // Needed to pick up CRYPT define if set and return values.
  107. #include <commctrl.h>  // Common controls - mainly ListView and ImageList
  108. #include <commdlg.h>   // Common dialogs - OpenFile dialog
  109. #ifndef _WIN32_WCE
  110. #include <shlobj.h>    // On NT, we use the SHBrowseForFolder() stuff.
  111. #include <shellapi.h>  // CommandLineToArgvW() and ExtractIconEx()
  112. #endif
  113. #include "intrface.h"  // Interface between Info-ZIP and us
  114. #include "winmain.h"   // Us
  115. }
  116. #include <tchar.h>     // Must be outside of extern "C" block
  117. //******************************************************************************
  118. //***** "Local" Global Variables
  119. //******************************************************************************
  120. static LPCTSTR         g_szAppName     = TEXT("Pocket UnZip");
  121. static LPCTSTR         g_szClass       = TEXT("PocketUnZip");
  122. static LPCTSTR         g_szRegKey      = TEXT("Software\Pocket UnZip");
  123. static LPCTSTR         g_szTempDir     = NULL;
  124. static HWND            g_hWndList      = NULL;
  125. static HWND            g_hWndCmdBar    = NULL;
  126. static int             g_cyCmdBar      = 0;
  127. static HFONT           g_hFontBanner   = NULL;
  128. static HICON           g_hIconMain     = NULL;
  129. static WNDPROC         g_wpSaveAsDlg   = NULL;
  130. static WNDPROC         g_wpEdit        = NULL;
  131. static int             g_sortColumn    = -1;
  132. static BOOL            g_fExpandedView = FALSE;
  133. static BOOL            g_fLoading      = FALSE;
  134. static BOOL            g_fSkipped      = FALSE;
  135. static BOOL            g_fViewing      = FALSE;
  136. static HWND            g_hWndWaitFor   = NULL;
  137. static FILE_TYPE_NODE *g_pftHead       = NULL;
  138. #ifdef _WIN32_WCE
  139. static LPCTSTR         g_szHelpFile    = TEXT("\windows\punzip.htp");
  140. #else
  141. static LPCTSTR         g_szHelpFile    = TEXT("punzip.html");
  142. #endif
  143. static COLUMN g_columns[] = {
  144.    { TEXT("Name"),       LVCFMT_LEFT  },
  145.    { TEXT("Size"),       LVCFMT_RIGHT },
  146.    { TEXT("Type"),       LVCFMT_LEFT  },
  147.    { TEXT("Modified"),   LVCFMT_LEFT  },
  148.    { TEXT("Attributes"), LVCFMT_LEFT  },
  149.    { TEXT("Compressed"), LVCFMT_RIGHT },
  150.    { TEXT("Ratio"),      LVCFMT_RIGHT },
  151.    { TEXT("Method"),     LVCFMT_LEFT  },
  152.    { TEXT("CRC"),        LVCFMT_LEFT  },
  153.    { TEXT("Comment"),    LVCFMT_LEFT  }
  154. };
  155. //******************************************************************************
  156. //***** Local Function Prototypes
  157. //******************************************************************************
  158. // Startup and Shutdown Functions
  159. void InitializeApplication(LPCTSTR szZipFile);
  160. void ShutdownApplication();
  161. void RegisterUnzip();
  162. void BuildImageList();
  163. // Our Main Window's Message Handler
  164. LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  165. // Event Handlers for our Main Window
  166. int OnCreate();
  167. void OnFileOpen();
  168. void OnActionView();
  169. void OnActionSelectAll();
  170. void OnViewExpandedView();
  171. void OnHelp();
  172. // Event Handlers for our List View
  173. void OnGetDispInfo(LV_DISPINFO *plvdi);
  174. void OnDeleteItem(NM_LISTVIEW *pnmlv);
  175. void OnItemChanged(NM_LISTVIEW *pnmlv);
  176. // List View Sort Functions
  177. void Sort(int sortColumn, BOOL fForce);
  178. int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM sortColumn);
  179. // Helper/Utility Functions
  180. void SetCaptionText(LPCTSTR szPrefix);
  181. void DrawBanner(HDC hdc);
  182. void AddDeleteColumns();
  183. void ResizeColumns();
  184. LPCTSTR GetZipErrorString(int error);
  185. void AddFileToListView(FILE_NODE *pFile);
  186. void EnableAllMenuItems(UINT uMenuItem, BOOL fEnabled);
  187. void CheckAllMenuItems(UINT uMenuItem, BOOL fChecked);
  188. void CenterWindow(HWND hWnd);
  189. void AddTextToEdit(LPCSTR szText);
  190. LPTSTR FormatValue(LPTSTR szValue, DWORD dwValue);
  191. LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes);
  192. LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType);
  193. LPCSTR GetFileFromPath(LPCSTR szPath);
  194. void ForwardSlashesToBackSlashesA(LPSTR szBuffer);
  195. void ForwardSlashesToBackSlashesW(LPWSTR szBuffer);
  196. void DeleteDirectory(LPTSTR szPath);
  197. // Registry Functions
  198. void RegWriteKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPCTSTR szValue);
  199. BOOL RegReadKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPTSTR szValue, DWORD cBytes);
  200. void WriteOptionString(LPCTSTR szOption, LPCTSTR szValue);
  201. void WriteOptionInt(LPCTSTR szOption, DWORD dwValue);
  202. LPTSTR GetOptionString(LPCTSTR szOption, LPCTSTR szDefault, LPTSTR szValue, DWORD nSize);
  203. DWORD GetOptionInt(LPCTSTR szOption, DWORD dwDefault);
  204. // EDIT Control Subclass Functions
  205. void DisableEditing(HWND hWndEdit);
  206. LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  207. // MRU Functions
  208. void InitializeMRU();
  209. void AddFileToMRU(LPCSTR szFile);
  210. void RemoveFileFromMRU(LPCTSTR szFile);
  211. void ActivateMRU(UINT uIDItem);
  212. // Open Zip File Functions
  213. void ReadZipFileList(LPCWSTR wszPath);
  214. // Zip File Properties Dialog Functions
  215. BOOL CALLBACK DlgProcProperties(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  216. void MergeValues(int *p1, int p2);
  217. void CheckThreeStateBox(HWND hDlg, int nIDButton, int state);
  218. // Extract/Test Dialog Functions
  219. void ExtractOrTestFiles(BOOL fExtract);
  220. BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  221. // Folder Browsing Dialog Functions
  222. BOOL FolderBrowser(LPTSTR szPath, DWORD dwLength);
  223. BOOL CALLBACK DlgProcBrowser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  224. void SubclassSaveAsDlg();
  225. // Extraction/Test/View Progress Dialog Functions
  226. BOOL CALLBACK DlgProcExtractProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  227. BOOL CALLBACK DlgProcViewProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  228. void UpdateProgress(EXTRACT_INFO *pei, BOOL fFull);
  229. // Replace File Dialog Functions
  230. int PromptToReplace(LPCSTR szPath);
  231. BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  232. // Password Dialog Functions
  233. BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  234. // View Association Dialog Functions
  235. BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  236. // Comment Dialog Functions
  237. BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  238. // About Dialog Functions
  239. BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  240. //******************************************************************************
  241. //***** WinMain - Our one and only entry point
  242. //******************************************************************************
  243. // Entrypoint is a tiny bit different on Windows CE - UNICODE command line.
  244. #ifdef _WIN32_WCE
  245. extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
  246.                               LPTSTR lpCmdLine, int nCmdShow)
  247. #else
  248. extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  249.                               LPSTR lpCmdLine, int nCmdShow)
  250. #endif
  251. {
  252.    // Wrap the whole ball of wax in a big exception handler.
  253.    __try {
  254.       // Store global instance handle.
  255.       g_hInst = hInstance;
  256.       // Create our banner font.  We need to do this before creating our window.
  257.       // This font handle will be deleted in ShutdownApplication().
  258.       LOGFONT lf;
  259.       ZeroMemory(&lf, sizeof(lf));
  260.       lf.lfHeight = 16;
  261.       lf.lfWeight = FW_BOLD;
  262.       lf.lfCharSet = ANSI_CHARSET;
  263.       lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  264.       lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  265.       lf.lfQuality = DEFAULT_QUALITY;
  266.       lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
  267.       _tcscpy(lf.lfFaceName, TEXT("MS Sans Serif"));
  268.       g_hFontBanner = CreateFontIndirect(&lf);
  269.       // Define the window class for our application's main window.
  270.       WNDCLASS wc;
  271.       ZeroMemory(&wc, sizeof(wc));
  272.       wc.lpszClassName = g_szClass;
  273.       wc.hInstance     = hInstance;
  274.       wc.lpfnWndProc   = WndProc;
  275.       wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  276.       TCHAR *szZipPath = NULL;
  277. #ifdef _WIN32_WCE
  278.       // Get our main window's small icon.  On Windows CE, we need to send ourself
  279.       // a WM_SETICON in order for our task bar to update itself.
  280.       g_hIconMain = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_UNZIP), 
  281.                                      IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  282.       wc.hIcon = g_hIconMain;
  283.       // On Windows CE, we only need the WS_VISIBLE flag.
  284.       DWORD dwStyle = WS_VISIBLE;
  285.       // Get and store command line file (if any).
  286.       if (lpCmdLine && *lpCmdLine) {
  287.          szZipPath = lpCmdLine;
  288.       }
  289. #else
  290.       // On NT we add a cursor, icon, and nenu to our application's window class.
  291.       wc.hCursor      = LoadCursor(NULL, IDC_ARROW);
  292.       wc.hIcon        = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_UNZIP));
  293.       wc.lpszMenuName = MAKEINTRESOURCE(IDR_UNZIP);
  294.       // On Windows NT, we use the standard overlapped window style.
  295.       DWORD dwStyle = WS_OVERLAPPEDWINDOW;
  296.       TCHAR szBuffer[_MAX_PATH];
  297.       // Get and store command line file (if any).
  298.       if (lpCmdLine && *lpCmdLine) {
  299.          mbstowcs(szBuffer, lpCmdLine, countof(szBuffer));
  300.          szZipPath = szBuffer;
  301.       }
  302. #endif
  303.       // Register our window class with the OS.
  304.       if (!RegisterClass(&wc)) {
  305.          DebugOut(TEXT("RegisterClass() failed [%u]"), GetLastError());
  306.       }
  307.       // Create our main window using our registered window class.
  308.       g_hWndMain = CreateWindow(wc.lpszClassName, g_szAppName, dwStyle,
  309.                                 CW_USEDEFAULT, CW_USEDEFAULT, 
  310.                                 CW_USEDEFAULT, CW_USEDEFAULT,
  311.                                 NULL, NULL, hInstance, NULL);
  312.       // Quit now if we failed to create our main window.
  313.       if (!g_hWndMain) {
  314.          DebugOut(TEXT("CreateWindow() failed [%u]"), GetLastError());
  315.          ShutdownApplication();
  316.          return 0;
  317.       }
  318.       // Make sure our window is visible.  Really only needed for NT.
  319.       ShowWindow(g_hWndMain, nCmdShow);
  320.       // Load our keyboard accelerator shortcuts.
  321.       MSG    msg;
  322.       HACCEL hAccel = LoadAccelerators(g_hInst, MAKEINTRESOURCE(IDR_UNZIP));
  323.       DWORD  dwPaintFlags = 0;
  324.       // The message pump.  Loop until we get a WM_QUIT message.
  325.       while (GetMessage(&msg, NULL, 0, 0)) {
  326.       
  327.          // Check to see if this is an accelerator and handle it if neccessary.
  328.          if (!TranslateAccelerator(g_hWndMain, hAccel, &msg)) {
  329.             // If a normal message, then dispatch it to the correct window.
  330.             TranslateMessage(&msg);
  331.             DispatchMessage(&msg); 
  332.             // Wait until our application is up an visible before trying to
  333.             // initialize some of our structures and load any command line file.
  334.             if ((msg.message == WM_PAINT) && (dwPaintFlags != 0x11)) {
  335.                if (msg.hwnd == g_hWndWaitFor) {
  336.                   dwPaintFlags |= 0x01;
  337.                } else if (msg.hwnd == g_hWndList) {
  338.                   dwPaintFlags |= 0x10;
  339.                }
  340.                if (dwPaintFlags == 0x11) {
  341.                   InitializeApplication((szZipPath && *szZipPath) ? 
  342.                                         szZipPath : NULL);
  343.                }
  344.             }
  345.          }
  346.       }
  347.       // Clean up code.
  348.       ShutdownApplication();
  349.       // Nice clean finish - were out of here.
  350.       return msg.wParam;
  351.    } __except(EXCEPTION_EXECUTE_HANDLER) {
  352.       // Something very bad happened.  Try our best to appear somewhat graceful.
  353.       MessageBox(NULL, 
  354.          TEXT("An internal error occurred.  Possible causes are that you are ")
  355.          TEXT("out of memory, a ZIP file (if one is loaded) contains an ")
  356.          TEXT("unexpected error, or there is a bug in our program (that's why ")
  357.          TEXT("it's free).  Pocket UnZip cannot continue.  It will exit now, ")
  358.          TEXT("but you may restart it and try again.nn")
  359.          TEXT("If the problem persists, please write to stevemil@pobox.com with ")
  360.          TEXT("any information that might help track down the problem."),
  361.          g_szAppName, MB_ICONERROR | MB_OK);
  362.    }
  363.    return 1;
  364. }
  365. //******************************************************************************
  366. //***** Startup and Shutdown Functions
  367. //******************************************************************************
  368. void InitializeApplication(LPCTSTR szZipFile) {
  369.    // This function is called after our class is registered and all our windows
  370.    // are created and visible to the user.
  371.    // Show hour glass cursor.
  372.    HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  373.    // Register UnZip in the registry to handle ".ZIP" files.
  374.    RegisterUnzip();
  375.    // Enumerate the system file assoications and build an image list.
  376.    BuildImageList();
  377.    // Load our initial MRU into our menu.
  378.    InitializeMRU();
  379.    // Restore/remove our cursor.
  380.    SetCursor(hCur);
  381.    // Clear our initialization window handle.
  382.    g_hWndWaitFor = NULL;
  383.    // Load our command line file if one was specified. Otherwise, just update
  384.    // our banner to show that no file is loaded.
  385.    if (szZipFile) {
  386.       ReadZipFileList(szZipFile);
  387.    } else {
  388.       DrawBanner(NULL);
  389.    }
  390.    // Enable some controls.
  391.    EnableAllMenuItems(IDM_FILE_OPEN,          TRUE);
  392.    EnableAllMenuItems(IDM_FILE_CLOSE,         TRUE);
  393.    EnableAllMenuItems(IDM_VIEW_EXPANDED_VIEW, TRUE);
  394.    EnableAllMenuItems(IDM_HELP_ABOUT,         TRUE);
  395.    // Set our temporary directory.
  396. #ifdef _WIN32_WCE
  397.    g_szTempDir = TEXT("\Temporary Pocket UnZip Files");
  398. #else 
  399.    g_szTempDir = TEXT("C:\Temporary Pocket UnZip Files");
  400.    // Set the drive to be the same drive as the OS installation is on.
  401.    TCHAR szPath[_MAX_PATH];
  402.    if (GetWindowsDirectory(szPath, countof(szPath))) {
  403.       *((LPTSTR)g_szTempDir) = *szPath;
  404.    }
  405. #endif
  406. }
  407. //******************************************************************************
  408. void ShutdownApplication() {
  409.    
  410.    // Free our banner font.
  411.    if (g_hFontBanner) {
  412.       DeleteObject(g_hFontBanner);
  413.       g_hFontBanner = NULL;
  414.    }
  415.    // Delete our FILE_TYPE_NODE linked list.
  416.    for (FILE_TYPE_NODE *pft = g_pftHead; pft; ) {
  417.       FILE_TYPE_NODE *pftNext = pft->pNext;
  418.       delete[] (BYTE*)pft;
  419.       pft = pftNext;
  420.    }
  421.    g_pftHead = NULL;
  422.    // If there are no other instances of our application open, then delete our
  423.    // temporary directory and all the files in it.  Any files opened for viewing
  424.    // should be locked and will fail to delete.  This is to be expected.
  425.    if (g_szTempDir && (FindWindow(g_szClass, NULL) == NULL)) {
  426.       TCHAR szPath[_MAX_PATH];
  427.       _tcscpy(szPath, g_szTempDir);
  428.       DeleteDirectory(szPath);
  429.    }
  430. }
  431. //******************************************************************************
  432. void RegisterUnzip() {
  433. #ifdef _WIN32_WCE
  434.    // WARNING!  Since Windows CE does not support any way to get your binary's
  435.    // name at runtime, we have to hard-code in "punzip.exe".  If our binary is
  436.    // not named this or is in a non-path directory, then we will fail to
  437.    // register ourself with the system as the default application to handle
  438.    // ".zip" files.
  439.    TCHAR szPath[32] = TEXT("punzip.exe");
  440. #else
  441.    // Get our module's path and file name.  We use the short path name for the
  442.    // registry because it is guarenteed to contain no spaces.
  443.    TCHAR szLongPath[_MAX_PATH];
  444.    TCHAR szPath[_MAX_PATH];
  445.    GetModuleFileName(NULL, szLongPath, countof(szLongPath));
  446.    GetShortPathName(szLongPath, szPath, countof(szPath));
  447. #endif
  448.    // Store a pointer to the end of our path for easy appending.
  449.    LPTSTR szEnd = szPath + _tcslen(szPath);
  450.    // Associate "ZIP" file extensions to our application
  451.    RegWriteKey(HKEY_CLASSES_ROOT, TEXT(".zip"), TEXT("zipfile"));
  452.    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile"), TEXT("ZIP File"));
  453.    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\shell"), NULL);
  454.    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\shell\Open"), NULL);
  455.    _tcscpy(szEnd, TEXT(" %1"));
  456.    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\shell\Open\command"), szPath);
  457.    // Register our program icon for all ZIP files.
  458.    _stprintf(szEnd, TEXT(",-%u"), IDI_ZIPFILE);
  459.    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\DefaultIcon"), szPath);
  460.    // Create our application option location.
  461.    RegWriteKey(HKEY_CURRENT_USER, TEXT("Software"), NULL);
  462.    RegWriteKey(HKEY_CURRENT_USER, g_szRegKey, NULL);
  463. }
  464. //******************************************************************************
  465. void BuildImageList() {
  466.    // Create our global image list.
  467. #ifdef _WIN32_WCE
  468.  
  469.    // On Windows CE, we can't spare a color for the mask, so we have to create
  470.    // the mask in a separate monochrome bitmap.
  471.    HIMAGELIST hil = ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 8, 8);
  472.    // Load our default bitmaps into the image list.
  473.    HBITMAP hBmpImageList = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST));
  474.    HBITMAP hBmpMask = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST_MASK));
  475.    ImageList_Add(hil, hBmpImageList, hBmpMask);
  476.    DeleteObject(hBmpImageList);
  477.    DeleteObject(hBmpMask);
  478. #else
  479.    // On Windows NT, we use magenta as a transparency mask color.
  480.    HIMAGELIST hil = ImageList_LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST),
  481.                                          16, 8, RGB(255, 0, 255));
  482. #endif
  483.    // Set up for our registry file type enumeration.
  484.    FILE_TYPE_NODE *pftLast = NULL;
  485.    TCHAR szExtension[128], szKey[128], szDescription[_MAX_PATH], szIconFile[_MAX_PATH + 16];
  486.    DWORD dwIndex = 0, dwCount = countof(szExtension);
  487.    // Enumerate all the keys immediately under HKEY_CLASSES_ROOT.
  488.    while (ERROR_SUCCESS == RegEnumKeyEx(HKEY_CLASSES_ROOT, dwIndex++, szExtension, 
  489.                                         &dwCount, NULL, NULL, NULL, NULL))
  490.    {
  491.       dwCount = countof(szExtension);
  492.       // Check to see if we read an extension key (starts with a period)
  493.       if (*szExtension != TEXT('.')) {
  494.          continue;
  495.       }
  496.       // Read the actual key name for this extension.
  497.       if (!RegReadKey(HKEY_CLASSES_ROOT, szExtension, szKey, sizeof(szKey))) {
  498.          continue;
  499.       }
  500.       // Read the Description for this extension.
  501.       RegReadKey(HKEY_CLASSES_ROOT, szKey, szDescription, sizeof(szDescription));
  502.       HICON hIcon = NULL;
  503.       LPTSTR szEnd = szKey + _tcslen(szKey);
  504.       // Attempt to get an icon for this extension from the "DefaultIcon" key.
  505.       _tcscpy(szEnd, TEXT("\DefaultIcon"));
  506.       if (RegReadKey(HKEY_CLASSES_ROOT, szKey, szIconFile, sizeof(szIconFile))) {
  507.          // Look for the comma between the file name and the image.
  508.          LPTSTR szImageId = _tcschr(szIconFile, TEXT(','));
  509.          if (szImageId) {
  510.             // NULL terminate the file name portion of szIconFile.
  511.             *(szImageId++) = TEXT('');
  512.             // Get the image ID value from szIconFile.
  513.             int imageId = _ttoi(szImageId);
  514.             // Extract the icon from the module specified in szIconFile.
  515.             ExtractIconEx(szIconFile, imageId, NULL, &hIcon, 1);
  516.             if (hIcon == NULL) {
  517.                ExtractIconEx(szIconFile, imageId, &hIcon, NULL, 1);
  518.             }
  519.          }
  520.       }
  521.       // If we failed to get the icon using the "DefaultIcon" key, then try
  522.       // using the "shellOpencommand" key.
  523.       if (hIcon == NULL) {
  524.          _tcscpy(szEnd, TEXT("\shell\Open\command"));
  525.          if (RegReadKey(HKEY_CLASSES_ROOT, szKey, szIconFile, sizeof(szIconFile))) {
  526.             // Get a pointer to just the binary - strip quotes and spaces.
  527.             LPTSTR szPath;
  528.             if (*szIconFile == TEXT('"')) {
  529.                szPath = szIconFile + 1;
  530.                if (szEnd = _tcschr(szPath, TEXT('"'))) {
  531.                   *szEnd = TEXT('');
  532.                }
  533.             } else {
  534.                szPath = szIconFile;
  535.                if (szEnd = _tcschr(szPath, TEXT(' '))) {
  536.                   *szEnd = TEXT('');
  537.                }
  538.             }
  539.             // Extract the icon from the module specified in szIconFile.
  540.             ExtractIconEx(szPath, 0, NULL, &hIcon, 1);
  541.             if (hIcon == NULL) {
  542.                ExtractIconEx(szPath, 0, &hIcon, NULL, 1);
  543.             }
  544.          }
  545.       }
  546.       // If we found an icon, add it to our image list.
  547.       int image = -1;
  548.       if (hIcon) {
  549.          image = ImageList_AddIcon(hil, hIcon);
  550.       }
  551.       // If no icon could be found, then check to see if this is an executable.
  552.       if ((image == -1) && (
  553. #ifndef _WIN32_WCE // Windows CE only recognizes EXE's as executable.
  554.          !_tcsicmp(szExtension + 1, TEXT("bat")) ||
  555.          !_tcsicmp(szExtension + 1, TEXT("cmd")) ||
  556.          !_tcsicmp(szExtension + 1, TEXT("com")) ||
  557. #endif
  558.          !_tcsicmp(szExtension + 1, TEXT("exe"))))
  559.       {
  560.          image = IMAGE_APPLICATION;
  561.       }
  562.       // If we don't have a description or a icon, then bail on this extension.
  563.       if (!*szDescription && (image < 0)) {
  564.          continue;
  565.       }
  566.          
  567.       // Create our FILE_TYPE_NODE.
  568.       int length = _tcslen(szExtension) - 1 + _tcslen(szDescription);
  569.       FILE_TYPE_NODE *pft = (FILE_TYPE_NODE*) new BYTE[
  570.          sizeof(FILE_TYPE_NODE) + (sizeof(TCHAR) * length)];
  571.       // Bail out if we could not create our node.
  572.       if (!pft) {
  573.          DebugOut(TEXT("Not enough memory to create a FILE_TYPE_NODE."));
  574.          continue;
  575.       }
  576.       // Fill in the node.
  577.       pft->pNext = NULL;
  578.       pft->image = (image >= 0) ? image : IMAGE_GENERIC;
  579.       wcstombs(pft->szExtAndDesc, szExtension + 1, length + 3);
  580.       wcstombs(pft->szExtAndDesc + strlen(pft->szExtAndDesc) + 1, 
  581.                szDescription, length + 3);
  582.       // Add the node to our list.
  583.       if (pftLast) {
  584.          pftLast->pNext = pft;
  585.       } else {
  586.          g_pftHead = pft;
  587.       }
  588.       pftLast = pft;
  589.    }
  590.    // Assign this image list to our tree control.
  591.    ListView_SetImageList(g_hWndList, hil, LVSIL_SMALL);
  592. }
  593. //******************************************************************************
  594. //***** Our Main Window's Message Handler
  595. //******************************************************************************
  596. LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  597.    switch(uMsg) {
  598.       case WM_CREATE:
  599.          g_hWndMain = hWnd;
  600.          return OnCreate();
  601.       case WM_ERASEBKGND:
  602.          DrawBanner((HDC)wParam);
  603.          return 0;
  604.       case WM_SIZE:
  605.          // Resize our list view control to match our client area.
  606.          MoveWindow(g_hWndList, 0, g_cyCmdBar + 22, LOWORD(lParam), 
  607.                     HIWORD(lParam) - (g_cyCmdBar + 22), TRUE);
  608. #ifndef _WIN32_WCE
  609.          // On NT we have to resize our toolbar as well.
  610.          MoveWindow(g_hWndCmdBar, 0, 0, LOWORD(lParam), g_cyCmdBar, TRUE);
  611. #endif
  612.          return 0;
  613.       
  614.       case WM_SETFOCUS:
  615.          // Always direct focus to our list control.
  616.          SetFocus(g_hWndList);
  617.          return 0;
  618.       case WM_DESTROY:
  619.          PostQuitMessage(0);
  620.          return 0;
  621.       
  622.       case WM_HELP:
  623.          OnHelp();
  624.          return 0;
  625.       case WM_PRIVATE:
  626.          switch (wParam) {
  627. #ifdef _WIN32_WCE
  628.             case MSG_SUBCLASS_DIALOG:
  629.                SubclassSaveAsDlg();
  630.                return 0;
  631. #endif
  632.             case MSG_ADD_TEXT_TO_EDIT:
  633.                AddTextToEdit((LPCSTR)lParam);
  634.                return 0;
  635.             
  636.             case MSG_PROMPT_TO_REPLACE:
  637.                return PromptToReplace((LPCSTR)lParam);
  638. #if CRYPT
  639.             case MSG_PROMPT_FOR_PASSWORD:
  640.                return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_PASSWORD),
  641.                                      g_hDlgProgress, (DLGPROC)DlgProcPassword,
  642.                                      lParam);
  643. #endif
  644.             case MSG_UPDATE_PROGRESS_PARTIAL:
  645.                UpdateProgress((EXTRACT_INFO*)lParam, FALSE);
  646.                return 0;
  647.             case MSG_UPDATE_PROGRESS_COMPLETE:
  648.                UpdateProgress((EXTRACT_INFO*)lParam, TRUE);
  649.                return 0;
  650.          }
  651.          return 0;
  652.       case WM_NOTIFY:
  653.          switch (((LPNMHDR)lParam)->code) {
  654.             case LVN_GETDISPINFO:
  655.                OnGetDispInfo((LV_DISPINFO*)lParam);
  656.                return 0;
  657.             case LVN_DELETEITEM:
  658.                OnDeleteItem((NM_LISTVIEW*)lParam);
  659.                return 0;
  660.             case LVN_COLUMNCLICK:
  661.                Sort(((NM_LISTVIEW*)lParam)->iSubItem, FALSE);
  662.                return 0;
  663.             case LVN_ITEMCHANGED:
  664.                OnItemChanged((NM_LISTVIEW*)lParam);
  665.                return 0;
  666.             case NM_DBLCLK:
  667.             case NM_RETURN:
  668.                OnActionView();
  669.                return 0;
  670.          }
  671.          return 0;
  672.       case WM_COMMAND:
  673.          switch (LOWORD(wParam)) {
  674.             case IDM_FILE_OPEN:
  675.                OnFileOpen();
  676.                return 0;
  677.             
  678.             case IDM_FILE_PROPERTIES:
  679.                DialogBox(g_hInst, MAKEINTRESOURCE(IDD_PROPERTIES), hWnd, (DLGPROC)DlgProcProperties);
  680.                return 0;
  681.             case IDM_FILE_CLOSE:
  682.                SendMessage(hWnd, WM_CLOSE, 0, 0);
  683.                return 0;
  684.             case IDM_ACTION_EXTRACT_ALL:
  685.                OnActionSelectAll();
  686.                // Fall through to IDM_ACTION_EXTRACT
  687.             case IDM_ACTION_EXTRACT:
  688.                ExtractOrTestFiles(TRUE);
  689.                return 0;
  690.             case IDM_ACTION_TEST_ALL:
  691.                OnActionSelectAll();
  692.                // Fall through to IDM_ACTION_TEST
  693.             case IDM_ACTION_TEST:
  694.                ExtractOrTestFiles(FALSE);
  695.                return 0;
  696.             case IDM_ACTION_VIEW:
  697.                OnActionView();
  698.                return 0;
  699.             case IDM_ACTION_SELECT_ALL:
  700.                OnActionSelectAll();
  701.                return 0;
  702.             case IDM_VIEW_EXPANDED_VIEW:
  703.                OnViewExpandedView();
  704.                return 0;
  705.             case IDM_VIEW_COMMENT:
  706.                DialogBox(g_hInst, MAKEINTRESOURCE(IDD_COMMENT), hWnd, (DLGPROC)DlgProcComment);
  707.                return 0;
  708.             case IDM_HELP_ABOUT:
  709.                DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)DlgProcAbout);
  710.                return 0;
  711.             case IDHELP:
  712.                return SendMessage(hWnd, WM_HELP, 0, 0);
  713.             default:
  714.                // Check to see if a MRU file was selected.
  715.                if ((LOWORD(wParam) >= MRU_START_ID) && 
  716.                    (LOWORD(wParam) < (MRU_START_ID + MRU_MAX_FILE)))
  717.                {
  718.                   ActivateMRU(LOWORD(wParam));
  719.                }
  720.          }
  721.     }
  722.     return DefWindowProc(hWnd, uMsg, wParam, lParam);
  723. }          
  724. //******************************************************************************
  725. //***** Event Handlers for our Main Window
  726. //******************************************************************************
  727. int OnCreate() {
  728.    // Our toolbar buttons.
  729.    static TBBUTTON tbButton[] = {
  730.       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
  731.       { 0, IDM_FILE_OPEN,          0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
  732.       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
  733.       { 1, IDM_FILE_PROPERTIES,    0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
  734.       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
  735.       { 2, IDM_ACTION_EXTRACT,     0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
  736.       { 3, IDM_ACTION_EXTRACT_ALL, 0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
  737.       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
  738.       { 4, IDM_ACTION_TEST,        0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
  739.       { 5, IDM_ACTION_TEST_ALL,    0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
  740.       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
  741.       { 6, IDM_ACTION_VIEW,        0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
  742.       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
  743.       { 7, IDM_VIEW_EXPANDED_VIEW, 0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
  744.       { 8, IDM_VIEW_COMMENT,       0, TBSTYLE_BUTTON, 0, 0, 0, -1 }
  745.    };
  746.    // Our toolbar buttons' tool tip text.
  747.    static LPTSTR szToolTips[] = {
  748.        TEXT(""),  // Menu
  749.        TEXT("Open (Ctrl+O)"),
  750.        TEXT("Properties (Alt+Enter)"),
  751.        TEXT("Extract Selected Files"),
  752.        TEXT("Extract All Files"),
  753.        TEXT("Test Selected Files"),
  754.        TEXT("Test All Files"),
  755.        TEXT("View Selected File"),
  756.        TEXT("Expanded View"),
  757.        TEXT("View Zip File Comment")
  758.    };
  759.    // Initialize the common controls.
  760.    InitCommonControls();
  761.    // Check to see if we have a help file.
  762.    BOOL fHelp = (GetFileAttributes(g_szHelpFile) != 0xFFFFFFFF);
  763.    // Set our window's icon so it can update the task bar.
  764.    if (g_hIconMain) {
  765.       SendMessage(g_hWndMain, WM_SETICON, FALSE, (LPARAM)g_hIconMain);
  766.    }
  767.    // Create the tree control.  Our main window will resize it to fit.
  768.    g_hWndList = CreateWindow(WC_LISTVIEW, TEXT(""),
  769.                              WS_VSCROLL | WS_CHILD | WS_VISIBLE | 
  770.                              LVS_REPORT | LVS_SHOWSELALWAYS,
  771.                              0, 0, 0, 0, g_hWndMain, NULL, g_hInst, NULL);
  772. #ifdef _WIN32_WCE
  773.    // Create a command bar and add the toolbar bitmaps to it.
  774.    g_hWndCmdBar = CommandBar_Create(g_hInst, g_hWndMain, 1);
  775.    CommandBar_AddBitmap(g_hWndCmdBar, g_hInst, IDB_TOOLBAR, 9, 16, 16);
  776.    CommandBar_InsertMenubar(g_hWndCmdBar, g_hInst, IDR_UNZIP, 0);
  777.    CommandBar_AddButtons(g_hWndCmdBar, countof(tbButton), tbButton);
  778.    CommandBar_AddAdornments(g_hWndCmdBar, fHelp ? CMDBAR_HELP : 0, 0);
  779.    // Add tool tips to the tool bar.
  780.    CommandBar_AddToolTips(g_hWndCmdBar, countof(szToolTips), szToolTips);
  781.    // Store the height of the command bar for later calculations.
  782.    g_cyCmdBar = CommandBar_Height(g_hWndCmdBar);
  783.    // We set our wait window handle to our menu window within our command bar.
  784.    // This is the last window that will be painted during startup of our app.
  785.    g_hWndWaitFor = GetWindow(g_hWndCmdBar, GW_CHILD);
  786.    // Add the help item to our help menu if we have a help file.
  787.    if (fHelp) {
  788.       HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 3);
  789.       InsertMenu(hMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
  790.       InsertMenu(hMenu, 0, MF_BYPOSITION | MF_ENABLED, IDHELP, TEXT("&Help"));
  791.    }
  792. #else
  793.    // Create a tool bar and add the toolbar bitmaps to it.
  794.    g_hWndCmdBar = CreateToolbarEx(g_hWndMain, WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS,
  795.                                   1, 9, g_hInst, IDB_TOOLBAR, tbButton, 
  796.                                   countof(tbButton), 16, 16, 16, 16, 
  797.                                   sizeof(TBBUTTON));
  798.    // Get our tool tip control.
  799.    HWND hWndTT = (HWND)SendMessage(g_hWndCmdBar, TB_GETTOOLTIPS, 0, 0);
  800.    // Set our tool tip strings.
  801.    TOOLINFO ti;
  802.    ti.cbSize = sizeof(ti);
  803.    int tip = 0, button; 
  804.    while (SendMessage(hWndTT, TTM_ENUMTOOLS, tip++, (LPARAM)&ti)) {
  805.       for (button = 0; button < countof(tbButton); button++) {
  806.          if (tbButton[button].idCommand == (int)ti.uId) {
  807.             ti.lpszText = szToolTips[tbButton[button].iBitmap + 1];
  808.             SendMessage(hWndTT, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
  809.             break;
  810.          }
  811.       }
  812.    }
  813.    // Store the height of the tool bar for later calculations.
  814.    RECT rc;
  815.    GetWindowRect(g_hWndCmdBar, &rc);
  816.    g_cyCmdBar = rc.bottom - rc.top;
  817.    // We set our wait window handle to our toolbar.
  818.    // This is the last window that will be painted during the startup of our app.
  819.    g_hWndWaitFor = g_hWndCmdBar;
  820.    // Add the help item to our help menu if we have a help file.
  821.    if (fHelp) {
  822.       HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 3);
  823.       InsertMenu(hMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
  824.       InsertMenu(hMenu, 0, MF_BYPOSITION | MF_ENABLED, IDHELP, TEXT("&HelptF1"));
  825.    }
  826. #endif // _WIN32_WCE
  827.    // Enable Full Row Select - This feature is supported on Windows CE and was
  828.    // introduced to Win95/NT with IE 3.0.  If the user does not have a 
  829.    // COMCTL32.DLL that supports this feature, then they will just see the 
  830.    // old standard First Column Select.
  831.    SendMessage(g_hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT |
  832.                SendMessage(g_hWndList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0));
  833.   
  834.    // Get our expanded view option from the registry.
  835.    g_fExpandedView = GetOptionInt(TEXT("ExpandedView"), FALSE);
  836.    // Show or remove menu check for expanded view option.
  837.    CheckAllMenuItems(IDM_VIEW_EXPANDED_VIEW, g_fExpandedView);
  838.    // Create our columns.
  839.    AddDeleteColumns();
  840.    // Set our current sort column to our name column
  841.    Sort(0, TRUE);
  842.    return 0;
  843. }
  844. //******************************************************************************
  845. void OnFileOpen() {
  846.    TCHAR szPath[_MAX_PATH] = TEXT("");
  847.    OPENFILENAME ofn;
  848.    ZeroMemory(&ofn, sizeof(ofn));
  849.    ofn.lStructSize  = sizeof(ofn);
  850.    ofn.hwndOwner    = g_hWndMain;
  851.    ofn.hInstance    = g_hInst;
  852.    ofn.lpstrFilter  = TEXT("ZIP files (*.zip)*.zipSFX files (*.exe)*.exeAll Files (*.*)*.*");
  853.    ofn.nFilterIndex = 1;
  854.    ofn.lpstrFile    = szPath;
  855.    ofn.nMaxFile     = countof(szPath);
  856.    ofn.Flags        = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
  857.    ofn.lpstrDefExt  = TEXT("zip");
  858.    if (GetOpenFileName(&ofn)) {
  859.       ReadZipFileList(szPath);
  860.    }
  861. }
  862. //******************************************************************************
  863. void OnActionView() {
  864.    // We only allow a view if one item is selected.
  865.    int count = ListView_GetSelectedCount(g_hWndList);
  866.    if (count != 1) {
  867.       return;
  868.    }
  869.    // Query the selected item for its FILE_NODE.
  870.    LV_ITEM lvi;
  871.    ZeroMemory(&lvi, sizeof(lvi));
  872.    lvi.mask = LVIF_IMAGE | LVIF_PARAM;
  873.    lvi.iItem = ListView_GetNextItem(g_hWndList, -1, LVNI_SELECTED);
  874.    ListView_GetItem(g_hWndList, &lvi);
  875.    FILE_NODE *pfn = (FILE_NODE*)lvi.lParam;
  876.    // Bail out if the selected item is a folder or volume label.
  877.    if (pfn->dwAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_VOLUME)) {
  878.       MessageBox(g_hWndMain, TEXT("You cannot view folders or volume labels."), 
  879.                  g_szAppName, MB_ICONINFORMATION | MB_OK);
  880.       return;
  881.    }
  882.    // Make sure our temporary directory exists.
  883.    CreateDirectory(g_szTempDir, NULL);
  884.    TCHAR szPath[_MAX_PATH + 256];
  885.    // Set our extraction directory to our temporary directory.
  886.    if (!SetExtractToDirectory((LPTSTR)g_szTempDir)) {
  887.       
  888.       // Create error message.  Use szPath buffer because it is handy.
  889.       _stprintf(szPath,
  890.          TEXT("Could not create "%s"nn")
  891.          TEXT("Most likely cause is that your drive is full."),
  892.          g_szTempDir);
  893.       // Display error message.
  894.       MessageBox(g_hWndMain, szPath, g_szAppName, MB_ICONERROR | MB_OK);
  895.       return;
  896.    }
  897.    // Create our single item file array.
  898.    CHAR *argv[2] = { pfn->szPathAndMethod, NULL };
  899.    // Create a buffer to store the mapped name of the file.  If the has to be
  900.    // renamed to be compatible with our file system, then we need to know that
  901.    // new name in order to open it correctly.
  902.    CHAR szMappedPath[_MAX_PATH];
  903.    *szMappedPath = '';
  904.    // Configure our extract structure.
  905.    EXTRACT_INFO ei;
  906.    ZeroMemory(&ei, sizeof(ei));
  907.    ei.fExtract      = TRUE;
  908.    ei.dwFileCount   = 1;
  909.    ei.dwByteCount   = pfn->dwSize;
  910.    ei.szFileList    = argv;
  911.    ei.fRestorePaths = FALSE;
  912.    ei.overwriteMode = OM_PROMPT;
  913.    ei.szMappedPath  = szMappedPath;
  914.    // Clear our skipped flag and set our viewing flag.
  915.    g_fSkipped = FALSE;
  916.    g_fViewing = TRUE;
  917.    // Display our progress dialog and do the extraction.
  918.    DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_VIEW_PROGRESS), g_hWndMain, 
  919.                   (DLGPROC)DlgProcViewProgress, (LPARAM)&ei);
  920.    // Clear our viewing flag.
  921.    g_fViewing = FALSE;
  922.    // Check to see if the user skipped the file by aborting the decryption or
  923.    // overwrite prompts.  The only other case that causes us to skip a file
  924.    // is when the user enters the incorrect password too many times.  In this
  925.    // case, IZ_BADPWD will be returned.
  926.    if (g_fSkipped) {
  927.       return;
  928.    }
  929.    if (ei.result == IZ_BADPWD) {
  930.       MessageBox(g_hWndMain, TEXT("Password was incorrect.  The file has been skipped."),
  931.                  g_szAppName, MB_ICONWARNING | MB_OK);
  932.       return;
  933.    }
  934.    // Check to see if the extraction failed.
  935.    if (ei.result != PK_OK) {
  936.       if (ei.result == PK_ABORTED) {
  937.          _tcscpy(szPath, GetZipErrorString(ei.result));
  938.       } else {
  939.          // Create error message.  Use szPath buffer because it is handy.
  940.          _stprintf(szPath,
  941.             TEXT("Could not extract "%S".nn%snnTry using the Test or ")
  942.             TEXT("Extract action on the file for more details."),
  943.             *szMappedPath ? szMappedPath : pfn->szPathAndMethod,
  944.             GetZipErrorString(ei.result));
  945.       }
  946.       // Display error message.
  947.       MessageBox(g_hWndMain, szPath, g_szAppName, MB_ICONERROR | MB_OK);
  948.       // If we managed to create a bad file, then delete it.
  949.       if (*szMappedPath) {
  950.          mbstowcs(szPath, szMappedPath, countof(szPath));
  951.          SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
  952.          if (!DeleteFile(szPath)) {
  953.             SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
  954.          }
  955.       }
  956.       return;
  957.    }
  958.    // Convert the file name to UNICODE.
  959.    mbstowcs(szPath, szMappedPath, countof(szPath));
  960.    // Prepare to launch the file.
  961.    SHELLEXECUTEINFO sei;
  962.    ZeroMemory(&sei, sizeof(sei));
  963.    sei.cbSize      = sizeof(sei);
  964.    sei.hwnd        = g_hWndMain;
  965.    sei.lpDirectory = g_szTempDir;
  966.    sei.nShow       = SW_SHOWNORMAL;
  967. #ifdef _WIN32_WCE
  968.    TCHAR szApp[_MAX_PATH];
  969.    // On Windows CE, there is no default file association dialog that appears
  970.    // when ShellExecuteEx() is given an unknown file type.  We check to see if
  971.    // file is unknown, and display our own file association prompt.
  972.    // Check our file image to see if this file has no associated viewer.
  973.    if (lvi.iImage == IMAGE_GENERIC) {
  974.       // Display our file association prompt dialog.
  975.       if (IDOK != DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_VIEW_ASSOCIATION),
  976.                                  g_hWndMain, (DLGPROC)DlgProcViewAssociation,
  977.                                  (LPARAM)szApp))
  978.       {
  979.          // If the user aborted the association prompt, then delete file and exit.
  980.          SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
  981.          if (!DeleteFile(szPath)) {
  982.             SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
  983.          }
  984.          return;
  985.       }
  986.       // Set the file to be the viewer app and the parameters to be the file.
  987.       // Note: Some applications require that arguments with spaces be quoted,
  988.       // while other applications choked when quotes we part of the filename.
  989.       // In the end, it seems safer to leave the quotes off.
  990.       sei.lpFile = szApp;
  991.       sei.lpParameters = szPath;
  992.    } else {
  993.       sei.lpFile = szPath;
  994.    }
  995. #else
  996.    // On NT, ShellExecuteEx() will prompt user for association if needed.
  997.    sei.lpFile = szPath;
  998. #endif
  999.    // Launch the file.  All errors will be displayed by ShellExecuteEx().
  1000.    ShellExecuteEx(&sei);
  1001. }
  1002. //******************************************************************************
  1003. void OnActionSelectAll() {
  1004.    for (int i = ListView_GetItemCount(g_hWndList) - 1; i >= 0; i--) {
  1005.       ListView_SetItemState(g_hWndList, i, LVIS_SELECTED, LVIS_SELECTED);
  1006.    }
  1007. }
  1008. //******************************************************************************
  1009. void OnViewExpandedView() {
  1010.    // Toggle our expanded view option.
  1011.    g_fExpandedView = !g_fExpandedView;
  1012.    // Show or remove menu check and toolbar button press.
  1013.    CheckAllMenuItems(IDM_VIEW_EXPANDED_VIEW, g_fExpandedView);
  1014.    // Display the new columns.
  1015.    AddDeleteColumns();
  1016.    // Re-sort if we just did away with out sort column.
  1017.    if (!g_fExpandedView && (g_sortColumn > 3)) {
  1018.       Sort(0, TRUE);
  1019.    }
  1020.    // Write our expanded view option to the registry.
  1021.    WriteOptionInt(TEXT("ExpandedView"), g_fExpandedView);
  1022. }
  1023. //******************************************************************************
  1024. void OnHelp() {
  1025.    // Prepare to launch the help file.
  1026.    SHELLEXECUTEINFO sei;
  1027.    ZeroMemory(&sei, sizeof(sei));
  1028.    sei.cbSize      = sizeof(sei);
  1029.    sei.hwnd        = g_hWndMain;
  1030.    sei.lpFile      = g_szHelpFile;
  1031.    // Launch the file.
  1032.    ShellExecuteEx(&sei);
  1033. }
  1034. //******************************************************************************
  1035. //***** Event Handlers for our List View
  1036. //******************************************************************************
  1037. void OnGetDispInfo(LV_DISPINFO *plvdi) {
  1038.    // Make sure we have the minimum amount of data to process this event.
  1039.    if ((plvdi->item.iItem < 0) || !plvdi->item.lParam || !plvdi->item.pszText) {
  1040.       return;
  1041.    }
  1042.    // Get a pointer to the file node for this item.
  1043.    FILE_NODE *pFile = (FILE_NODE*)plvdi->item.lParam;
  1044.    CHAR szBuffer[_MAX_PATH * 2];
  1045.    switch (plvdi->item.iSubItem) {
  1046.       case 0: // Name
  1047.          // Copy the string to a new string while removing all non-printables.
  1048.          fnfilter(pFile->szPathAndMethod, (uch*)szBuffer);
  1049.          // Change all forward slashes to back slashes in the buffer
  1050.          ForwardSlashesToBackSlashesA(szBuffer);
  1051.          // Convert the string to UNICODE and store it in our list control.
  1052.          mbstowcs(plvdi->item.pszText, szBuffer, plvdi->item.cchTextMax);
  1053.          return;
  1054.       case 1: // Size
  1055.          FormatValue(plvdi->item.pszText, pFile->dwSize);
  1056.          return;
  1057.       case 2: // Type
  1058.          mbstowcs(plvdi->item.pszText, BuildTypeString(pFile, szBuffer), 
  1059.                   plvdi->item.cchTextMax);
  1060.          return;
  1061.       case 3: // Modified
  1062.          int hour; hour = (pFile->dwModified >> 6) & 0x001F;
  1063.          _stprintf(plvdi->item.pszText, TEXT("%u/%u/%u %u:%02u %cM"),
  1064.                    (pFile->dwModified  >> 16) & 0x000F,
  1065.                    (pFile->dwModified  >> 11) & 0x001F,
  1066.                    ((pFile->dwModified >> 20) & 0x0FFF) % 100,
  1067.                    (hour % 12) ? (hour % 12) : 12,
  1068.                    pFile->dwModified & 0x003F,
  1069.                    hour >= 12 ? 'P' : 'A');
  1070.          return;
  1071.       case 4: // Attributes
  1072.          BuildAttributesString(plvdi->item.pszText, pFile->dwAttributes);
  1073.          return;
  1074.       case 5: // Compressed
  1075.          FormatValue(plvdi->item.pszText, pFile->dwCompressedSize);
  1076.          return;
  1077.       case 6: // Ratio
  1078.          int factor; factor = ratio(pFile->dwSize, pFile->dwCompressedSize);
  1079.          _stprintf(plvdi->item.pszText, TEXT("%d.%d%%"), factor / 10, 
  1080.                    ((factor < 0) ? -factor : factor) % 10);
  1081.          return;
  1082.       case 7: // Method
  1083.          mbstowcs(plvdi->item.pszText, pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1, 
  1084.                   plvdi->item.cchTextMax);
  1085.          return;
  1086.       case 8: // CRC
  1087.          _stprintf(plvdi->item.pszText, L"%08X", pFile->dwCRC);
  1088.          return;
  1089.       case 9: // Comment
  1090.          mbstowcs(plvdi->item.pszText, pFile->szComment ? pFile->szComment : "",
  1091.                   plvdi->item.cchTextMax);
  1092.          return;
  1093.    }
  1094. }
  1095. //******************************************************************************
  1096. void OnDeleteItem(NM_LISTVIEW *pnmlv) {
  1097.    if (pnmlv->lParam) {
  1098.       // Free any comment string associated with this item.
  1099.       if (((FILE_NODE*)pnmlv->lParam)->szComment) {
  1100.          delete[] (CHAR*)((FILE_NODE*)pnmlv->lParam)->szComment;
  1101.       }
  1102.       // Free the item itself.
  1103.       delete[] (LPBYTE)pnmlv->lParam;
  1104.    }
  1105. }
  1106. //******************************************************************************
  1107. void OnItemChanged(NM_LISTVIEW *pnmlv) {
  1108.    int count = ListView_GetSelectedCount(pnmlv->hdr.hwndFrom);
  1109.    EnableAllMenuItems(IDM_FILE_PROPERTIES, count > 0);
  1110.    EnableAllMenuItems(IDM_ACTION_EXTRACT,  count > 0);
  1111.    EnableAllMenuItems(IDM_ACTION_TEST,     count > 0);
  1112.    EnableAllMenuItems(IDM_ACTION_VIEW,     count == 1);
  1113. }
  1114. //******************************************************************************
  1115. //***** List View Sort Functions
  1116. //******************************************************************************
  1117. void Sort(int sortColumn, BOOL fForce) {
  1118.    // Do not change the column header text if it is already correct.
  1119.    if (sortColumn != g_sortColumn) {
  1120.       TCHAR szColumn[32];
  1121.       LV_COLUMN lvc;
  1122.       lvc.mask = LVCF_TEXT;
  1123.       lvc.pszText = szColumn; 
  1124.       // Remove the '^' from the current sort column.
  1125.       if (g_sortColumn != -1) {
  1126.          _stprintf(szColumn, (g_columns[g_sortColumn].format == LVCFMT_LEFT) ? 
  1127.                    TEXT("%s   ") : TEXT("   %s"), g_columns[g_sortColumn].szName);
  1128.          ListView_SetColumn(g_hWndList, g_sortColumn, &lvc);
  1129.       }
  1130.       // Set the new sort column.
  1131.       g_sortColumn = sortColumn;
  1132.       // Add the '^' to the new sort column.
  1133.       _stprintf(szColumn, (g_columns[g_sortColumn].format == LVCFMT_LEFT) ? 
  1134.                 TEXT("%s ^") : TEXT("^ %s"), g_columns[g_sortColumn].szName);
  1135.       ListView_SetColumn(g_hWndList, g_sortColumn, &lvc);
  1136.       // Sort the list by the new column.
  1137.       ListView_SortItems(g_hWndList, CompareFunc, g_sortColumn);
  1138.    } else if (fForce) {
  1139.       // Force the list to sort by the same column.
  1140.       ListView_SortItems(g_hWndList, CompareFunc, g_sortColumn);
  1141.    }
  1142. }
  1143. //******************************************************************************
  1144. int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM sortColumn) {
  1145.    FILE_NODE *pFile1 = (FILE_NODE*)lParam1, *pFile2 = (FILE_NODE*)lParam2;
  1146.    TCHAR szBuffer1[8], szBuffer2[8];
  1147.    // Return Negative value if the first item should precede the second.
  1148.    // Return Positive value if the first item should follow the second.
  1149.    // Return Zero if the two items are equivalent.
  1150.    int result = 0;
  1151.    // Compute the relationship based on the current sort column
  1152.    switch (sortColumn) {
  1153.       case 1: // Size - Smallest to Largest
  1154.          if (pFile1->dwSize != pFile2->dwSize) {
  1155.             result = ((pFile1->dwSize < pFile2->dwSize) ? -1 : 1);
  1156.          }
  1157.          break;
  1158.       case 2: { // Type - Volume Label's first, then directories, then files
  1159.          int f1 = (pFile1->dwAttributes & FILE_ATTRIBUTE_VOLUME)    ? 1 : 
  1160.                   (pFile1->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 3;
  1161.          int f2 = (pFile2->dwAttributes & FILE_ATTRIBUTE_VOLUME)    ? 1 : 
  1162.                   (pFile2->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 3;
  1163.          if ((f1 == 3) && (f2 == 3)) {
  1164.             CHAR szType1[128];
  1165.             CHAR szType2[128];
  1166.             result = _stricmp(BuildTypeString(pFile1, szType1),
  1167.                               BuildTypeString(pFile2, szType2));
  1168.          } else {
  1169.             result = f1 - f2;
  1170.          }
  1171.          break;
  1172.       }
  1173.       case 3: // Modified - Newest to Oldest
  1174.          if (pFile1->dwModified != pFile2->dwModified) {
  1175.             result = ((pFile1->dwModified > pFile2->dwModified) ? -1 : 1);
  1176.          }
  1177.          break;
  1178.       case 4: // Attributes - String Sort
  1179.          result = _tcscmp(BuildAttributesString(szBuffer1, pFile1->dwAttributes),
  1180.                           BuildAttributesString(szBuffer2, pFile2->dwAttributes));
  1181.          break;
  1182.       case 5: // Compressed Size - Smallest to Largest
  1183.          if (pFile1->dwCompressedSize != pFile2->dwCompressedSize) {
  1184.             result = ((pFile1->dwCompressedSize < pFile2->dwCompressedSize) ? -1 : 1);
  1185.          }
  1186.          break;
  1187.       case 6: // Ratio - Smallest to Largest
  1188.          int factor1, factor2;
  1189.          factor1 = ratio(pFile1->dwSize, pFile1->dwCompressedSize);
  1190.          factor2 = ratio(pFile2->dwSize, pFile2->dwCompressedSize);
  1191.          result = factor1 - factor2;
  1192.          break;
  1193.       case 7: // Method - String Sort
  1194.          result = _stricmp(pFile1->szPathAndMethod + strlen(pFile1->szPathAndMethod) + 1,
  1195.                            pFile2->szPathAndMethod + strlen(pFile2->szPathAndMethod) + 1);
  1196.          break;
  1197.       case 8: // CRC - Smallest to Largest
  1198.          if (pFile1->dwCRC != pFile2->dwCRC) {
  1199.             result = ((pFile1->dwCRC < pFile2->dwCRC) ? -1 : 1);
  1200.          }
  1201.          break;
  1202.       case 9: // Comment - String Sort
  1203.          result = _stricmp(pFile1->szComment ? pFile1->szComment : "",
  1204.                            pFile2->szComment ? pFile2->szComment : "");
  1205.          break;
  1206.    }
  1207.    // If the sort resulted in a tie, we use the name to break the tie.
  1208.    if (result == 0) {
  1209.       result = _stricmp(pFile1->szPathAndMethod, pFile2->szPathAndMethod);
  1210.    }
  1211.    return result;
  1212. }
  1213. //******************************************************************************
  1214. //***** Helper/Utility Functions
  1215. //******************************************************************************
  1216. void SetCaptionText(LPCTSTR szPrefix) {
  1217.    TCHAR szCaption[_MAX_PATH + 32];
  1218.    if (szPrefix && *g_szZipFile) {
  1219.       _stprintf(szCaption, TEXT("%s - %S"), szPrefix, GetFileFromPath(g_szZipFile));
  1220.    } else if (szPrefix) {
  1221.       _stprintf(szCaption, TEXT("%s - Pocket UnZip"), szPrefix);
  1222.    } else if (*g_szZipFile) {
  1223.       _stprintf(szCaption, TEXT("%S"), GetFileFromPath(g_szZipFile));
  1224.    } else {
  1225.       _tcscpy(szCaption, TEXT("Pocket UnZip"));
  1226.    }
  1227.    SetWindowText(g_hWndMain, szCaption);
  1228. }
  1229. //******************************************************************************
  1230. void DrawBanner(HDC hdc) {
  1231.    // If we were not passed in a DC, then get one now.
  1232.    BOOL fReleaseDC = FALSE;
  1233.    if (!hdc) {
  1234.       hdc = GetDC(g_hWndMain);
  1235.       fReleaseDC = TRUE;
  1236.    }
  1237.    // Compute the banner rectangle.
  1238.    RECT rc;
  1239.    GetClientRect(g_hWndMain, &rc);
  1240.    rc.top += g_cyCmdBar;
  1241.    rc.bottom = rc.top + 22;
  1242.    // Fill in the background with a light grey brush.
  1243.    FillRect(hdc, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
  1244.    // Draw a highlight line across the top of our banner.
  1245.    POINT pt[2] = { { rc.left, rc.top + 1 }, { rc.right, rc.top + 1 } };
  1246.    SelectObject(hdc, GetStockObject(WHITE_PEN));
  1247.    Polyline(hdc, pt, 2);
  1248.    // Get the ZIP file image.  We do this only once and cache the result.
  1249.    // Note that you do not need to free icons as they are a resource.
  1250.    static HICON hIcon = NULL;
  1251.    if (!hIcon) {
  1252.       hIcon = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_ZIPFILE), 
  1253.                                IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  1254.    }
  1255.    
  1256.    // Draw the ZIP file image.
  1257.    DrawIconEx(hdc, rc.left + 6, rc.top + 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
  1258.    // Set our font and colors.
  1259.    HFONT hFontStock = (HFONT)SelectObject(hdc, g_hFontBanner);
  1260.    SetTextColor(hdc, RGB(0, 0, 0));
  1261.    SetBkMode(hdc, TRANSPARENT);
  1262.    rc.left   += 26;      
  1263.    rc.right  -= 48;
  1264.    rc.bottom -=  2;
  1265.    // Decide what text to display.
  1266.    TCHAR szPath[_MAX_PATH + 16];
  1267.    if (g_hWndWaitFor) {
  1268.       _tcscpy(szPath, TEXT("Initializing..."));
  1269.    } else if (*g_szZipFile) {
  1270.       if (g_fLoading) {
  1271.          _stprintf(szPath, TEXT("Loading %S"), g_szZipFile);
  1272.       } else {
  1273.          mbstowcs(szPath, g_szZipFile, countof(szPath));
  1274.       }
  1275.    } else {
  1276.       _tcscpy(szPath, TEXT("No File Loaded"));
  1277.    }
  1278.    // Draw the banner text.
  1279.    DrawText(hdc, szPath, _tcslen(szPath), &rc,
  1280.             DT_NOPREFIX | DT_SINGLELINE | DT_LEFT | DT_VCENTER);
  1281.    // Remove all non stock objects from the DC
  1282.    SelectObject(hdc, hFontStock);
  1283.    // Free our DC if we created it.
  1284.    if (fReleaseDC) {
  1285.       ReleaseDC(g_hWndMain, hdc);
  1286.    }
  1287. }
  1288. //******************************************************************************
  1289. void AddDeleteColumns() {
  1290.    static int curColumns = 0;
  1291.    int column, newColumns = (g_fExpandedView ? countof(g_columns) : 4);
  1292.    // Are we adding columns?
  1293.    if (newColumns > curColumns) {
  1294.       // Set up column structure.
  1295.       TCHAR szColumn[32];
  1296.       LV_COLUMN lvc;
  1297.       lvc.mask = LVCF_TEXT | LVCF_FMT;
  1298.       lvc.pszText = szColumn;
  1299.       // Loop through each column we need to add.
  1300.       for (column = curColumns; column < newColumns; column++) {
  1301.          // Build the real column string.
  1302.          _stprintf(szColumn, (g_columns[column].format == LVCFMT_LEFT) ? 
  1303.                    TEXT("%s   ") : TEXT("   %s"), g_columns[column].szName);
  1304.          // Insert the column with the correct format.
  1305.          lvc.fmt = g_columns[column].format;
  1306.          ListView_InsertColumn(g_hWndList, column, &lvc);
  1307.       }
  1308.    // Otherwise, we are removing columns.
  1309.    } else {
  1310.       // Loop through each column we need to delete and delete them.
  1311.       for (column = curColumns - 1; column >= newColumns; column--) {
  1312.          ListView_DeleteColumn(g_hWndList, column);
  1313.       }
  1314.    }
  1315.    // Store our new column count statically to help us with the next call to 
  1316.    // AddDeleteColumns().
  1317.    curColumns = newColumns;
  1318.    // Re-calcualte our column widths.
  1319.    ResizeColumns();
  1320. }
  1321. //******************************************************************************
  1322. void ResizeColumns() {
  1323.    // Hide the window since we are going to be doing some column shifting.
  1324.    ShowWindow(g_hWndList, SW_HIDE);
  1325.    // Resize all the columns to best fit both the column data and the header.
  1326.    for (int column = 0; column < countof(g_columns); column++) {
  1327.       ListView_SetColumnWidth(g_hWndList, column, LVSCW_AUTOSIZE_USEHEADER);
  1328.    }
  1329.    // Show the window again.
  1330.    ShowWindow(g_hWndList, SW_SHOW);
  1331. }
  1332. //******************************************************************************
  1333. LPCTSTR GetZipErrorString(int error) {
  1334.    switch (error) {
  1335.       case PK_OK: // no error
  1336.          return TEXT("Operation completed successfully.");
  1337.       case PK_WARN: // warning error
  1338.          return TEXT("There were warnings during the operation.");
  1339.       case PK_ERR:    // error in zipfile
  1340.       case PK_BADERR: // severe error in zipfile
  1341.          return TEXT("The operation could not be successfully completed.  ")
  1342.                 TEXT("Possible causes are that the ZIP file contains errors, ")
  1343.                 TEXT("or that an error occurred while trying to create a ")
  1344.                 TEXT("directory or file.");
  1345.       case PK_MEM:  // insufficient memory
  1346.       case PK_MEM2: // insufficient memory
  1347.       case PK_MEM3: // insufficient memory
  1348.       case PK_MEM4: // insufficient memory
  1349.       case PK_MEM5: // insufficient memory
  1350.          return TEXT("There is not enough memory to perform the operation.  ")
  1351.                 TEXT("Try closing other running applications or adjust your ")
  1352.                 TEXT("memory configuration.");
  1353.       case PK_NOZIP: // zipfile not found or corrupt.
  1354.          return TEXT("The ZIP file either contains errors or could not be found.");
  1355.       case PK_PARAM: // bad or illegal parameters specified
  1356.          break; // Not used in the Windows CE port.
  1357.       case PK_FIND: // no files found in ZIP file
  1358.          return TEXT("The ZIP file contains errors that prevented the ")
  1359.                 TEXT("operation from completing successfully.  A possible ")
  1360.                 TEXT("cause is that one or more of the files listed as being ")
  1361.                 TEXT("in the ZIP file could not actually be found within the ")
  1362.                 TEXT("ZIP file itself.");
  1363.       case PK_DISK: // disk full or file locked
  1364.          return TEXT("An error occurred while attempting to save a file.  ")
  1365.                 TEXT("Possible causes are that your file storage is full or ")
  1366.                 TEXT("read only, or that a file with the same name already ")
  1367.                 TEXT("exists and is locked by another application.");
  1368.       case PK_EOF: // unexpected end of file
  1369.          return TEXT("The ZIP file contains errors that prevented the ")
  1370.                 TEXT("operation from completing successfully.  A possible ")
  1371.                 TEXT("cause is that your ZIP file is incomplete and might be ")
  1372.                 TEXT("truncated.");
  1373.       case IZ_UNSUP:  // no files found: all unsup. compr/encrypt.
  1374.          return TEXT("None of the files could be processed because they were ")
  1375.                 TEXT("all compressed using an unsupported compression or ")
  1376.                 TEXT("encryption algorithm.");
  1377.          
  1378.       case IZ_BADPWD: // no files found: all had bad password.
  1379.          return TEXT("None of the files could be processed because all the ")
  1380.                 TEXT("password(s) specified were incorrect.");
  1381.       case PK_EXCEPTION: // exception occurred
  1382.          return TEXT("An internal error occurred.  Possible causes are that ")
  1383.                 TEXT("you are out of memory, you are out of file storage ")
  1384.                 TEXT("space, the ZIP file contains unexpected errors, or there ")
  1385.                 TEXT("is a bug in our program (that's why it's free).");
  1386.       case PK_ABORTED: // user aborted
  1387.          return TEXT("The operation was aborted.");
  1388.    }
  1389.    return TEXT("An unknown error occurred while processing the ZIP file.");
  1390. }
  1391. //******************************************************************************
  1392. void AddFileToListView(FILE_NODE *pFile) {
  1393.    // Set up our List View Item structure.
  1394.    LV_ITEM lvi;
  1395.    ZeroMemory(&lvi, sizeof(lvi));
  1396.    lvi.mask    = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  1397.    lvi.pszText = LPSTR_TEXTCALLBACK;
  1398.    lvi.lParam  = (LPARAM)pFile;
  1399.    lvi.iImage  = IMAGE_GENERIC;
  1400.    // Special case Volume Labels.
  1401.    if (pFile->dwAttributes & FILE_ATTRIBUTE_VOLUME) {
  1402.       pFile->szType = "Volume Label";
  1403.       lvi.iImage = IMAGE_VOLUME;
  1404.    // Special case folders.
  1405.    } else if (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1406.       pFile->szType = "Folder";
  1407.       lvi.iImage = IMAGE_FOLDER;
  1408.    // Do a lookup on the file extension.
  1409.    } else {
  1410.       // Locate the file portion of our path.
  1411.       LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
  1412.       // Find the extension portion of our file.
  1413.       LPCSTR pszExt = strrchr(pszFile, '.');
  1414.       // Search our known extension list for this extension.
  1415.       if (pszExt && *(pszExt + 1)) {
  1416.          // Loop through our linked list
  1417.          for (FILE_TYPE_NODE *pft = g_pftHead; pft; pft = pft->pNext) {
  1418.             // Check for a match.
  1419.             if (!_stricmp(pszExt + 1, pft->szExtAndDesc)) {
  1420.                // We found a match, store the image and type string and exit loop.
  1421.                lvi.iImage = pft->image;
  1422.                pFile->szType = pft->szExtAndDesc + strlen(pft->szExtAndDesc) + 1;
  1423.                if (!*pFile->szType) {
  1424.                   pFile->szType = NULL;
  1425.                }
  1426.                break;
  1427.             }
  1428.          }
  1429.       }
  1430.    }
  1431.    // Add the item to our list.
  1432.    ListView_InsertItem(g_hWndList, &lvi);
  1433. }
  1434. //******************************************************************************
  1435. void EnableAllMenuItems(UINT uMenuItem, BOOL fEnabled) {
  1436. #ifdef _WIN32_WCE
  1437.    HMENU hMenu = CommandBar_GetMenu(g_hWndCmdBar, 0);
  1438. #else
  1439.    HMENU hMenu = GetMenu(g_hWndMain);
  1440. #endif
  1441.    EnableMenuItem(hMenu, uMenuItem, fEnabled ? MF_ENABLED : MF_GRAYED);
  1442.    SendMessage(g_hWndCmdBar, TB_ENABLEBUTTON, uMenuItem, MAKELONG(fEnabled, 0));
  1443. }
  1444. //******************************************************************************
  1445. void CheckAllMenuItems(UINT uMenuItem, BOOL fChecked) {
  1446. #ifdef _WIN32_WCE
  1447.    HMENU hMenu = CommandBar_GetMenu(g_hWndCmdBar, 0);
  1448. #else
  1449.    HMENU hMenu = GetMenu(g_hWndMain);
  1450. #endif
  1451.    CheckMenuItem(hMenu, uMenuItem, fChecked ? MF_CHECKED : MF_UNCHECKED);
  1452.    SendMessage(g_hWndCmdBar, TB_PRESSBUTTON, uMenuItem, MAKELONG(fChecked, 0));
  1453. }
  1454. //******************************************************************************
  1455. void CenterWindow(HWND hWnd) {
  1456.    RECT rc, rcParent;
  1457.    // Get our window rectangle.
  1458.    GetWindowRect(hWnd, &rc);
  1459.    // Get our parent's window rectangle.
  1460.    GetWindowRect(GetParent(hWnd), &rcParent);
  1461.    // Center our window over our parent's window.
  1462.    SetWindowPos(hWnd, NULL, 
  1463.       rcParent.left + ((rcParent.right  - rcParent.left) - (rc.right  - rc.left)) / 2,
  1464.       rcParent.top  + ((rcParent.bottom - rcParent.top ) - (rc.bottom - rc.top )) / 2,
  1465.       0, 0, SWP_NOZORDER | SWP_NOSIZE);
  1466. }
  1467. //******************************************************************************
  1468. void AddTextToEdit(LPCSTR szText) {
  1469.    if (!g_hWndEdit) {
  1470.       return;
  1471.    }
  1472.    // Add the characters one by one to our edit box while performing the 
  1473.    // the following newline conversions:
  1474.    //    Single CR -> CR/LF
  1475.    //    Single LF -> CR/LF
  1476.    //    CR and LF -> CR/LF
  1477.    //    LF and CR -> CR/LF
  1478.    //    0 - 31    -> ^char
  1479.    TCHAR szOut[256], *pszOut = szOut;
  1480.    CHAR *pszIn = (LPSTR)szText, cPrev = '';
  1481.    while (*pszIn) {
  1482.       if (*pszIn == 'n') {
  1483.          if (cPrev == 'r') {
  1484.             cPrev = '';
  1485.          } else {
  1486.             *(pszOut++) = TEXT('r');
  1487.             *(pszOut++) = TEXT('n');
  1488.             cPrev = 'n';
  1489.          }
  1490.       } else if (*pszIn == 'r') {
  1491.          if (cPrev == 'n') {
  1492.             cPrev = '';
  1493.          } else {
  1494.             *(pszOut++) = TEXT('r');
  1495.             *(pszOut++) = TEXT('n');
  1496.             cPrev = 'r';
  1497.          }
  1498.       } else if ((*pszIn < 32) && (*pszIn != 't')) {
  1499.          *(pszOut++) = (TCHAR)'^';
  1500.          *(pszOut++) = (TCHAR)(64 + *pszIn);
  1501.          cPrev = *pszIn;
  1502.       } else {
  1503.          *(pszOut++) = (TCHAR)*pszIn;
  1504.          cPrev = *pszIn;
  1505.       }
  1506.       pszIn++;
  1507.       // If our out buffer is full, then dump it to the edit box.
  1508.       if ((pszOut - szOut) > 253) {
  1509.          *pszOut = TEXT('');
  1510.          SendMessage(g_hWndEdit, EM_SETSEL, 65536, 65536);
  1511.          SendMessage(g_hWndEdit, EM_REPLACESEL, FALSE, (LPARAM)szOut);
  1512.          pszOut = szOut;
  1513.       }
  1514.    }
  1515.    // One final flush of any partially full out buffer.
  1516.    if (pszOut > szOut) {
  1517.       *pszOut = TEXT('');
  1518.       SendMessage(g_hWndEdit, EM_SETSEL, 65536, 65536);
  1519.       SendMessage(g_hWndEdit, EM_REPLACESEL, FALSE, (LPARAM)szOut);
  1520.    }
  1521. }
  1522. //******************************************************************************
  1523. LPTSTR FormatValue(LPTSTR szValue, DWORD dwValue) {
  1524.    DWORD dw = 0, dwGroup[4] = { 0, 0, 0, 0 };
  1525.    while (dwValue) {
  1526.       dwGroup[dw++] = dwValue % 1000;
  1527.       dwValue /= 1000;
  1528.    }
  1529.    switch (dw) {
  1530.       case 2:  _stprintf(szValue, TEXT("%u,%03u"), dwGroup[1], dwGroup[0]); break;
  1531.       case 3:  _stprintf(szValue, TEXT("%u,%03u,%03u"), dwGroup[2], dwGroup[1], dwGroup[0]); break;
  1532.       case 4:  _stprintf(szValue, TEXT("%u,%03u,%03u,%03u"), dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]); break;
  1533.       default: _stprintf(szValue, TEXT("%u"), dwGroup[0]);
  1534.    }
  1535.    return szValue;
  1536. }