which included commits to RCS files with non-trunk default branches. git-svn-id: svn://10.65.10.50/trunk@5403 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			3780 lines
		
	
	
		
			131 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			3780 lines
		
	
	
		
			131 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| //******************************************************************************
 | |
| //
 | |
| // File:        WINMAIN.CPP
 | |
| //
 | |
| // Description: This module contains all the Windows specific code for Pocket
 | |
| //              UnZip.  It contains the entire user interface.  This code knows
 | |
| //              almost nothing about the Info-ZIP code.  All Info-ZIP related
 | |
| //              functions are wrapped by helper functions in INTRFACE.CPP.  The
 | |
| //              code in this module only calls those wrapper functions and
 | |
| //              INTRFACE.CPP handles all the details and callbacks of the 
 | |
| //              Info-ZIP code.
 | |
| //
 | |
| // Copyright:   All the source files for Pocket UnZip, except for components
 | |
| //              written by the Info-ZIP group, are copyrighted 1997 by Steve P.
 | |
| //              Miller.  The product "Pocket UnZip" itself is property of the
 | |
| //              author and cannot be altered in any way without written consent
 | |
| //              from Steve P. Miller.
 | |
| //
 | |
| // Disclaimer:  All project files are provided "as is" with no guarantee of
 | |
| //              their correctness.  The authors are not liable for any outcome
 | |
| //              that is the result of using this source.  The source for Pocket
 | |
| //              UnZip has been placed in the public domain to help provide an
 | |
| //              understanding of its implementation.  You are hereby granted
 | |
| //              full permission to use this source in any way you wish, except
 | |
| //              to alter Pocket UnZip itself.  For comments, suggestions, and
 | |
| //              bug reports, please write to stevemil@pobox.com.
 | |
| //
 | |
| // Functions:   WinMain
 | |
| //              InitializeApplication
 | |
| //              ShutdownApplication
 | |
| //              RegisterUnzip
 | |
| //              BuildImageList
 | |
| //              WndProc
 | |
| //              OnCreate
 | |
| //              OnFileOpen
 | |
| //              OnActionView
 | |
| //              OnActionSelectAll
 | |
| //              OnViewExpandedView
 | |
| //              OnHelp
 | |
| //              OnGetDispInfo
 | |
| //              OnDeleteItem
 | |
| //              OnItemChanged
 | |
| //              Sort
 | |
| //              CompareFunc
 | |
| //              SetCaptionText
 | |
| //              DrawBanner
 | |
| //              AddDeleteColumns
 | |
| //              ResizeColumns
 | |
| //              GetZipErrorString
 | |
| //              AddFileToListView
 | |
| //              EnableAllMenuItems
 | |
| //              CheckAllMenuItems
 | |
| //              CenterWindow
 | |
| //              AddTextToEdit
 | |
| //              FormatValue
 | |
| //              BuildAttributesString
 | |
| //              BuildTypeString
 | |
| //              GetFileFromPath
 | |
| //              ForwardSlashesToBackSlashesA
 | |
| //              ForwardSlashesToBackSlashesW
 | |
| //              DeleteDirectory(LPTSTR szPath);
 | |
| //              RegWriteKey
 | |
| //              RegReadKey
 | |
| //              WriteOptionString
 | |
| //              WriteOptionInt
 | |
| //              GetOptionString
 | |
| //              GetOptionInt
 | |
| //              DisableEditing
 | |
| //              EditSubclassProc
 | |
| //              GetMenuString
 | |
| //              InitializeMRU
 | |
| //              AddFileToMRU
 | |
| //              RemoveFileFromMRU
 | |
| //              ActivateMRU
 | |
| //              ReadZipFileList
 | |
| //              DlgProcProperties
 | |
| //              MergeValues
 | |
| //              CheckThreeStateBox
 | |
| //              ExtractOrTestFiles
 | |
| //              DlgProcExtractOrTest
 | |
| //              FolderBrowser
 | |
| //              DlgProcBrowser
 | |
| //              SubclassSaveAsDlg
 | |
| //              DlgProcExtractProgress
 | |
| //              DlgProcViewProgress
 | |
| //              UpdateProgress
 | |
| //              PromptToReplace
 | |
| //              DlgProcReplace
 | |
| //              DlgProcPassword
 | |
| //              DlgProcViewAssociation
 | |
| //              DlgProcComment
 | |
| //              DlgProcAbout
 | |
| //
 | |
| //
 | |
| // Date      Name          History
 | |
| // --------  ------------  -----------------------------------------------------
 | |
| // 02/01/97  Steve Miller  Created (Version 1.0 using Info-ZIP UnZip 5.30)
 | |
| //
 | |
| //******************************************************************************
 | |
| 
 | |
| extern "C" {
 | |
| #define __WINMAIN_CPP__
 | |
| #define UNZIP_INTERNAL
 | |
| 
 | |
| #include "unzip.h"
 | |
| 
 | |
| #include "version.h"   // Only needed by consts.h (VERSION_DATE & VersionDate)
 | |
| #include "consts.h"    // Only include once - defines constant string messages.
 | |
| 
 | |
| #include "crypt.h"     // Needed to pick up CRYPT define if set and return values.
 | |
| 
 | |
| #include <commctrl.h>  // Common controls - mainly ListView and ImageList
 | |
| #include <commdlg.h>   // Common dialogs - OpenFile dialog
 | |
| 
 | |
| #ifndef _WIN32_WCE
 | |
| #include <shlobj.h>    // On NT, we use the SHBrowseForFolder() stuff.
 | |
| #include <shellapi.h>  // CommandLineToArgvW() and ExtractIconEx()
 | |
| #endif
 | |
| 
 | |
| #include "intrface.h"  // Interface between Info-ZIP and us
 | |
| #include "winmain.h"   // Us
 | |
| }
 | |
| #include <tchar.h>     // Must be outside of extern "C" block
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** "Local" Global Variables
 | |
| //******************************************************************************
 | |
| 
 | |
| static LPCTSTR         g_szAppName     = TEXT("Pocket UnZip");
 | |
| static LPCTSTR         g_szClass       = TEXT("PocketUnZip");
 | |
| static LPCTSTR         g_szRegKey      = TEXT("Software\\Pocket UnZip");
 | |
| static LPCTSTR         g_szTempDir     = NULL;
 | |
| static HWND            g_hWndList      = NULL;
 | |
| static HWND            g_hWndCmdBar    = NULL;
 | |
| static int             g_cyCmdBar      = 0;
 | |
| static HFONT           g_hFontBanner   = NULL;
 | |
| static HICON           g_hIconMain     = NULL;
 | |
| static WNDPROC         g_wpSaveAsDlg   = NULL;
 | |
| static WNDPROC         g_wpEdit        = NULL;
 | |
| static int             g_sortColumn    = -1;
 | |
| static BOOL            g_fExpandedView = FALSE;
 | |
| static BOOL            g_fLoading      = FALSE;
 | |
| static BOOL            g_fSkipped      = FALSE;
 | |
| static BOOL            g_fViewing      = FALSE;
 | |
| static HWND            g_hWndWaitFor   = NULL;
 | |
| static FILE_TYPE_NODE *g_pftHead       = NULL;
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| static LPCTSTR         g_szHelpFile    = TEXT("\\windows\\punzip.htp");
 | |
| #else
 | |
| static LPCTSTR         g_szHelpFile    = TEXT("punzip.html");
 | |
| #endif
 | |
| 
 | |
| static COLUMN g_columns[] = {
 | |
|    { TEXT("Name"),       LVCFMT_LEFT  },
 | |
|    { TEXT("Size"),       LVCFMT_RIGHT },
 | |
|    { TEXT("Type"),       LVCFMT_LEFT  },
 | |
|    { TEXT("Modified"),   LVCFMT_LEFT  },
 | |
|    { TEXT("Attributes"), LVCFMT_LEFT  },
 | |
|    { TEXT("Compressed"), LVCFMT_RIGHT },
 | |
|    { TEXT("Ratio"),      LVCFMT_RIGHT },
 | |
|    { TEXT("Method"),     LVCFMT_LEFT  },
 | |
|    { TEXT("CRC"),        LVCFMT_LEFT  },
 | |
|    { TEXT("Comment"),    LVCFMT_LEFT  }
 | |
| };
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Local Function Prototypes
 | |
| //******************************************************************************
 | |
| 
 | |
| // Startup and Shutdown Functions
 | |
| void InitializeApplication(LPCTSTR szZipFile);
 | |
| void ShutdownApplication();
 | |
| void RegisterUnzip();
 | |
| void BuildImageList();
 | |
| 
 | |
| // Our Main Window's Message Handler
 | |
| LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| 
 | |
| // Event Handlers for our Main Window
 | |
| int OnCreate();
 | |
| void OnFileOpen();
 | |
| void OnActionView();
 | |
| void OnActionSelectAll();
 | |
| void OnViewExpandedView();
 | |
| void OnHelp();
 | |
| 
 | |
| // Event Handlers for our List View
 | |
| void OnGetDispInfo(LV_DISPINFO *plvdi);
 | |
| void OnDeleteItem(NM_LISTVIEW *pnmlv);
 | |
| void OnItemChanged(NM_LISTVIEW *pnmlv);
 | |
| 
 | |
| // List View Sort Functions
 | |
| void Sort(int sortColumn, BOOL fForce);
 | |
| int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM sortColumn);
 | |
| 
 | |
| // Helper/Utility Functions
 | |
| void SetCaptionText(LPCTSTR szPrefix);
 | |
| void DrawBanner(HDC hdc);
 | |
| void AddDeleteColumns();
 | |
| void ResizeColumns();
 | |
| LPCTSTR GetZipErrorString(int error);
 | |
| void AddFileToListView(FILE_NODE *pFile);
 | |
| void EnableAllMenuItems(UINT uMenuItem, BOOL fEnabled);
 | |
| void CheckAllMenuItems(UINT uMenuItem, BOOL fChecked);
 | |
| void CenterWindow(HWND hWnd);
 | |
| void AddTextToEdit(LPCSTR szText);
 | |
| LPTSTR FormatValue(LPTSTR szValue, DWORD dwValue);
 | |
| LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes);
 | |
| LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType);
 | |
| LPCSTR GetFileFromPath(LPCSTR szPath);
 | |
| void ForwardSlashesToBackSlashesA(LPSTR szBuffer);
 | |
| void ForwardSlashesToBackSlashesW(LPWSTR szBuffer);
 | |
| void DeleteDirectory(LPTSTR szPath);
 | |
| 
 | |
| // Registry Functions
 | |
| void RegWriteKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPCTSTR szValue);
 | |
| BOOL RegReadKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPTSTR szValue, DWORD cBytes);
 | |
| void WriteOptionString(LPCTSTR szOption, LPCTSTR szValue);
 | |
| void WriteOptionInt(LPCTSTR szOption, DWORD dwValue);
 | |
| LPTSTR GetOptionString(LPCTSTR szOption, LPCTSTR szDefault, LPTSTR szValue, DWORD nSize);
 | |
| DWORD GetOptionInt(LPCTSTR szOption, DWORD dwDefault);
 | |
| 
 | |
| // EDIT Control Subclass Functions
 | |
| void DisableEditing(HWND hWndEdit);
 | |
| LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| 
 | |
| // MRU Functions
 | |
| void InitializeMRU();
 | |
| void AddFileToMRU(LPCSTR szFile);
 | |
| void RemoveFileFromMRU(LPCTSTR szFile);
 | |
| void ActivateMRU(UINT uIDItem);
 | |
| 
 | |
| // Open Zip File Functions
 | |
| void ReadZipFileList(LPCWSTR wszPath);
 | |
| 
 | |
| // Zip File Properties Dialog Functions
 | |
| BOOL CALLBACK DlgProcProperties(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| void MergeValues(int *p1, int p2);
 | |
| void CheckThreeStateBox(HWND hDlg, int nIDButton, int state);
 | |
| 
 | |
| // Extract/Test Dialog Functions
 | |
| void ExtractOrTestFiles(BOOL fExtract);
 | |
| BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| 
 | |
| // Folder Browsing Dialog Functions
 | |
| BOOL FolderBrowser(LPTSTR szPath, DWORD dwLength);
 | |
| BOOL CALLBACK DlgProcBrowser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| void SubclassSaveAsDlg();
 | |
| 
 | |
| // Extraction/Test/View Progress Dialog Functions
 | |
| BOOL CALLBACK DlgProcExtractProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| BOOL CALLBACK DlgProcViewProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| void UpdateProgress(EXTRACT_INFO *pei, BOOL fFull);
 | |
| 
 | |
| // Replace File Dialog Functions
 | |
| int PromptToReplace(LPCSTR szPath);
 | |
| BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| 
 | |
| // Password Dialog Functions
 | |
| BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| 
 | |
| // View Association Dialog Functions
 | |
| BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| 
 | |
| // Comment Dialog Functions
 | |
| BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| 
 | |
| // About Dialog Functions
 | |
| BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** WinMain - Our one and only entry point
 | |
| //******************************************************************************
 | |
| 
 | |
| // Entrypoint is a tiny bit different on Windows CE - UNICODE command line.
 | |
| #ifdef _WIN32_WCE
 | |
| extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
 | |
|                               LPTSTR lpCmdLine, int nCmdShow)
 | |
| #else
 | |
| extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 | |
|                               LPSTR lpCmdLine, int nCmdShow)
 | |
| #endif
 | |
| {
 | |
|    // Wrap the whole ball of wax in a big exception handler.
 | |
|    __try {
 | |
| 
 | |
|       // Store global instance handle.
 | |
|       g_hInst = hInstance;
 | |
| 
 | |
|       // Create our banner font.  We need to do this before creating our window.
 | |
|       // This font handle will be deleted in ShutdownApplication().
 | |
|       LOGFONT lf;
 | |
|       ZeroMemory(&lf, sizeof(lf));
 | |
|       lf.lfHeight = 16;
 | |
|       lf.lfWeight = FW_BOLD;
 | |
|       lf.lfCharSet = ANSI_CHARSET;
 | |
|       lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
 | |
|       lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
 | |
|       lf.lfQuality = DEFAULT_QUALITY;
 | |
|       lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
 | |
|       _tcscpy(lf.lfFaceName, TEXT("MS Sans Serif"));
 | |
|       g_hFontBanner = CreateFontIndirect(&lf);
 | |
| 
 | |
|       // Define the window class for our application's main window.
 | |
|       WNDCLASS wc;
 | |
|       ZeroMemory(&wc, sizeof(wc));
 | |
|       wc.lpszClassName = g_szClass;
 | |
|       wc.hInstance     = hInstance;
 | |
|       wc.lpfnWndProc   = WndProc;
 | |
|       wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 | |
| 
 | |
|       TCHAR *szZipPath = NULL;
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| 
 | |
|       // Get our main window's small icon.  On Windows CE, we need to send ourself
 | |
|       // a WM_SETICON in order for our task bar to update itself.
 | |
|       g_hIconMain = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_UNZIP), 
 | |
|                                      IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
 | |
|       wc.hIcon = g_hIconMain;
 | |
| 
 | |
|       // On Windows CE, we only need the WS_VISIBLE flag.
 | |
|       DWORD dwStyle = WS_VISIBLE;
 | |
| 
 | |
|       // Get and store command line file (if any).
 | |
|       if (lpCmdLine && *lpCmdLine) {
 | |
|          szZipPath = lpCmdLine;
 | |
|       }
 | |
| 
 | |
| #else
 | |
| 
 | |
|       // On NT we add a cursor, icon, and nenu to our application's window class.
 | |
|       wc.hCursor      = LoadCursor(NULL, IDC_ARROW);
 | |
|       wc.hIcon        = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_UNZIP));
 | |
|       wc.lpszMenuName = MAKEINTRESOURCE(IDR_UNZIP);
 | |
| 
 | |
|       // On Windows NT, we use the standard overlapped window style.
 | |
|       DWORD dwStyle = WS_OVERLAPPEDWINDOW;
 | |
| 
 | |
|       TCHAR szBuffer[_MAX_PATH];
 | |
| 
 | |
|       // Get and store command line file (if any).
 | |
|       if (lpCmdLine && *lpCmdLine) {
 | |
|          mbstowcs(szBuffer, lpCmdLine, countof(szBuffer));
 | |
|          szZipPath = szBuffer;
 | |
|       }
 | |
| 
 | |
| #endif
 | |
| 
 | |
|       // Register our window class with the OS.
 | |
|       if (!RegisterClass(&wc)) {
 | |
|          DebugOut(TEXT("RegisterClass() failed [%u]"), GetLastError());
 | |
|       }
 | |
| 
 | |
|       // Create our main window using our registered window class.
 | |
|       g_hWndMain = CreateWindow(wc.lpszClassName, g_szAppName, dwStyle,
 | |
|                                 CW_USEDEFAULT, CW_USEDEFAULT, 
 | |
|                                 CW_USEDEFAULT, CW_USEDEFAULT,
 | |
|                                 NULL, NULL, hInstance, NULL);
 | |
| 
 | |
|       // Quit now if we failed to create our main window.
 | |
|       if (!g_hWndMain) {
 | |
|          DebugOut(TEXT("CreateWindow() failed [%u]"), GetLastError());
 | |
|          ShutdownApplication();
 | |
|          return 0;
 | |
|       }
 | |
| 
 | |
|       // Make sure our window is visible.  Really only needed for NT.
 | |
|       ShowWindow(g_hWndMain, nCmdShow);
 | |
| 
 | |
|       // Load our keyboard accelerator shortcuts.
 | |
|       MSG    msg;
 | |
|       HACCEL hAccel = LoadAccelerators(g_hInst, MAKEINTRESOURCE(IDR_UNZIP));
 | |
|       DWORD  dwPaintFlags = 0;
 | |
| 
 | |
|       // The message pump.  Loop until we get a WM_QUIT message.
 | |
