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

压缩解压

开发平台:

MultiPlatform

  1. //******************************************************************************
  2. LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes) {
  3.    // Build the attribute string according to the flags specified for this file.
  4.    _stprintf(szBuffer, TEXT("%s%s%s%s%s%s%s%s"),
  5.              (dwAttributes & FILE_ATTRIBUTE_VOLUME)    ? TEXT("V") : TEXT(""),
  6.              (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? TEXT("D") : TEXT(""),
  7.              (dwAttributes & FILE_ATTRIBUTE_READONLY)  ? TEXT("R") : TEXT(""),
  8.              (dwAttributes & FILE_ATTRIBUTE_ARCHIVE)   ? TEXT("A") : TEXT(""),
  9.              (dwAttributes & FILE_ATTRIBUTE_HIDDEN)    ? TEXT("H") : TEXT(""),
  10.              (dwAttributes & FILE_ATTRIBUTE_SYSTEM)    ? TEXT("S") : TEXT(""),
  11.              (dwAttributes & FILE_ATTRIBUTE_ENCRYPTED) ? TEXT("E") : TEXT(""),
  12.              (dwAttributes & FILE_ATTRIBUTE_COMMENT)   ? TEXT("C") : TEXT(""));
  13.    return szBuffer;
  14. }
  15. //******************************************************************************
  16. LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType) {
  17.    // First check to see if we have a known description.
  18.    if (pFile->szType) {
  19.       return pFile->szType;
  20.    }
  21.    // Locate the file portion of our path.
  22.    LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
  23.    // Get the extension portion of the file.
  24.    LPCSTR pszExt = strrchr(pszFile, '.');
  25.    // If we have an extension create a type name for this file.
  26.    if (pszExt && *(pszExt + 1)) {
  27.       strcpy(szType, pszExt + 1);
  28.       _strupr(szType);
  29.       strcat(szType, " File");
  30.       return szType;
  31.    }
  32.    
  33.    // If no extension, then use the default "File".
  34.    return "File";
  35. }
  36. //******************************************************************************
  37. LPCSTR GetFileFromPath(LPCSTR szPath) {
  38.    LPCSTR p1 = strrchr(szPath, '/'), p2 = strrchr(szPath, '\');
  39.    if (p1 && (p1 > p2)) {
  40.       return p1 + 1;
  41.    } else if (p2) {
  42.       return p2 + 1;
  43.    }
  44.    return szPath;
  45. }
  46. //******************************************************************************
  47. void ForwardSlashesToBackSlashesA(LPSTR szBuffer) {
  48.    while (*szBuffer) {
  49.       if (*szBuffer == '/') {
  50.          *szBuffer = '\';
  51.       }
  52.       szBuffer++;
  53.    }
  54. }
  55. //******************************************************************************
  56. void ForwardSlashesToBackSlashesW(LPWSTR szBuffer) {
  57.    while (*szBuffer) {
  58.       if (*szBuffer == L'/') {
  59.          *szBuffer = L'\';
  60.       }
  61.       szBuffer++;
  62.    }
  63. }
  64. //******************************************************************************
  65. void DeleteDirectory(LPTSTR szPath) {
  66.    // Make note to where the end of our path is.
  67.    LPTSTR szEnd = szPath + _tcslen(szPath);
  68.    // Add our search spec to the path.
  69.    _tcscpy(szEnd, TEXT("\*.*"));
  70.    // Start a directory search.
  71.    WIN32_FIND_DATA w32fd;
  72.    HANDLE hFind = FindFirstFile(szPath, &w32fd);
  73.    // Loop through all entries in this directory.
  74.    if (hFind != INVALID_HANDLE_VALUE) {
  75.       do {
  76.          // Append the file/directory name to the path.
  77.          _tcscpy(szEnd + 1, w32fd.cFileName);
  78.          // Check to see if this entry is a subdirectory.
  79.          if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  80.             // Ignore current directory (.) and previous directory (..)
  81.             if (_tcscmp(w32fd.cFileName, TEXT("."))   && 
  82.                 _tcscmp(w32fd.cFileName, TEXT("..")))
  83.             {
  84.                // Recurse into DeleteDirectory() to delete subdirectory.
  85.                DeleteDirectory(szPath);
  86.             }
  87.          // Otherwise, it must be a file.
  88.          } else {
  89.             // If the file is marked as read-only, then change to read/write.
  90.             if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  91.                SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
  92.             }
  93.             // Attempt to delete the file.  If we fail and the file used to be
  94.             // read-only, then set the read-only bit back on it.
  95.             if (!DeleteFile(szPath) && 
  96.                 (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
  97.             {
  98.                SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
  99.             }
  100.          }
  101.       // Get the next directory entry.
  102.       } while (FindNextFile(hFind, &w32fd));
  103.       // Close the directory search.
  104.       FindClose(hFind);
  105.    }
  106.    // Remove the directory.
  107.    *szEnd = TEXT('');
  108.    RemoveDirectory(szPath);
  109. }
  110. //******************************************************************************
  111. //***** Registry Functions
  112. //******************************************************************************
  113. void RegWriteKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPCTSTR szValue) {
  114.    HKEY  hKey = NULL;
  115.    DWORD dwDisposition;
  116.    if (RegCreateKeyEx(hKeyRoot, szSubKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) {
  117.       if (szValue) {
  118.          RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szValue, 
  119.                        sizeof(TCHAR) * (_tcslen(szValue) + 1));
  120.       }
  121.       RegCloseKey(hKey);
  122.    }
  123. }
  124. //******************************************************************************
  125. BOOL RegReadKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPTSTR szValue, DWORD cBytes) {
  126.    *szValue = TEXT('');
  127.    HKEY hKey = NULL;
  128.    LRESULT lResult = -1;
  129.    if (RegOpenKeyEx(hKeyRoot, szSubKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
  130.       lResult = RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)szValue, &cBytes);
  131.       RegCloseKey(hKey);
  132.    }
  133.    return ((lResult == ERROR_SUCCESS) && *szValue);
  134. }
  135. //******************************************************************************
  136. void WriteOptionString(LPCTSTR szOption, LPCTSTR szValue) {
  137.    HKEY hKey = NULL;
  138.    if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
  139.       RegSetValueEx(hKey, szOption, 0, REG_SZ, (LPBYTE)szValue, 
  140.                     sizeof(TCHAR) * (_tcslen(szValue) + 1));
  141.       RegCloseKey(hKey);
  142.    }
  143. }
  144. //******************************************************************************
  145. void WriteOptionInt(LPCTSTR szOption, DWORD dwValue) {
  146.    HKEY hKey = NULL;
  147.    if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
  148.       RegSetValueEx(hKey, szOption, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
  149.       RegCloseKey(hKey);
  150.    }
  151. }
  152. //******************************************************************************
  153. LPTSTR GetOptionString(LPCTSTR szOption, LPCTSTR szDefault, LPTSTR szValue, DWORD nSize) {
  154.    HKEY hKey = NULL;
  155.    LONG lResult = -1;
  156.    if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
  157.       lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)szValue, &nSize);
  158.       RegCloseKey(hKey);
  159.    }
  160.    if (lResult != ERROR_SUCCESS) {
  161.       _tcscpy(szValue, szDefault);
  162.    }
  163.    return szValue;
  164. }
  165. //******************************************************************************
  166. DWORD GetOptionInt(LPCTSTR szOption, DWORD dwDefault) {
  167.    HKEY  hKey = NULL;
  168.    LONG  lResult = -1;
  169.    DWORD dwValue;
  170.    DWORD nSize = sizeof(dwValue);
  171.    if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
  172.       lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)&dwValue, &nSize);
  173.       RegCloseKey(hKey);
  174.    }
  175.    return (lResult == ERROR_SUCCESS) ? dwValue : dwDefault;
  176. }
  177. //******************************************************************************
  178. //***** EDIT Control Subclass Functions
  179. //******************************************************************************
  180. void DisableEditing(HWND hWndEdit) {
  181.    
  182.    // Make sure the control does not have ES_READONLY or ES_WANTRETURN styles.
  183.    DWORD dwStyle = (DWORD)GetWindowLong(hWndEdit, GWL_STYLE);
  184.    if (dwStyle & (ES_READONLY | ES_WANTRETURN)) {
  185.       SetWindowLong(hWndEdit, GWL_STYLE, dwStyle & ~(ES_READONLY | ES_WANTRETURN));
  186.    }
  187.    // Subclass the control so we can intercept certain keys.
  188.    g_wpEdit = (WNDPROC)GetWindowLong(hWndEdit, GWL_WNDPROC);
  189.    SetWindowLong(hWndEdit, GWL_WNDPROC, (LONG)EditSubclassProc);
  190. }
  191. //******************************************************************************
  192. LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  193.    BOOL fCtrl, fShift;
  194.    switch (uMsg) {
  195.       // For cut, paste, delete, and undo, the control post itself a message.
  196.       // we throw away that message.  This works as a fail-safe in case we miss
  197.       // some keystroke that causes one of these operations.  This also disables
  198.       // the context menu on NT from causing one of these actions to occur.
  199.       case WM_CUT:
  200.       case WM_PASTE:
  201.       case WM_CLEAR:
  202.       case WM_UNDO:
  203.          MessageBeep(0);
  204.          return 0;
  205.       // WM_CHAR is used for normal characters. A-Z, numbers, symbols, enter,
  206.       // backspace, esc, and tab. In does not include del or movement keys.
  207.       case WM_CHAR:
  208.          fCtrl  = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
  209.          // We only allow CTRL-C (copy), plain ESC, plain TAB, plain ENTER.
  210.          if (( fCtrl && (wParam == 3))         ||
  211.              (!fCtrl && (wParam == VK_ESCAPE)) ||
  212.              (!fCtrl && (wParam == VK_RETURN)) ||
  213.              (!fCtrl && (wParam == VK_TAB)))
  214.          {
  215.             break;
  216.          }
  217.          MessageBeep(0);
  218.          return 0;
  219.       // WM_KEYDOWN handles del, insert, arrows, pg up/down, home/end.
  220.       case WM_KEYDOWN:
  221.          fCtrl  = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
  222.          fShift = (GetKeyState(VK_SHIFT)   & 0x8000) ? TRUE : FALSE;
  223.          // Skip all forms of DELETE, SHIFT-INSERT (paste), 
  224.          // CTRL-RETURN (hard-return), and CTRL-TAB (hard-tab).
  225.          if ((          (wParam == VK_DELETE)) || 
  226.              (fShift && (wParam == VK_INSERT)) ||
  227.              (fCtrl  && (wParam == VK_RETURN)) ||
  228.              (fCtrl  && (wParam == VK_TAB)))
  229.          {
  230.             MessageBeep(0);
  231.             return 0;
  232.          }
  233.          break;
  234.    }
  235.    return CallWindowProc(g_wpEdit, hWnd, uMsg, wParam, lParam);
  236. }
  237. //******************************************************************************
  238. //***** MRU Functions
  239. //******************************************************************************
  240. #ifdef _WIN32_WCE
  241. int GetMenuString(HMENU hMenu, UINT uIDItem, LPTSTR lpString, int nMaxCount, 
  242.                   UINT uFlag) {
  243.    MENUITEMINFO mii;
  244.    ZeroMemory(&mii, sizeof(mii));
  245.    mii.cbSize = sizeof(mii);
  246.    mii.fMask = MIIM_TYPE;
  247.    mii.dwTypeData = lpString;
  248.    mii.cch = nMaxCount;
  249.    return (GetMenuItemInfo(hMenu, uIDItem, uFlag == MF_BYPOSITION, &mii) ?
  250.            mii.cch : 0);
  251. }
  252. #endif
  253. //******************************************************************************
  254. void InitializeMRU() {
  255.    
  256.    TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
  257.    int   i, j;
  258.    // Get our menu handle.
  259. #ifdef _WIN32_WCE
  260.    HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
  261. #else
  262.    HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
  263. #endif
  264.    // Read all our current MRUs from the registry.
  265.    for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
  266.       // Build option name for current MRU and read from registry.
  267.       _stprintf(szOption, TEXT("MRU%d"), i+1);
  268.       GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
  269.       // If this MRU exists, then add it.
  270.       if (szMRU[i][3]) {
  271.          // Build the accelerator prefix for this menu item.
  272.          szMRU[i][0] = TEXT('&');
  273.          szMRU[i][1] = TEXT('1') + j;
  274.          szMRU[i][2] = TEXT(' ');
  275.          // Add the item to our menu.
  276.          InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
  277.                     szMRU[i]);
  278.          // Increment our actual MRU count.
  279.          j++;
  280.       }
  281.    }
  282. }
  283. //******************************************************************************
  284. void AddFileToMRU(LPCSTR szFile) {
  285.    
  286.    TCHAR szMRU[MRU_MAX_FILE + 1][_MAX_PATH + 4], szOption[8];
  287.    int   i, j;
  288.    // Store the new file in our first MRU index.
  289.    mbstowcs(&szMRU[0][3], szFile, _MAX_PATH);
  290.    //---------------------------------------------------------------------------
  291.    // We first read the current MRU list from the registry, merge in our new
  292.    // file at the top, and then write back to the registry.  The registry merge
  293.    // is done to allow multiple instances of Pocket UnZip to maintain a global
  294.    // MRU list independent to this current instance's MRU list.
  295.    //---------------------------------------------------------------------------
  296.    // Read all our current MRUs from the registry.
  297.    for (i = 1; i <= MRU_MAX_FILE; i++) {
  298.       // Build option name for current MRU and read from registry.
  299.       _stprintf(szOption, TEXT("MRU%d"), i);
  300.       GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
  301.    }
  302.    // Write our new merged MRU list back to the registry.
  303.    for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
  304.       // If this MRU exists and is different then our new file, then add it.
  305.       if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
  306.          // Build option name for current MRU and write to registry.
  307.          _stprintf(szOption, TEXT("MRU%d"), ++j);
  308.          WriteOptionString(szOption, &szMRU[i][3]);
  309.       }
  310.    }
  311.    //---------------------------------------------------------------------------
  312.    // The next thing we need to do is read our local MRU from our File menu,
  313.    // merge in our new file, and store the new list back to our File menu.
  314.    //---------------------------------------------------------------------------
  315.    // Get our menu handle.
  316. #ifdef _WIN32_WCE
  317.    HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
  318. #else
  319.    HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
  320. #endif
  321.    // Read all our current MRUs from our File Menu.
  322.    for (i = 1; i <= MRU_MAX_FILE; i++) {
  323.       // Query our file Menu for a MRU file.
  324.       if (GetMenuString(hMenu, MRU_START_ID + i - 1, szMRU[i], 
  325.                         countof(szMRU[0]), MF_BYCOMMAND))
  326.       {
  327.          // Delete this item from the menu for now.
  328.          DeleteMenu(hMenu, MRU_START_ID + i - 1, MF_BYCOMMAND);
  329.       } else {
  330.          szMRU[i][3] = TEXT('');
  331.       }
  332.    }
  333.    // Write our new merged MRU list back to the File menu.
  334.    for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
  335.       // If this MRU exists and is different then our new file, then add it.
  336.       if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
  337.          // Build the accelerator prefix for this menu item.
  338.          szMRU[i][0] = TEXT('&');
  339.          szMRU[i][1] = TEXT('1') + j;
  340.          szMRU[i][2] = TEXT(' ');
  341.          // Add the item to our menu.
  342.          InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
  343.                     szMRU[i]);
  344.          // Increment our actual MRU count.
  345.          j++;
  346.       }
  347.    }
  348. }
  349. //******************************************************************************
  350. void RemoveFileFromMRU(LPCTSTR szFile) {
  351.    TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
  352.    int   i, j;
  353.    BOOL  fFound;
  354.    //---------------------------------------------------------------------------
  355.    // We first look for this file in our global MRU stored in the registry.  We
  356.    // read the current MRU list from the registry, and then write it back while
  357.    // removing all occurrances of the file specified.
  358.    //---------------------------------------------------------------------------
  359.    // Read all our current MRUs from the registry.
  360.    for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
  361.       // Build option name for current MRU and read from registry.
  362.       _stprintf(szOption, TEXT("MRU%d"), i+1);
  363.       GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
  364.       // Check for a match.
  365.       if (!_tcsicmp(szFile, &szMRU[i][3])) {
  366.          szMRU[i][3] = TEXT('');
  367.          fFound = TRUE;
  368.       }
  369.    }
  370.    // Only write the MRU back to the registry if we found a file to remove.
  371.    if (fFound) {
  372.       // Write the updated MRU list back to the registry.
  373.       for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
  374.          // If this MRU still exists, then add it.
  375.          if (szMRU[i][3]) {
  376.             // Build option name for current MRU and write to registry.
  377.             _stprintf(szOption, TEXT("MRU%d"), ++j);
  378.             WriteOptionString(szOption, &szMRU[i][3]);
  379.          }
  380.       }
  381.       // If our list got smaller, clear the unused items in the registry.
  382.       while (j++ < MRU_MAX_FILE) {
  383.          _stprintf(szOption, TEXT("MRU%d"), j);
  384.          WriteOptionString(szOption, TEXT(""));
  385.       }
  386.    }
  387.    //---------------------------------------------------------------------------
  388.    // We next thing we do is look for this file in our local MRU stored in our
  389.    // File menu.  We read the current MRU list from the menu, and then write it
  390.    // back while removing all occurrances of the file specified.
  391.    //---------------------------------------------------------------------------
  392.    // Get our menu handle.
  393. #ifdef _WIN32_WCE
  394.    HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
  395. #else
  396.    HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
  397. #endif
  398.    // Read all our current MRUs from our File Menu.
  399.    for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
  400.       // Query our file Menu for a MRU file.
  401.       if (!GetMenuString(hMenu, MRU_START_ID + i, szMRU[i], countof(szMRU[0]),
  402.           MF_BYCOMMAND))
  403.       {
  404.          szMRU[i][3] = TEXT('');
  405.       }
  406.       // Check for a match.
  407.       if (!_tcsicmp(szFile, &szMRU[i][3])) {
  408.          szMRU[i][3] = TEXT('');
  409.          fFound = TRUE;
  410.       }
  411.    }
  412.    // Only update menu if we found a file to remove.
  413.    if (fFound) {
  414.       // Clear out our menu's MRU list.
  415.       for (i = MRU_START_ID; i < (MRU_START_ID + MRU_MAX_FILE); i++) {
  416.          DeleteMenu(hMenu, i, MF_BYCOMMAND);
  417.       }
  418.       // Write the rest of our MRU list back to the menu.
  419.       for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
  420.          // If this MRU still exists, then add it.
  421.          if (szMRU[i][3]) {
  422.             // Build the accelerator prefix for this menu item.
  423.             szMRU[i][0] = TEXT('&');
  424.             szMRU[i][1] = TEXT('1') + j;
  425.             szMRU[i][2] = TEXT(' ');
  426.             // Add the item to our menu.
  427.             InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
  428.                        szMRU[i]);
  429.             // Increment our actual MRU count.
  430.             j++;
  431.          }
  432.       }
  433.    }
  434. }
  435. //******************************************************************************
  436. void ActivateMRU(UINT uIDItem) {
  437.    TCHAR szFile[_MAX_PATH + 4];
  438.    // Get our menu handle.
  439. #ifdef _WIN32_WCE
  440.    HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
  441. #else
  442.    HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
  443. #endif
  444.    // Query our menu for the selected MRU.
  445.    if (GetMenuString(hMenu, uIDItem, szFile, countof(szFile), MF_BYCOMMAND)) {
  446.       // Move past 3 character accelerator prefix and open the file.
  447.       ReadZipFileList(&szFile[3]);
  448.    }
  449. }
  450. //******************************************************************************
  451. //***** Open Zip File Functions
  452. //******************************************************************************
  453. void ReadZipFileList(LPCWSTR wszPath) {
  454.    // Show wait cursor.
  455.    HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  456.    wcstombs(g_szZipFile, wszPath, countof(g_szZipFile));
  457.    // Update our banner to show that we are loading.
  458.    g_fLoading = TRUE;
  459.    DrawBanner(NULL);
  460.    // Update our caption to show that we are loading.
  461.    SetCaptionText(TEXT("Loading"));
  462.    // Clear our list view.
  463.    ListView_DeleteAllItems(g_hWndList);
  464.    // Ghost all our Unzip related menu items.
  465.    EnableAllMenuItems(IDM_FILE_PROPERTIES,    FALSE);
  466.    EnableAllMenuItems(IDM_ACTION_EXTRACT,     FALSE);
  467.    EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, FALSE);
  468.    EnableAllMenuItems(IDM_ACTION_TEST,        FALSE);
  469.    EnableAllMenuItems(IDM_ACTION_TEST_ALL,    FALSE);
  470.    EnableAllMenuItems(IDM_ACTION_VIEW,        FALSE);
  471.    EnableAllMenuItems(IDM_ACTION_SELECT_ALL,  FALSE);
  472.    EnableAllMenuItems(IDM_VIEW_COMMENT,       FALSE);
  473.    // Let Info-ZIP and our callbacks do the work.
  474.    SendMessage(g_hWndList, WM_SETREDRAW, FALSE, 0);
  475.    int result = DoListFiles(g_szZipFile);
  476.    SendMessage(g_hWndList, WM_SETREDRAW, TRUE, 0);
  477.    // Restore/remove cursor.
  478.    SetCursor(hCur);
  479.    // Update our column widths
  480.    ResizeColumns();
  481.    if ((result == PK_OK) || (result == PK_WARN)) {
  482.       // Sort the items by name.
  483.       Sort(0, TRUE);
  484.       // Update this file to our MRU list and menu.
  485.       AddFileToMRU(g_szZipFile);
  486.       // Enabled the comment button if the zip file has a comment.
  487.       if (lpUserFunctions->cchComment) {
  488.          EnableAllMenuItems(IDM_VIEW_COMMENT, TRUE);
  489.       }
  490.       // Update other items that are related to having a Zip file loaded.
  491.       EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, TRUE);
  492.       EnableAllMenuItems(IDM_ACTION_TEST_ALL,    TRUE);
  493.       EnableAllMenuItems(IDM_ACTION_SELECT_ALL,  TRUE);
  494.    } else {
  495.       // Make sure we didn't partially load and added a few files.
  496.       ListView_DeleteAllItems(g_hWndList);
  497.       // If the file itself is bad or missing, then remove it from our MRU.
  498.       if ((result == PK_ERR) || (result == PK_BADERR) || (result == PK_NOZIP) ||
  499.           (result == PK_FIND) || (result == PK_EOF))
  500.       {
  501.          RemoveFileFromMRU(wszPath);
  502.       }
  503.       // Display an error.
  504.       TCHAR szError[_MAX_PATH + 128];
  505.       _stprintf(szError, TEXT("Failure loading "%s".nn"), wszPath);
  506.       _tcscat(szError, GetZipErrorString(result));
  507.       MessageBox(g_hWndMain, szError, g_szAppName, MB_OK | MB_ICONERROR);
  508.       // Clear our file status.
  509.       *g_szZipFile = '';
  510.    }
  511.    // Update our caption to show that we are done loading.
  512.    SetCaptionText(NULL);
  513.    // Update our banner to show that we are done loading.
  514.    g_fLoading = FALSE;
  515.    DrawBanner(NULL);
  516. }
  517. //******************************************************************************
  518. //***** Zip File Properties Dialog Functions
  519. //******************************************************************************
  520. BOOL CALLBACK DlgProcProperties(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  521.    switch (uMsg) {
  522.       case WM_INITDIALOG: {
  523.          // Add "General" and "Comments" tabs to tab control.  We are using a
  524.          // poor man's version of a property sheet.  We display our 2 pages
  525.          // by showing and hiding controls as necessary.  For our purposes,
  526.          // this is much easier than dealing with separate property pages.
  527.          TC_ITEM tci;
  528.          tci.mask = TCIF_TEXT;
  529.          tci.pszText = TEXT("General");
  530.          TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 0, &tci);
  531.          tci.pszText = TEXT("Comment");
  532.          TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 1, &tci);
  533. #ifdef _WIN32_WCE
  534.          // Add "Ok" button to caption bar.
  535.          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | 
  536.                        GetWindowLong(hDlg, GWL_EXSTYLE));
  537. #endif
  538.          // Center us over our parent.
  539.          CenterWindow(hDlg);
  540.          int    directory = -1, readOnly = -1, archive = -1, hidden = -1;
  541.          int    system = -1, encrypted = -1;
  542.          int    year = -1, month = -1, day = -1, hour = -1, minute = -1, pm = -1;
  543.          DWORD  dwSize = 0, dwCompressedSize = 0;
  544.          LPCSTR szPath = NULL, szMethod = NULL, szComment = NULL;
  545.          DWORD  dwCRC = 0, dwCount = 0, dwCommentCount = 0;
  546.          TCHAR  szBuffer[MAX_PATH];
  547.          // Loop through all selected items.
  548.          LV_ITEM lvi;
  549.          ZeroMemory(&lvi, sizeof(lvi));
  550.          lvi.mask = LVIF_PARAM;
  551.          lvi.iItem = -1;
  552.          while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) != -1) {
  553.             // Get the FILE_NODE for the selected item.
  554.             ListView_GetItem(g_hWndList, &lvi);
  555.             FILE_NODE *pFile = (FILE_NODE*)lvi.lParam;
  556.             // Merge this file's attributes into our accumulative attributes.
  557.             MergeValues(&directory, (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
  558.             MergeValues(&readOnly,  (pFile->dwAttributes & FILE_ATTRIBUTE_READONLY)  != 0);
  559.             MergeValues(&archive,   (pFile->dwAttributes & FILE_ATTRIBUTE_ARCHIVE)   != 0);
  560.             MergeValues(&hidden,    (pFile->dwAttributes & FILE_ATTRIBUTE_HIDDEN)    != 0);
  561.             MergeValues(&system,    (pFile->dwAttributes & FILE_ATTRIBUTE_SYSTEM)    != 0);
  562.             MergeValues(&encrypted, (pFile->dwAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0);
  563.             // Merge this file's date/time into our accumulative date/time.
  564.             int curHour = (pFile->dwModified >> 6) & 0x001F;
  565.             MergeValues(&year,   (pFile->dwModified >> 20) & 0x0FFF);
  566.             MergeValues(&month,  (pFile->dwModified >> 16) & 0x000F);
  567.             MergeValues(&day,    (pFile->dwModified >> 11) & 0x001F);
  568.             MergeValues(&hour,   (curHour % 12) ? (curHour % 12) : 12);
  569.             MergeValues(&minute, pFile->dwModified & 0x003F);
  570.             MergeValues(&pm,     curHour >= 12);
  571.             // Store this file's name.
  572.             szPath = pFile->szPathAndMethod;
  573.             // Store this file's CRC.
  574.             dwCRC = pFile->dwCRC;
  575.             // Add the size and compressed size to our accumulative sizes.
  576.             dwSize += pFile->dwSize;
  577.             dwCompressedSize += pFile->dwCompressedSize;
  578.             // Merge in our compression method.
  579.             LPCSTR szCurMethod = pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1;
  580.             if ((szMethod == NULL) || !strcmp(szMethod, szCurMethod)) {
  581.                szMethod = szCurMethod;
  582.             } else {
  583.                szMethod = "Multiple Methods";
  584.             }
  585.             // Increment our file count.
  586.             dwCount++;
  587.             // Increment our comment count if this file has a comment.
  588.             if (pFile->szComment) {
  589.                szComment = pFile->szComment;
  590.                dwCommentCount++;
  591.             }
  592.          };
  593.          if (dwCount > 1) {
  594.             // If multiple items selected, then display a selected count string
  595.             // in place of the file name.
  596.             _stprintf(szBuffer, TEXT("%u items selected."), dwCount);
  597.             SetDlgItemText(hDlg, IDC_FILE, szBuffer);
  598.             // Display "Multiple" for CRC if multiple items selected.
  599.             SetDlgItemText(hDlg, IDC_CRC, TEXT("Multiple CRCs"));
  600.          } else {
  601.             // Set the file name text for the single item selected.
  602.             mbstowcs(szBuffer, szPath, countof(szBuffer));
  603.             ForwardSlashesToBackSlashesW(szBuffer);
  604.             SetDlgItemText(hDlg, IDC_FILE, szBuffer);
  605.             // Set the CRC text for the single item selected.
  606.             _stprintf(szBuffer, TEXT("0x%08X"), dwCRC);
  607.             SetDlgItemText(hDlg, IDC_CRC, szBuffer);
  608.          }
  609.          // Set the Size tally text.
  610.          FormatValue(szBuffer, dwSize);
  611.          _tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
  612.          SetDlgItemText(hDlg, IDC_FILE_SIZE, szBuffer);
  613.          // Set the Compressed Size tally text.
  614.          FormatValue(szBuffer, dwCompressedSize);
  615.          _tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
  616.          SetDlgItemText(hDlg, IDC_COMPRESSED_SIZE, szBuffer);
  617.          // Set the Compression Factor text.
  618.          int factor = ratio(dwSize, dwCompressedSize);
  619.          _stprintf(szBuffer, TEXT("%d.%d%%"), factor / 10, 
  620.                    ((factor < 0) ? -factor : factor) % 10);
  621.          SetDlgItemText(hDlg, IDC_COMPRESSON_FACTOR, szBuffer);
  622.          // Set the Compression Method text.
  623.          mbstowcs(szBuffer, szMethod, countof(szBuffer));
  624.          SetDlgItemText(hDlg, IDC_COMPRESSION_METHOD, szBuffer);
  625.          // Set the Attribute check boxes.
  626.          CheckThreeStateBox(hDlg, IDC_DIRECTORY, directory);
  627.          CheckThreeStateBox(hDlg, IDC_READONLY,  readOnly);
  628.          CheckThreeStateBox(hDlg, IDC_ARCHIVE,   archive);
  629.          CheckThreeStateBox(hDlg, IDC_HIDDEN,    hidden);
  630.          CheckThreeStateBox(hDlg, IDC_SYSTEM,    system);
  631.          CheckThreeStateBox(hDlg, IDC_ENCRYPTED, encrypted);
  632.          // Build and set the Modified Date text.  The MS compiler does not
  633.          // consider "??/" to be a valid string.  "??/" is a trigraph that is
  634.          // turned into "" by the preprocessor and causes grief for the compiler.
  635.          LPTSTR psz = szBuffer;
  636.          psz += ((month  < 0) ? _stprintf(psz, TEXT("??/")) : 
  637.                                 _stprintf(psz, TEXT("%u/"), month));
  638.          psz += ((day    < 0) ? _stprintf(psz, TEXT("??/")) :
  639.                                 _stprintf(psz, TEXT("%u/"), day));
  640.          psz += ((year   < 0) ? _stprintf(psz, TEXT("?? ")) : 
  641.                                 _stprintf(psz, TEXT("%u "), year % 100));
  642.          psz += ((hour   < 0) ? _stprintf(psz, TEXT("??:")) : 
  643.                                 _stprintf(psz, TEXT("%u:"), hour));
  644.          psz += ((minute < 0) ? _stprintf(psz, TEXT("?? ")) : 
  645.                                 _stprintf(psz, TEXT("%02u "), minute));
  646.          psz += ((pm     < 0) ? _stprintf(psz, TEXT("?M")) : 
  647.                                 _stprintf(psz, TEXT("%cM"), pm ? TEXT('P') : TEXT('A')));
  648.          SetDlgItemText(hDlg, IDC_MODIFIED, szBuffer);
  649.          // Store a global handle to our edit control.
  650.          g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
  651.          // Disable our edit box from being edited.
  652.          DisableEditing(g_hWndEdit);
  653.          // Stuff the appropriate message into the Comment edit control.
  654.          if (dwCommentCount == 0) {
  655.             if (dwCount == 1) {
  656.                AddTextToEdit("This file does not have a comment.");
  657.             } else {
  658.                AddTextToEdit("None of the selected files have a comment.");
  659.             }
  660.          } else if (dwCount == 1) {
  661.             AddTextToEdit(szComment);
  662.          } else {
  663.             CHAR szTemp[64];
  664.             _stprintf(szBuffer, TEXT("%u of the selected files %s a comment."), 
  665.                       dwCommentCount, (dwCommentCount == 1)? TEXT("has") : TEXT("have"));
  666.             wcstombs(szTemp, szBuffer, countof(szTemp));
  667.             AddTextToEdit(szTemp);
  668.          }
  669.          g_hWndEdit = NULL;
  670.          // Whooh, done with WM_INITDIALOG
  671.          return TRUE;
  672.       }
  673.       case WM_NOTIFY:
  674.          // Check to see if tab control was changed to new tab.
  675.          if (((NMHDR*)lParam)->code == TCN_SELCHANGE) {
  676.             HWND hWndTab     = ((NMHDR*)lParam)->hwndFrom;
  677.             HWND hWndComment = GetDlgItem(hDlg, IDC_COMMENT);
  678.             HWND hWnd        = GetWindow(hDlg, GW_CHILD);
  679.             // If General tab selected, hide comment edit box and show all other controls.
  680.             if (TabCtrl_GetCurSel(hWndTab) == 0) {
  681.                while (hWnd) {
  682.                   ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd != hWndComment)) ?
  683.                              SW_SHOW : SW_HIDE);
  684.                   hWnd = GetWindow(hWnd, GW_HWNDNEXT);
  685.                }
  686.             // If Comment tab selected, hide all controls except comment edit box.
  687.             } else {
  688.                while (hWnd) {
  689.                   ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd == hWndComment)) ?
  690.                              SW_SHOW : SW_HIDE);
  691.                   hWnd = GetWindow(hWnd, GW_HWNDNEXT);
  692.                }
  693.             }
  694.          }
  695.          return FALSE;
  696.       case WM_COMMAND:
  697.          // Exit the dialog on OK (Enter) or CANCEL (Esc).
  698.          if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
  699.             EndDialog(hDlg, LOWORD(wParam));
  700.          }
  701.          return FALSE;
  702.    }
  703.    return FALSE;
  704. }
  705. //******************************************************************************
  706. void MergeValues(int *p1, int p2) {
  707.    if ((*p1 == -1) || (*p1 == p2)) {
  708.       *p1 = p2;
  709.    } else {
  710.       *p1 = -2;
  711.    }
  712. }
  713. //******************************************************************************
  714. void CheckThreeStateBox(HWND hDlg, int nIDButton, int state) {
  715.    CheckDlgButton(hDlg, nIDButton, (state == 0) ? BST_UNCHECKED : 
  716.                                    (state == 1) ? BST_CHECKED : 
  717.                                                   BST_INDETERMINATE);
  718. }
  719. //******************************************************************************
  720. //***** Extract/Test Dialog Functions
  721. //******************************************************************************
  722. void ExtractOrTestFiles(BOOL fExtract) {
  723.    EXTRACT_INFO ei;
  724.    ZeroMemory(&ei, sizeof(ei));
  725.    // Set our Extract or Test flag.
  726.    ei.fExtract = fExtract;
  727.    // Get the number of selected items and make sure we have at least one item.
  728.    if ((ei.dwFileCount = ListView_GetSelectedCount(g_hWndList)) <= 0) {
  729.       return;
  730.    }
  731.    // If we are not extracting/testing all, then create and buffer large enough to
  732.    // hold the file list for all the selected files.
  733.    if ((int)ei.dwFileCount != ListView_GetItemCount(g_hWndList)) {
  734.       ei.szFileList = new LPSTR[ei.dwFileCount + 1];
  735.       if (!ei.szFileList) {
  736.          MessageBox(g_hWndMain, GetZipErrorString(PK_MEM), g_szAppName, 
  737.                     MB_ICONERROR | MB_OK);
  738.          return;
  739.       }
  740.    }
  741.    ei.dwFileCount = 0;
  742.    ei.dwByteCount = 0;
  743.    LV_ITEM lvi;
  744.    ZeroMemory(&lvi, sizeof(lvi));
  745.    lvi.mask = LVIF_PARAM;
  746.    lvi.iItem = -1;
  747.    // Walk through all the selected files to build our counts and set our file
  748.    // list pointers into our FILE_NODE paths for each selected item.
  749.    while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) >= 0) {
  750.       ListView_GetItem(g_hWndList, &lvi);
  751.       if (ei.szFileList) {
  752.          ei.szFileList[ei.dwFileCount] = ((FILE_NODE*)lvi.lParam)->szPathAndMethod;
  753.       }
  754.       ei.dwFileCount++;
  755.       ei.dwByteCount += ((FILE_NODE*)lvi.lParam)->dwSize;
  756.    }
  757.    if (ei.szFileList) {
  758.       ei.szFileList[ei.dwFileCount] = NULL;
  759.    }
  760.    // If we are extracting, display the extract dialog to query for parameters.
  761.    if (!fExtract || (DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT), g_hWndMain, 
  762.                                     (DLGPROC)DlgProcExtractOrTest, (LPARAM)&ei) == IDOK))
  763.    {
  764.       // Display our progress dialog and do the extraction/test.
  765.       DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT_PROGRESS), g_hWndMain, 
  766.                      (DLGPROC)DlgProcExtractProgress, (LPARAM)&ei);
  767.    }
  768.    // Free our file list buffer if we created one.
  769.    if (ei.szFileList) {
  770.       delete[] ei.szFileList;
  771.    }
  772. }
  773. //******************************************************************************
  774. BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  775.    static EXTRACT_INFO *pei;
  776.    TCHAR  szPath[_MAX_PATH];
  777.    switch (uMsg) {
  778.       case WM_INITDIALOG:
  779.          
  780.          // Store our extract information structure.
  781.          pei = (EXTRACT_INFO*)lParam;
  782.          // Load our settings.
  783.          pei->fRestorePaths = GetOptionInt(TEXT("RestorePaths"), TRUE);
  784.          pei->overwriteMode = (OVERWRITE_MODE)GetOptionInt(TEXT("OverwriteMode"), OM_PROMPT);
  785.          // Load and set our path string.
  786.          GetOptionString(TEXT("ExtractToDirectory"), TEXT("\"), szPath, sizeof(szPath));
  787.          SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
  788.          // Set the state of all the controls.
  789.          SetDlgItemText(hDlg, IDC_FILE_COUNT, FormatValue(szPath, pei->dwFileCount));
  790.          SetDlgItemText(hDlg, IDC_BYTE_COUNT, FormatValue(szPath, pei->dwByteCount));
  791.          CheckDlgButton(hDlg, IDC_RESTORE_PATHS, pei->fRestorePaths);
  792.          CheckDlgButton(hDlg, IDC_OVERWRITE_PROMPT, pei->overwriteMode == OM_PROMPT);
  793.          CheckDlgButton(hDlg, IDC_OVERWRITE_NEWER,  pei->overwriteMode == OM_NEWER);
  794.          CheckDlgButton(hDlg, IDC_OVERWRITE_ALWAYS, pei->overwriteMode == OM_ALWAYS);
  795.          CheckDlgButton(hDlg, IDC_OVERWRITE_NEVER,  pei->overwriteMode == OM_NEVER);
  796.          // Limit our edit control to max path.
  797.          SendDlgItemMessage(hDlg, IDC_EXTRACT_TO, EM_LIMITTEXT, sizeof(szPath) - 1, 0);
  798.          // Center our dialog.
  799.          CenterWindow(hDlg);
  800.          return TRUE;
  801.       case WM_COMMAND:
  802.          switch (LOWORD(wParam)) {
  803.             case IDOK:
  804.                // Force us to read and validate the extract to directory.
  805.                SendMessage(hDlg, WM_COMMAND, MAKELONG(IDC_EXTRACT_TO, EN_KILLFOCUS), 0);
  806.                // Get our current path string.
  807.                GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
  808.                // Verify our "extract to" path is valid.
  809.                if (!SetExtractToDirectory(szPath)) {
  810.                   MessageBox(hDlg, TEXT("The directory you entered is invalid or does not exist."), 
  811.                              g_szAppName, MB_ICONERROR | MB_OK);
  812.                   SetFocus(GetDlgItem(hDlg, IDC_EXTRACT_TO));
  813.                   return FALSE;
  814.                }
  815.                // Query other control values.
  816.                pei->fRestorePaths = IsDlgButtonChecked(hDlg, IDC_RESTORE_PATHS);
  817.                pei->overwriteMode = 
  818.                   IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEWER)  ? OM_NEWER  :
  819.                   IsDlgButtonChecked(hDlg, IDC_OVERWRITE_ALWAYS) ? OM_ALWAYS :
  820.                   IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEVER)  ? OM_NEVER  : OM_PROMPT;
  821.                // Write our settings.
  822.                WriteOptionInt(TEXT("RestorePaths"), pei->fRestorePaths);
  823.                WriteOptionInt(TEXT("OverwriteMode"), pei->overwriteMode);
  824.                WriteOptionString(TEXT("ExtractToDirectory"), szPath);
  825.                // Fall through to IDCANCEL
  826.                
  827.             case IDCANCEL:
  828.                EndDialog(hDlg, LOWORD(wParam));
  829.                return FALSE;
  830.             case IDC_EXTRACT_TO:
  831.  
  832.                // Make sure the path ends in a wack ().
  833.                if (HIWORD(wParam) == EN_KILLFOCUS) {
  834.                   GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
  835.                   int length = _tcslen(szPath);
  836.                   if ((length == 0) || szPath[length - 1] != TEXT('\')) {
  837.                      szPath[length    ] = TEXT('\');
  838.                      szPath[length + 1] = TEXT('');
  839.                      SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
  840.                   }
  841.                }
  842.                return FALSE;
  843.             
  844.             case IDC_BROWSE:
  845.                GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
  846.                if (FolderBrowser(szPath, countof(szPath))) {
  847.                   SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
  848.                }
  849.                return FALSE;
  850.          }
  851.          return FALSE;
  852.    }
  853.    return FALSE;
  854. }
  855. //******************************************************************************
  856. //***** Folder Browsing Dialog Functions
  857. //******************************************************************************
  858. BOOL FolderBrowser(LPTSTR szPath, DWORD dwLength) {
  859. #ifdef _WIN32_WCE
  860.    // On Windows CE, we use a common save-as dialog to query the diretory.  We
  861.    // display the dialog in this function, and then we sublass it.  Our subclass
  862.    // functions tweaks the dialog a bit and and returns the path.
  863.    ForwardSlashesToBackSlashesW(szPath);
  864.    TCHAR szInitialDir[_MAX_PATH];
  865.    _tcscpy(szInitialDir, szPath);
  866.    // Remove trailing wacks from path - The common dialog doesn't like them.
  867.    int length = _tcslen(szInitialDir);
  868.    while ((length > 0) && (szInitialDir[length - 1] == TEXT('\'))) {
  869.       szInitialDir[--length] = TEXT('');
  870.    }
  871.    // Set up the parameters for our save-as dialog.
  872.    OPENFILENAME ofn;
  873.    ZeroMemory(&ofn, sizeof(ofn));
  874.    ofn.lStructSize     = sizeof(ofn);
  875.    ofn.hwndOwner       = g_hWndMain;
  876.    ofn.hInstance       = g_hInst;
  877.    ofn.lpstrFilter     = TEXT(" !");
  878.    ofn.nFilterIndex    = 1;
  879.    ofn.lpstrFile       = szPath;
  880.    ofn.nMaxFile        = dwLength;
  881.    ofn.lpstrInitialDir = *szInitialDir ? szInitialDir : NULL;
  882.    ofn.lpstrTitle      = TEXT("Extract To");
  883.    ofn.Flags           = OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_NOTESTFILECREATE;
  884.    // Post a message to our main window telling it that we are about to create
  885.    // a save as dialog.  Our main window will receive this message after the
  886.    // save as dialog is created.  This gives us a change to subclass the save as
  887.    // dialog.
  888.    PostMessage(g_hWndMain, WM_PRIVATE, MSG_SUBCLASS_DIALOG, 0);
  889.    // Create and display the common save-as dialog.
  890.    if (GetSaveFileName(&ofn)) {
  891.       // If success, then remove are special "!" filename from the end.
  892.       szPath[_tcslen(szPath) - 1] = TEXT('');
  893.       return TRUE;
  894.    }
  895.    return FALSE;
  896. #else // !_WIN32_WCE
  897.    // On Windows NT, the shell provides us with a nice folder browser dialog.
  898.    // We don't need to jump through any hoops to make it work like on Windows CE.
  899.    // The only problem is that on VC 4.0, the libraries don't export the UNICODE
  900.    // shell APIs because only Win95 had a shell library at the time.  The
  901.    // following code requires headers and libs from VC 4.2 or later.
  902.    // Set up our BROWSEINFO structure.
  903.    BROWSEINFO bi;
  904.    ZeroMemory(&bi, sizeof(bi));
  905.    bi.hwndOwner = g_hWndMain;
  906.    bi.pszDisplayName = szPath;
  907.    bi.lpszTitle = TEXT("Extract To");
  908.    bi.ulFlags = BIF_RETURNONLYFSDIRS;
  909.  
  910.    // Prompt user for path.
  911.    LPITEMIDLIST piidl = SHBrowseForFolder(&bi);
  912.    if (!piidl) {
  913.       return FALSE;
  914.    }
  915.    // Build path string.
  916.    SHGetPathFromIDList(piidl, szPath);
  917.  
  918.    // Free the PIDL returned by SHBrowseForFolder. 
  919.    LPMALLOC pMalloc = NULL;
  920.    SHGetMalloc(&pMalloc);
  921.    pMalloc->Free(piidl); 
  922.  
  923.    // Add trailing wack if one is not present.
  924.    int length = _tcslen(szPath);
  925.    if ((length > 0) && (szPath[length - 1] != TEXT('\'))) {
  926.       szPath[length++] = TEXT('\');
  927.       szPath[length]   = TEXT('');
  928.    }
  929.    return TRUE;
  930. #endif // _WIN32_WCE
  931. }
  932. //******************************************************************************
  933. #ifdef _WIN32_WCE
  934. BOOL CALLBACK DlgProcBrowser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  935.    // This is our subclass of Windows CE's common save-as dialog.  We intercept
  936.    // the messages we care about and forward everything else to the original
  937.    // window procedure for the dialog.
  938.    if (uMsg == WM_PRIVATE) { // wParam always equals MSG_INIT_DIALOG
  939.       RECT rc1, rc2;
  940.       // Get the window rectangle for the name edit control.
  941.       HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_NAME_EDIT);
  942.       GetWindowRect(hWnd, &rc1);
  943.       POINT pt1 = { rc1.left, rc1.top };
  944.       ScreenToClient(hDlg, &pt1);
  945.       // Hide all the windows we don't want.
  946.       ShowWindow(hWnd, SW_HIDE);
  947.       ShowWindow(GetDlgItem(hDlg, IDC_SAVE_NAME_PROMPT), SW_HIDE);
  948.       ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_PROMPT), SW_HIDE);
  949.       ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_LIST), SW_HIDE);
  950.       // Get the window rectangle for the file list.
  951.       hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
  952.       GetWindowRect(hWnd, &rc2);
  953.       POINT pt2 = { rc2.left, rc2.top };
  954.       ScreenToClient(hDlg, &pt2);
  955.       // Resize the file list to fill the dialog.
  956.       MoveWindow(hWnd, pt2.x, pt2.y, rc2.right - rc2.left, rc1.bottom - rc2.top, TRUE);
  957.    } else if ((uMsg == WM_COMMAND) && (LOWORD(wParam) == IDOK)) {
  958.       // Get our file list window.
  959.       HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
  960.       // Check to see if a directory is selected.
  961.       if (ListView_GetNextItem(hWnd, -1, LVNI_SELECTED) >= 0) {
  962.          // If a directory is highlighted, then we post ourself a "Ok".  The "Ok"
  963.          // we are processing now will cause us to change into the highlighted
  964.          // directory, and our posted "Ok" will close the dialog in that directory.
  965.          PostMessage(hDlg, uMsg, wParam, lParam);
  966.       } else {
  967.          // If no directory is selected, then enter the imaginary filename "!"
  968.          // into the name edit control and let the "Ok" end this dialog. The 
  969.          // result will be the correct path with a "!" at the end.
  970.          SetDlgItemText(hDlg, IDC_SAVE_NAME_EDIT, TEXT("!"));
  971.       }
  972.    }
  973.    // Pass all messages to the base control's window proc.
  974.    return CallWindowProc(g_wpSaveAsDlg, hDlg, uMsg, wParam, lParam);
  975. }
  976. #endif // _WIN32_WCE
  977. //******************************************************************************
  978. #ifdef _WIN32_WCE
  979. void SubclassSaveAsDlg() {
  980.    // Get our cuurent thread ID so we can compare it to other thread IDs.
  981.    DWORD dwThreadId = GetCurrentThreadId();
  982.    // Get the the top window in the z-order that is a child of the desktop.
  983.    // Dialogs are always children of the desktop on CE.  This first window
  984.    // should be the dialog we are looking for, but we will walk the window list
  985.    // just in case.
  986.    HWND hWnd = GetWindow(g_hWndMain, GW_HWNDFIRST);
  987.    // Walk the window list.
  988.    while (hWnd) {
  989.    
  990.       // Check to see if this window was created by us and has controls from a
  991.       // common "save as" dialog.
  992.       if ((GetWindowThreadProcessId(hWnd, NULL) == dwThreadId) &&
  993.            GetDlgItem(hWnd, IDC_SAVE_FILE_LIST) &&
  994.            GetDlgItem(hWnd, IDC_SAVE_NAME_EDIT))
  995.       {
  996.          // We found our dialog.  Subclass it.
  997.          g_wpSaveAsDlg = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
  998.          SetWindowLong(hWnd, GWL_WNDPROC, (LONG)DlgProcBrowser);
  999.          // Send our new dialog a message so it can do its initialization.
  1000.          SendMessage(hWnd, WM_PRIVATE, MSG_INIT_DIALOG, 0);
  1001.       }
  1002.       // Get the next window in our window list.
  1003.       hWnd = GetWindow(hWnd, GW_HWNDNEXT);
  1004.    }
  1005. }
  1006. #endif // _WIN32_WCE
  1007. //******************************************************************************
  1008. //***** Extraction/Test/View Progress Dialog Functions
  1009. //******************************************************************************
  1010. BOOL CALLBACK DlgProcExtractProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1011.    static EXTRACT_INFO *pei;
  1012.    static BOOL fComplete;
  1013.    static HWND hWndButton;
  1014.    TCHAR szBuffer[32];
  1015.    switch (uMsg) {
  1016.       case WM_INITDIALOG:
  1017.          
  1018.          // Globally store our handle so our worker thread can post to us.
  1019.          g_hDlgProgress = hDlg;
  1020.          // Get a pointer to our extract information structure.
  1021.          pei = (EXTRACT_INFO*)lParam;
  1022.          // Clear our complete flag.  It will be set to TRUE when done.
  1023.          fComplete = FALSE;
  1024.          // Get and store our edit control.
  1025.          g_hWndEdit = GetDlgItem(hDlg, IDC_LOG);
  1026.          // Disable our edit box from being edited.
  1027.          DisableEditing(g_hWndEdit);
  1028.          // Store a static handle for our Abort/Close button.
  1029.          hWndButton = GetDlgItem(hDlg, IDCANCEL);
  1030. #ifdef _WIN32_WCE
  1031.          // Set our No-Drag style
  1032.          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_NODRAG |GetWindowLong(hDlg, GWL_EXSTYLE));
  1033.          RECT rc1, rc2, rcEdit;
  1034.          // Get our current client size.
  1035.          GetClientRect(hDlg, &rc1);
  1036.          // Get the window rectangle for the edit control in client coordinates.
  1037.          GetWindowRect(g_hWndEdit, &rcEdit);
  1038.          ScreenToClient(hDlg, ((POINT*)&rcEdit));
  1039.          ScreenToClient(hDlg, ((POINT*)&rcEdit) + 1);
  1040.          // Resize our dialog to be full screen (same size as parent).
  1041.          GetWindowRect(g_hWndMain, &rc2);
  1042.          MoveWindow(hDlg, rc2.left, rc2.top, rc2.right - rc2.left, 
  1043.                     rc2.bottom - rc2.top + 1, FALSE);
  1044.          // Get our new client size.
  1045.          GetClientRect(hDlg, &rc2);
  1046.          // Resize our edit box to fill the client.
  1047.          MoveWindow(g_hWndEdit, rcEdit.left, rcEdit.top, 
  1048.                     (rcEdit.right  - rcEdit.left) + (rc2.right  - rc1.right),
  1049.                     (rcEdit.bottom - rcEdit.top)  + (rc2.bottom - rc1.bottom),
  1050.                     FALSE);
  1051. #else
  1052.          // On NT, we just center our dialog over our parent.
  1053.          CenterWindow(hDlg);
  1054. #endif
  1055.          // Store some globals until the extract/test finishes.
  1056.          pei->hWndEditFile       = GetDlgItem(hDlg, IDC_FILE);
  1057.          pei->hWndProgFile       = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
  1058.          pei->hWndProgTotal      = GetDlgItem(hDlg, IDC_TOTAL_PROGRESS);
  1059.          pei->hWndPercentage     = GetDlgItem(hDlg, IDC_PERCENTAGE);
  1060.          pei->hWndFilesProcessed = GetDlgItem(hDlg, IDC_FILES_PROCESSED);
  1061.          pei->hWndBytesProcessed = GetDlgItem(hDlg, IDC_BYTES_PROCESSED);
  1062.          if (pei->fExtract) {
  1063.             // Set our main window's caption.
  1064.             SetCaptionText(TEXT("Extracting"));
  1065.          } else {
  1066.             // Set our main window's caption.
  1067.             SetCaptionText(TEXT("Testing"));
  1068.             // Hide the current file progress for test since it never moves.
  1069.             ShowWindow(pei->hWndProgFile, SW_HIDE);
  1070.          }
  1071.          // Set the ranges on our progress bars.
  1072.          SendMessage(pei->hWndProgFile,  PBM_SETRANGE, 0, 
  1073.                      MAKELPARAM(0, PROGRESS_MAX));
  1074.          SendMessage(pei->hWndProgTotal, PBM_SETRANGE, 0, 
  1075.                      MAKELPARAM(0, PROGRESS_MAX));
  1076.          // Set our file and byte totals.
  1077.          SetDlgItemText(hDlg, IDC_FILES_TOTAL, 
  1078.                         FormatValue(szBuffer, pei->dwFileCount));
  1079.          SetDlgItemText(hDlg, IDC_BYTES_TOTAL, 
  1080.                         FormatValue(szBuffer, pei->dwByteCount));
  1081.          // Luanch our Extract/Test thread and wait for WM_PRIVATE
  1082.          DoExtractOrTestFiles(g_szZipFile, pei);
  1083.          return TRUE;
  1084.       case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
  1085.                        // test/extract is complete.
  1086.          // Check to see if the operation was a success
  1087.          if ((pei->result == PK_OK) || (pei->result == PK_WARN)) {
  1088.             // Set all our fields to their "100%" settings.
  1089.             SendMessage(pei->hWndProgFile,  PBM_SETPOS, PROGRESS_MAX, 0);
  1090.             SendMessage(pei->hWndProgTotal, PBM_SETPOS, PROGRESS_MAX, 0);
  1091.             SetWindowText(pei->hWndPercentage, TEXT("100%"));
  1092.             SetDlgItemText(hDlg, IDC_FILES_PROCESSED, 
  1093.                            FormatValue(szBuffer, pei->dwFileCount));
  1094.             SetDlgItemText(hDlg, IDC_BYTES_PROCESSED, 
  1095.                            FormatValue(szBuffer, pei->dwByteCount));
  1096.          }
  1097.          // Update our status text.
  1098.          SetWindowText(pei->hWndEditFile, 
  1099.             (pei->result == PK_OK)      ? TEXT("Completed.  There were no warnings or errors.") :
  1100.             (pei->result == PK_WARN)    ? TEXT("Completed.  There was one or more warnings.") :
  1101.             (pei->result == PK_ABORTED) ? TEXT("Aborted.  There may be warnings or errors.") :
  1102.                                           TEXT("Completed.  There was one or more errors."));
  1103.          // Clear our global edit handle.
  1104.          g_hWndEdit = NULL;
  1105.          // Update our caption to show that we are done extracting/testing.
  1106.          SetCaptionText(NULL);
  1107.          // Change our abort button to now read "Close".
  1108.          SetWindowText(hWndButton, TEXT("&Close"));
  1109.          EnableWindow(hWndButton, TRUE);
  1110.          // Display an error dialog if an error occurred.
  1111.          if ((pei->result != PK_OK) && (pei->result != PK_WARN)) {
  1112.             MessageBox(hDlg, GetZipErrorString(pei->result),
  1113.                        g_szAppName, MB_ICONERROR | MB_OK);
  1114.          }
  1115.          // We are done.  Allow the user to close the dialog.
  1116.          fComplete = TRUE;
  1117.          return FALSE;
  1118.       case WM_COMMAND:
  1119.          switch (LOWORD(wParam)) {
  1120.             case IDCANCEL:
  1121.                // If abort is pressed, then set a flag that our worker thread
  1122.                // periodically checks to decide if it needs to bail out.
  1123.                if (!fComplete && !pei->fAbort) {
  1124.                   pei->fAbort = TRUE;
  1125.                   SetWindowText(hWndButton, TEXT("Aborting..."));
  1126.                   EnableWindow(hWndButton, FALSE);
  1127.                   return FALSE;
  1128.                }
  1129.                // fall through to IDOK
  1130.             case IDOK:
  1131.                // Don't allow dialog to close until extract/test is complete.
  1132.                if (fComplete) {
  1133.                   g_hDlgProgress = NULL;
  1134.                   EndDialog(hDlg, LOWORD(wParam));
  1135.                }
  1136.                return FALSE;
  1137.          }
  1138.          return FALSE;
  1139.    }
  1140.    return FALSE;
  1141. }
  1142. //******************************************************************************
  1143. BOOL CALLBACK DlgProcViewProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1144.    static EXTRACT_INFO *pei;
  1145.    switch (uMsg) {
  1146.       case WM_INITDIALOG:
  1147.          
  1148.          // Globally store our handle so our worker thread can post to us.
  1149.          g_hDlgProgress = hDlg;
  1150.          // Get a pointer to our extract information structure.
  1151.          pei = (EXTRACT_INFO*)lParam;
  1152.          // Center our dialog over our parent.
  1153.          CenterWindow(hDlg);
  1154.          // Store some globals until the extract finishes.
  1155.          pei->hWndProgFile = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
  1156.          // Set the ranges on our progress bar.
  1157.          SendDlgItemMessage(hDlg, IDC_FILE_PROGRESS, PBM_SETRANGE, 0, 
  1158.                             MAKELPARAM(0, PROGRESS_MAX));
  1159.          // Luanch our Extract thread and wait for WM_PRIVATE message.
  1160.          DoExtractOrTestFiles(g_szZipFile, pei);
  1161.          return TRUE;
  1162.       case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
  1163.                        // test/extract is complete.
  1164.          // We are done.  Close our dialog.  Any errors will be reported by
  1165.          // OnActionView().
  1166.          g_hDlgProgress = NULL;
  1167.          EndDialog(hDlg, LOWORD(wParam));
  1168.          return FALSE;
  1169.       case WM_COMMAND:
  1170.          // If abort is pressed, then set a flag that our worker thread
  1171.          // periodically checks to decide if it needs to bail out.
  1172.          if ((LOWORD(wParam) == IDCANCEL) && !pei->fAbort) {
  1173.             pei->fAbort = TRUE;
  1174.             SetWindowText(GetDlgItem(hDlg, IDCANCEL), TEXT("Aborting..."));
  1175.             EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
  1176.             return FALSE;
  1177.          }
  1178.    }
  1179.    return FALSE;
  1180. }
  1181. //******************************************************************************
  1182. void UpdateProgress(EXTRACT_INFO *pei, BOOL fFull) {
  1183.    DWORD dwFile, dwTotal, dwPercentage;
  1184.    TCHAR szBuffer[_MAX_PATH + 32];
  1185.    // Compute our file progress bar position.
  1186.    if (pei->dwBytesTotalThisFile) {
  1187.       dwFile = (DWORD)(((DWORDLONG)PROGRESS_MAX * 
  1188.                         (DWORDLONG)pei->dwBytesWrittenThisFile) / 
  1189.                         (DWORDLONG)pei->dwBytesTotalThisFile);
  1190.    } else {
  1191.       dwFile = PROGRESS_MAX;
  1192.    }
  1193.    // Set our file progress indicators.
  1194.    SendMessage(pei->hWndProgFile,  PBM_SETPOS, dwFile,  0);
  1195.    // If we are only updating our View Progress dialog, then we are done.
  1196.    if (!pei->hWndProgTotal) {
  1197.       return;
  1198.    }
  1199.    // Compute our total progress bar position.
  1200.    dwTotal = (DWORD)(((DWORDLONG)PROGRESS_MAX * 
  1201.                       (DWORDLONG)(pei->dwBytesWrittenPreviousFiles + 
  1202.                                   pei->dwBytesWrittenThisFile + 
  1203.                                   pei->dwFile)) / 
  1204.                       (DWORDLONG)(pei->dwByteCount + 
  1205.                                   pei->dwFileCount));
  1206.    dwPercentage = dwTotal / (PROGRESS_MAX / 100);
  1207.    // Set our total progress indicators.
  1208.    SendMessage(pei->hWndProgTotal, PBM_SETPOS, dwTotal, 0);
  1209.    // Set our total percentage text.
  1210.    _stprintf(szBuffer, TEXT("%u%%"), dwPercentage);
  1211.    SetWindowText(pei->hWndPercentage, szBuffer);
  1212.    // Set our current file and byte process counts.
  1213.    FormatValue(szBuffer, pei->dwFile - 1);
  1214.    SetWindowText(pei->hWndFilesProcessed, szBuffer);
  1215.    FormatValue(szBuffer, pei->dwBytesWrittenPreviousFiles + 
  1216.                pei->dwBytesWrittenThisFile);
  1217.    SetWindowText(pei->hWndBytesProcessed, szBuffer);
  1218.    if (fFull) {
  1219.       // Build our message string.
  1220.       _stprintf(szBuffer, TEXT("%Sing: %S"), pei->fExtract ? 
  1221.                 "Extract" : "Test", pei->szFile);
  1222.       // Change all forward slashes to back slashes in the buffer.
  1223.       ForwardSlashesToBackSlashesW(szBuffer);
  1224.       // Update the file name in our dialog.
  1225.       SetWindowText(pei->hWndEditFile, szBuffer);
  1226.    }
  1227. }
  1228. //******************************************************************************
  1229. //***** Replace File Dialog Functions
  1230. //******************************************************************************
  1231. int PromptToReplace(LPCSTR szPath) {
  1232.    // Check to see if we are extracting for view only.
  1233.    if (g_fViewing) {
  1234.       // Build prompt.
  1235.       TCHAR szMessage[_MAX_PATH + 128];
  1236.       _stprintf(szMessage, 
  1237.          TEXT("A file named "%S" has already been extracted for viewing.  ")
  1238.          TEXT("That file might be opened and locked for viewing by another application.nn")
  1239.          TEXT("Would you like to attempt to overwirite it with the new file?"),
  1240.          GetFileFromPath(szPath));
  1241.       
  1242.       // Display prompt.
  1243.       if (IDYES == MessageBox(g_hDlgProgress, szMessage, g_szAppName, 
  1244.                               MB_ICONWARNING | MB_YESNO))
  1245.       {
  1246.          // Tell Info-ZIP to continue with extraction.
  1247.          return IDM_REPLACE_YES;
  1248.       }
  1249.       // Remember that the file was skipped and tell Info-ZIP to abort extraction.
  1250.       g_fSkipped = TRUE;
  1251.       return IDM_REPLACE_NO;
  1252.    }
  1253.    
  1254.    // Otherwise, do the normal replace prompt dialog.
  1255.    return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_REPLACE), g_hWndMain, 
  1256.                          (DLGPROC)DlgProcReplace, (LPARAM)szPath);
  1257. }
  1258. //******************************************************************************
  1259. BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1260.    TCHAR szMessage[_MAX_PATH + 32];
  1261.    switch (uMsg) {
  1262.       case WM_INITDIALOG:
  1263.          // Play the question tone to alert the user.
  1264.          MessageBeep(MB_ICONQUESTION);
  1265.          
  1266.          // Display a message with the file name.
  1267.          _stprintf(szMessage, TEXT(""%S" already exists."), (LPCSTR)lParam);
  1268.          // Change all forward slashes to back slashes in the buffer.
  1269.          ForwardSlashesToBackSlashesW(szMessage);
  1270.          // Display the file string.
  1271.          SetDlgItemText(hDlg, IDC_FILE, szMessage);
  1272.          // Center our dialog over our parent.
  1273.          CenterWindow(hDlg);
  1274.          return TRUE;
  1275.       case WM_COMMAND:
  1276.          switch (LOWORD(wParam)) {
  1277.             case IDCANCEL:
  1278.             case IDOK:
  1279.                EndDialog(hDlg, IDM_REPLACE_NO);
  1280.                break;
  1281.             case IDM_REPLACE_ALL:
  1282.             case IDM_REPLACE_NONE:
  1283.             case IDM_REPLACE_YES:
  1284.             case IDM_REPLACE_NO:
  1285.                EndDialog(hDlg, wParam);
  1286.                break;
  1287.          }
  1288.          return FALSE;
  1289.    }
  1290.    return FALSE;
  1291. }
  1292. //******************************************************************************
  1293. //***** Password Dialog Functions
  1294. //******************************************************************************
  1295. #if CRYPT
  1296. BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1297.    
  1298.    // Return Values:
  1299.    //    IZ_PW_ENTERED    got some PWD string, use/try it
  1300.    //    IZ_PW_CANCEL     no password available (for this entry)
  1301.    //    IZ_PW_CANCELALL  no password, skip any further PWD request
  1302.    //    IZ_PW_ERROR      failure (no mem, no tty, ...)
  1303.    static DECRYPT_INFO *pdi;
  1304.    TCHAR szMessage[_MAX_PATH + 32];
  1305.    switch (uMsg) {
  1306.       case WM_INITDIALOG:
  1307.          // Play the question tone to alert the user.
  1308.          MessageBeep(MB_ICONQUESTION);
  1309.          
  1310. #ifdef _WIN32_WCE
  1311.          // Add "Ok" button to caption bar.
  1312.          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | 
  1313.                        GetWindowLong(hDlg, GWL_EXSTYLE));
  1314. #endif
  1315.          // Store our decrypt information structure.
  1316.          pdi = (DECRYPT_INFO*)lParam;
  1317.          // Display a message with the file name.
  1318.          _stprintf(szMessage, TEXT(""%S" is encrypted."), pdi->szFile);
  1319.          // Change all forward slashes to back slashes in the buffer.
  1320.          ForwardSlashesToBackSlashesW(szMessage);
  1321.          // Display the message with the file name.
  1322.          SetDlgItemText(hDlg, IDC_FILE, szMessage);
  1323.          // Display the appropriate prompt.
  1324.          if (pdi->retry) {
  1325.             _stprintf(szMessage, TEXT("Password was incorrect. Please re-enter (%d/%d)."),
  1326.                      MAX_PASSWORD_RETRIES - pdi->retry + 2, MAX_PASSWORD_RETRIES + 1);
  1327.             SetDlgItemText(hDlg, IDC_PROMPT, szMessage);
  1328.          } else {
  1329.             SetDlgItemText(hDlg, IDC_PROMPT, TEXT("Please enter the password."));
  1330.          }
  1331.          // Limit the password to the size of the password buffer we have been given.
  1332.          SendDlgItemMessage(hDlg, IDC_PASSWORD, EM_LIMITTEXT, pdi->nSize - 1, 0);
  1333.          // Center our dialog over our parent.
  1334.          CenterWindow(hDlg);
  1335.          return TRUE;
  1336.       case WM_COMMAND:
  1337.          switch (LOWORD(wParam)) {
  1338.             case IDOK:
  1339.                // Store the password in our return password buffer.
  1340.                GetDlgItemText(hDlg, IDC_PASSWORD, szMessage, countof(szMessage));
  1341.                wcstombs(pdi->szPassword, szMessage, pdi->nSize);
  1342.                EndDialog(hDlg, IZ_PW_ENTERED);
  1343.                return FALSE;
  1344.             case IDCANCEL:
  1345.                g_fSkipped = TRUE;
  1346.                EndDialog(hDlg, IZ_PW_CANCEL);
  1347.                return FALSE;
  1348.             case IDC_SKIP_ALL:
  1349.                g_fSkipped = TRUE;
  1350.                EndDialog(hDlg, IZ_PW_CANCELALL);
  1351.                return FALSE;
  1352.          }
  1353.          return FALSE;
  1354.    }
  1355.    return FALSE;
  1356. }
  1357. #endif // CRYPT
  1358. //******************************************************************************
  1359. //***** View Association Dialog Functions
  1360. //******************************************************************************
  1361. BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1362.    static LPTSTR szApp;
  1363.    switch (uMsg) {
  1364.       case WM_INITDIALOG:
  1365.          // Store the path buffer for our application.
  1366.          szApp = (LPTSTR)lParam;
  1367.          // Read our default viewer from the registry.
  1368. #ifdef _WIN32_WCE
  1369.          GetOptionString(TEXT("FileViewer"), TEXT("\Windows\PWord.exe"), 
  1370.                          szApp, sizeof(TCHAR) * _MAX_PATH);
  1371. #else
  1372.          GetOptionString(TEXT("FileViewer"), TEXT("notepad.exe"), 
  1373.                          szApp, sizeof(TCHAR) * _MAX_PATH);
  1374. #endif
  1375.          // Limit our edit control to our buffer size.
  1376.          SendDlgItemMessage(hDlg, IDC_PATH, EM_LIMITTEXT, _MAX_PATH - 1, 0);
  1377.          // Set our path string in our dialog.
  1378.          SetDlgItemText(hDlg, IDC_PATH, szApp);
  1379.          // Center our dialog over our parent.
  1380.          CenterWindow(hDlg);
  1381.          return TRUE;
  1382.       case WM_COMMAND:
  1383.          switch (LOWORD(wParam)) {
  1384.             case IDOK:
  1385.                // Get the text currently in the path edit box and store it.
  1386.                GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
  1387.                WriteOptionString(TEXT("FileViewer"), szApp);
  1388.                // Fall through
  1389.             case IDCANCEL:
  1390.                EndDialog(hDlg, LOWORD(wParam));
  1391.                break;
  1392.             case IDC_BROWSE:
  1393.                // Get the text currently in the path edit box.
  1394.                GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
  1395.                // Get the direcory from the path text.
  1396.                ForwardSlashesToBackSlashesW(szApp);
  1397.                TCHAR szInitialDir[_MAX_PATH], *szFile;
  1398.                _tcscpy(szInitialDir, szApp);
  1399.                if (szFile = _tcsrchr(szInitialDir, TEXT('\'))) {
  1400.                   *szFile = TEXT('');
  1401.                }
  1402.                // Prepare to display browse dialog.
  1403.                OPENFILENAME ofn;
  1404.                ZeroMemory(&ofn, sizeof(ofn));
  1405.                ofn.lStructSize     = sizeof(ofn);
  1406.                ofn.hwndOwner       = hDlg;
  1407.                ofn.hInstance       = g_hInst;
  1408.                ofn.lpstrFilter     = TEXT("Programs (*.exe)*.exeAll Files (*.*)*.*");
  1409.                ofn.nFilterIndex    = 1;
  1410.                ofn.lpstrFile       = szApp;
  1411.                ofn.nMaxFile        = _MAX_PATH;
  1412.                ofn.lpstrInitialDir = szInitialDir;
  1413.                ofn.lpstrTitle      = TEXT("Open With...");
  1414.                ofn.Flags           = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
  1415.                ofn.lpstrDefExt     = TEXT("exe");
  1416.                // Display the browse dialog and update our path edit box if neccessary.
  1417.                if (GetOpenFileName(&ofn)) {
  1418.                   SetDlgItemText(hDlg, IDC_PATH, szApp);
  1419.                }
  1420.                break;
  1421.          }
  1422.          return FALSE;
  1423.    }
  1424.    return FALSE;
  1425. }
  1426. //******************************************************************************
  1427. //***** Comment Dialog Functions
  1428. //******************************************************************************
  1429. BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1430.    RECT    rc;
  1431.    HCURSOR hCur;
  1432.    int     result;
  1433.    switch (uMsg) {
  1434.       case WM_INITDIALOG:
  1435.          // Get the handle to our edit box and store it globally.
  1436.          g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
  1437.          // Disable our edit box from being edited.
  1438.          DisableEditing(g_hWndEdit);
  1439. #ifdef _WIN32_WCE
  1440.          // Add "Ok" button to caption bar and make window No-Drag.
  1441.          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | WS_EX_NODRAG |
  1442.                        GetWindowLong(hDlg, GWL_EXSTYLE));
  1443.          // On CE, we resize our dialog to be full screen (same size as parent).
  1444.          GetWindowRect(g_hWndMain, &rc);
  1445.          MoveWindow(hDlg, rc.left, rc.top, rc.right - rc.left, 
  1446.                     rc.bottom - rc.top + 1, FALSE);
  1447. #else
  1448.          // On NT we just center the dialog.
  1449.          CenterWindow(hDlg);
  1450. #endif
  1451.          // Set our edit control to be the full size of our dialog.
  1452.          GetClientRect(hDlg, &rc);
  1453.          MoveWindow(g_hWndEdit, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
  1454.          // Show hour glass cursor while processing comment.
  1455.          hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1456.          // Let Info-ZIP and our callbacks do the work.
  1457.          result = DoGetComment(g_szZipFile);
  1458.          // Restore/remove our cursor.
  1459.          SetCursor(hCur);
  1460.          // Display an error dialog if an error occurred.
  1461.          if ((result != PK_OK) && (result != PK_WARN)) {
  1462.             MessageBox(g_hWndMain, GetZipErrorString(result), g_szAppName,
  1463.                        MB_ICONERROR | MB_OK);
  1464.          }
  1465.          // Clear our global edit box handle as we are done with it.
  1466.          g_hWndEdit = NULL;
  1467.          // Return FALSE to prevent edit box from gaining focus and showing highlight.
  1468.          return FALSE;
  1469.       case WM_COMMAND:
  1470.          if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
  1471.             EndDialog(hDlg, LOWORD(wParam));
  1472.          }
  1473.          return FALSE;
  1474.    }
  1475.    return FALSE;
  1476. }
  1477. //******************************************************************************
  1478. //***** About Dialog Functions
  1479. //******************************************************************************
  1480. BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1481.    switch (uMsg) {
  1482.       case WM_INITDIALOG:
  1483. #ifdef _WIN32_WCE
  1484.          // Add "Ok" button to caption bar.
  1485.          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | 
  1486.                        GetWindowLong(hDlg, GWL_EXSTYLE));
  1487. #endif
  1488.          // Fill in a few static members.
  1489.          TCHAR szBuffer[80];
  1490.          SetDlgItemText(hDlg, IDC_PRODUCT, TEXT(VER_PRODUCT_STR));
  1491.          _stprintf(szBuffer, TEXT("Freeware Version %S"), VER_FULLVERSION_STR);
  1492.          SetDlgItemText(hDlg, IDC_VERSION, szBuffer);
  1493.          _stprintf(szBuffer, TEXT("Developed by %S"), VER_DEVELOPER_STR);
  1494.          SetDlgItemText(hDlg, IDC_DEVELOPER, szBuffer);
  1495.          SetDlgItemText(hDlg, IDC_COPYRIGHT, TEXT(VER_COPYRIGHT_STR));
  1496.          SetDlgItemText(hDlg, IDC_COMMENT, TEXT(VER_COMMENT_STR));
  1497.          // Center the dialog over our parent.
  1498.          CenterWindow(hDlg);
  1499.          return TRUE;
  1500.       case WM_COMMAND:
  1501.          if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
  1502.             EndDialog(hDlg, 0);
  1503.          }
  1504.          return FALSE;
  1505.    }
  1506.    return FALSE;
  1507. }