|       while (GetMessage(&msg, NULL, 0, 0)) {
 | |
|       
 | |
|          // Check to see if this is an accelerator and handle it if neccessary.
 | |
|          if (!TranslateAccelerator(g_hWndMain, hAccel, &msg)) {
 | |
| 
 | |
|             // If a normal message, then dispatch it to the correct window.
 | |
|             TranslateMessage(&msg);
 | |
|             DispatchMessage(&msg); 
 | |
| 
 | |
|             // Wait until our application is up an visible before trying to
 | |
|             // initialize some of our structures and load any command line file.
 | |
|             if ((msg.message == WM_PAINT) && (dwPaintFlags != 0x11)) {
 | |
|                if (msg.hwnd == g_hWndWaitFor) {
 | |
|                   dwPaintFlags |= 0x01;
 | |
|                } else if (msg.hwnd == g_hWndList) {
 | |
|                   dwPaintFlags |= 0x10;
 | |
|                }
 | |
|                if (dwPaintFlags == 0x11) {
 | |
|                   InitializeApplication((szZipPath && *szZipPath) ? 
 | |
|                                         szZipPath : NULL);
 | |
|                }
 | |
|             }
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       // Clean up code.
 | |
|       ShutdownApplication();
 | |
| 
 | |
|       // Nice clean finish - were out of here.
 | |
|       return msg.wParam;
 | |
| 
 | |
| 
 | |
|    } __except(EXCEPTION_EXECUTE_HANDLER) {
 | |
| 
 | |
|       // Something very bad happened.  Try our best to appear somewhat graceful.
 | |
|       MessageBox(NULL, 
 | |
|          TEXT("An internal error occurred.  Possible causes are that you are ")
 | |
|          TEXT("out of memory, a ZIP file (if one is loaded) contains an ")
 | |
|          TEXT("unexpected error, or there is a bug in our program (that's why ")
 | |
|          TEXT("it's free).  Pocket UnZip cannot continue.  It will exit now, ")
 | |
|          TEXT("but you may restart it and try again.\n\n")
 | |
|          TEXT("If the problem persists, please write to stevemil@pobox.com with ")
 | |
|          TEXT("any information that might help track down the problem."),
 | |
|          g_szAppName, MB_ICONERROR | MB_OK);
 | |
|    }
 | |
| 
 | |
|    return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Startup and Shutdown Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| void InitializeApplication(LPCTSTR szZipFile) {
 | |
| 
 | |
|    // This function is called after our class is registered and all our windows
 | |
|    // are created and visible to the user.
 | |
| 
 | |
|    // Show hour glass cursor.
 | |
|    HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
 | |
| 
 | |
|    // Register UnZip in the registry to handle ".ZIP" files.
 | |
|    RegisterUnzip();
 | |
| 
 | |
|    // Enumerate the system file assoications and build an image list.
 | |
|    BuildImageList();
 | |
| 
 | |
|    // Load our initial MRU into our menu.
 | |
|    InitializeMRU();
 | |
| 
 | |
|    // Restore/remove our cursor.
 | |
|    SetCursor(hCur);
 | |
| 
 | |
|    // Clear our initialization window handle.
 | |
|    g_hWndWaitFor = NULL;
 | |
| 
 | |
|    // Load our command line file if one was specified. Otherwise, just update
 | |
|    // our banner to show that no file is loaded.
 | |
|    if (szZipFile) {
 | |
|       ReadZipFileList(szZipFile);
 | |
|    } else {
 | |
|       DrawBanner(NULL);
 | |
|    }
 | |
| 
 | |
|    // Enable some controls.
 | |
|    EnableAllMenuItems(IDM_FILE_OPEN,          TRUE);
 | |
|    EnableAllMenuItems(IDM_FILE_CLOSE,         TRUE);
 | |
|    EnableAllMenuItems(IDM_VIEW_EXPANDED_VIEW, TRUE);
 | |
|    EnableAllMenuItems(IDM_HELP_ABOUT,         TRUE);
 | |
| 
 | |
|    // Set our temporary directory.
 | |
| #ifdef _WIN32_WCE
 | |
|    g_szTempDir = TEXT("\\Temporary Pocket UnZip Files");
 | |
| #else 
 | |
|    g_szTempDir = TEXT("C:\\Temporary Pocket UnZip Files");
 | |
| 
 | |
|    // Set the drive to be the same drive as the OS installation is on.
 | |
|    TCHAR szPath[_MAX_PATH];
 | |
|    if (GetWindowsDirectory(szPath, countof(szPath))) {
 | |
|       *((LPTSTR)g_szTempDir) = *szPath;
 | |
|    }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void ShutdownApplication() {
 | |
|    
 | |
|    // Free our banner font.
 | |
|    if (g_hFontBanner) {
 | |
|       DeleteObject(g_hFontBanner);
 | |
|       g_hFontBanner = NULL;
 | |
|    }
 | |
| 
 | |
|    // Delete our FILE_TYPE_NODE linked list.
 | |
|    for (FILE_TYPE_NODE *pft = g_pftHead; pft; ) {
 | |
|       FILE_TYPE_NODE *pftNext = pft->pNext;
 | |
|       delete[] (BYTE*)pft;
 | |
|       pft = pftNext;
 | |
|    }
 | |
|    g_pftHead = NULL;
 | |
| 
 | |
|    // If there are no other instances of our application open, then delete our
 | |
|    // temporary directory and all the files in it.  Any files opened for viewing
 | |
|    // should be locked and will fail to delete.  This is to be expected.
 | |
|    if (g_szTempDir && (FindWindow(g_szClass, NULL) == NULL)) {
 | |
|       TCHAR szPath[_MAX_PATH];
 | |
|       _tcscpy(szPath, g_szTempDir);
 | |
|       DeleteDirectory(szPath);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void RegisterUnzip() {
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| 
 | |
|    // WARNING!  Since Windows CE does not support any way to get your binary's
 | |
|    // name at runtime, we have to hard-code in "punzip.exe".  If our binary is
 | |
|    // not named this or is in a non-path directory, then we will fail to
 | |
|    // register ourself with the system as the default application to handle
 | |
|    // ".zip" files.
 | |
|    TCHAR szPath[32] = TEXT("punzip.exe");
 | |
| 
 | |
| #else
 | |
| 
 | |
|    // Get our module's path and file name.  We use the short path name for the
 | |
|    // registry because it is guarenteed to contain no spaces.
 | |
|    TCHAR szLongPath[_MAX_PATH];
 | |
|    TCHAR szPath[_MAX_PATH];
 | |
|    GetModuleFileName(NULL, szLongPath, countof(szLongPath));
 | |
|    GetShortPathName(szLongPath, szPath, countof(szPath));
 | |
| 
 | |
| #endif
 | |
| 
 | |
|    // Store a pointer to the end of our path for easy appending.
 | |
|    LPTSTR szEnd = szPath + _tcslen(szPath);
 | |
| 
 | |
|    // Associate "ZIP" file extensions to our application
 | |
|    RegWriteKey(HKEY_CLASSES_ROOT, TEXT(".zip"), TEXT("zipfile"));
 | |
|    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile"), TEXT("ZIP File"));
 | |
|    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\shell"), NULL);
 | |
|    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\shell\\Open"), NULL);
 | |
|    _tcscpy(szEnd, TEXT(" %1"));
 | |
|    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\shell\\Open\\command"), szPath);
 | |
| 
 | |
|    // Register our program icon for all ZIP files.
 | |
|    _stprintf(szEnd, TEXT(",-%u"), IDI_ZIPFILE);
 | |
|    RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\DefaultIcon"), szPath);
 | |
| 
 | |
|    // Create our application option location.
 | |
|    RegWriteKey(HKEY_CURRENT_USER, TEXT("Software"), NULL);
 | |
|    RegWriteKey(HKEY_CURRENT_USER, g_szRegKey, NULL);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void BuildImageList() {
 | |
| 
 | |
|    // Create our global image list.
 | |
| #ifdef _WIN32_WCE
 | |
|  
 | |
|    // On Windows CE, we can't spare a color for the mask, so we have to create
 | |
|    // the mask in a separate monochrome bitmap.
 | |
| 
 | |
|    HIMAGELIST hil = ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 8, 8);
 | |
| 
 | |
|    // Load our default bitmaps into the image list.
 | |
|    HBITMAP hBmpImageList = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST));
 | |
|    HBITMAP hBmpMask = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST_MASK));
 | |
|    ImageList_Add(hil, hBmpImageList, hBmpMask);
 | |
|    DeleteObject(hBmpImageList);
 | |
|    DeleteObject(hBmpMask);
 | |
| 
 | |
| #else
 | |
| 
 | |
|    // On Windows NT, we use magenta as a transparency mask color.
 | |
|    HIMAGELIST hil = ImageList_LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST),
 | |
|                                          16, 8, RGB(255, 0, 255));
 | |
| #endif
 | |
| 
 | |
|    // Set up for our registry file type enumeration.
 | |
|    FILE_TYPE_NODE *pftLast = NULL;
 | |
|    TCHAR szExtension[128], szKey[128], szDescription[_MAX_PATH], szIconFile[_MAX_PATH + 16];
 | |
|    DWORD dwIndex = 0, dwCount = countof(szExtension);
 | |
| 
 | |
|    // Enumerate all the keys immediately under HKEY_CLASSES_ROOT.
 | |
|    while (ERROR_SUCCESS == RegEnumKeyEx(HKEY_CLASSES_ROOT, dwIndex++, szExtension, 
 | |
|                                         &dwCount, NULL, NULL, NULL, NULL))
 | |
|    {
 | |
|       dwCount = countof(szExtension);
 | |
| 
 | |
|       // Check to see if we read an extension key (starts with a period)
 | |
|       if (*szExtension != TEXT('.')) {
 | |
|          continue;
 | |
|       }
 | |
| 
 | |
|       // Read the actual key name for this extension.
 | |
|       if (!RegReadKey(HKEY_CLASSES_ROOT, szExtension, szKey, sizeof(szKey))) {
 | |
|          continue;
 | |
|       }
 | |
| 
 | |
|       // Read the Description for this extension.
 | |
|       RegReadKey(HKEY_CLASSES_ROOT, szKey, szDescription, sizeof(szDescription));
 | |
| 
 | |
|       HICON hIcon = NULL;
 | |
|       LPTSTR szEnd = szKey + _tcslen(szKey);
 | |
| 
 | |
|       // Attempt to get an icon for this extension from the "DefaultIcon" key.
 | |
|       _tcscpy(szEnd, TEXT("\\DefaultIcon"));
 | |
|       if (RegReadKey(HKEY_CLASSES_ROOT, szKey, szIconFile, sizeof(szIconFile))) {
 | |
| 
 | |
|          // Look for the comma between the file name and the image.
 | |
|          LPTSTR szImageId = _tcschr(szIconFile, TEXT(','));
 | |
|          if (szImageId) {
 | |
| 
 | |
|             // NULL terminate the file name portion of szIconFile.
 | |
|             *(szImageId++) = TEXT('\0');
 | |
| 
 | |
|             // Get the image ID value from szIconFile.
 | |
|             int imageId = _ttoi(szImageId);
 | |
| 
 | |
|             // Extract the icon from the module specified in szIconFile.
 | |
|             ExtractIconEx(szIconFile, imageId, NULL, &hIcon, 1);
 | |
|             if (hIcon == NULL) {
 | |
|                ExtractIconEx(szIconFile, imageId, &hIcon, NULL, 1);
 | |
|             }
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       // If we failed to get the icon using the "DefaultIcon" key, then try
 | |
|       // using the "shell\Open\command" key.
 | |
|       if (hIcon == NULL) {
 | |
| 
 | |
|          _tcscpy(szEnd, TEXT("\\shell\\Open\\command"));
 | |
|          if (RegReadKey(HKEY_CLASSES_ROOT, szKey, szIconFile, sizeof(szIconFile))) {
 | |
| 
 | |
|             // Get a pointer to just the binary - strip quotes and spaces.
 | |
|             LPTSTR szPath;
 | |
|             if (*szIconFile == TEXT('\"')) {
 | |
|                szPath = szIconFile + 1;
 | |
|                if (szEnd = _tcschr(szPath, TEXT('\"'))) {
 | |
|                   *szEnd = TEXT('\0');
 | |
|                }
 | |
|             } else {
 | |
|                szPath = szIconFile;
 | |
|                if (szEnd = _tcschr(szPath, TEXT(' '))) {
 | |
|                   *szEnd = TEXT('\0');
 | |
|                }
 | |
|             }
 | |
| 
 | |
|             // Extract the icon from the module specified in szIconFile.
 | |
|             ExtractIconEx(szPath, 0, NULL, &hIcon, 1);
 | |
|             if (hIcon == NULL) {
 | |
|                ExtractIconEx(szPath, 0, &hIcon, NULL, 1);
 | |
|             }
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       // If we found an icon, add it to our image list.
 | |
|       int image = -1;
 | |
|       if (hIcon) {
 | |
|          image = ImageList_AddIcon(hil, hIcon);
 | |
|       }
 | |
| 
 | |
|       // If no icon could be found, then check to see if this is an executable.
 | |
|       if ((image == -1) && (
 | |
| #ifndef _WIN32_WCE // Windows CE only recognizes EXE's as executable.
 | |
|          !_tcsicmp(szExtension + 1, TEXT("bat")) ||
 | |
|          !_tcsicmp(szExtension + 1, TEXT("cmd")) ||
 | |
|          !_tcsicmp(szExtension + 1, TEXT("com")) ||
 | |
| #endif
 | |
|          !_tcsicmp(szExtension + 1, TEXT("exe"))))
 | |
|       {
 | |
|          image = IMAGE_APPLICATION;
 | |
|       }
 | |
| 
 | |
|       // If we don't have a description or a icon, then bail on this extension.
 | |
|       if (!*szDescription && (image < 0)) {
 | |
|          continue;
 | |
|       }
 | |
|          
 | |
|       // Create our FILE_TYPE_NODE.
 | |
|       int length = _tcslen(szExtension) - 1 + _tcslen(szDescription);
 | |
|       FILE_TYPE_NODE *pft = (FILE_TYPE_NODE*) new BYTE[
 | |
|          sizeof(FILE_TYPE_NODE) + (sizeof(TCHAR) * length)];
 | |
| 
 | |
|       // Bail out if we could not create our node.
 | |
|       if (!pft) {
 | |
|          DebugOut(TEXT("Not enough memory to create a FILE_TYPE_NODE."));
 | |
|          continue;
 | |
|       }
 | |
| 
 | |
|       // Fill in the node.
 | |
|       pft->pNext = NULL;
 | |
|       pft->image = (image >= 0) ? image : IMAGE_GENERIC;
 | |
|       wcstombs(pft->szExtAndDesc, szExtension + 1, length + 3);
 | |
|       wcstombs(pft->szExtAndDesc + strlen(pft->szExtAndDesc) + 1, 
 | |
|                szDescription, length + 3);
 | |
| 
 | |
|       // Add the node to our list.
 | |
|       if (pftLast) {
 | |
|          pftLast->pNext = pft;
 | |
|       } else {
 | |
|          g_pftHead = pft;
 | |
|       }
 | |
|       pftLast = pft;
 | |
|    }
 | |
| 
 | |
|    // Assign this image list to our tree control.
 | |
|    ListView_SetImageList(g_hWndList, hil, LVSIL_SMALL);
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Our Main Window's Message Handler
 | |
| //******************************************************************************
 | |
| 
 | |
| LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    switch(uMsg) {
 | |
|       case WM_CREATE:
 | |
|          g_hWndMain = hWnd;
 | |
|          return OnCreate();
 | |
| 
 | |
|       case WM_ERASEBKGND:
 | |
|          DrawBanner((HDC)wParam);
 | |
|          return 0;
 | |
| 
 | |
|       case WM_SIZE:
 | |
|          // Resize our list view control to match our client area.
 | |
|          MoveWindow(g_hWndList, 0, g_cyCmdBar + 22, LOWORD(lParam), 
 | |
|                     HIWORD(lParam) - (g_cyCmdBar + 22), TRUE);
 | |
| 
 | |
| #ifndef _WIN32_WCE
 | |
|          // On NT we have to resize our toolbar as well.
 | |
|          MoveWindow(g_hWndCmdBar, 0, 0, LOWORD(lParam), g_cyCmdBar, TRUE);
 | |
| #endif
 | |
|          return 0;
 | |
|       
 | |
|       case WM_SETFOCUS:
 | |
|          // Always direct focus to our list control.
 | |
|          SetFocus(g_hWndList);
 | |
|          return 0;
 | |
| 
 | |
|       case WM_DESTROY:
 | |
|          PostQuitMessage(0);
 | |
|          return 0;
 | |
|       
 | |
|       case WM_HELP:
 | |
|          OnHelp();
 | |
|          return 0;
 | |
| 
 | |
|       case WM_PRIVATE:
 | |
|          switch (wParam) {
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
|             case MSG_SUBCLASS_DIALOG:
 | |
|                SubclassSaveAsDlg();
 | |
|                return 0;
 | |
| #endif
 | |
|             case MSG_ADD_TEXT_TO_EDIT:
 | |
|                AddTextToEdit((LPCSTR)lParam);
 | |
|                return 0;
 | |
|             
 | |
|             case MSG_PROMPT_TO_REPLACE:
 | |
|                return PromptToReplace((LPCSTR)lParam);
 | |
| 
 | |
| #if CRYPT
 | |
|             case MSG_PROMPT_FOR_PASSWORD:
 | |
|                return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_PASSWORD),
 | |
|                                      g_hDlgProgress, (DLGPROC)DlgProcPassword,
 | |
|                                      lParam);
 | |
| #endif
 | |
| 
 | |
|             case MSG_UPDATE_PROGRESS_PARTIAL:
 | |
|                UpdateProgress((EXTRACT_INFO*)lParam, FALSE);
 | |
|                return 0;
 | |
| 
 | |
|             case MSG_UPDATE_PROGRESS_COMPLETE:
 | |
|                UpdateProgress((EXTRACT_INFO*)lParam, TRUE);
 | |
|                return 0;
 | |
|          }
 | |
|          return 0;
 | |
| 
 | |
|       case WM_NOTIFY:
 | |
|          switch (((LPNMHDR)lParam)->code) {
 | |
| 
 | |
|             case LVN_GETDISPINFO:
 | |
|                OnGetDispInfo((LV_DISPINFO*)lParam);
 | |
|                return 0;
 | |
| 
 | |
|             case LVN_DELETEITEM:
 | |
|                OnDeleteItem((NM_LISTVIEW*)lParam);
 | |
|                return 0;
 | |
| 
 | |
|             case LVN_COLUMNCLICK:
 | |
|                Sort(((NM_LISTVIEW*)lParam)->iSubItem, FALSE);
 | |
|                return 0;
 | |
| 
 | |
|             case LVN_ITEMCHANGED:
 | |
|                OnItemChanged((NM_LISTVIEW*)lParam);
 | |
|                return 0;
 | |
| 
 | |
|             case NM_DBLCLK:
 | |
|             case NM_RETURN:
 | |
|                OnActionView();
 | |
|                return 0;
 | |
|          }
 | |
| 
 | |
|          return 0;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          switch (LOWORD(wParam)) {
 | |
| 
 | |
|             case IDM_FILE_OPEN:
 | |
|                OnFileOpen();
 | |
|                return 0;
 | |
|             
 | |
|             case IDM_FILE_PROPERTIES:
 | |
|                DialogBox(g_hInst, MAKEINTRESOURCE(IDD_PROPERTIES), hWnd, (DLGPROC)DlgProcProperties);
 | |
|                return 0;
 | |
| 
 | |
|             case IDM_FILE_CLOSE:
 | |
|                SendMessage(hWnd, WM_CLOSE, 0, 0);
 | |
|                return 0;
 | |
| 
 | |
|             case IDM_ACTION_EXTRACT_ALL:
 | |
|                OnActionSelectAll();
 | |
|                // Fall through to IDM_ACTION_EXTRACT
 | |
| 
 | |
|             case IDM_ACTION_EXTRACT:
 | |
|                ExtractOrTestFiles(TRUE);
 | |
|                return 0;
 | |
| 
 | |
|             case IDM_ACTION_TEST_ALL:
 | |
|                OnActionSelectAll();
 | |
|                // Fall through to IDM_ACTION_TEST
 | |
| 
 | |
|             case IDM_ACTION_TEST:
 | |
|                ExtractOrTestFiles(FALSE);
 | |
|                return 0;
 | |
| 
 | |
|             case IDM_ACTION_VIEW:
 | |
|                OnActionView();
 | |
|                return 0;
 | |
| 
 | |
|             case IDM_ACTION_SELECT_ALL:
 | |
|                OnActionSelectAll();
 | |
|                return 0;
 | |
| 
 | |
|             case IDM_VIEW_EXPANDED_VIEW:
 | |
|                OnViewExpandedView();
 | |
|                return 0;
 | |
| 
 | |
|             case IDM_VIEW_COMMENT:
 | |
|                DialogBox(g_hInst, MAKEINTRESOURCE(IDD_COMMENT), hWnd, (DLGPROC)DlgProcComment);
 | |
|                return 0;
 | |
| 
 | |
|             case IDM_HELP_ABOUT:
 | |
|                DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)DlgProcAbout);
 | |
|                return 0;
 | |
| 
 | |
|             case IDHELP:
 | |
|                return SendMessage(hWnd, WM_HELP, 0, 0);
 | |
| 
 | |
|             default:
 | |
|                // Check to see if a MRU file was selected.
 | |
|                if ((LOWORD(wParam) >= MRU_START_ID) && 
 | |
|                    (LOWORD(wParam) < (MRU_START_ID + MRU_MAX_FILE)))
 | |
|                {
 | |
|                   ActivateMRU(LOWORD(wParam));
 | |
|                }
 | |
|          }
 | |
|     }
 | |
|     return DefWindowProc(hWnd, uMsg, wParam, lParam);
 | |
| }          
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Event Handlers for our Main Window
 | |
| //******************************************************************************
 | |
| 
 | |
| int OnCreate() {
 | |
| 
 | |
|    // Our toolbar buttons.
 | |
|    static TBBUTTON tbButton[] = {
 | |
|       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 | |
|       { 0, IDM_FILE_OPEN,          0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 | |
|       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 | |
|       { 1, IDM_FILE_PROPERTIES,    0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 | |
|       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 | |
|       { 2, IDM_ACTION_EXTRACT,     0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 | |
|       { 3, IDM_ACTION_EXTRACT_ALL, 0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 | |
|       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 | |
|       { 4, IDM_ACTION_TEST,        0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 | |
|       { 5, IDM_ACTION_TEST_ALL,    0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 | |
|       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 | |
|       { 6, IDM_ACTION_VIEW,        0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 | |
|       { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 | |
|       { 7, IDM_VIEW_EXPANDED_VIEW, 0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 | |
|       { 8, IDM_VIEW_COMMENT,       0, TBSTYLE_BUTTON, 0, 0, 0, -1 }
 | |
|    };
 | |
| 
 | |
|    // Our toolbar buttons' tool tip text.
 | |
|    static LPTSTR szToolTips[] = {
 | |
|        TEXT(""),  // Menu
 | |
|        TEXT("Open (Ctrl+O)"),
 | |
|        TEXT("Properties (Alt+Enter)"),
 | |
|        TEXT("Extract Selected Files"),
 | |
|        TEXT("Extract All Files"),
 | |
|        TEXT("Test Selected Files"),
 | |
|        TEXT("Test All Files"),
 | |
|        TEXT("View Selected File"),
 | |
|        TEXT("Expanded View"),
 | |
|        TEXT("View Zip File Comment")
 | |
|    };
 | |
| 
 | |
|    // Initialize the common controls.
 | |
|    InitCommonControls();
 | |
| 
 | |
|    // Check to see if we have a help file.
 | |
|    BOOL fHelp = (GetFileAttributes(g_szHelpFile) != 0xFFFFFFFF);
 | |
| 
 | |
|    // Set our window's icon so it can update the task bar.
 | |
|    if (g_hIconMain) {
 | |
|       SendMessage(g_hWndMain, WM_SETICON, FALSE, (LPARAM)g_hIconMain);
 | |
|    }
 | |
| 
 | |
|    // Create the tree control.  Our main window will resize it to fit.
 | |
|    g_hWndList = CreateWindow(WC_LISTVIEW, TEXT(""),
 | |
|                              WS_VSCROLL | WS_CHILD | WS_VISIBLE | 
 | |
|                              LVS_REPORT | LVS_SHOWSELALWAYS,
 | |
|                              0, 0, 0, 0, g_hWndMain, NULL, g_hInst, NULL);
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| 
 | |
|    // Create a command bar and add the toolbar bitmaps to it.
 | |
|    g_hWndCmdBar = CommandBar_Create(g_hInst, g_hWndMain, 1);
 | |
|    CommandBar_AddBitmap(g_hWndCmdBar, g_hInst, IDB_TOOLBAR, 9, 16, 16);
 | |
|    CommandBar_InsertMenubar(g_hWndCmdBar, g_hInst, IDR_UNZIP, 0);
 | |
|    CommandBar_AddButtons(g_hWndCmdBar, countof(tbButton), tbButton);
 | |
|    CommandBar_AddAdornments(g_hWndCmdBar, fHelp ? CMDBAR_HELP : 0, 0);
 | |
| 
 | |
|    // Add tool tips to the tool bar.
 | |
|    CommandBar_AddToolTips(g_hWndCmdBar, countof(szToolTips), szToolTips);
 | |
| 
 | |
|    // Store the height of the command bar for later calculations.
 | |
|    g_cyCmdBar = CommandBar_Height(g_hWndCmdBar);
 | |
| 
 | |
|    // We set our wait window handle to our menu window within our command bar.
 | |
|    // This is the last window that will be painted during startup of our app.
 | |
|    g_hWndWaitFor = GetWindow(g_hWndCmdBar, GW_CHILD);
 | |
| 
 | |
|    // Add the help item to our help menu if we have a help file.
 | |
|    if (fHelp) {
 | |
|       HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 3);
 | |
|       InsertMenu(hMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
 | |
|       InsertMenu(hMenu, 0, MF_BYPOSITION | MF_ENABLED, IDHELP, TEXT("&Help"));
 | |
|    }
 | |
| 
 | |
| #else
 | |
| 
 | |
|    // Create a tool bar and add the toolbar bitmaps to it.
 | |
|    g_hWndCmdBar = CreateToolbarEx(g_hWndMain, WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS,
 | |
|                                   1, 9, g_hInst, IDB_TOOLBAR, tbButton, 
 | |
|                                   countof(tbButton), 16, 16, 16, 16, 
 | |
|                                   sizeof(TBBUTTON));
 | |
| 
 | |
|    // Get our tool tip control.
 | |
|    HWND hWndTT = (HWND)SendMessage(g_hWndCmdBar, TB_GETTOOLTIPS, 0, 0);
 | |
| 
 | |
|    // Set our tool tip strings.
 | |
|    TOOLINFO ti;
 | |
|    ti.cbSize = sizeof(ti);
 | |
|    int tip = 0, button; 
 | |
|    while (SendMessage(hWndTT, TTM_ENUMTOOLS, tip++, (LPARAM)&ti)) {
 | |
|       for (button = 0; button < countof(tbButton); button++) {
 | |
|          if (tbButton[button].idCommand == (int)ti.uId) {
 | |
|             ti.lpszText = szToolTips[tbButton[button].iBitmap + 1];
 | |
|             SendMessage(hWndTT, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
 | |
|             break;
 | |
|          }
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Store the height of the tool bar for later calculations.
 | |
|    RECT rc;
 | |
|    GetWindowRect(g_hWndCmdBar, &rc);
 | |
|    g_cyCmdBar = rc.bottom - rc.top;
 | |
| 
 | |
|    // We set our wait window handle to our toolbar.
 | |
|    // This is the last window that will be painted during the startup of our app.
 | |
|    g_hWndWaitFor = g_hWndCmdBar;
 | |
| 
 | |
|    // Add the help item to our help menu if we have a help file.
 | |
|    if (fHelp) {
 | |
|       HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 3);
 | |
|       InsertMenu(hMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
 | |
|       InsertMenu(hMenu, 0, MF_BYPOSITION | MF_ENABLED, IDHELP, TEXT("&Help\tF1"));
 | |
|    }
 | |
| 
 | |
| #endif // _WIN32_WCE
 | |
| 
 | |
|    // Enable Full Row Select - This feature is supported on Windows CE and was
 | |
|    // introduced to Win95/NT with IE 3.0.  If the user does not have a 
 | |
|    // COMCTL32.DLL that supports this feature, then they will just see the 
 | |
|    // old standard First Column Select.
 | |
|    SendMessage(g_hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT |
 | |
|                SendMessage(g_hWndList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0));
 | |
|   
 | |
|    // Get our expanded view option from the registry.
 | |
|    g_fExpandedView = GetOptionInt(TEXT("ExpandedView"), FALSE);
 | |
| 
 | |
|    // Show or remove menu check for expanded view option.
 | |
|    CheckAllMenuItems(IDM_VIEW_EXPANDED_VIEW, g_fExpandedView);
 | |
| 
 | |
|    // Create our columns.
 | |
|    AddDeleteColumns();
 | |
| 
 | |
|    // Set our current sort column to our name column
 | |
|    Sort(0, TRUE);
 | |
| 
 | |
|    return 0;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void OnFileOpen() {
 | |
| 
 | |
|    TCHAR szPath[_MAX_PATH] = TEXT("");
 | |
| 
 | |
|    OPENFILENAME ofn;
 | |
|    ZeroMemory(&ofn, sizeof(ofn));
 | |
| 
 | |
|    ofn.lStructSize  = sizeof(ofn);
 | |
|    ofn.hwndOwner    = g_hWndMain;
 | |
|    ofn.hInstance    = g_hInst;
 | |
|    ofn.lpstrFilter  = TEXT("ZIP files (*.zip)\0*.zip\0SFX files (*.exe)\0*.exe\0All Files (*.*)\0*.*\0");
 | |
|    ofn.nFilterIndex = 1;
 | |
|    ofn.lpstrFile    = szPath;
 | |
|    ofn.nMaxFile     = countof(szPath);
 | |
|    ofn.Flags        = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
 | |
|    ofn.lpstrDefExt  = TEXT("zip");
 | |
| 
 | |
|    if (GetOpenFileName(&ofn)) {
 | |
|       ReadZipFileList(szPath);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void OnActionView() {
 | |
| 
 | |
|    // We only allow a view if one item is selected.
 | |
|    int count = ListView_GetSelectedCount(g_hWndList);
 | |
|    if (count != 1) {
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Query the selected item for its FILE_NODE.
 | |
|    LV_ITEM lvi;
 | |
|    ZeroMemory(&lvi, sizeof(lvi));
 | |
|    lvi.mask = LVIF_IMAGE | LVIF_PARAM;
 | |
|    lvi.iItem = ListView_GetNextItem(g_hWndList, -1, LVNI_SELECTED);
 | |
|    ListView_GetItem(g_hWndList, &lvi);
 | |
|    FILE_NODE *pfn = (FILE_NODE*)lvi.lParam;
 | |
| 
 | |
|    // Bail out if the selected item is a folder or volume label.
 | |
|    if (pfn->dwAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_VOLUME)) {
 | |
|       MessageBox(g_hWndMain, TEXT("You cannot view folders or volume labels."), 
 | |
|                  g_szAppName, MB_ICONINFORMATION | MB_OK);
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Make sure our temporary directory exists.
 | |
|    CreateDirectory(g_szTempDir, NULL);
 | |
| 
 | |
|    TCHAR szPath[_MAX_PATH + 256];
 | |
| 
 | |
|    // Set our extraction directory to our temporary directory.
 | |
|    if (!SetExtractToDirectory((LPTSTR)g_szTempDir)) {
 | |
|       
 | |
|       // Create error message.  Use szPath buffer because it is handy.
 | |
|       _stprintf(szPath,
 | |
|          TEXT("Could not create \"%s\"\n\n")
 | |
|          TEXT("Most likely cause is that your drive is full."),
 | |
|          g_szTempDir);
 | |
| 
 | |
|       // Display error message.
 | |
|       MessageBox(g_hWndMain, szPath, g_szAppName, MB_ICONERROR | MB_OK);
 | |
| 
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Create our single item file array.
 | |
|    CHAR *argv[2] = { pfn->szPathAndMethod, NULL };
 | |
| 
 | |
|    // Create a buffer to store the mapped name of the file.  If the has to be
 | |
|    // renamed to be compatible with our file system, then we need to know that
 | |
|    // new name in order to open it correctly.
 | |
|    CHAR szMappedPath[_MAX_PATH];
 | |
|    *szMappedPath = '\0';
 | |
| 
 | |
|    // Configure our extract structure.
 | |
|    EXTRACT_INFO ei;
 | |
|    ZeroMemory(&ei, sizeof(ei));
 | |
|    ei.fExtract      = TRUE;
 | |
|    ei.dwFileCount   = 1;
 | |
|    ei.dwByteCount   = pfn->dwSize;
 | |
|    ei.szFileList    = argv;
 | |
|    ei.fRestorePaths = FALSE;
 | |
|    ei.overwriteMode = OM_PROMPT;
 | |
|    ei.szMappedPath  = szMappedPath;
 | |
| 
 | |
|    // Clear our skipped flag and set our viewing flag.
 | |
|    g_fSkipped = FALSE;
 | |
|    g_fViewing = TRUE;
 | |
| 
 | |
|    // Display our progress dialog and do the extraction.
 | |
|    DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_VIEW_PROGRESS), g_hWndMain, 
 | |
|                   (DLGPROC)DlgProcViewProgress, (LPARAM)&ei);
 | |
| 
 | |
|    // Clear our viewing flag.
 | |
|    g_fViewing = FALSE;
 | |
| 
 | |
|    // Check to see if the user skipped the file by aborting the decryption or
 | |
|    // overwrite prompts.  The only other case that causes us to skip a file
 | |
|    // is when the user enters the incorrect password too many times.  In this
 | |
|    // case, IZ_BADPWD will be returned.
 | |
|    if (g_fSkipped) {
 | |
|       return;
 | |
|    }
 | |
|    if (ei.result == IZ_BADPWD) {
 | |
|       MessageBox(g_hWndMain, TEXT("Password was incorrect.  The file has been skipped."),
 | |
|                  g_szAppName, MB_ICONWARNING | MB_OK);
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Check to see if the extraction failed.
 | |
|    if (ei.result != PK_OK) {
 | |
| 
 | |
|       if (ei.result == PK_ABORTED) {
 | |
|          _tcscpy(szPath, GetZipErrorString(ei.result));
 | |
| 
 | |
|       } else {
 | |
|          // Create error message.  Use szPath buffer because it is handy.
 | |
|          _stprintf(szPath,
 | |
|             TEXT("Could not extract \"%S\".\n\n%s\n\nTry using the Test or ")
 | |
|             TEXT("Extract action on the file for more details."),
 | |
|             *szMappedPath ? szMappedPath : pfn->szPathAndMethod,
 | |
|             GetZipErrorString(ei.result));
 | |
|       }
 | |
| 
 | |
|       // Display error message.
 | |
|       MessageBox(g_hWndMain, szPath, g_szAppName, MB_ICONERROR | MB_OK);
 | |
| 
 | |
|       // If we managed to create a bad file, then delete it.
 | |
|       if (*szMappedPath) {
 | |
|          mbstowcs(szPath, szMappedPath, countof(szPath));
 | |
|          SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
 | |
|          if (!DeleteFile(szPath)) {
 | |
|             SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Convert the file name to UNICODE.
 | |
|    mbstowcs(szPath, szMappedPath, countof(szPath));
 | |
| 
 | |
|    // Prepare to launch the file.
 | |
|    SHELLEXECUTEINFO sei;
 | |
|    ZeroMemory(&sei, sizeof(sei));
 | |
|    sei.cbSize      = sizeof(sei);
 | |
|    sei.hwnd        = g_hWndMain;
 | |
|    sei.lpDirectory = g_szTempDir;
 | |
|    sei.nShow       = SW_SHOWNORMAL;
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| 
 | |
|    TCHAR szApp[_MAX_PATH];
 | |
| 
 | |
|    // On Windows CE, there is no default file association dialog that appears
 | |
|    // when ShellExecuteEx() is given an unknown file type.  We check to see if
 | |
|    // file is unknown, and display our own file association prompt.
 | |
| 
 | |
|    // Check our file image to see if this file has no associated viewer.
 | |
|    if (lvi.iImage == IMAGE_GENERIC) {
 | |
| 
 | |
|       // Display our file association prompt dialog.
 | |
|       if (IDOK != DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_VIEW_ASSOCIATION),
 | |
|                                  g_hWndMain, (DLGPROC)DlgProcViewAssociation,
 | |
|                                  (LPARAM)szApp))
 | |
|       {
 | |
|          // If the user aborted the association prompt, then delete file and exit.
 | |
|          SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
 | |
|          if (!DeleteFile(szPath)) {
 | |
|             SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
 | |
|          }
 | |
|          return;
 | |
|       }
 | |
|       // Set the file to be the viewer app and the parameters to be the file.
 | |
|       // Note: Some applications require that arguments with spaces be quoted,
 | |
|       // while other applications choked when quotes we part of the filename.
 | |
|       // In the end, it seems safer to leave the quotes off.
 | |
|       sei.lpFile = szApp;
 | |
|       sei.lpParameters = szPath;
 | |
|    } else {
 | |
|       sei.lpFile = szPath;
 | |
|    }
 | |
| 
 | |
| #else
 | |
| 
 | |
|    // On NT, ShellExecuteEx() will prompt user for association if needed.
 | |
|    sei.lpFile = szPath;
 | |
| 
 | |
| #endif
 | |
| 
 | |
|    // Launch the file.  All errors will be displayed by ShellExecuteEx().
 | |
|    ShellExecuteEx(&sei);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void OnActionSelectAll() {
 | |
|    for (int i = ListView_GetItemCount(g_hWndList) - 1; i >= 0; i--) {
 | |
|       ListView_SetItemState(g_hWndList, i, LVIS_SELECTED, LVIS_SELECTED);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void OnViewExpandedView() {
 | |
| 
 | |
|    // Toggle our expanded view option.
 | |
|    g_fExpandedView = !g_fExpandedView;
 | |
| 
 | |
|    // Show or remove menu check and toolbar button press.
 | |
|    CheckAllMenuItems(IDM_VIEW_EXPANDED_VIEW, g_fExpandedView);
 | |
| 
 | |
|    // Display the new columns.
 | |
|    AddDeleteColumns();
 | |
| 
 | |
|    // Re-sort if we just did away with out sort column.
 | |
|    if (!g_fExpandedView && (g_sortColumn > 3)) {
 | |
|       Sort(0, TRUE);
 | |
|    }
 | |
| 
 | |
|    // Write our expanded view option to the registry.
 | |
|    WriteOptionInt(TEXT("ExpandedView"), g_fExpandedView);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void OnHelp() {
 | |
| 
 | |
|    // Prepare to launch the help file.
 | |
|    SHELLEXECUTEINFO sei;
 | |
|    ZeroMemory(&sei, sizeof(sei));
 | |
|    sei.cbSize      = sizeof(sei);
 | |
|    sei.hwnd        = g_hWndMain;
 | |
|    sei.lpFile      = g_szHelpFile;
 | |
| 
 | |
|    // Launch the file.
 | |
|    ShellExecuteEx(&sei);
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Event Handlers for our List View
 | |
| //******************************************************************************
 | |
| 
 | |
| void OnGetDispInfo(LV_DISPINFO *plvdi) {
 | |
| 
 | |
|    // Make sure we have the minimum amount of data to process this event.
 | |
|    if ((plvdi->item.iItem < 0) || !plvdi->item.lParam || !plvdi->item.pszText) {
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Get a pointer to the file node for this item.
 | |
|    FILE_NODE *pFile = (FILE_NODE*)plvdi->item.lParam;
 | |
| 
 | |
|    CHAR szBuffer[_MAX_PATH * 2];
 | |
| 
 | |
|    switch (plvdi->item.iSubItem) {
 | |
| 
 | |
|       case 0: // Name
 | |
| 
 | |
|          // Copy the string to a new string while removing all non-printables.
 | |
|          fnfilter(pFile->szPathAndMethod, (uch*)szBuffer);
 | |
| 
 | |
|          // Change all forward slashes to back slashes in the buffer
 | |
|          ForwardSlashesToBackSlashesA(szBuffer);
 | |
| 
 | |
|          // Convert the string to UNICODE and store it in our list control.
 | |
|          mbstowcs(plvdi->item.pszText, szBuffer, plvdi->item.cchTextMax);
 | |
| 
 | |
|          return;
 | |
| 
 | |
|       case 1: // Size
 | |
|          FormatValue(plvdi->item.pszText, pFile->dwSize);
 | |
|          return;
 | |
| 
 | |
|       case 2: // Type
 | |
|          mbstowcs(plvdi->item.pszText, BuildTypeString(pFile, szBuffer), 
 | |
|                   plvdi->item.cchTextMax);
 | |
|          return;
 | |
| 
 | |
|       case 3: // Modified
 | |
|          int hour; hour = (pFile->dwModified >> 6) & 0x001F;
 | |
|          _stprintf(plvdi->item.pszText, TEXT("%u/%u/%u %u:%02u %cM"),
 | |
|                    (pFile->dwModified  >> 16) & 0x000F,
 | |
|                    (pFile->dwModified  >> 11) & 0x001F,
 | |
|                    ((pFile->dwModified >> 20) & 0x0FFF) % 100,
 | |
|                    (hour % 12) ? (hour % 12) : 12,
 | |
|                    pFile->dwModified & 0x003F,
 | |
|                    hour >= 12 ? 'P' : 'A');
 | |
|          return;
 | |
| 
 | |
|       case 4: // Attributes
 | |
|          BuildAttributesString(plvdi->item.pszText, pFile->dwAttributes);
 | |
|          return;
 | |
| 
 | |
|       case 5: // Compressed
 | |
|          FormatValue(plvdi->item.pszText, pFile->dwCompressedSize);
 | |
|          return;
 | |
| 
 | |
|       case 6: // Ratio
 | |
|          int factor; factor = ratio(pFile->dwSize, pFile->dwCompressedSize);
 | |
|          _stprintf(plvdi->item.pszText, TEXT("%d.%d%%"), factor / 10, 
 | |
|                    ((factor < 0) ? -factor : factor) % 10);
 | |
|          return;
 | |
| 
 | |
|       case 7: // Method
 | |
|          mbstowcs(plvdi->item.pszText, pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1, 
 | |
|                   plvdi->item.cchTextMax);
 | |
|          return;
 | |
| 
 | |
|       case 8: // CRC
 | |
|          _stprintf(plvdi->item.pszText, L"%08X", pFile->dwCRC);
 | |
|          return;
 | |
| 
 | |
|       case 9: // Comment
 | |
|          mbstowcs(plvdi->item.pszText, pFile->szComment ? pFile->szComment : "",
 | |
|                   plvdi->item.cchTextMax);
 | |
|          return;
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void OnDeleteItem(NM_LISTVIEW *pnmlv) {
 | |
|    if (pnmlv->lParam) {
 | |
| 
 | |
|       // Free any comment string associated with this item.
 | |
|       if (((FILE_NODE*)pnmlv->lParam)->szComment) {
 | |
|          delete[] (CHAR*)((FILE_NODE*)pnmlv->lParam)->szComment;
 | |
|       }
 | |
| 
 | |
|       // Free the item itself.
 | |
|       delete[] (LPBYTE)pnmlv->lParam;
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void OnItemChanged(NM_LISTVIEW *pnmlv) {
 | |
|    int count = ListView_GetSelectedCount(pnmlv->hdr.hwndFrom);
 | |
|    EnableAllMenuItems(IDM_FILE_PROPERTIES, count > 0);
 | |
|    EnableAllMenuItems(IDM_ACTION_EXTRACT,  count > 0);
 | |
|    EnableAllMenuItems(IDM_ACTION_TEST,     count > 0);
 | |
|    EnableAllMenuItems(IDM_ACTION_VIEW,     count == 1);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** List View Sort Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| void Sort(int sortColumn, BOOL fForce) {
 | |
| 
 | |
|    // Do not change the column header text if it is already correct.
 | |
|    if (sortColumn != g_sortColumn) {
 | |
| 
 | |
|       TCHAR szColumn[32];
 | |
|       LV_COLUMN lvc;
 | |
|       lvc.mask = LVCF_TEXT;
 | |
|       lvc.pszText = szColumn; 
 | |
| 
 | |
|       // Remove the '^' from the current sort column.
 | |
|       if (g_sortColumn != -1) {
 | |
|          _stprintf(szColumn, (g_columns[g_sortColumn].format == LVCFMT_LEFT) ? 
 | |
|                    TEXT("%s   ") : TEXT("   %s"), g_columns[g_sortColumn].szName);
 | |
|          ListView_SetColumn(g_hWndList, g_sortColumn, &lvc);
 | |
|       }
 | |
| 
 | |
|       // Set the new sort column.
 | |
|       g_sortColumn = sortColumn;
 | |
| 
 | |
|       // Add the '^' to the new sort column.
 | |
|       _stprintf(szColumn, (g_columns[g_sortColumn].format == LVCFMT_LEFT) ? 
 | |
|                 TEXT("%s ^") : TEXT("^ %s"), g_columns[g_sortColumn].szName);
 | |
|       ListView_SetColumn(g_hWndList, g_sortColumn, &lvc);
 | |
| 
 | |
|       // Sort the list by the new column.
 | |
|       ListView_SortItems(g_hWndList, CompareFunc, g_sortColumn);
 | |
| 
 | |
|    } else if (fForce) {
 | |
|       // Force the list to sort by the same column.
 | |
|       ListView_SortItems(g_hWndList, CompareFunc, g_sortColumn);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM sortColumn) {
 | |
|    FILE_NODE *pFile1 = (FILE_NODE*)lParam1, *pFile2 = (FILE_NODE*)lParam2;
 | |
|    TCHAR szBuffer1[8], szBuffer2[8];
 | |
| 
 | |
|    // Return Negative value if the first item should precede the second.
 | |
|    // Return Positive value if the first item should follow the second.
 | |
|    // Return Zero if the two items are equivalent.
 | |
| 
 | |
|    int result = 0;
 | |
| 
 | |
|    // Compute the relationship based on the current sort column
 | |
|    switch (sortColumn) {
 | |
| 
 | |
|       case 1: // Size - Smallest to Largest
 | |
|          if (pFile1->dwSize != pFile2->dwSize) {
 | |
|             result = ((pFile1->dwSize < pFile2->dwSize) ? -1 : 1);
 | |
|          }
 | |
|          break;
 | |
| 
 | |
|       case 2: { // Type - Volume Label's first, then directories, then files
 | |
|          int f1 = (pFile1->dwAttributes & FILE_ATTRIBUTE_VOLUME)    ? 1 : 
 | |
|                   (pFile1->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 3;
 | |
|          int f2 = (pFile2->dwAttributes & FILE_ATTRIBUTE_VOLUME)    ? 1 : 
 | |
|                   (pFile2->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 3;
 | |
|          if ((f1 == 3) && (f2 == 3)) {
 | |
|             CHAR szType1[128];
 | |
|             CHAR szType2[128];
 | |
|             result = _stricmp(BuildTypeString(pFile1, szType1),
 | |
|                               BuildTypeString(pFile2, szType2));
 | |
|          } else {
 | |
|             result = f1 - f2;
 | |
|          }
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       case 3: // Modified - Newest to Oldest
 | |
|          if (pFile1->dwModified != pFile2->dwModified) {
 | |
|             result = ((pFile1->dwModified > pFile2->dwModified) ? -1 : 1);
 | |
|          }
 | |
|          break;
 | |
| 
 | |
|       case 4: // Attributes - String Sort
 | |
|          result = _tcscmp(BuildAttributesString(szBuffer1, pFile1->dwAttributes),
 | |
|                           BuildAttributesString(szBuffer2, pFile2->dwAttributes));
 | |
|          break;
 | |
| 
 | |
|       case 5: // Compressed Size - Smallest to Largest
 | |
|          if (pFile1->dwCompressedSize != pFile2->dwCompressedSize) {
 | |
|             result = ((pFile1->dwCompressedSize < pFile2->dwCompressedSize) ? -1 : 1);
 | |
|          }
 | |
|          break;
 | |
| 
 | |
|       case 6: // Ratio - Smallest to Largest
 | |
|          int factor1, factor2;
 | |
|          factor1 = ratio(pFile1->dwSize, pFile1->dwCompressedSize);
 | |
|          factor2 = ratio(pFile2->dwSize, pFile2->dwCompressedSize);
 | |
|          result = factor1 - factor2;
 | |
|          break;
 | |
| 
 | |
|       case 7: // Method - String Sort
 | |
|          result = _stricmp(pFile1->szPathAndMethod + strlen(pFile1->szPathAndMethod) + 1,
 | |
|                            pFile2->szPathAndMethod + strlen(pFile2->szPathAndMethod) + 1);
 | |
|          break;
 | |
| 
 | |
|       case 8: // CRC - Smallest to Largest
 | |
|          if (pFile1->dwCRC != pFile2->dwCRC) {
 | |
|             result = ((pFile1->dwCRC < pFile2->dwCRC) ? -1 : 1);
 | |
|          }
 | |
|          break;
 | |
| 
 | |
|       case 9: // Comment - String Sort
 | |
|          result = _stricmp(pFile1->szComment ? pFile1->szComment : "",
 | |
|                            pFile2->szComment ? pFile2->szComment : "");
 | |
|          break;
 | |
|    }
 | |
| 
 | |
|    // If the sort resulted in a tie, we use the name to break the tie.
 | |
|    if (result == 0) {
 | |
|       result = _stricmp(pFile1->szPathAndMethod, pFile2->szPathAndMethod);
 | |
|    }
 | |
| 
 | |
|    return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Helper/Utility Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| void SetCaptionText(LPCTSTR szPrefix) {
 | |
|    TCHAR szCaption[_MAX_PATH + 32];
 | |
|    if (szPrefix && *g_szZipFile) {
 | |
|       _stprintf(szCaption, TEXT("%s - %S"), szPrefix, GetFileFromPath(g_szZipFile));
 | |
|    } else if (szPrefix) {
 | |
|       _stprintf(szCaption, TEXT("%s - Pocket UnZip"), szPrefix);
 | |
|    } else if (*g_szZipFile) {
 | |
|       _stprintf(szCaption, TEXT("%S"), GetFileFromPath(g_szZipFile));
 | |
|    } else {
 | |
|       _tcscpy(szCaption, TEXT("Pocket UnZip"));
 | |
|    }
 | |
|    SetWindowText(g_hWndMain, szCaption);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void DrawBanner(HDC hdc) {
 | |
| 
 | |
|    // If we were not passed in a DC, then get one now.
 | |
|    BOOL fReleaseDC = FALSE;
 | |
|    if (!hdc) {
 | |
|       hdc = GetDC(g_hWndMain);
 | |
|       fReleaseDC = TRUE;
 | |
|    }
 | |
| 
 | |
|    // Compute the banner rectangle.
 | |
|    RECT rc;
 | |
|    GetClientRect(g_hWndMain, &rc);
 | |
|    rc.top += g_cyCmdBar;
 | |
|    rc.bottom = rc.top + 22;
 | |
| 
 | |
|    // Fill in the background with a light grey brush.
 | |
|    FillRect(hdc, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
 | |
| 
 | |
|    // Draw a highlight line across the top of our banner.
 | |
|    POINT pt[2] = { { rc.left, rc.top + 1 }, { rc.right, rc.top + 1 } };
 | |
| 
 | |
|    SelectObject(hdc, GetStockObject(WHITE_PEN));
 | |
|    Polyline(hdc, pt, 2);
 | |
| 
 | |
|    // Get the ZIP file image.  We do this only once and cache the result.
 | |
|    // Note that you do not need to free icons as they are a resource.
 | |
|    static HICON hIcon = NULL;
 | |
|    if (!hIcon) {
 | |
|       hIcon = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_ZIPFILE), 
 | |
|                                IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
 | |
|    }
 | |
|    
 | |
|    // Draw the ZIP file image.
 | |
|    DrawIconEx(hdc, rc.left + 6, rc.top + 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
 | |
| 
 | |
|    // Set our font and colors.
 | |
|    HFONT hFontStock = (HFONT)SelectObject(hdc, g_hFontBanner);
 | |
|    SetTextColor(hdc, RGB(0, 0, 0));
 | |
|    SetBkMode(hdc, TRANSPARENT);
 | |
| 
 | |
|    rc.left   += 26;      
 | |
|    rc.right  -= 48;
 | |
|    rc.bottom -=  2;
 | |
| 
 | |
|    // Decide what text to display.
 | |
|    TCHAR szPath[_MAX_PATH + 16];
 | |
|    if (g_hWndWaitFor) {
 | |
|       _tcscpy(szPath, TEXT("Initializing..."));
 | |
|    } else if (*g_szZipFile) {
 | |
|       if (g_fLoading) {
 | |
|          _stprintf(szPath, TEXT("Loading %S"), g_szZipFile);
 | |
|       } else {
 | |
|          mbstowcs(szPath, g_szZipFile, countof(szPath));
 | |
|       }
 | |
|    } else {
 | |
|       _tcscpy(szPath, TEXT("No File Loaded"));
 | |
|    }
 | |
| 
 | |
|    // Draw the banner text.
 | |
|    DrawText(hdc, szPath, _tcslen(szPath), &rc,
 | |
|             DT_NOPREFIX | DT_SINGLELINE | DT_LEFT | DT_VCENTER);
 | |
| 
 | |
|    // Remove all non stock objects from the DC
 | |
|    SelectObject(hdc, hFontStock);
 | |
| 
 | |
|    // Free our DC if we created it.
 | |
|    if (fReleaseDC) {
 | |
|       ReleaseDC(g_hWndMain, hdc);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void AddDeleteColumns() {
 | |
| 
 | |
|    static int curColumns = 0;
 | |
|    int column, newColumns = (g_fExpandedView ? countof(g_columns) : 4);
 | |
| 
 | |
|    // Are we adding columns?
 | |
|    if (newColumns > curColumns) {
 | |
| 
 | |
|       // Set up column structure.
 | |
|       TCHAR szColumn[32];
 | |
|       LV_COLUMN lvc;
 | |
|       lvc.mask = LVCF_TEXT | LVCF_FMT;
 | |
|       lvc.pszText = szColumn;
 | |
| 
 | |
|       // Loop through each column we need to add.
 | |
|       for (column = curColumns; column < newColumns; column++) {
 | |
| 
 | |
|          // Build the real column string.
 | |
|          _stprintf(szColumn, (g_columns[column].format == LVCFMT_LEFT) ? 
 | |
|                    TEXT("%s   ") : TEXT("   %s"), g_columns[column].szName);
 | |
| 
 | |
|          // Insert the column with the correct format.
 | |
|          lvc.fmt = g_columns[column].format;
 | |
|          ListView_InsertColumn(g_hWndList, column, &lvc);
 | |
|       }
 | |
| 
 | |
|    // Otherwise, we are removing columns.
 | |
|    } else {
 | |
| 
 | |
|       // Loop through each column we need to delete and delete them.
 | |
|       for (column = curColumns - 1; column >= newColumns; column--) {
 | |
|          ListView_DeleteColumn(g_hWndList, column);
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Store our new column count statically to help us with the next call to 
 | |
|    // AddDeleteColumns().
 | |
|    curColumns = newColumns;
 | |
| 
 | |
|    // Re-calcualte our column widths.
 | |
|    ResizeColumns();
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void ResizeColumns() {
 | |
| 
 | |
|    // Hide the window since we are going to be doing some column shifting.
 | |
|    ShowWindow(g_hWndList, SW_HIDE);
 | |
| 
 | |
|    // Resize all the columns to best fit both the column data and the header.
 | |
|    for (int column = 0; column < countof(g_columns); column++) {
 | |
|       ListView_SetColumnWidth(g_hWndList, column, LVSCW_AUTOSIZE_USEHEADER);
 | |
|    }
 | |
| 
 | |
|    // Show the window again.
 | |
|    ShowWindow(g_hWndList, SW_SHOW);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| LPCTSTR GetZipErrorString(int error) {
 | |
| 
 | |
|    switch (error) {
 | |
| 
 | |
|       case PK_OK: // no error
 | |
|          return TEXT("Operation completed successfully.");
 | |
| 
 | |
|       case PK_WARN: // warning error
 | |
|          return TEXT("There were warnings during the operation.");
 | |
| 
 | |
|       case PK_ERR:    // error in zipfile
 | |
|       case PK_BADERR: // severe error in zipfile
 | |
|          return TEXT("The operation could not be successfully completed.  ")
 | |
|                 TEXT("Possible causes are that the ZIP file contains errors, ")
 | |
|                 TEXT("or that an error occurred while trying to create a ")
 | |
|                 TEXT("directory or file.");
 | |
| 
 | |
|       case PK_MEM:  // insufficient memory
 | |
|       case PK_MEM2: // insufficient memory
 | |
|       case PK_MEM3: // insufficient memory
 | |
|       case PK_MEM4: // insufficient memory
 | |
|       case PK_MEM5: // insufficient memory
 | |
|          return TEXT("There is not enough memory to perform the operation.  ")
 | |
|                 TEXT("Try closing other running applications or adjust your ")
 | |
|                 TEXT("memory configuration.");
 | |
| 
 | |
|       case PK_NOZIP: // zipfile not found or corrupt.
 | |
|          return TEXT("The ZIP file either contains errors or could not be found.");
 | |
| 
 | |
|       case PK_PARAM: // bad or illegal parameters specified
 | |
|          break; // Not used in the Windows CE port.
 | |
| 
 | |
|       case PK_FIND: // no files found in ZIP file
 | |
|          return TEXT("The ZIP file contains errors that prevented the ")
 | |
|                 TEXT("operation from completing successfully.  A possible ")
 | |
|                 TEXT("cause is that one or more of the files listed as being ")
 | |
|                 TEXT("in the ZIP file could not actually be found within the ")
 | |
|                 TEXT("ZIP file itself.");
 | |
| 
 | |
|       case PK_DISK: // disk full or file locked
 | |
|          return TEXT("An error occurred while attempting to save a file.  ")
 | |
|                 TEXT("Possible causes are that your file storage is full or ")
 | |
|                 TEXT("read only, or that a file with the same name already ")
 | |
|                 TEXT("exists and is locked by another application.");
 | |
| 
 | |
|       case PK_EOF: // unexpected end of file
 | |
|          return TEXT("The ZIP file contains errors that prevented the ")
 | |
|                 TEXT("operation from completing successfully.  A possible ")
 | |
|                 TEXT("cause is that your ZIP file is incomplete and might be ")
 | |
|                 TEXT("truncated.");
 | |
| 
 | |
|       case IZ_UNSUP:  // no files found: all unsup. compr/encrypt.
 | |
|          return TEXT("None of the files could be processed because they were ")
 | |
|                 TEXT("all compressed using an unsupported compression or ")
 | |
|                 TEXT("encryption algorithm.");
 | |
|          
 | |
|       case IZ_BADPWD: // no files found: all had bad password.
 | |
|          return TEXT("None of the files could be processed because all the ")
 | |
|                 TEXT("password(s) specified were incorrect.");
 | |
| 
 | |
|       case PK_EXCEPTION: // exception occurred
 | |
|          return TEXT("An internal error occurred.  Possible causes are that ")
 | |
|                 TEXT("you are out of memory, you are out of file storage ")
 | |
|                 TEXT("space, the ZIP file contains unexpected errors, or there ")
 | |
|                 TEXT("is a bug in our program (that's why it's free).");
 | |
| 
 | |
|       case PK_ABORTED: // user aborted
 | |
|          return TEXT("The operation was aborted.");
 | |
|    }
 | |
| 
 | |
|    return TEXT("An unknown error occurred while processing the ZIP file.");
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void AddFileToListView(FILE_NODE *pFile) {
 | |
| 
 | |
|    // Set up our List View Item structure.
 | |
|    LV_ITEM lvi;
 | |
|    ZeroMemory(&lvi, sizeof(lvi));
 | |
|    lvi.mask    = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
 | |
|    lvi.pszText = LPSTR_TEXTCALLBACK;
 | |
|    lvi.lParam  = (LPARAM)pFile;
 | |
|    lvi.iImage  = IMAGE_GENERIC;
 | |
| 
 | |
|    // Special case Volume Labels.
 | |
|    if (pFile->dwAttributes & FILE_ATTRIBUTE_VOLUME) {
 | |
|       pFile->szType = "Volume Label";
 | |
|       lvi.iImage = IMAGE_VOLUME;
 | |
| 
 | |
|    // Special case folders.
 | |
|    } else if (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
 | |
|       pFile->szType = "Folder";
 | |
|       lvi.iImage = IMAGE_FOLDER;
 | |
| 
 | |
|    // Do a lookup on the file extension.
 | |
|    } else {
 | |
| 
 | |
|       // Locate the file portion of our path.
 | |
|       LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
 | |
| 
 | |
|       // Find the extension portion of our file.
 | |
|       LPCSTR pszExt = strrchr(pszFile, '.');
 | |
| 
 | |
|       // Search our known extension list for this extension.
 | |
|       if (pszExt && *(pszExt + 1)) {
 | |
| 
 | |
|          // Loop through our linked list
 | |
|          for (FILE_TYPE_NODE *pft = g_pftHead; pft; pft = pft->pNext) {
 | |
| 
 | |
|             // Check for a match.
 | |
|             if (!_stricmp(pszExt + 1, pft->szExtAndDesc)) {
 | |
| 
 | |
|                // We found a match, store the image and type string and exit loop.
 | |
|                lvi.iImage = pft->image;
 | |
|                pFile->szType = pft->szExtAndDesc + strlen(pft->szExtAndDesc) + 1;
 | |
|                if (!*pFile->szType) {
 | |
|                   pFile->szType = NULL;
 | |
|                }
 | |
|                break;
 | |
|             }
 | |
|          }
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Add the item to our list.
 | |
|    ListView_InsertItem(g_hWndList, &lvi);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void EnableAllMenuItems(UINT uMenuItem, BOOL fEnabled) {
 | |
| #ifdef _WIN32_WCE
 | |
|    HMENU hMenu = CommandBar_GetMenu(g_hWndCmdBar, 0);
 | |
| #else
 | |
|    HMENU hMenu = GetMenu(g_hWndMain);
 | |
| #endif
 | |
|    EnableMenuItem(hMenu, uMenuItem, fEnabled ? MF_ENABLED : MF_GRAYED);
 | |
|    SendMessage(g_hWndCmdBar, TB_ENABLEBUTTON, uMenuItem, MAKELONG(fEnabled, 0));
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void CheckAllMenuItems(UINT uMenuItem, BOOL fChecked) {
 | |
| #ifdef _WIN32_WCE
 | |
|    HMENU hMenu = CommandBar_GetMenu(g_hWndCmdBar, 0);
 | |
| #else
 | |
|    HMENU hMenu = GetMenu(g_hWndMain);
 | |
| #endif
 | |
|    CheckMenuItem(hMenu, uMenuItem, fChecked ? MF_CHECKED : MF_UNCHECKED);
 | |
|    SendMessage(g_hWndCmdBar, TB_PRESSBUTTON, uMenuItem, MAKELONG(fChecked, 0));
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void CenterWindow(HWND hWnd) {
 | |
| 
 | |
|    RECT rc, rcParent;
 | |
| 
 | |
|    // Get our window rectangle.
 | |
|    GetWindowRect(hWnd, &rc);
 | |
| 
 | |
|    // Get our parent's window rectangle.
 | |
|    GetWindowRect(GetParent(hWnd), &rcParent);
 | |
| 
 | |
|    // Center our window over our parent's window.
 | |
|    SetWindowPos(hWnd, NULL, 
 | |
|       rcParent.left + ((rcParent.right  - rcParent.left) - (rc.right  - rc.left)) / 2,
 | |
|       rcParent.top  + ((rcParent.bottom - rcParent.top ) - (rc.bottom - rc.top )) / 2,
 | |
|       0, 0, SWP_NOZORDER | SWP_NOSIZE);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void AddTextToEdit(LPCSTR szText) {
 | |
| 
 | |
|    if (!g_hWndEdit) {
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Add the characters one by one to our edit box while performing the 
 | |
|    // the following newline conversions:
 | |
|    //    Single CR -> CR/LF
 | |
|    //    Single LF -> CR/LF
 | |
|    //    CR and LF -> CR/LF
 | |
|    //    LF and CR -> CR/LF
 | |
|    //    0 - 31    -> ^char
 | |
| 
 | |
|    TCHAR szOut[256], *pszOut = szOut;
 | |
|    CHAR *pszIn = (LPSTR)szText, cPrev = '\0';
 | |
| 
 | |
|    while (*pszIn) {
 | |
| 
 | |
|       if (*pszIn == '\n') {
 | |
|          if (cPrev == '\r') {
 | |
|             cPrev = '\0';
 | |
|          } else {
 | |
|             *(pszOut++) = TEXT('\r');
 | |
|             *(pszOut++) = TEXT('\n');
 | |
|             cPrev = '\n';
 | |
|          }
 | |
| 
 | |
|       } else if (*pszIn == '\r') {
 | |
|          if (cPrev == '\n') {
 | |
|             cPrev = '\0';
 | |
|          } else {
 | |
|             *(pszOut++) = TEXT('\r');
 | |
|             *(pszOut++) = TEXT('\n');
 | |
|             cPrev = '\r';
 | |
|          }
 | |
| 
 | |
|       } else if ((*pszIn < 32) && (*pszIn != '\t')) {
 | |
|          *(pszOut++) = (TCHAR)'^';
 | |
|          *(pszOut++) = (TCHAR)(64 + *pszIn);
 | |
|          cPrev = *pszIn;
 | |
| 
 | |
|       } else {
 | |
|          *(pszOut++) = (TCHAR)*pszIn;
 | |
|          cPrev = *pszIn;
 | |
|       }
 | |
|       pszIn++;
 | |
| 
 | |
|       // If our out buffer is full, then dump it to the edit box.
 | |
|       if ((pszOut - szOut) > 253) {
 | |
|          *pszOut = TEXT('\0');
 | |
|          SendMessage(g_hWndEdit, EM_SETSEL, 65536, 65536);
 | |
|          SendMessage(g_hWndEdit, EM_REPLACESEL, FALSE, (LPARAM)szOut);
 | |
|          pszOut = szOut;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // One final flush of any partially full out buffer.
 | |
|    if (pszOut > szOut) {
 | |
|       *pszOut = TEXT('\0');
 | |
|       SendMessage(g_hWndEdit, EM_SETSEL, 65536, 65536);
 | |
|       SendMessage(g_hWndEdit, EM_REPLACESEL, FALSE, (LPARAM)szOut);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| LPTSTR FormatValue(LPTSTR szValue, DWORD dwValue) {
 | |
|    DWORD dw = 0, dwGroup[4] = { 0, 0, 0, 0 };
 | |
|    while (dwValue) {
 | |
|       dwGroup[dw++] = dwValue % 1000;
 | |
|       dwValue /= 1000;
 | |
|    }
 | |
|    switch (dw) {
 | |
|       case 2:  _stprintf(szValue, TEXT("%u,%03u"), dwGroup[1], dwGroup[0]); break;
 | |
|       case 3:  _stprintf(szValue, TEXT("%u,%03u,%03u"), dwGroup[2], dwGroup[1], dwGroup[0]); break;
 | |
|       case 4:  _stprintf(szValue, TEXT("%u,%03u,%03u,%03u"), dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]); break;
 | |
|       default: _stprintf(szValue, TEXT("%u"), dwGroup[0]);
 | |
|    }
 | |
|    return szValue;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes) {
 | |
|    // Build the attribute string according to the flags specified for this file.
 | |
|    _stprintf(szBuffer, TEXT("%s%s%s%s%s%s%s%s"),
 | |
|              (dwAttributes & FILE_ATTRIBUTE_VOLUME)    ? TEXT("V") : TEXT(""),
 | |
|              (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? TEXT("D") : TEXT(""),
 | |
|              (dwAttributes & FILE_ATTRIBUTE_READONLY)  ? TEXT("R") : TEXT(""),
 | |
|              (dwAttributes & FILE_ATTRIBUTE_ARCHIVE)   ? TEXT("A") : TEXT(""),
 | |
|              (dwAttributes & FILE_ATTRIBUTE_HIDDEN)    ? TEXT("H") : TEXT(""),
 | |
|              (dwAttributes & FILE_ATTRIBUTE_SYSTEM)    ? TEXT("S") : TEXT(""),
 | |
|              (dwAttributes & FILE_ATTRIBUTE_ENCRYPTED) ? TEXT("E") : TEXT(""),
 | |
|              (dwAttributes & FILE_ATTRIBUTE_COMMENT)   ? TEXT("C") : TEXT(""));
 | |
|    return szBuffer;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType) {
 | |
| 
 | |
|    // First check to see if we have a known description.
 | |
|    if (pFile->szType) {
 | |
|       return pFile->szType;
 | |
|    }
 | |
| 
 | |
|    // Locate the file portion of our path.
 | |
|    LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
 | |
| 
 | |
|    // Get the extension portion of the file.
 | |
|    LPCSTR pszExt = strrchr(pszFile, '.');
 | |
| 
 | |
|    // If we have an extension create a type name for this file.
 | |
|    if (pszExt && *(pszExt + 1)) {
 | |
|       strcpy(szType, pszExt + 1);
 | |
|       _strupr(szType);
 | |
|       strcat(szType, " File");
 | |
|       return szType;
 | |
|    }
 | |
|    
 | |
|    // If no extension, then use the default "File".
 | |
|    return "File";
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| LPCSTR GetFileFromPath(LPCSTR szPath) {
 | |
|    LPCSTR p1 = strrchr(szPath, '/'), p2 = strrchr(szPath, '\\');
 | |
|    if (p1 && (p1 > p2)) {
 | |
|       return p1 + 1;
 | |
|    } else if (p2) {
 | |
|       return p2 + 1;
 | |
|    }
 | |
|    return szPath;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void ForwardSlashesToBackSlashesA(LPSTR szBuffer) {
 | |
|    while (*szBuffer) {
 | |
|       if (*szBuffer == '/') {
 | |
|          *szBuffer = '\\';
 | |
|       }
 | |
|       szBuffer++;
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void ForwardSlashesToBackSlashesW(LPWSTR szBuffer) {
 | |
|    while (*szBuffer) {
 | |
|       if (*szBuffer == L'/') {
 | |
|          *szBuffer = L'\\';
 | |
|       }
 | |
|       szBuffer++;
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void DeleteDirectory(LPTSTR szPath) {
 | |
| 
 | |
|    // Make note to where the end of our path is.
 | |
|    LPTSTR szEnd = szPath + _tcslen(szPath);
 | |
| 
 | |
|    // Add our search spec to the path.
 | |
|    _tcscpy(szEnd, TEXT("\\*.*"));
 | |
| 
 | |
|    // Start a directory search.
 | |
|    WIN32_FIND_DATA w32fd;
 | |
|    HANDLE hFind = FindFirstFile(szPath, &w32fd);
 | |
| 
 | |
|    // Loop through all entries in this directory.
 | |
|    if (hFind != INVALID_HANDLE_VALUE) {
 | |
| 
 | |
|       do {
 | |
|          // Append the file/directory name to the path.
 | |
|          _tcscpy(szEnd + 1, w32fd.cFileName);
 | |
| 
 | |
|          // Check to see if this entry is a subdirectory.
 | |
|          if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
 | |
| 
 | |
|             // Ignore current directory (.) and previous directory (..)
 | |
|             if (_tcscmp(w32fd.cFileName, TEXT("."))   && 
 | |
|                 _tcscmp(w32fd.cFileName, TEXT("..")))
 | |
|             {
 | |
|                // Recurse into DeleteDirectory() to delete subdirectory.
 | |
|                DeleteDirectory(szPath);
 | |
|             }
 | |
| 
 | |
|          // Otherwise, it must be a file.
 | |
|          } else {
 | |
| 
 | |
|             // If the file is marked as read-only, then change to read/write.
 | |
|             if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
 | |
|                SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
 | |
|             }
 | |
| 
 | |
|             // Attempt to delete the file.  If we fail and the file used to be
 | |
|             // read-only, then set the read-only bit back on it.
 | |
|             if (!DeleteFile(szPath) && 
 | |
|                 (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
 | |
|             {
 | |
|                SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
 | |
|             }
 | |
|          }
 | |
| 
 | |
|       // Get the next directory entry.
 | |
|       } while (FindNextFile(hFind, &w32fd));
 | |
| 
 | |
|       // Close the directory search.
 | |
|       FindClose(hFind);
 | |
|    }
 | |
| 
 | |
|    // Remove the directory.
 | |
|    *szEnd = TEXT('\0');
 | |
|    RemoveDirectory(szPath);
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Registry Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| void RegWriteKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPCTSTR szValue) {
 | |
|    HKEY  hKey = NULL;
 | |
|    DWORD dwDisposition;
 | |
| 
 | |
|    if (RegCreateKeyEx(hKeyRoot, szSubKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) {
 | |
|       if (szValue) {
 | |
|          RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szValue, 
 | |
|                        sizeof(TCHAR) * (_tcslen(szValue) + 1));
 | |
|       }
 | |
|       RegCloseKey(hKey);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| BOOL RegReadKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPTSTR szValue, DWORD cBytes) {
 | |
|    *szValue = TEXT('\0');
 | |
|    HKEY hKey = NULL;
 | |
|    LRESULT lResult = -1;
 | |
| 
 | |
|    if (RegOpenKeyEx(hKeyRoot, szSubKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
 | |
|       lResult = RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)szValue, &cBytes);
 | |
|       RegCloseKey(hKey);
 | |
|    }
 | |
|    return ((lResult == ERROR_SUCCESS) && *szValue);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void WriteOptionString(LPCTSTR szOption, LPCTSTR szValue) {
 | |
|    HKEY hKey = NULL;
 | |
| 
 | |
|    if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
 | |
|       RegSetValueEx(hKey, szOption, 0, REG_SZ, (LPBYTE)szValue, 
 | |
|                     sizeof(TCHAR) * (_tcslen(szValue) + 1));
 | |
|       RegCloseKey(hKey);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void WriteOptionInt(LPCTSTR szOption, DWORD dwValue) {
 | |
|    HKEY hKey = NULL;
 | |
| 
 | |
|    if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
 | |
|       RegSetValueEx(hKey, szOption, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
 | |
|       RegCloseKey(hKey);
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| LPTSTR GetOptionString(LPCTSTR szOption, LPCTSTR szDefault, LPTSTR szValue, DWORD nSize) {
 | |
|    HKEY hKey = NULL;
 | |
|    LONG lResult = -1;
 | |
| 
 | |
|    if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
 | |
|       lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)szValue, &nSize);
 | |
|       RegCloseKey(hKey);
 | |
|    }
 | |
|    if (lResult != ERROR_SUCCESS) {
 | |
|       _tcscpy(szValue, szDefault);
 | |
|    }
 | |
|    return szValue;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| DWORD GetOptionInt(LPCTSTR szOption, DWORD dwDefault) {
 | |
|    HKEY  hKey = NULL;
 | |
|    LONG  lResult = -1;
 | |
|    DWORD dwValue;
 | |
|    DWORD nSize = sizeof(dwValue);
 | |
| 
 | |
|    if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
 | |
|       lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)&dwValue, &nSize);
 | |
|       RegCloseKey(hKey);
 | |
|    }
 | |
|    return (lResult == ERROR_SUCCESS) ? dwValue : dwDefault;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** EDIT Control Subclass Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| void DisableEditing(HWND hWndEdit) {
 | |
|    
 | |
|    // Make sure the control does not have ES_READONLY or ES_WANTRETURN styles.
 | |
|    DWORD dwStyle = (DWORD)GetWindowLong(hWndEdit, GWL_STYLE);
 | |
|    if (dwStyle & (ES_READONLY | ES_WANTRETURN)) {
 | |
|       SetWindowLong(hWndEdit, GWL_STYLE, dwStyle & ~(ES_READONLY | ES_WANTRETURN));
 | |
|    }
 | |
| 
 | |
|    // Subclass the control so we can intercept certain keys.
 | |
|    g_wpEdit = (WNDPROC)GetWindowLong(hWndEdit, GWL_WNDPROC);
 | |
|    SetWindowLong(hWndEdit, GWL_WNDPROC, (LONG)EditSubclassProc);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    BOOL fCtrl, fShift;
 | |
| 
 | |
|    switch (uMsg) {
 | |
|       // For cut, paste, delete, and undo, the control post itself a message.
 | |
|       // we throw away that message.  This works as a fail-safe in case we miss
 | |
|       // some keystroke that causes one of these operations.  This also disables
 | |
|       // the context menu on NT from causing one of these actions to occur.
 | |
|       case WM_CUT:
 | |
|       case WM_PASTE:
 | |
|       case WM_CLEAR:
 | |
|       case WM_UNDO:
 | |
|          MessageBeep(0);
 | |
|          return 0;
 | |
| 
 | |
|       // WM_CHAR is used for normal characters. A-Z, numbers, symbols, enter,
 | |
|       // backspace, esc, and tab. In does not include del or movement keys.
 | |
|       case WM_CHAR:
 | |
|          fCtrl  = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
 | |
| 
 | |
|          // We only allow CTRL-C (copy), plain ESC, plain TAB, plain ENTER.
 | |
|          if (( fCtrl && (wParam == 3))         ||
 | |
|              (!fCtrl && (wParam == VK_ESCAPE)) ||
 | |
|              (!fCtrl && (wParam == VK_RETURN)) ||
 | |
|              (!fCtrl && (wParam == VK_TAB)))
 | |
|          {
 | |
|             break;
 | |
|          }
 | |
|          MessageBeep(0);
 | |
|          return 0;
 | |
| 
 | |
|       // WM_KEYDOWN handles del, insert, arrows, pg up/down, home/end.
 | |
|       case WM_KEYDOWN:
 | |
|          fCtrl  = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
 | |
|          fShift = (GetKeyState(VK_SHIFT)   & 0x8000) ? TRUE : FALSE;
 | |
| 
 | |
|          // Skip all forms of DELETE, SHIFT-INSERT (paste), 
 | |
|          // CTRL-RETURN (hard-return), and CTRL-TAB (hard-tab).
 | |
|          if ((          (wParam == VK_DELETE)) || 
 | |
|              (fShift && (wParam == VK_INSERT)) ||
 | |
|              (fCtrl  && (wParam == VK_RETURN)) ||
 | |
|              (fCtrl  && (wParam == VK_TAB)))
 | |
|          {
 | |
|             MessageBeep(0);
 | |
|             return 0;
 | |
|          }
 | |
|          break;
 | |
|    }
 | |
|    return CallWindowProc(g_wpEdit, hWnd, uMsg, wParam, lParam);
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** MRU Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| int GetMenuString(HMENU hMenu, UINT uIDItem, LPTSTR lpString, int nMaxCount, 
 | |
|                   UINT uFlag) {
 | |
|    MENUITEMINFO mii;
 | |
|    ZeroMemory(&mii, sizeof(mii));
 | |
|    mii.cbSize = sizeof(mii);
 | |
|    mii.fMask = MIIM_TYPE;
 | |
|    mii.dwTypeData = lpString;
 | |
|    mii.cch = nMaxCount;
 | |
|    return (GetMenuItemInfo(hMenu, uIDItem, uFlag == MF_BYPOSITION, &mii) ?
 | |
|            mii.cch : 0);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| //******************************************************************************
 | |
| void InitializeMRU() {
 | |
|    
 | |
|    TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
 | |
|    int   i, j;
 | |
| 
 | |
|    // Get our menu handle.
 | |
| #ifdef _WIN32_WCE
 | |
|    HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
 | |
| #else
 | |
|    HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
 | |
| #endif
 | |
| 
 | |
|    // Read all our current MRUs from the registry.
 | |
|    for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
 | |
| 
 | |
|       // Build option name for current MRU and read from registry.
 | |
|       _stprintf(szOption, TEXT("MRU%d"), i+1);
 | |
|       GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
 | |
| 
 | |
|       // If this MRU exists, then add it.
 | |
|       if (szMRU[i][3]) {
 | |
| 
 | |
|          // Build the accelerator prefix for this menu item.
 | |
|          szMRU[i][0] = TEXT('&');
 | |
|          szMRU[i][1] = TEXT('1') + j;
 | |
|          szMRU[i][2] = TEXT(' ');
 | |
| 
 | |
|          // Add the item to our menu.
 | |
|          InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
 | |
|                     szMRU[i]);
 | |
| 
 | |
|          // Increment our actual MRU count.
 | |
|          j++;
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void AddFileToMRU(LPCSTR szFile) {
 | |
|    
 | |
|    TCHAR szMRU[MRU_MAX_FILE + 1][_MAX_PATH + 4], szOption[8];
 | |
|    int   i, j;
 | |
| 
 | |
|    // Store the new file in our first MRU index.
 | |
|    mbstowcs(&szMRU[0][3], szFile, _MAX_PATH);
 | |
| 
 | |
|    //---------------------------------------------------------------------------
 | |
|    // We first read the current MRU list from the registry, merge in our new
 | |
|    // file at the top, and then write back to the registry.  The registry merge
 | |
|    // is done to allow multiple instances of Pocket UnZip to maintain a global
 | |
|    // MRU list independent to this current instance's MRU list.
 | |
|    //---------------------------------------------------------------------------
 | |
| 
 | |
|    // Read all our current MRUs from the registry.
 | |
|    for (i = 1; i <= MRU_MAX_FILE; i++) {
 | |
| 
 | |
|       // Build option name for current MRU and read from registry.
 | |
|       _stprintf(szOption, TEXT("MRU%d"), i);
 | |
|       GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
 | |
|    }
 | |
| 
 | |
|    // Write our new merged MRU list back to the registry.
 | |
|    for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
 | |
| 
 | |
|       // If this MRU exists and is different then our new file, then add it.
 | |
|       if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
 | |
| 
 | |
|          // Build option name for current MRU and write to registry.
 | |
|          _stprintf(szOption, TEXT("MRU%d"), ++j);
 | |
|          WriteOptionString(szOption, &szMRU[i][3]);
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    //---------------------------------------------------------------------------
 | |
|    // The next thing we need to do is read our local MRU from our File menu,
 | |
|    // merge in our new file, and store the new list back to our File menu.
 | |
|    //---------------------------------------------------------------------------
 | |
| 
 | |
|    // Get our menu handle.
 | |
| #ifdef _WIN32_WCE
 | |
|    HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
 | |
| #else
 | |
|    HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
 | |
| #endif
 | |
| 
 | |
|    // Read all our current MRUs from our File Menu.
 | |
|    for (i = 1; i <= MRU_MAX_FILE; i++) {
 | |
| 
 | |
|       // Query our file Menu for a MRU file.
 | |
|       if (GetMenuString(hMenu, MRU_START_ID + i - 1, szMRU[i], 
 | |
|                         countof(szMRU[0]), MF_BYCOMMAND))
 | |
|       {
 | |
|          // Delete this item from the menu for now.
 | |
|          DeleteMenu(hMenu, MRU_START_ID + i - 1, MF_BYCOMMAND);
 | |
|       } else {
 | |
|          szMRU[i][3] = TEXT('\0');
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Write our new merged MRU list back to the File menu.
 | |
|    for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
 | |
| 
 | |
|       // If this MRU exists and is different then our new file, then add it.
 | |
|       if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
 | |
| 
 | |
|          // Build the accelerator prefix for this menu item.
 | |
|          szMRU[i][0] = TEXT('&');
 | |
|          szMRU[i][1] = TEXT('1') + j;
 | |
|          szMRU[i][2] = TEXT(' ');
 | |
| 
 | |
|          // Add the item to our menu.
 | |
|          InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
 | |
|                     szMRU[i]);
 | |
| 
 | |
|          // Increment our actual MRU count.
 | |
|          j++;
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void RemoveFileFromMRU(LPCTSTR szFile) {
 | |
| 
 | |
|    TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
 | |
|    int   i, j;
 | |
|    BOOL  fFound;
 | |
| 
 | |
|    //---------------------------------------------------------------------------
 | |
|    // We first look for this file in our global MRU stored in the registry.  We
 | |
|    // read the current MRU list from the registry, and then write it back while
 | |
|    // removing all occurrances of the file specified.
 | |
|    //---------------------------------------------------------------------------
 | |
| 
 | |
|    // Read all our current MRUs from the registry.
 | |
|    for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
 | |
| 
 | |
|       // Build option name for current MRU and read from registry.
 | |
|       _stprintf(szOption, TEXT("MRU%d"), i+1);
 | |
|       GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
 | |
| 
 | |
|       // Check for a match.
 | |
|       if (!_tcsicmp(szFile, &szMRU[i][3])) {
 | |
|          szMRU[i][3] = TEXT('\0');
 | |
|          fFound = TRUE;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Only write the MRU back to the registry if we found a file to remove.
 | |
|    if (fFound) {
 | |
| 
 | |
|       // Write the updated MRU list back to the registry.
 | |
|       for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
 | |
| 
 | |
|          // If this MRU still exists, then add it.
 | |
|          if (szMRU[i][3]) {
 | |
| 
 | |
|             // Build option name for current MRU and write to registry.
 | |
|             _stprintf(szOption, TEXT("MRU%d"), ++j);
 | |
|             WriteOptionString(szOption, &szMRU[i][3]);
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       // If our list got smaller, clear the unused items in the registry.
 | |
|       while (j++ < MRU_MAX_FILE) {
 | |
|          _stprintf(szOption, TEXT("MRU%d"), j);
 | |
|          WriteOptionString(szOption, TEXT(""));
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    //---------------------------------------------------------------------------
 | |
|    // We next thing we do is look for this file in our local MRU stored in our
 | |
|    // File menu.  We read the current MRU list from the menu, and then write it
 | |
|    // back while removing all occurrances of the file specified.
 | |
|    //---------------------------------------------------------------------------
 | |
| 
 | |
|    // Get our menu handle.
 | |
| #ifdef _WIN32_WCE
 | |
|    HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
 | |
| #else
 | |
|    HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
 | |
| #endif
 | |
| 
 | |
|    // Read all our current MRUs from our File Menu.
 | |
|    for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
 | |
| 
 | |
|       // Query our file Menu for a MRU file.
 | |
|       if (!GetMenuString(hMenu, MRU_START_ID + i, szMRU[i], countof(szMRU[0]),
 | |
|           MF_BYCOMMAND))
 | |
|       {
 | |
|          szMRU[i][3] = TEXT('\0');
 | |
|       }
 | |
| 
 | |
|       // Check for a match.
 | |
|       if (!_tcsicmp(szFile, &szMRU[i][3])) {
 | |
|          szMRU[i][3] = TEXT('\0');
 | |
|          fFound = TRUE;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Only update menu if we found a file to remove.
 | |
|    if (fFound) {
 | |
| 
 | |
|       // Clear out our menu's MRU list.
 | |
|       for (i = MRU_START_ID; i < (MRU_START_ID + MRU_MAX_FILE); i++) {
 | |
|          DeleteMenu(hMenu, i, MF_BYCOMMAND);
 | |
|       }
 | |
| 
 | |
|       // Write the rest of our MRU list back to the menu.
 | |
|       for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
 | |
| 
 | |
|          // If this MRU still exists, then add it.
 | |
|          if (szMRU[i][3]) {
 | |
| 
 | |
|             // Build the accelerator prefix for this menu item.
 | |
|             szMRU[i][0] = TEXT('&');
 | |
|             szMRU[i][1] = TEXT('1') + j;
 | |
|             szMRU[i][2] = TEXT(' ');
 | |
| 
 | |
|             // Add the item to our menu.
 | |
|             InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
 | |
|                        szMRU[i]);
 | |
| 
 | |
|             // Increment our actual MRU count.
 | |
|             j++;
 | |
|          }
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void ActivateMRU(UINT uIDItem) {
 | |
|    TCHAR szFile[_MAX_PATH + 4];
 | |
| 
 | |
|    // Get our menu handle.
 | |
| #ifdef _WIN32_WCE
 | |
|    HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
 | |
| #else
 | |
|    HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
 | |
| #endif
 | |
| 
 | |
|    // Query our menu for the selected MRU.
 | |
|    if (GetMenuString(hMenu, uIDItem, szFile, countof(szFile), MF_BYCOMMAND)) {
 | |
| 
 | |
|       // Move past 3 character accelerator prefix and open the file.
 | |
|       ReadZipFileList(&szFile[3]);
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Open Zip File Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| void ReadZipFileList(LPCWSTR wszPath) {
 | |
| 
 | |
|    // Show wait cursor.
 | |
|    HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
 | |
| 
 | |
|    wcstombs(g_szZipFile, wszPath, countof(g_szZipFile));
 | |
| 
 | |
|    // Update our banner to show that we are loading.
 | |
|    g_fLoading = TRUE;
 | |
|    DrawBanner(NULL);
 | |
| 
 | |
|    // Update our caption to show that we are loading.
 | |
|    SetCaptionText(TEXT("Loading"));
 | |
| 
 | |
|    // Clear our list view.
 | |
|    ListView_DeleteAllItems(g_hWndList);
 | |
| 
 | |
|    // Ghost all our Unzip related menu items.
 | |
|    EnableAllMenuItems(IDM_FILE_PROPERTIES,    FALSE);
 | |
|    EnableAllMenuItems(IDM_ACTION_EXTRACT,     FALSE);
 | |
|    EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, FALSE);
 | |
|    EnableAllMenuItems(IDM_ACTION_TEST,        FALSE);
 | |
|    EnableAllMenuItems(IDM_ACTION_TEST_ALL,    FALSE);
 | |
|    EnableAllMenuItems(IDM_ACTION_VIEW,        FALSE);
 | |
|    EnableAllMenuItems(IDM_ACTION_SELECT_ALL,  FALSE);
 | |
|    EnableAllMenuItems(IDM_VIEW_COMMENT,       FALSE);
 | |
| 
 | |
|    // Let Info-ZIP and our callbacks do the work.
 | |
|    SendMessage(g_hWndList, WM_SETREDRAW, FALSE, 0);
 | |
|    int result = DoListFiles(g_szZipFile);
 | |
|    SendMessage(g_hWndList, WM_SETREDRAW, TRUE, 0);
 | |
| 
 | |
|    // Restore/remove cursor.
 | |
|    SetCursor(hCur);
 | |
| 
 | |
|    // Update our column widths
 | |
|    ResizeColumns();
 | |
| 
 | |
|    if ((result == PK_OK) || (result == PK_WARN)) {
 | |
| 
 | |
|       // Sort the items by name.
 | |
|       Sort(0, TRUE);
 | |
| 
 | |
|       // Update this file to our MRU list and menu.
 | |
|       AddFileToMRU(g_szZipFile);
 | |
| 
 | |
|       // Enabled the comment button if the zip file has a comment.
 | |
|       if (lpUserFunctions->cchComment) {
 | |
|          EnableAllMenuItems(IDM_VIEW_COMMENT, TRUE);
 | |
|       }
 | |
| 
 | |
|       // Update other items that are related to having a Zip file loaded.
 | |
|       EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, TRUE);
 | |
|       EnableAllMenuItems(IDM_ACTION_TEST_ALL,    TRUE);
 | |
|       EnableAllMenuItems(IDM_ACTION_SELECT_ALL,  TRUE);
 | |
| 
 | |
|    } else {
 | |
| 
 | |
|       // Make sure we didn't partially load and added a few files.
 | |
|       ListView_DeleteAllItems(g_hWndList);
 | |
| 
 | |
|       // If the file itself is bad or missing, then remove it from our MRU.
 | |
|       if ((result == PK_ERR) || (result == PK_BADERR) || (result == PK_NOZIP) ||
 | |
|           (result == PK_FIND) || (result == PK_EOF))
 | |
|       {
 | |
|          RemoveFileFromMRU(wszPath);
 | |
|       }
 | |
| 
 | |
|       // Display an error.
 | |
|       TCHAR szError[_MAX_PATH + 128];
 | |
|       _stprintf(szError, TEXT("Failure loading \"%s\".\n\n"), wszPath);
 | |
|       _tcscat(szError, GetZipErrorString(result));
 | |
|       MessageBox(g_hWndMain, szError, g_szAppName, MB_OK | MB_ICONERROR);
 | |
| 
 | |
|       // Clear our file status.
 | |
|       *g_szZipFile = '\0';
 | |
|    }
 | |
| 
 | |
|    // Update our caption to show that we are done loading.
 | |
|    SetCaptionText(NULL);
 | |
| 
 | |
|    // Update our banner to show that we are done loading.
 | |
|    g_fLoading = FALSE;
 | |
|    DrawBanner(NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Zip File Properties Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| BOOL CALLBACK DlgProcProperties(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG: {
 | |
| 
 | |
|          // Add "General" and "Comments" tabs to tab control.  We are using a
 | |
|          // poor man's version of a property sheet.  We display our 2 pages
 | |
|          // by showing and hiding controls as necessary.  For our purposes,
 | |
|          // this is much easier than dealing with separate property pages.
 | |
| 
 | |
|          TC_ITEM tci;
 | |
|          tci.mask = TCIF_TEXT;
 | |
|          tci.pszText = TEXT("General");
 | |
|          TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 0, &tci);
 | |
|          tci.pszText = TEXT("Comment");
 | |
|          TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 1, &tci);
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
|          // Add "Ok" button to caption bar.
 | |
|          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | 
 | |
|                        GetWindowLong(hDlg, GWL_EXSTYLE));
 | |
| #endif
 | |
|          // Center us over our parent.
 | |
|          CenterWindow(hDlg);
 | |
| 
 | |
|          int    directory = -1, readOnly = -1, archive = -1, hidden = -1;
 | |
|          int    system = -1, encrypted = -1;
 | |
|          int    year = -1, month = -1, day = -1, hour = -1, minute = -1, pm = -1;
 | |
|          DWORD  dwSize = 0, dwCompressedSize = 0;
 | |
|          LPCSTR szPath = NULL, szMethod = NULL, szComment = NULL;
 | |
|          DWORD  dwCRC = 0, dwCount = 0, dwCommentCount = 0;
 | |
|          TCHAR  szBuffer[MAX_PATH];
 | |
| 
 | |
|          // Loop through all selected items.
 | |
|          LV_ITEM lvi;
 | |
|          ZeroMemory(&lvi, sizeof(lvi));
 | |
|          lvi.mask = LVIF_PARAM;
 | |
|          lvi.iItem = -1;
 | |
|          while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) != -1) {
 | |
| 
 | |
|             // Get the FILE_NODE for the selected item.
 | |
|             ListView_GetItem(g_hWndList, &lvi);
 | |
|             FILE_NODE *pFile = (FILE_NODE*)lvi.lParam;
 | |
| 
 | |
|             // Merge this file's attributes into our accumulative attributes.
 | |
|             MergeValues(&directory, (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
 | |
|             MergeValues(&readOnly,  (pFile->dwAttributes & FILE_ATTRIBUTE_READONLY)  != 0);
 | |
|             MergeValues(&archive,   (pFile->dwAttributes & FILE_ATTRIBUTE_ARCHIVE)   != 0);
 | |
|             MergeValues(&hidden,    (pFile->dwAttributes & FILE_ATTRIBUTE_HIDDEN)    != 0);
 | |
|             MergeValues(&system,    (pFile->dwAttributes & FILE_ATTRIBUTE_SYSTEM)    != 0);
 | |
|             MergeValues(&encrypted, (pFile->dwAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0);
 | |
| 
 | |
|             // Merge this file's date/time into our accumulative date/time.
 | |
|             int curHour = (pFile->dwModified >> 6) & 0x001F;
 | |
|             MergeValues(&year,   (pFile->dwModified >> 20) & 0x0FFF);
 | |
|             MergeValues(&month,  (pFile->dwModified >> 16) & 0x000F);
 | |
|             MergeValues(&day,    (pFile->dwModified >> 11) & 0x001F);
 | |
|             MergeValues(&hour,   (curHour % 12) ? (curHour % 12) : 12);
 | |
|             MergeValues(&minute, pFile->dwModified & 0x003F);
 | |
|             MergeValues(&pm,     curHour >= 12);
 | |
| 
 | |
|             // Store this file's name.
 | |
|             szPath = pFile->szPathAndMethod;
 | |
| 
 | |
|             // Store this file's CRC.
 | |
|             dwCRC = pFile->dwCRC;
 | |
| 
 | |
|             // Add the size and compressed size to our accumulative sizes.
 | |
|             dwSize += pFile->dwSize;
 | |
|             dwCompressedSize += pFile->dwCompressedSize;
 | |
| 
 | |
|             // Merge in our compression method.
 | |
|             LPCSTR szCurMethod = pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1;
 | |
|             if ((szMethod == NULL) || !strcmp(szMethod, szCurMethod)) {
 | |
|                szMethod = szCurMethod;
 | |
|             } else {
 | |
|                szMethod = "Multiple Methods";
 | |
|             }
 | |
| 
 | |
|             // Increment our file count.
 | |
|             dwCount++;
 | |
| 
 | |
|             // Increment our comment count if this file has a comment.
 | |
|             if (pFile->szComment) {
 | |
|                szComment = pFile->szComment;
 | |
|                dwCommentCount++;
 | |
|             }
 | |
|          };
 | |
| 
 | |
|          if (dwCount > 1) {
 | |
| 
 | |
|             // If multiple items selected, then display a selected count string
 | |
|             // in place of the file name.
 | |
|             _stprintf(szBuffer, TEXT("%u items selected."), dwCount);
 | |
|             SetDlgItemText(hDlg, IDC_FILE, szBuffer);
 | |
| 
 | |
|             // Display "Multiple" for CRC if multiple items selected.
 | |
|             SetDlgItemText(hDlg, IDC_CRC, TEXT("Multiple CRCs"));
 | |
| 
 | |
|          } else {
 | |
| 
 | |
|             // Set the file name text for the single item selected.
 | |
|             mbstowcs(szBuffer, szPath, countof(szBuffer));
 | |
|             ForwardSlashesToBackSlashesW(szBuffer);
 | |
|             SetDlgItemText(hDlg, IDC_FILE, szBuffer);
 | |
| 
 | |
|             // Set the CRC text for the single item selected.
 | |
|             _stprintf(szBuffer, TEXT("0x%08X"), dwCRC);
 | |
|             SetDlgItemText(hDlg, IDC_CRC, szBuffer);
 | |
|          }
 | |
| 
 | |
|          // Set the Size tally text.
 | |
|          FormatValue(szBuffer, dwSize);
 | |
|          _tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
 | |
|          SetDlgItemText(hDlg, IDC_FILE_SIZE, szBuffer);
 | |
| 
 | |
|          // Set the Compressed Size tally text.
 | |
|          FormatValue(szBuffer, dwCompressedSize);
 | |
|          _tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
 | |
|          SetDlgItemText(hDlg, IDC_COMPRESSED_SIZE, szBuffer);
 | |
| 
 | |
|          // Set the Compression Factor text.
 | |
|          int factor = ratio(dwSize, dwCompressedSize);
 | |
|          _stprintf(szBuffer, TEXT("%d.%d%%"), factor / 10, 
 | |
|                    ((factor < 0) ? -factor : factor) % 10);
 | |
|          SetDlgItemText(hDlg, IDC_COMPRESSON_FACTOR, szBuffer);
 | |
| 
 | |
|          // Set the Compression Method text.
 | |
|          mbstowcs(szBuffer, szMethod, countof(szBuffer));
 | |
|          SetDlgItemText(hDlg, IDC_COMPRESSION_METHOD, szBuffer);
 | |
| 
 | |
|          // Set the Attribute check boxes.
 | |
|          CheckThreeStateBox(hDlg, IDC_DIRECTORY, directory);
 | |
|          CheckThreeStateBox(hDlg, IDC_READONLY,  readOnly);
 | |
|          CheckThreeStateBox(hDlg, IDC_ARCHIVE,   archive);
 | |
|          CheckThreeStateBox(hDlg, IDC_HIDDEN,    hidden);
 | |
|          CheckThreeStateBox(hDlg, IDC_SYSTEM,    system);
 | |
|          CheckThreeStateBox(hDlg, IDC_ENCRYPTED, encrypted);
 | |
| 
 | |
|          // Build and set the Modified Date text.  The MS compiler does not
 | |
|          // consider "??/" to be a valid string.  "??/" is a trigraph that is
 | |
|          // turned into "\" by the preprocessor and causes grief for the compiler.
 | |
|          LPTSTR psz = szBuffer;
 | |
|          psz += ((month  < 0) ? _stprintf(psz, TEXT("?\?/")) : 
 | |
|                                 _stprintf(psz, TEXT("%u/"), month));
 | |
|          psz += ((day    < 0) ? _stprintf(psz, TEXT("?\?/")) :
 | |
|                                 _stprintf(psz, TEXT("%u/"), day));
 | |
|          psz += ((year   < 0) ? _stprintf(psz, TEXT("?\? ")) : 
 | |
|                                 _stprintf(psz, TEXT("%u "), year % 100));
 | |
|          psz += ((hour   < 0) ? _stprintf(psz, TEXT("?\?:")) : 
 | |
|                                 _stprintf(psz, TEXT("%u:"), hour));
 | |
|          psz += ((minute < 0) ? _stprintf(psz, TEXT("?\? ")) : 
 | |
|                                 _stprintf(psz, TEXT("%02u "), minute));
 | |
|          psz += ((pm     < 0) ? _stprintf(psz, TEXT("?M")) : 
 | |
|                                 _stprintf(psz, TEXT("%cM"), pm ? TEXT('P') : TEXT('A')));
 | |
|          SetDlgItemText(hDlg, IDC_MODIFIED, szBuffer);
 | |
| 
 | |
|          // Store a global handle to our edit control.
 | |
|          g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
 | |
| 
 | |
|          // Disable our edit box from being edited.
 | |
|          DisableEditing(g_hWndEdit);
 | |
| 
 | |
|          // Stuff the appropriate message into the Comment edit control.
 | |
|          if (dwCommentCount == 0) {
 | |
|             if (dwCount == 1) {
 | |
|                AddTextToEdit("This file does not have a comment.");
 | |
|             } else {
 | |
|                AddTextToEdit("None of the selected files have a comment.");
 | |
|             }
 | |
|          } else if (dwCount == 1) {
 | |
|             AddTextToEdit(szComment);
 | |
|          } else {
 | |
|             CHAR szTemp[64];
 | |
|             _stprintf(szBuffer, TEXT("%u of the selected files %s a comment."), 
 | |
|                       dwCommentCount, (dwCommentCount == 1)? TEXT("has") : TEXT("have"));
 | |
|             wcstombs(szTemp, szBuffer, countof(szTemp));
 | |
|             AddTextToEdit(szTemp);
 | |
|          }
 | |
|          g_hWndEdit = NULL;
 | |
| 
 | |
| 
 | |
|          // Whooh, done with WM_INITDIALOG
 | |
|          return TRUE;
 | |
|       }
 | |
| 
 | |
|       case WM_NOTIFY:
 | |
|          // Check to see if tab control was changed to new tab.
 | |
|          if (((NMHDR*)lParam)->code == TCN_SELCHANGE) {
 | |
|             HWND hWndTab     = ((NMHDR*)lParam)->hwndFrom;
 | |
|             HWND hWndComment = GetDlgItem(hDlg, IDC_COMMENT);
 | |
|             HWND hWnd        = GetWindow(hDlg, GW_CHILD);
 | |
| 
 | |
|             // If General tab selected, hide comment edit box and show all other controls.
 | |
|             if (TabCtrl_GetCurSel(hWndTab) == 0) {
 | |
|                while (hWnd) {
 | |
|                   ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd != hWndComment)) ?
 | |
|                              SW_SHOW : SW_HIDE);
 | |
|                   hWnd = GetWindow(hWnd, GW_HWNDNEXT);
 | |
|                }
 | |
| 
 | |
|             // If Comment tab selected, hide all controls except comment edit box.
 | |
|             } else {
 | |
|                while (hWnd) {
 | |
|                   ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd == hWndComment)) ?
 | |
|                              SW_SHOW : SW_HIDE);
 | |
|                   hWnd = GetWindow(hWnd, GW_HWNDNEXT);
 | |
|                }
 | |
|             }
 | |
|          }
 | |
|          return FALSE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          // Exit the dialog on OK (Enter) or CANCEL (Esc).
 | |
|          if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
 | |
|             EndDialog(hDlg, LOWORD(wParam));
 | |
|          }
 | |
|          return FALSE;
 | |
|    }
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void MergeValues(int *p1, int p2) {
 | |
|    if ((*p1 == -1) || (*p1 == p2)) {
 | |
|       *p1 = p2;
 | |
|    } else {
 | |
|       *p1 = -2;
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void CheckThreeStateBox(HWND hDlg, int nIDButton, int state) {
 | |
|    CheckDlgButton(hDlg, nIDButton, (state == 0) ? BST_UNCHECKED : 
 | |
|                                    (state == 1) ? BST_CHECKED : 
 | |
|                                                   BST_INDETERMINATE);
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Extract/Test Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| void ExtractOrTestFiles(BOOL fExtract) {
 | |
| 
 | |
|    EXTRACT_INFO ei;
 | |
|    ZeroMemory(&ei, sizeof(ei));
 | |
| 
 | |
|    // Set our Extract or Test flag.
 | |
|    ei.fExtract = fExtract;
 | |
| 
 | |
|    // Get the number of selected items and make sure we have at least one item.
 | |
|    if ((ei.dwFileCount = ListView_GetSelectedCount(g_hWndList)) <= 0) {
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // If we are not extracting/testing all, then create and buffer large enough to
 | |
|    // hold the file list for all the selected files.
 | |
|    if ((int)ei.dwFileCount != ListView_GetItemCount(g_hWndList)) {
 | |
|       ei.szFileList = new LPSTR[ei.dwFileCount + 1];
 | |
|       if (!ei.szFileList) {
 | |
|          MessageBox(g_hWndMain, GetZipErrorString(PK_MEM), g_szAppName, 
 | |
|                     MB_ICONERROR | MB_OK);
 | |
|          return;
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    ei.dwFileCount = 0;
 | |
|    ei.dwByteCount = 0;
 | |
| 
 | |
|    LV_ITEM lvi;
 | |
|    ZeroMemory(&lvi, sizeof(lvi));
 | |
|    lvi.mask = LVIF_PARAM;
 | |
|    lvi.iItem = -1;
 | |
| 
 | |
|    // Walk through all the selected files to build our counts and set our file
 | |
|    // list pointers into our FILE_NODE paths for each selected item.
 | |
|    while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) >= 0) {
 | |
|       ListView_GetItem(g_hWndList, &lvi);
 | |
|       if (ei.szFileList) {
 | |
|          ei.szFileList[ei.dwFileCount] = ((FILE_NODE*)lvi.lParam)->szPathAndMethod;
 | |
|       }
 | |
|       ei.dwFileCount++;
 | |
|       ei.dwByteCount += ((FILE_NODE*)lvi.lParam)->dwSize;
 | |
|    }
 | |
|    if (ei.szFileList) {
 | |
|       ei.szFileList[ei.dwFileCount] = NULL;
 | |
|    }
 | |
| 
 | |
|    // If we are extracting, display the extract dialog to query for parameters.
 | |
|    if (!fExtract || (DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT), g_hWndMain, 
 | |
|                                     (DLGPROC)DlgProcExtractOrTest, (LPARAM)&ei) == IDOK))
 | |
|    {
 | |
|       // Display our progress dialog and do the extraction/test.
 | |
|       DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT_PROGRESS), g_hWndMain, 
 | |
|                      (DLGPROC)DlgProcExtractProgress, (LPARAM)&ei);
 | |
|    }
 | |
| 
 | |
|    // Free our file list buffer if we created one.
 | |
|    if (ei.szFileList) {
 | |
|       delete[] ei.szFileList;
 | |
|    }
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    static EXTRACT_INFO *pei;
 | |
|    TCHAR  szPath[_MAX_PATH];
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG:
 | |
|          
 | |
|          // Store our extract information structure.
 | |
|          pei = (EXTRACT_INFO*)lParam;
 | |
| 
 | |
|          // Load our settings.
 | |
|          pei->fRestorePaths = GetOptionInt(TEXT("RestorePaths"), TRUE);
 | |
|          pei->overwriteMode = (OVERWRITE_MODE)GetOptionInt(TEXT("OverwriteMode"), OM_PROMPT);
 | |
| 
 | |
|          // Load and set our path string.
 | |
|          GetOptionString(TEXT("ExtractToDirectory"), TEXT("\\"), szPath, sizeof(szPath));
 | |
|          SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
 | |
| 
 | |
|          // Set the state of all the controls.
 | |
|          SetDlgItemText(hDlg, IDC_FILE_COUNT, FormatValue(szPath, pei->dwFileCount));
 | |
|          SetDlgItemText(hDlg, IDC_BYTE_COUNT, FormatValue(szPath, pei->dwByteCount));
 | |
|          CheckDlgButton(hDlg, IDC_RESTORE_PATHS, pei->fRestorePaths);
 | |
|          CheckDlgButton(hDlg, IDC_OVERWRITE_PROMPT, pei->overwriteMode == OM_PROMPT);
 | |
|          CheckDlgButton(hDlg, IDC_OVERWRITE_NEWER,  pei->overwriteMode == OM_NEWER);
 | |
|          CheckDlgButton(hDlg, IDC_OVERWRITE_ALWAYS, pei->overwriteMode == OM_ALWAYS);
 | |
|          CheckDlgButton(hDlg, IDC_OVERWRITE_NEVER,  pei->overwriteMode == OM_NEVER);
 | |
| 
 | |
|          // Limit our edit control to max path.
 | |
|          SendDlgItemMessage(hDlg, IDC_EXTRACT_TO, EM_LIMITTEXT, sizeof(szPath) - 1, 0);
 | |
| 
 | |
|          // Center our dialog.
 | |
|          CenterWindow(hDlg);
 | |
|          return TRUE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          switch (LOWORD(wParam)) {
 | |
| 
 | |
|             case IDOK:
 | |
| 
 | |
|                // Force us to read and validate the extract to directory.
 | |
|                SendMessage(hDlg, WM_COMMAND, MAKELONG(IDC_EXTRACT_TO, EN_KILLFOCUS), 0);
 | |
| 
 | |
|                // Get our current path string.
 | |
|                GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
 | |
| 
 | |
|                // Verify our "extract to" path is valid.
 | |
|                if (!SetExtractToDirectory(szPath)) {
 | |
|                   MessageBox(hDlg, TEXT("The directory you entered is invalid or does not exist."), 
 | |
|                              g_szAppName, MB_ICONERROR | MB_OK);
 | |
|                   SetFocus(GetDlgItem(hDlg, IDC_EXTRACT_TO));
 | |
|                   return FALSE;
 | |
|                }
 | |
| 
 | |
|                // Query other control values.
 | |
|                pei->fRestorePaths = IsDlgButtonChecked(hDlg, IDC_RESTORE_PATHS);
 | |
|                pei->overwriteMode = 
 | |
|                   IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEWER)  ? OM_NEWER  :
 | |
|                   IsDlgButtonChecked(hDlg, IDC_OVERWRITE_ALWAYS) ? OM_ALWAYS :
 | |
|                   IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEVER)  ? OM_NEVER  : OM_PROMPT;
 | |
| 
 | |
|                // Write our settings.
 | |
|                WriteOptionInt(TEXT("RestorePaths"), pei->fRestorePaths);
 | |
|                WriteOptionInt(TEXT("OverwriteMode"), pei->overwriteMode);
 | |
|                WriteOptionString(TEXT("ExtractToDirectory"), szPath);
 | |
| 
 | |
|                // Fall through to IDCANCEL
 | |
|                
 | |
|             case IDCANCEL:
 | |
|                EndDialog(hDlg, LOWORD(wParam));
 | |
|                return FALSE;
 | |
| 
 | |
|             case IDC_EXTRACT_TO:
 | |
|  
 | |
|                // Make sure the path ends in a wack (\).
 | |
|                if (HIWORD(wParam) == EN_KILLFOCUS) {
 | |
|                   GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
 | |
|                   int length = _tcslen(szPath);
 | |
|                   if ((length == 0) || szPath[length - 1] != TEXT('\\')) {
 | |
|                      szPath[length    ] = TEXT('\\');
 | |
|                      szPath[length + 1] = TEXT('\0');
 | |
|                      SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
 | |
|                   }
 | |
|                }
 | |
|                return FALSE;
 | |
|             
 | |
|             case IDC_BROWSE:
 | |
|                GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
 | |
|                if (FolderBrowser(szPath, countof(szPath))) {
 | |
|                   SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
 | |
|                }
 | |
|                return FALSE;
 | |
|          }
 | |
|          return FALSE;
 | |
|    }
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Folder Browsing Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| BOOL FolderBrowser(LPTSTR szPath, DWORD dwLength) {
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| 
 | |
|    // On Windows CE, we use a common save-as dialog to query the diretory.  We
 | |
|    // display the dialog in this function, and then we sublass it.  Our subclass
 | |
|    // functions tweaks the dialog a bit and and returns the path.
 | |
| 
 | |
|    ForwardSlashesToBackSlashesW(szPath);
 | |
| 
 | |
|    TCHAR szInitialDir[_MAX_PATH];
 | |
|    _tcscpy(szInitialDir, szPath);
 | |
| 
 | |
|    // Remove trailing wacks from path - The common dialog doesn't like them.
 | |
|    int length = _tcslen(szInitialDir);
 | |
|    while ((length > 0) && (szInitialDir[length - 1] == TEXT('\\'))) {
 | |
|       szInitialDir[--length] = TEXT('\0');
 | |
|    }
 | |
| 
 | |
|    // Set up the parameters for our save-as dialog.
 | |
|    OPENFILENAME ofn;
 | |
|    ZeroMemory(&ofn, sizeof(ofn));
 | |
|    ofn.lStructSize     = sizeof(ofn);
 | |
|    ofn.hwndOwner       = g_hWndMain;
 | |
|    ofn.hInstance       = g_hInst;
 | |
|    ofn.lpstrFilter     = TEXT(" \0!\0");
 | |
|    ofn.nFilterIndex    = 1;
 | |
|    ofn.lpstrFile       = szPath;
 | |
|    ofn.nMaxFile        = dwLength;
 | |
|    ofn.lpstrInitialDir = *szInitialDir ? szInitialDir : NULL;
 | |
|    ofn.lpstrTitle      = TEXT("Extract To");
 | |
|    ofn.Flags           = OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_NOTESTFILECREATE;
 | |
| 
 | |
|    // Post a message to our main window telling it that we are about to create
 | |
|    // a save as dialog.  Our main window will receive this message after the
 | |
|    // save as dialog is created.  This gives us a change to subclass the save as
 | |
|    // dialog.
 | |
|    PostMessage(g_hWndMain, WM_PRIVATE, MSG_SUBCLASS_DIALOG, 0);
 | |
| 
 | |
|    // Create and display the common save-as dialog.
 | |
|    if (GetSaveFileName(&ofn)) {
 | |
| 
 | |
|       // If success, then remove are special "!" filename from the end.
 | |
|       szPath[_tcslen(szPath) - 1] = TEXT('\0');
 | |
|       return TRUE;
 | |
|    }
 | |
|    return FALSE;
 | |
| 
 | |
| #else // !_WIN32_WCE
 | |
| 
 | |
|    // On Windows NT, the shell provides us with a nice folder browser dialog.
 | |
|    // We don't need to jump through any hoops to make it work like on Windows CE.
 | |
|    // The only problem is that on VC 4.0, the libraries don't export the UNICODE
 | |
|    // shell APIs because only Win95 had a shell library at the time.  The
 | |
|    // following code requires headers and libs from VC 4.2 or later.
 | |
| 
 | |
|    // Set up our BROWSEINFO structure.
 | |
|    BROWSEINFO bi;
 | |
|    ZeroMemory(&bi, sizeof(bi));
 | |
|    bi.hwndOwner = g_hWndMain;
 | |
|    bi.pszDisplayName = szPath;
 | |
|    bi.lpszTitle = TEXT("Extract To");
 | |
|    bi.ulFlags = BIF_RETURNONLYFSDIRS;
 | |
|  
 | |
|    // Prompt user for path.
 | |
|    LPITEMIDLIST piidl = SHBrowseForFolder(&bi);
 | |
|    if (!piidl) {
 | |
|       return FALSE;
 | |
|    }
 | |
| 
 | |
|    // Build path string.
 | |
|    SHGetPathFromIDList(piidl, szPath);
 | |
|  
 | |
|    // Free the PIDL returned by SHBrowseForFolder. 
 | |
|    LPMALLOC pMalloc = NULL;
 | |
|    SHGetMalloc(&pMalloc);
 | |
|    pMalloc->Free(piidl); 
 | |
|  
 | |
|    // Add trailing wack if one is not present.
 | |
|    int length = _tcslen(szPath);
 | |
|    if ((length > 0) && (szPath[length - 1] != TEXT('\\'))) {
 | |
|       szPath[length++] = TEXT('\\');
 | |
|       szPath[length]   = TEXT('\0');
 | |
|    }
 | |
| 
 | |
|    return TRUE;
 | |
| 
 | |
| #endif // _WIN32_WCE
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| #ifdef _WIN32_WCE
 | |
| BOOL CALLBACK DlgProcBrowser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    // This is our subclass of Windows CE's common save-as dialog.  We intercept
 | |
|    // the messages we care about and forward everything else to the original
 | |
|    // window procedure for the dialog.
 | |
| 
 | |
|    if (uMsg == WM_PRIVATE) { // wParam always equals MSG_INIT_DIALOG
 | |
| 
 | |
|       RECT rc1, rc2;
 | |
| 
 | |
|       // Get the window rectangle for the name edit control.
 | |
|       HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_NAME_EDIT);
 | |
|       GetWindowRect(hWnd, &rc1);
 | |
|       POINT pt1 = { rc1.left, rc1.top };
 | |
|       ScreenToClient(hDlg, &pt1);
 | |
| 
 | |
|       // Hide all the windows we don't want.
 | |
|       ShowWindow(hWnd, SW_HIDE);
 | |
|       ShowWindow(GetDlgItem(hDlg, IDC_SAVE_NAME_PROMPT), SW_HIDE);
 | |
|       ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_PROMPT), SW_HIDE);
 | |
|       ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_LIST), SW_HIDE);
 | |
| 
 | |
|       // Get the window rectangle for the file list.
 | |
|       hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
 | |
|       GetWindowRect(hWnd, &rc2);
 | |
|       POINT pt2 = { rc2.left, rc2.top };
 | |
|       ScreenToClient(hDlg, &pt2);
 | |
| 
 | |
|       // Resize the file list to fill the dialog.
 | |
|       MoveWindow(hWnd, pt2.x, pt2.y, rc2.right - rc2.left, rc1.bottom - rc2.top, TRUE);
 | |
| 
 | |
|    } else if ((uMsg == WM_COMMAND) && (LOWORD(wParam) == IDOK)) {
 | |
| 
 | |
|       // Get our file list window.
 | |
|       HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
 | |
| 
 | |
|       // Check to see if a directory is selected.
 | |
|       if (ListView_GetNextItem(hWnd, -1, LVNI_SELECTED) >= 0) {
 | |
| 
 | |
|          // If a directory is highlighted, then we post ourself a "Ok".  The "Ok"
 | |
|          // we are processing now will cause us to change into the highlighted
 | |
|          // directory, and our posted "Ok" will close the dialog in that directory.
 | |
|          PostMessage(hDlg, uMsg, wParam, lParam);
 | |
| 
 | |
|       } else {
 | |
|          // If no directory is selected, then enter the imaginary filename "!"
 | |
|          // into the name edit control and let the "Ok" end this dialog. The 
 | |
|          // result will be the correct path with a "\!" at the end.
 | |
|          SetDlgItemText(hDlg, IDC_SAVE_NAME_EDIT, TEXT("!"));
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    // Pass all messages to the base control's window proc.
 | |
|    return CallWindowProc(g_wpSaveAsDlg, hDlg, uMsg, wParam, lParam);
 | |
| }
 | |
| #endif // _WIN32_WCE
 | |
| 
 | |
| //******************************************************************************
 | |
| #ifdef _WIN32_WCE
 | |
| void SubclassSaveAsDlg() {
 | |
| 
 | |
|    // Get our cuurent thread ID so we can compare it to other thread IDs.
 | |
|    DWORD dwThreadId = GetCurrentThreadId();
 | |
| 
 | |
|    // Get the the top window in the z-order that is a child of the desktop.
 | |
|    // Dialogs are always children of the desktop on CE.  This first window
 | |
|    // should be the dialog we are looking for, but we will walk the window list
 | |
|    // just in case.
 | |
|    HWND hWnd = GetWindow(g_hWndMain, GW_HWNDFIRST);
 | |
| 
 | |
|    // Walk the window list.
 | |
|    while (hWnd) {
 | |
|    
 | |
|       // Check to see if this window was created by us and has controls from a
 | |
|       // common "save as" dialog.
 | |
|       if ((GetWindowThreadProcessId(hWnd, NULL) == dwThreadId) &&
 | |
|            GetDlgItem(hWnd, IDC_SAVE_FILE_LIST) &&
 | |
|            GetDlgItem(hWnd, IDC_SAVE_NAME_EDIT))
 | |
|       {
 | |
|          // We found our dialog.  Subclass it.
 | |
|          g_wpSaveAsDlg = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
 | |
|          SetWindowLong(hWnd, GWL_WNDPROC, (LONG)DlgProcBrowser);
 | |
| 
 | |
|          // Send our new dialog a message so it can do its initialization.
 | |
|          SendMessage(hWnd, WM_PRIVATE, MSG_INIT_DIALOG, 0);
 | |
|       }
 | |
| 
 | |
|       // Get the next window in our window list.
 | |
|       hWnd = GetWindow(hWnd, GW_HWNDNEXT);
 | |
|    }
 | |
| }
 | |
| #endif // _WIN32_WCE
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Extraction/Test/View Progress Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| BOOL CALLBACK DlgProcExtractProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    static EXTRACT_INFO *pei;
 | |
|    static BOOL fComplete;
 | |
|    static HWND hWndButton;
 | |
|    TCHAR szBuffer[32];
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG:
 | |
|          
 | |
|          // Globally store our handle so our worker thread can post to us.
 | |
|          g_hDlgProgress = hDlg;
 | |
| 
 | |
|          // Get a pointer to our extract information structure.
 | |
|          pei = (EXTRACT_INFO*)lParam;
 | |
| 
 | |
|          // Clear our complete flag.  It will be set to TRUE when done.
 | |
|          fComplete = FALSE;
 | |
| 
 | |
|          // Get and store our edit control.
 | |
|          g_hWndEdit = GetDlgItem(hDlg, IDC_LOG);
 | |
| 
 | |
|          // Disable our edit box from being edited.
 | |
|          DisableEditing(g_hWndEdit);
 | |
| 
 | |
|          // Store a static handle for our Abort/Close button.
 | |
|          hWndButton = GetDlgItem(hDlg, IDCANCEL);
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
| 
 | |
|          // Set our No-Drag style
 | |
|          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_NODRAG |GetWindowLong(hDlg, GWL_EXSTYLE));
 | |
| 
 | |
|          RECT rc1, rc2, rcEdit;
 | |
| 
 | |
|          // Get our current client size.
 | |
|          GetClientRect(hDlg, &rc1);
 | |
| 
 | |
|          // Get the window rectangle for the edit control in client coordinates.
 | |
|          GetWindowRect(g_hWndEdit, &rcEdit);
 | |
|          ScreenToClient(hDlg, ((POINT*)&rcEdit));
 | |
|          ScreenToClient(hDlg, ((POINT*)&rcEdit) + 1);
 | |
| 
 | |
|          // Resize our dialog to be full screen (same size as parent).
 | |
|          GetWindowRect(g_hWndMain, &rc2);
 | |
|          MoveWindow(hDlg, rc2.left, rc2.top, rc2.right - rc2.left, 
 | |
|                     rc2.bottom - rc2.top + 1, FALSE);
 | |
| 
 | |
|          // Get our new client size.
 | |
|          GetClientRect(hDlg, &rc2);
 | |
| 
 | |
|          // Resize our edit box to fill the client.
 | |
|          MoveWindow(g_hWndEdit, rcEdit.left, rcEdit.top, 
 | |
|                     (rcEdit.right  - rcEdit.left) + (rc2.right  - rc1.right),
 | |
|                     (rcEdit.bottom - rcEdit.top)  + (rc2.bottom - rc1.bottom),
 | |
|                     FALSE);
 | |
| 
 | |
| #else
 | |
|          // On NT, we just center our dialog over our parent.
 | |
|          CenterWindow(hDlg);
 | |
| #endif
 | |
| 
 | |
|          // Store some globals until the extract/test finishes.
 | |
|          pei->hWndEditFile       = GetDlgItem(hDlg, IDC_FILE);
 | |
|          pei->hWndProgFile       = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
 | |
|          pei->hWndProgTotal      = GetDlgItem(hDlg, IDC_TOTAL_PROGRESS);
 | |
|          pei->hWndPercentage     = GetDlgItem(hDlg, IDC_PERCENTAGE);
 | |
|          pei->hWndFilesProcessed = GetDlgItem(hDlg, IDC_FILES_PROCESSED);
 | |
|          pei->hWndBytesProcessed = GetDlgItem(hDlg, IDC_BYTES_PROCESSED);
 | |
| 
 | |
|          if (pei->fExtract) {
 | |
|             // Set our main window's caption.
 | |
|             SetCaptionText(TEXT("Extracting"));
 | |
| 
 | |
|          } else {
 | |
|             // Set our main window's caption.
 | |
|             SetCaptionText(TEXT("Testing"));
 | |
| 
 | |
|             // Hide the current file progress for test since it never moves.
 | |
|             ShowWindow(pei->hWndProgFile, SW_HIDE);
 | |
|          }
 | |
| 
 | |
|          // Set the ranges on our progress bars.
 | |
|          SendMessage(pei->hWndProgFile,  PBM_SETRANGE, 0, 
 | |
|                      MAKELPARAM(0, PROGRESS_MAX));
 | |
|          SendMessage(pei->hWndProgTotal, PBM_SETRANGE, 0, 
 | |
|                      MAKELPARAM(0, PROGRESS_MAX));
 | |
| 
 | |
|          // Set our file and byte totals.
 | |
|          SetDlgItemText(hDlg, IDC_FILES_TOTAL, 
 | |
|                         FormatValue(szBuffer, pei->dwFileCount));
 | |
|          SetDlgItemText(hDlg, IDC_BYTES_TOTAL, 
 | |
|                         FormatValue(szBuffer, pei->dwByteCount));
 | |
| 
 | |
|          // Luanch our Extract/Test thread and wait for WM_PRIVATE
 | |
|          DoExtractOrTestFiles(g_szZipFile, pei);
 | |
| 
 | |
|          return TRUE;
 | |
| 
 | |
| 
 | |
|       case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
 | |
|                        // test/extract is complete.
 | |
| 
 | |
|          // Check to see if the operation was a success
 | |
|          if ((pei->result == PK_OK) || (pei->result == PK_WARN)) {
 | |
| 
 | |
|             // Set all our fields to their "100%" settings.
 | |
|             SendMessage(pei->hWndProgFile,  PBM_SETPOS, PROGRESS_MAX, 0);
 | |
|             SendMessage(pei->hWndProgTotal, PBM_SETPOS, PROGRESS_MAX, 0);
 | |
|             SetWindowText(pei->hWndPercentage, TEXT("100%"));
 | |
|             SetDlgItemText(hDlg, IDC_FILES_PROCESSED, 
 | |
|                            FormatValue(szBuffer, pei->dwFileCount));
 | |
|             SetDlgItemText(hDlg, IDC_BYTES_PROCESSED, 
 | |
|                            FormatValue(szBuffer, pei->dwByteCount));
 | |
|          }
 | |
| 
 | |
|          // Update our status text.
 | |
|          SetWindowText(pei->hWndEditFile, 
 | |
|             (pei->result == PK_OK)      ? TEXT("Completed.  There were no warnings or errors.") :
 | |
|             (pei->result == PK_WARN)    ? TEXT("Completed.  There was one or more warnings.") :
 | |
|             (pei->result == PK_ABORTED) ? TEXT("Aborted.  There may be warnings or errors.") :
 | |
|                                           TEXT("Completed.  There was one or more errors."));
 | |
| 
 | |
|          // Clear our global edit handle.
 | |
|          g_hWndEdit = NULL;
 | |
| 
 | |
|          // Update our caption to show that we are done extracting/testing.
 | |
|          SetCaptionText(NULL);
 | |
| 
 | |
|          // Change our abort button to now read "Close".
 | |
|          SetWindowText(hWndButton, TEXT("&Close"));
 | |
|          EnableWindow(hWndButton, TRUE);
 | |
| 
 | |
|          // Display an error dialog if an error occurred.
 | |
|          if ((pei->result != PK_OK) && (pei->result != PK_WARN)) {
 | |
|             MessageBox(hDlg, GetZipErrorString(pei->result),
 | |
|                        g_szAppName, MB_ICONERROR | MB_OK);
 | |
|          }
 | |
| 
 | |
|          // We are done.  Allow the user to close the dialog.
 | |
|          fComplete = TRUE;
 | |
|          return FALSE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          switch (LOWORD(wParam)) {
 | |
|             case IDCANCEL:
 | |
|                // If abort is pressed, then set a flag that our worker thread
 | |
|                // periodically checks to decide if it needs to bail out.
 | |
|                if (!fComplete && !pei->fAbort) {
 | |
|                   pei->fAbort = TRUE;
 | |
|                   SetWindowText(hWndButton, TEXT("Aborting..."));
 | |
|                   EnableWindow(hWndButton, FALSE);
 | |
|                   return FALSE;
 | |
|                }
 | |
|                // fall through to IDOK
 | |
| 
 | |
|             case IDOK:
 | |
|                // Don't allow dialog to close until extract/test is complete.
 | |
|                if (fComplete) {
 | |
|                   g_hDlgProgress = NULL;
 | |
|                   EndDialog(hDlg, LOWORD(wParam));
 | |
|                }
 | |
|                return FALSE;
 | |
|          }
 | |
|          return FALSE;
 | |
|    }
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| BOOL CALLBACK DlgProcViewProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    static EXTRACT_INFO *pei;
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG:
 | |
|          
 | |
|          // Globally store our handle so our worker thread can post to us.
 | |
|          g_hDlgProgress = hDlg;
 | |
| 
 | |
|          // Get a pointer to our extract information structure.
 | |
|          pei = (EXTRACT_INFO*)lParam;
 | |
| 
 | |
|          // Center our dialog over our parent.
 | |
|          CenterWindow(hDlg);
 | |
| 
 | |
|          // Store some globals until the extract finishes.
 | |
|          pei->hWndProgFile = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
 | |
| 
 | |
|          // Set the ranges on our progress bar.
 | |
|          SendDlgItemMessage(hDlg, IDC_FILE_PROGRESS, PBM_SETRANGE, 0, 
 | |
|                             MAKELPARAM(0, PROGRESS_MAX));
 | |
| 
 | |
|          // Luanch our Extract thread and wait for WM_PRIVATE message.
 | |
|          DoExtractOrTestFiles(g_szZipFile, pei);
 | |
| 
 | |
|          return TRUE;
 | |
| 
 | |
|       case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
 | |
|                        // test/extract is complete.
 | |
| 
 | |
|          // We are done.  Close our dialog.  Any errors will be reported by
 | |
|          // OnActionView().
 | |
|          g_hDlgProgress = NULL;
 | |
|          EndDialog(hDlg, LOWORD(wParam));
 | |
|          return FALSE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          // If abort is pressed, then set a flag that our worker thread
 | |
|          // periodically checks to decide if it needs to bail out.
 | |
|          if ((LOWORD(wParam) == IDCANCEL) && !pei->fAbort) {
 | |
|             pei->fAbort = TRUE;
 | |
|             SetWindowText(GetDlgItem(hDlg, IDCANCEL), TEXT("Aborting..."));
 | |
|             EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
 | |
|             return FALSE;
 | |
|          }
 | |
|    }
 | |
| 
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| void UpdateProgress(EXTRACT_INFO *pei, BOOL fFull) {
 | |
| 
 | |
|    DWORD dwFile, dwTotal, dwPercentage;
 | |
|    TCHAR szBuffer[_MAX_PATH + 32];
 | |
| 
 | |
|    // Compute our file progress bar position.
 | |
|    if (pei->dwBytesTotalThisFile) {
 | |
|       dwFile = (DWORD)(((DWORDLONG)PROGRESS_MAX * 
 | |
|                         (DWORDLONG)pei->dwBytesWrittenThisFile) / 
 | |
|                         (DWORDLONG)pei->dwBytesTotalThisFile);
 | |
|    } else {
 | |
|       dwFile = PROGRESS_MAX;
 | |
|    }
 | |
| 
 | |
|    // Set our file progress indicators.
 | |
|    SendMessage(pei->hWndProgFile,  PBM_SETPOS, dwFile,  0);
 | |
| 
 | |
|    // If we are only updating our View Progress dialog, then we are done.
 | |
|    if (!pei->hWndProgTotal) {
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // Compute our total progress bar position.
 | |
|    dwTotal = (DWORD)(((DWORDLONG)PROGRESS_MAX * 
 | |
|                       (DWORDLONG)(pei->dwBytesWrittenPreviousFiles + 
 | |
|                                   pei->dwBytesWrittenThisFile + 
 | |
|                                   pei->dwFile)) / 
 | |
|                       (DWORDLONG)(pei->dwByteCount + 
 | |
|                                   pei->dwFileCount));
 | |
|    dwPercentage = dwTotal / (PROGRESS_MAX / 100);
 | |
| 
 | |
|    // Set our total progress indicators.
 | |
|    SendMessage(pei->hWndProgTotal, PBM_SETPOS, dwTotal, 0);
 | |
| 
 | |
|    // Set our total percentage text.
 | |
|    _stprintf(szBuffer, TEXT("%u%%"), dwPercentage);
 | |
|    SetWindowText(pei->hWndPercentage, szBuffer);
 | |
| 
 | |
|    // Set our current file and byte process counts.
 | |
|    FormatValue(szBuffer, pei->dwFile - 1);
 | |
|    SetWindowText(pei->hWndFilesProcessed, szBuffer);
 | |
|    FormatValue(szBuffer, pei->dwBytesWrittenPreviousFiles + 
 | |
|                pei->dwBytesWrittenThisFile);
 | |
|    SetWindowText(pei->hWndBytesProcessed, szBuffer);
 | |
| 
 | |
| 
 | |
|    if (fFull) {
 | |
| 
 | |
|       // Build our message string.
 | |
|       _stprintf(szBuffer, TEXT("%Sing: %S"), pei->fExtract ? 
 | |
|                 "Extract" : "Test", pei->szFile);
 | |
| 
 | |
|       // Change all forward slashes to back slashes in the buffer.
 | |
|       ForwardSlashesToBackSlashesW(szBuffer);
 | |
| 
 | |
|       // Update the file name in our dialog.
 | |
|       SetWindowText(pei->hWndEditFile, szBuffer);
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Replace File Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| int PromptToReplace(LPCSTR szPath) {
 | |
| 
 | |
|    // Check to see if we are extracting for view only.
 | |
|    if (g_fViewing) {
 | |
| 
 | |
|       // Build prompt.
 | |
|       TCHAR szMessage[_MAX_PATH + 128];
 | |
|       _stprintf(szMessage, 
 | |
|          TEXT("A file named \"%S\" has already been extracted for viewing.  ")
 | |
|          TEXT("That file might be opened and locked for viewing by another application.\n\n")
 | |
|          TEXT("Would you like to attempt to overwirite it with the new file?"),
 | |
|          GetFileFromPath(szPath));
 | |
|       
 | |
|       // Display prompt.
 | |
|       if (IDYES == MessageBox(g_hDlgProgress, szMessage, g_szAppName, 
 | |
|                               MB_ICONWARNING | MB_YESNO))
 | |
|       {
 | |
|          // Tell Info-ZIP to continue with extraction.
 | |
|          return IDM_REPLACE_YES;
 | |
|       }
 | |
| 
 | |
|       // Remember that the file was skipped and tell Info-ZIP to abort extraction.
 | |
|       g_fSkipped = TRUE;
 | |
|       return IDM_REPLACE_NO;
 | |
|    }
 | |
|    
 | |
|    // Otherwise, do the normal replace prompt dialog.
 | |
|    return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_REPLACE), g_hWndMain, 
 | |
|                          (DLGPROC)DlgProcReplace, (LPARAM)szPath);
 | |
| }
 | |
| 
 | |
| //******************************************************************************
 | |
| BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
|    TCHAR szMessage[_MAX_PATH + 32];
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG:
 | |
| 
 | |
|          // Play the question tone to alert the user.
 | |
|          MessageBeep(MB_ICONQUESTION);
 | |
|          
 | |
|          // Display a message with the file name.
 | |
|          _stprintf(szMessage, TEXT("\"%S\" already exists."), (LPCSTR)lParam);
 | |
| 
 | |
|          // Change all forward slashes to back slashes in the buffer.
 | |
|          ForwardSlashesToBackSlashesW(szMessage);
 | |
| 
 | |
|          // Display the file string.
 | |
|          SetDlgItemText(hDlg, IDC_FILE, szMessage);
 | |
| 
 | |
|          // Center our dialog over our parent.
 | |
|          CenterWindow(hDlg);
 | |
|          return TRUE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          switch (LOWORD(wParam)) {
 | |
| 
 | |
|             case IDCANCEL:
 | |
|             case IDOK:
 | |
|                EndDialog(hDlg, IDM_REPLACE_NO);
 | |
|                break;
 | |
| 
 | |
|             case IDM_REPLACE_ALL:
 | |
|             case IDM_REPLACE_NONE:
 | |
|             case IDM_REPLACE_YES:
 | |
|             case IDM_REPLACE_NO:
 | |
|                EndDialog(hDlg, wParam);
 | |
|                break;
 | |
|          }
 | |
|          return FALSE;
 | |
|    }
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Password Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| #if CRYPT
 | |
| 
 | |
| BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
|    
 | |
|    // Return Values:
 | |
|    //    IZ_PW_ENTERED    got some PWD string, use/try it
 | |
|    //    IZ_PW_CANCEL     no password available (for this entry)
 | |
|    //    IZ_PW_CANCELALL  no password, skip any further PWD request
 | |
|    //    IZ_PW_ERROR      failure (no mem, no tty, ...)
 | |
| 
 | |
|    static DECRYPT_INFO *pdi;
 | |
|    TCHAR szMessage[_MAX_PATH + 32];
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG:
 | |
| 
 | |
|          // Play the question tone to alert the user.
 | |
|          MessageBeep(MB_ICONQUESTION);
 | |
|          
 | |
| #ifdef _WIN32_WCE
 | |
|          // Add "Ok" button to caption bar.
 | |
|          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | 
 | |
|                        GetWindowLong(hDlg, GWL_EXSTYLE));
 | |
| #endif
 | |
| 
 | |
|          // Store our decrypt information structure.
 | |
|          pdi = (DECRYPT_INFO*)lParam;
 | |
| 
 | |
|          // Display a message with the file name.
 | |
|          _stprintf(szMessage, TEXT("\"%S\" is encrypted."), pdi->szFile);
 | |
| 
 | |
|          // Change all forward slashes to back slashes in the buffer.
 | |
|          ForwardSlashesToBackSlashesW(szMessage);
 | |
| 
 | |
|          // Display the message with the file name.
 | |
|          SetDlgItemText(hDlg, IDC_FILE, szMessage);
 | |
| 
 | |
|          // Display the appropriate prompt.
 | |
|          if (pdi->retry) {
 | |
|             _stprintf(szMessage, TEXT("Password was incorrect. Please re-enter (%d/%d)."),
 | |
|                      MAX_PASSWORD_RETRIES - pdi->retry + 2, MAX_PASSWORD_RETRIES + 1);
 | |
|             SetDlgItemText(hDlg, IDC_PROMPT, szMessage);
 | |
|          } else {
 | |
|             SetDlgItemText(hDlg, IDC_PROMPT, TEXT("Please enter the password."));
 | |
|          }
 | |
| 
 | |
|          // Limit the password to the size of the password buffer we have been given.
 | |
|          SendDlgItemMessage(hDlg, IDC_PASSWORD, EM_LIMITTEXT, pdi->nSize - 1, 0);
 | |
| 
 | |
|          // Center our dialog over our parent.
 | |
|          CenterWindow(hDlg);
 | |
|          return TRUE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          switch (LOWORD(wParam)) {
 | |
| 
 | |
|             case IDOK:
 | |
| 
 | |
|                // Store the password in our return password buffer.
 | |
|                GetDlgItemText(hDlg, IDC_PASSWORD, szMessage, countof(szMessage));
 | |
|                wcstombs(pdi->szPassword, szMessage, pdi->nSize);
 | |
|                EndDialog(hDlg, IZ_PW_ENTERED);
 | |
|                return FALSE;
 | |
| 
 | |
|             case IDCANCEL:
 | |
|                g_fSkipped = TRUE;
 | |
|                EndDialog(hDlg, IZ_PW_CANCEL);
 | |
|                return FALSE;
 | |
| 
 | |
|             case IDC_SKIP_ALL:
 | |
|                g_fSkipped = TRUE;
 | |
|                EndDialog(hDlg, IZ_PW_CANCELALL);
 | |
|                return FALSE;
 | |
|          }
 | |
|          return FALSE;
 | |
|    }
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| #endif // CRYPT
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** View Association Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    static LPTSTR szApp;
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG:
 | |
|          // Store the path buffer for our application.
 | |
|          szApp = (LPTSTR)lParam;
 | |
| 
 | |
|          // Read our default viewer from the registry.
 | |
| #ifdef _WIN32_WCE
 | |
|          GetOptionString(TEXT("FileViewer"), TEXT("\\Windows\\PWord.exe"), 
 | |
|                          szApp, sizeof(TCHAR) * _MAX_PATH);
 | |
| #else
 | |
|          GetOptionString(TEXT("FileViewer"), TEXT("notepad.exe"), 
 | |
|                          szApp, sizeof(TCHAR) * _MAX_PATH);
 | |
| #endif
 | |
| 
 | |
|          // Limit our edit control to our buffer size.
 | |
|          SendDlgItemMessage(hDlg, IDC_PATH, EM_LIMITTEXT, _MAX_PATH - 1, 0);
 | |
| 
 | |
|          // Set our path string in our dialog.
 | |
|          SetDlgItemText(hDlg, IDC_PATH, szApp);
 | |
| 
 | |
|          // Center our dialog over our parent.
 | |
|          CenterWindow(hDlg);
 | |
|          return TRUE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          switch (LOWORD(wParam)) {
 | |
| 
 | |
|             case IDOK:
 | |
|                // Get the text currently in the path edit box and store it.
 | |
|                GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
 | |
|                WriteOptionString(TEXT("FileViewer"), szApp);
 | |
|                // Fall through
 | |
| 
 | |
|             case IDCANCEL:
 | |
|                EndDialog(hDlg, LOWORD(wParam));
 | |
|                break;
 | |
| 
 | |
|             case IDC_BROWSE:
 | |
|                // Get the text currently in the path edit box.
 | |
|                GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
 | |
| 
 | |
|                // Get the direcory from the path text.
 | |
|                ForwardSlashesToBackSlashesW(szApp);
 | |
|                TCHAR szInitialDir[_MAX_PATH], *szFile;
 | |
|                _tcscpy(szInitialDir, szApp);
 | |
|                if (szFile = _tcsrchr(szInitialDir, TEXT('\\'))) {
 | |
|                   *szFile = TEXT('\0');
 | |
|                }
 | |
| 
 | |
|                // Prepare to display browse dialog.
 | |
|                OPENFILENAME ofn;
 | |
|                ZeroMemory(&ofn, sizeof(ofn));
 | |
|                ofn.lStructSize     = sizeof(ofn);
 | |
|                ofn.hwndOwner       = hDlg;
 | |
|                ofn.hInstance       = g_hInst;
 | |
|                ofn.lpstrFilter     = TEXT("Programs (*.exe)\0*.exe\0All Files (*.*)\0*.*\0");
 | |
|                ofn.nFilterIndex    = 1;
 | |
|                ofn.lpstrFile       = szApp;
 | |
|                ofn.nMaxFile        = _MAX_PATH;
 | |
|                ofn.lpstrInitialDir = szInitialDir;
 | |
|                ofn.lpstrTitle      = TEXT("Open With...");
 | |
|                ofn.Flags           = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
 | |
|                ofn.lpstrDefExt     = TEXT("exe");
 | |
| 
 | |
|                // Display the browse dialog and update our path edit box if neccessary.
 | |
|                if (GetOpenFileName(&ofn)) {
 | |
|                   SetDlgItemText(hDlg, IDC_PATH, szApp);
 | |
|                }
 | |
|                break;
 | |
|          }
 | |
|          return FALSE;
 | |
|    }
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** Comment Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
|    RECT    rc;
 | |
|    HCURSOR hCur;
 | |
|    int     result;
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG:
 | |
|          // Get the handle to our edit box and store it globally.
 | |
|          g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
 | |
| 
 | |
|          // Disable our edit box from being edited.
 | |
|          DisableEditing(g_hWndEdit);
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
|          // Add "Ok" button to caption bar and make window No-Drag.
 | |
|          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | WS_EX_NODRAG |
 | |
|                        GetWindowLong(hDlg, GWL_EXSTYLE));
 | |
| 
 | |
|          // On CE, we resize our dialog to be full screen (same size as parent).
 | |
|          GetWindowRect(g_hWndMain, &rc);
 | |
|          MoveWindow(hDlg, rc.left, rc.top, rc.right - rc.left, 
 | |
|                     rc.bottom - rc.top + 1, FALSE);
 | |
| #else
 | |
|          // On NT we just center the dialog.
 | |
|          CenterWindow(hDlg);
 | |
| #endif
 | |
| 
 | |
|          // Set our edit control to be the full size of our dialog.
 | |
|          GetClientRect(hDlg, &rc);
 | |
|          MoveWindow(g_hWndEdit, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
 | |
| 
 | |
|          // Show hour glass cursor while processing comment.
 | |
|          hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
 | |
| 
 | |
|          // Let Info-ZIP and our callbacks do the work.
 | |
|          result = DoGetComment(g_szZipFile);
 | |
| 
 | |
|          // Restore/remove our cursor.
 | |
|          SetCursor(hCur);
 | |
| 
 | |
|          // Display an error dialog if an error occurred.
 | |
|          if ((result != PK_OK) && (result != PK_WARN)) {
 | |
|             MessageBox(g_hWndMain, GetZipErrorString(result), g_szAppName,
 | |
|                        MB_ICONERROR | MB_OK);
 | |
|          }
 | |
| 
 | |
|          // Clear our global edit box handle as we are done with it.
 | |
|          g_hWndEdit = NULL;
 | |
| 
 | |
|          // Return FALSE to prevent edit box from gaining focus and showing highlight.
 | |
|          return FALSE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
 | |
|             EndDialog(hDlg, LOWORD(wParam));
 | |
|          }
 | |
|          return FALSE;
 | |
|    }
 | |
|    return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| //******************************************************************************
 | |
| //***** About Dialog Functions
 | |
| //******************************************************************************
 | |
| 
 | |
| BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | |
| 
 | |
|    switch (uMsg) {
 | |
| 
 | |
|       case WM_INITDIALOG:
 | |
| 
 | |
| #ifdef _WIN32_WCE
 | |
|          // Add "Ok" button to caption bar.
 | |
|          SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | 
 | |
|                        GetWindowLong(hDlg, GWL_EXSTYLE));
 | |
| #endif
 | |
| 
 | |
|          // Fill in a few static members.
 | |
|          TCHAR szBuffer[80];
 | |
|          SetDlgItemText(hDlg, IDC_PRODUCT, TEXT(VER_PRODUCT_STR));
 | |
|          _stprintf(szBuffer, TEXT("Freeware Version %S"), VER_FULLVERSION_STR);
 | |
|          SetDlgItemText(hDlg, IDC_VERSION, szBuffer);
 | |
|          _stprintf(szBuffer, TEXT("Developed by %S"), VER_DEVELOPER_STR);
 | |
|          SetDlgItemText(hDlg, IDC_DEVELOPER, szBuffer);
 | |
|          SetDlgItemText(hDlg, IDC_COPYRIGHT, TEXT(VER_COPYRIGHT_STR));
 | |
|          SetDlgItemText(hDlg, IDC_COMMENT, TEXT(VER_COMMENT_STR));
 | |
| 
 | |
|          // Center the dialog over our parent.
 | |
|          CenterWindow(hDlg);
 | |
|          return TRUE;
 | |
| 
 | |
|       case WM_COMMAND:
 | |
|          if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
 | |
|             EndDialog(hDlg, 0);
 | |
|          }
 | |
|          return FALSE;
 | |
|    }
 | |
|    return FALSE;
 | |
| }
 |