~ubuntu-branches/ubuntu/precise/unzip/precise-proposed

« back to all changes in this revision

Viewing changes to wince/winmain.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2004-06-06 17:57:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040606175746-nl7p2dgp3aobyc2c
Tags: upstream-5.51
ImportĀ upstreamĀ versionĀ 5.51

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 1990-2003 Info-ZIP.  All rights reserved.
 
3
 
 
4
  See the accompanying file LICENSE, version 2000-Apr-09 or later
 
5
  (the contents of which are also included in unzip.h) for terms of use.
 
6
  If, for some reason, all these files are missing, the Info-ZIP license
 
7
  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
 
8
*/
 
9
//******************************************************************************
 
10
//
 
11
// File:        WINMAIN.CPP
 
12
//
 
13
// Description: This module contains all the Windows specific code for Pocket
 
14
//              UnZip.  It contains the entire user interface.  This code knows
 
15
//              almost nothing about the Info-ZIP code.  All Info-ZIP related
 
16
//              functions are wrapped by helper functions in INTRFACE.CPP.  The
 
17
//              code in this module only calls those wrapper functions and
 
18
//              INTRFACE.CPP handles all the details and callbacks of the
 
19
//              Info-ZIP code.
 
20
//
 
21
// Copyright:   All the source files for Pocket UnZip, except for components
 
22
//              written by the Info-ZIP group, are copyrighted 1997 by Steve P.
 
23
//              Miller.  The product "Pocket UnZip" itself is property of the
 
24
//              author and cannot be altered in any way without written consent
 
25
//              from Steve P. Miller.
 
26
//
 
27
// Disclaimer:  All project files are provided "as is" with no guarantee of
 
28
//              their correctness.  The authors are not liable for any outcome
 
29
//              that is the result of using this source.  The source for Pocket
 
30
//              UnZip has been placed in the public domain to help provide an
 
31
//              understanding of its implementation.  You are hereby granted
 
32
//              full permission to use this source in any way you wish, except
 
33
//              to alter Pocket UnZip itself.  For comments, suggestions, and
 
34
//              bug reports, please write to stevemil@pobox.com.
 
35
//
 
36
// Functions:   WinMain
 
37
//              InitializeApplication
 
38
//              ShutdownApplication
 
39
//              RegisterUnzip
 
40
//              BuildImageList
 
41
//              WndProc
 
42
//              OnCreate
 
43
//              OnFileOpen
 
44
//              OnActionView
 
45
//              OnActionSelectAll
 
46
//              OnViewExpandedView
 
47
//              OnHelp
 
48
//              OnGetDispInfo
 
49
//              OnDeleteItem
 
50
//              OnItemChanged
 
51
//              Sort
 
52
//              CompareFunc
 
53
//              SetCaptionText
 
54
//              DrawBanner
 
55
//              AddDeleteColumns
 
56
//              ResizeColumns
 
57
//              GetZipErrorString
 
58
//              AddFileToListView
 
59
//              EnableAllMenuItems
 
60
//              CheckAllMenuItems
 
61
//              CenterWindow
 
62
//              AddTextToEdit
 
63
//              FormatValue
 
64
//              BuildAttributesString
 
65
//              BuildTypeString
 
66
//              GetFileFromPath
 
67
//              ForwardSlashesToBackSlashesA
 
68
//              ForwardSlashesToBackSlashesW
 
69
//              DeleteDirectory(LPTSTR szPath);
 
70
//              RegWriteKey
 
71
//              RegReadKey
 
72
//              WriteOptionString
 
73
//              WriteOptionInt
 
74
//              GetOptionString
 
75
//              GetOptionInt
 
76
//              DisableEditing
 
77
//              EditSubclassProc
 
78
//              GetMenuString
 
79
//              InitializeMRU
 
80
//              AddFileToMRU
 
81
//              RemoveFileFromMRU
 
82
//              ActivateMRU
 
83
//              ReadZipFileList
 
84
//              DlgProcProperties
 
85
//              MergeValues
 
86
//              CheckThreeStateBox
 
87
//              ExtractOrTestFiles
 
88
//              DlgProcExtractOrTest
 
89
//              FolderBrowser
 
90
//              DlgProcBrowser
 
91
//              SubclassSaveAsDlg
 
92
//              DlgProcExtractProgress
 
93
//              DlgProcViewProgress
 
94
//              UpdateProgress
 
95
//              PromptToReplace
 
96
//              DlgProcReplace
 
97
//              DlgProcPassword
 
98
//              DlgProcViewAssociation
 
99
//              DlgProcComment
 
100
//              DlgProcAbout
 
101
//
 
102
//
 
103
// Date      Name          History
 
104
// --------  ------------  -----------------------------------------------------
 
105
// 02/01/97  Steve Miller  Created (Version 1.0 using Info-ZIP UnZip 5.30)
 
106
//
 
107
//******************************************************************************
 
108
 
 
109
extern "C" {
 
110
#define __WINMAIN_CPP__
 
111
#define UNZIP_INTERNAL
 
112
 
 
113
#include "unzip.h"
 
114
 
 
115
#include "crypt.h"     // Needed to pick up CRYPT define setting and return values.
 
116
 
 
117
#include "unzvers.h"   // Only needed by consts.h (VERSION_DATE & VersionDate)
 
118
#include "consts.h"    // Only include once - defines constant string messages.
 
119
 
 
120
#include <commctrl.h>  // Common controls - mainly ListView and ImageList
 
121
#include <commdlg.h>   // Common dialogs - OpenFile dialog
 
122
 
 
123
#ifndef _WIN32_WCE
 
124
#include <shlobj.h>    // On NT, we use the SHBrowseForFolder() stuff.
 
125
#include <shellapi.h>  // CommandLineToArgvW() and ExtractIconEx()
 
126
#endif
 
127
 
 
128
#include "intrface.h"  // Interface between Info-ZIP and us
 
129
#include "winmain.h"   // Us
 
130
}
 
131
#include <tchar.h>     // Must be outside of extern "C" block
 
132
 
 
133
 
 
134
//******************************************************************************
 
135
//***** "Local" Global Variables
 
136
//******************************************************************************
 
137
 
 
138
static LPCTSTR         g_szAppName     = TEXT("Pocket UnZip");
 
139
static LPCTSTR         g_szClass       = TEXT("PocketUnZip");
 
140
static LPCTSTR         g_szRegKey      = TEXT("Software\\Pocket UnZip");
 
141
static LPCTSTR         g_szTempDir     = NULL;
 
142
static HWND            g_hWndList      = NULL;
 
143
static HWND            g_hWndCmdBar    = NULL;
 
144
static int             g_cyCmdBar      = 0;
 
145
static HFONT           g_hFontBanner   = NULL;
 
146
static HICON           g_hIconMain     = NULL;
 
147
static WNDPROC         g_wpSaveAsDlg   = NULL;
 
148
static WNDPROC         g_wpEdit        = NULL;
 
149
static int             g_sortColumn    = -1;
 
150
static BOOL            g_fExpandedView = FALSE;
 
151
static BOOL            g_fLoading      = FALSE;
 
152
static BOOL            g_fSkipped      = FALSE;
 
153
static BOOL            g_fViewing      = FALSE;
 
154
static HWND            g_hWndWaitFor   = NULL;
 
155
static FILE_TYPE_NODE *g_pftHead       = NULL;
 
156
 
 
157
#ifdef _WIN32_WCE
 
158
static LPCTSTR         g_szHelpFile    = TEXT("\\windows\\punzip.htp");
 
159
#else
 
160
static TCHAR           g_szTempDirPath[_MAX_PATH];
 
161
static LPCTSTR         g_szHelpFile    = TEXT("punzip.html");
 
162
#endif
 
163
 
 
164
static COLUMN g_columns[] = {
 
165
   { TEXT("Name"),       LVCFMT_LEFT  },
 
166
   { TEXT("Size"),       LVCFMT_RIGHT },
 
167
   { TEXT("Type"),       LVCFMT_LEFT  },
 
168
   { TEXT("Modified"),   LVCFMT_LEFT  },
 
169
   { TEXT("Attributes"), LVCFMT_LEFT  },
 
170
   { TEXT("Compressed"), LVCFMT_RIGHT },
 
171
   { TEXT("Ratio"),      LVCFMT_RIGHT },
 
172
   { TEXT("Method"),     LVCFMT_LEFT  },
 
173
   { TEXT("CRC"),        LVCFMT_LEFT  },
 
174
   { TEXT("Comment"),    LVCFMT_LEFT  }
 
175
};
 
176
 
 
177
 
 
178
//******************************************************************************
 
179
//***** Local Function Prototypes
 
180
//******************************************************************************
 
181
 
 
182
// Startup and Shutdown Functions
 
183
void InitializeApplication(LPCTSTR szZipFile);
 
184
void ShutdownApplication();
 
185
void RegisterUnzip();
 
186
void BuildImageList();
 
187
 
 
188
// Our Main Window's Message Handler
 
189
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
190
 
 
191
// Event Handlers for our Main Window
 
192
int OnCreate();
 
193
void OnFileOpen();
 
194
void OnActionView();
 
195
void OnActionSelectAll();
 
196
void OnViewExpandedView();
 
197
void OnHelp();
 
198
 
 
199
// Event Handlers for our List View
 
200
void OnGetDispInfo(LV_DISPINFO *plvdi);
 
201
void OnDeleteItem(NM_LISTVIEW *pnmlv);
 
202
void OnItemChanged(NM_LISTVIEW *pnmlv);
 
203
 
 
204
// List View Sort Functions
 
205
void Sort(int sortColumn, BOOL fForce);
 
206
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM sortColumn);
 
207
 
 
208
// Helper/Utility Functions
 
209
void SetCaptionText(LPCTSTR szPrefix);
 
210
void DrawBanner(HDC hdc);
 
211
void AddDeleteColumns();
 
212
void ResizeColumns();
 
213
LPCTSTR GetZipErrorString(int error);
 
214
void AddFileToListView(FILE_NODE *pFile);
 
215
void EnableAllMenuItems(UINT uMenuItem, BOOL fEnabled);
 
216
void CheckAllMenuItems(UINT uMenuItem, BOOL fChecked);
 
217
void CenterWindow(HWND hWnd);
 
218
void AddTextToEdit(LPCSTR szText);
 
219
LPTSTR FormatValue(LPTSTR szValue, DWORD dwValue);
 
220
LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes);
 
221
LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType);
 
222
LPCSTR GetFileFromPath(LPCSTR szPath);
 
223
void ForwardSlashesToBackSlashesA(LPSTR szBuffer);
 
224
#ifdef UNICODE
 
225
   void ForwardSlashesToBackSlashesW(LPWSTR szBuffer);
 
226
#  define ForwardSlashesToBackSlashes ForwardSlashesToBackSlashesW
 
227
#else
 
228
#  define ForwardSlashesToBackSlashes ForwardSlashesToBackSlashesA
 
229
#endif
 
230
void DeleteDirectory(LPTSTR szPath);
 
231
 
 
232
// Registry Functions
 
233
void RegWriteKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPCTSTR szValue);
 
234
BOOL RegReadKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPTSTR szValue, DWORD cBytes);
 
235
void WriteOptionString(LPCTSTR szOption, LPCTSTR szValue);
 
236
void WriteOptionInt(LPCTSTR szOption, DWORD dwValue);
 
237
LPTSTR GetOptionString(LPCTSTR szOption, LPCTSTR szDefault, LPTSTR szValue, DWORD nSize);
 
238
DWORD GetOptionInt(LPCTSTR szOption, DWORD dwDefault);
 
239
 
 
240
// EDIT Control Subclass Functions
 
241
void DisableEditing(HWND hWndEdit);
 
242
LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
243
 
 
244
// MRU Functions
 
245
void InitializeMRU();
 
246
void AddFileToMRU(LPCSTR szFile);
 
247
void RemoveFileFromMRU(LPCTSTR szFile);
 
248
void ActivateMRU(UINT uIDItem);
 
249
 
 
250
// Open Zip File Functions
 
251
void ReadZipFileList(LPCTSTR wszPath);
 
252
 
 
253
// Zip File Properties Dialog Functions
 
254
BOOL CALLBACK DlgProcProperties(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
255
void MergeValues(int *p1, int p2);
 
256
void CheckThreeStateBox(HWND hDlg, int nIDButton, int state);
 
257
 
 
258
// Extract/Test Dialog Functions
 
259
void ExtractOrTestFiles(BOOL fExtract);
 
260
BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
261
 
 
262
// Folder Browsing Dialog Functions
 
263
BOOL FolderBrowser(LPTSTR szPath, DWORD dwLength);
 
264
BOOL CALLBACK DlgProcBrowser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
265
void SubclassSaveAsDlg();
 
266
 
 
267
// Extraction/Test/View Progress Dialog Functions
 
268
BOOL CALLBACK DlgProcExtractProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
269
BOOL CALLBACK DlgProcViewProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
270
void UpdateProgress(EXTRACT_INFO *pei, BOOL fFull);
 
271
 
 
272
// Replace File Dialog Functions
 
273
int PromptToReplace(LPCSTR szPath);
 
274
BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
275
 
 
276
// Password Dialog Functions
 
277
BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
278
 
 
279
// View Association Dialog Functions
 
280
BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
281
 
 
282
// Comment Dialog Functions
 
283
BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
284
 
 
285
// About Dialog Functions
 
286
BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
287
 
 
288
 
 
289
//******************************************************************************
 
290
//***** WinMain - Our one and only entry point
 
291
//******************************************************************************
 
292
 
 
293
// Entrypoint is a tiny bit different on Windows CE - UNICODE command line.
 
294
#ifdef _WIN32_WCE
 
295
extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 
296
                              LPTSTR lpCmdLine, int nCmdShow)
 
297
#else
 
298
extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 
299
                              LPSTR lpCmdLine, int nCmdShow)
 
300
#endif
 
301
{
 
302
   // Wrap the whole ball of wax in a big exception handler.
 
303
   __try {
 
304
 
 
305
      // Store global instance handle.
 
306
      g_hInst = hInstance;
 
307
 
 
308
      // Create our banner font.  We need to do this before creating our window.
 
309
      // This font handle will be deleted in ShutdownApplication().
 
310
      LOGFONT lf;
 
311
      ZeroMemory(&lf, sizeof(lf));
 
312
      lf.lfHeight = 16;
 
313
      lf.lfWeight = FW_BOLD;
 
314
      lf.lfCharSet = ANSI_CHARSET;
 
315
      lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
 
316
      lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
 
317
      lf.lfQuality = DEFAULT_QUALITY;
 
318
      lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
 
319
      _tcscpy(lf.lfFaceName, TEXT("MS Sans Serif"));
 
320
      g_hFontBanner = CreateFontIndirect(&lf);
 
321
 
 
322
      // Define the window class for our application's main window.
 
323
      WNDCLASS wc;
 
324
      ZeroMemory(&wc, sizeof(wc));
 
325
      wc.lpszClassName = g_szClass;
 
326
      wc.hInstance     = hInstance;
 
327
      wc.lpfnWndProc   = WndProc;
 
328
      wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 
329
 
 
330
      TCHAR *szZipPath = NULL;
 
331
 
 
332
#ifdef _WIN32_WCE
 
333
 
 
334
      // Get our main window's small icon.  On Windows CE, we need to send ourself
 
335
      // a WM_SETICON in order for our task bar to update itself.
 
336
      g_hIconMain = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_UNZIP),
 
337
                                     IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
 
338
      wc.hIcon = g_hIconMain;
 
339
 
 
340
      // On Windows CE, we only need the WS_VISIBLE flag.
 
341
      DWORD dwStyle = WS_VISIBLE;
 
342
 
 
343
      // Get and store command line file (if any).
 
344
      if (lpCmdLine && *lpCmdLine) {
 
345
         szZipPath = lpCmdLine;
 
346
      }
 
347
 
 
348
#else
 
349
 
 
350
      // On NT we add a cursor, icon, and menu to our application's window class.
 
351
      wc.hCursor      = LoadCursor(NULL, IDC_ARROW);
 
352
      wc.hIcon        = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_UNZIP));
 
353
      wc.lpszMenuName = MAKEINTRESOURCE(IDR_UNZIP);
 
354
 
 
355
      // On Windows NT, we use the standard overlapped window style.
 
356
      DWORD dwStyle = WS_OVERLAPPEDWINDOW;
 
357
 
 
358
      TCHAR szBuffer[_MAX_PATH];
 
359
 
 
360
      // Get and store command line file (if any).
 
361
      if (lpCmdLine && *lpCmdLine) {
 
362
         MBSTOTSTR(szBuffer, lpCmdLine, countof(szBuffer));
 
363
         szZipPath = szBuffer;
 
364
      }
 
365
 
 
366
#endif
 
367
 
 
368
      // Register our window class with the OS.
 
369
      if (!RegisterClass(&wc)) {
 
370
         DebugOut(TEXT("RegisterClass() failed [%u]"), GetLastError());
 
371
      }
 
372
 
 
373
      // Create our main window using our registered window class.
 
374
      g_hWndMain = CreateWindow(wc.lpszClassName, g_szAppName, dwStyle,
 
375
                                CW_USEDEFAULT, CW_USEDEFAULT,
 
376
                                CW_USEDEFAULT, CW_USEDEFAULT,
 
377
                                NULL, NULL, hInstance, NULL);
 
378
 
 
379
      // Quit now if we failed to create our main window.
 
380
      if (!g_hWndMain) {
 
381
         DebugOut(TEXT("CreateWindow() failed [%u]"), GetLastError());
 
382
         ShutdownApplication();
 
383
         return 0;
 
384
      }
 
385
 
 
386
      // Make sure our window is visible.  Really only needed for NT.
 
387
      ShowWindow(g_hWndMain, nCmdShow);
 
388
 
 
389
      // Load our keyboard accelerator shortcuts.
 
390
      MSG    msg;
 
391
      HACCEL hAccel = LoadAccelerators(g_hInst, MAKEINTRESOURCE(IDR_UNZIP));
 
392
      DWORD  dwPaintFlags = 0;
 
393
 
 
394
      // The message pump.  Loop until we get a WM_QUIT message.
 
395
      while (GetMessage(&msg, NULL, 0, 0)) {
 
396
 
 
397
         // Check to see if this is an accelerator and handle it if neccessary.
 
398
         if (!TranslateAccelerator(g_hWndMain, hAccel, &msg)) {
 
399
 
 
400
            // If a normal message, then dispatch it to the correct window.
 
401
            TranslateMessage(&msg);
 
402
            DispatchMessage(&msg);
 
403
 
 
404
            // Wait until our application is up and visible before trying to
 
405
            // initialize some of our structures and load any command line file.
 
406
            if ((msg.message == WM_PAINT) && (dwPaintFlags != 0x11)) {
 
407
               if (msg.hwnd == g_hWndWaitFor) {
 
408
                  dwPaintFlags |= 0x01;
 
409
               } else if (msg.hwnd == g_hWndList) {
 
410
                  dwPaintFlags |= 0x10;
 
411
               }
 
412
               if (dwPaintFlags == 0x11) {
 
413
                  InitializeApplication((szZipPath && *szZipPath) ?
 
414
                                        szZipPath : NULL);
 
415
               }
 
416
            }
 
417
         }
 
418
      }
 
419
 
 
420
      // Clean up code.
 
421
      ShutdownApplication();
 
422
 
 
423
      // Nice clean finish - were out of here.
 
424
      return msg.wParam;
 
425
 
 
426
 
 
427
   } __except(EXCEPTION_EXECUTE_HANDLER) {
 
428
 
 
429
      // Something very bad happened.  Try our best to appear somewhat graceful.
 
430
      MessageBox(NULL,
 
431
         TEXT("An internal error occurred.  Possible causes are that you are ")
 
432
         TEXT("out of memory, a ZIP file (if one is loaded) contains an ")
 
433
         TEXT("unexpected error, or there is a bug in our program (that's why ")
 
434
         TEXT("it's free).  Pocket UnZip cannot continue.  It will exit now, ")
 
435
         TEXT("but you may restart it and try again.\n\n")
 
436
         TEXT("If the problem persists, please write to stevemil@pobox.com with ")
 
437
         TEXT("any information that might help track down the problem."),
 
438
         g_szAppName, MB_ICONERROR | MB_OK);
 
439
   }
 
440
 
 
441
   return 1;
 
442
}
 
443
 
 
444
 
 
445
//******************************************************************************
 
446
//***** Startup and Shutdown Functions
 
447
//******************************************************************************
 
448
 
 
449
void InitializeApplication(LPCTSTR szZipFile) {
 
450
 
 
451
   // This function is called after our class is registered and all our windows
 
452
   // are created and visible to the user.
 
453
 
 
454
   // Show hour glass cursor.
 
455
   HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
 
456
 
 
457
   // Register UnZip in the registry to handle ".ZIP" files.
 
458
   RegisterUnzip();
 
459
 
 
460
   // Enumerate the system file assoications and build an image list.
 
461
   BuildImageList();
 
462
 
 
463
   // Load our initial MRU into our menu.
 
464
   InitializeMRU();
 
465
 
 
466
   // Restore/remove our cursor.
 
467
   SetCursor(hCur);
 
468
 
 
469
   // Clear our initialization window handle.
 
470
   g_hWndWaitFor = NULL;
 
471
 
 
472
   // Load our command line file if one was specified. Otherwise, just update
 
473
   // our banner to show that no file is loaded.
 
474
   if (szZipFile) {
 
475
      ReadZipFileList(szZipFile);
 
476
   } else {
 
477
      DrawBanner(NULL);
 
478
   }
 
479
 
 
480
   // Enable some controls.
 
481
   EnableAllMenuItems(IDM_FILE_OPEN,          TRUE);
 
482
   EnableAllMenuItems(IDM_FILE_CLOSE,         TRUE);
 
483
   EnableAllMenuItems(IDM_VIEW_EXPANDED_VIEW, TRUE);
 
484
   EnableAllMenuItems(IDM_HELP_ABOUT,         TRUE);
 
485
 
 
486
   // Set our temporary directory.
 
487
#ifdef _WIN32_WCE
 
488
   g_szTempDir = TEXT("\\Temporary Pocket UnZip Files");
 
489
#else
 
490
   g_szTempDir = TEXT("C:\\Temporary Pocket UnZip Files");
 
491
 
 
492
   // Set the drive to be the same drive as the OS installation is on.
 
493
   if (GetWindowsDirectory(g_szTempDirPath, countof(g_szTempDirPath))) {
 
494
      lstrcpy(g_szTempDirPath + 3, TEXT("Temporary Pocket UnZip Files"));
 
495
      g_szTempDir  = g_szTempDirPath;
 
496
   }
 
497
#endif
 
498
}
 
499
 
 
500
//******************************************************************************
 
501
void ShutdownApplication() {
 
502
 
 
503
   // Free our banner font.
 
504
   if (g_hFontBanner) {
 
505
      DeleteObject(g_hFontBanner);
 
506
      g_hFontBanner = NULL;
 
507
   }
 
508
 
 
509
   // Delete our FILE_TYPE_NODE linked list.
 
510
   for (FILE_TYPE_NODE *pft = g_pftHead; pft; ) {
 
511
      FILE_TYPE_NODE *pftNext = pft->pNext;
 
512
      delete[] (BYTE*)pft;
 
513
      pft = pftNext;
 
514
   }
 
515
   g_pftHead = NULL;
 
516
 
 
517
   // If there are no other instances of our application open, then delete our
 
518
   // temporary directory and all the files in it.  Any files opened for viewing
 
519
   // should be locked and will fail to delete.  This is to be expected.
 
520
   if (g_szTempDir && (FindWindow(g_szClass, NULL) == NULL)) {
 
521
      TCHAR szPath[_MAX_PATH];
 
522
      _tcscpy(szPath, g_szTempDir);
 
523
      DeleteDirectory(szPath);
 
524
   }
 
525
}
 
526
 
 
527
//******************************************************************************
 
528
void RegisterUnzip() {
 
529
 
 
530
#ifdef _WIN32_WCE
 
531
 
 
532
   // WARNING!  Since Windows CE does not support any way to get your binary's
 
533
   // name at runtime, we have to hard-code in "punzip.exe".  If our binary is
 
534
   // not named this or is in a non-path directory, then we will fail to
 
535
   // register ourself with the system as the default application to handle
 
536
   // ".zip" files.
 
537
   TCHAR szPath[32] = TEXT("punzip.exe");
 
538
   TCHAR szTstPath[32];
 
539
 
 
540
#else
 
541
 
 
542
   // Get our module's path and file name.  We use the short path name for the
 
543
   // registry because it is guaranteed to contain no spaces.
 
544
   TCHAR szLongPath[_MAX_PATH];
 
545
   TCHAR szPath[_MAX_PATH];
 
546
   TCHAR szTstPath[_MAX_PATH];
 
547
   GetModuleFileName(NULL, szLongPath, countof(szLongPath));
 
548
   GetShortPathName(szLongPath, szPath, countof(szPath));
 
549
 
 
550
#endif
 
551
 
 
552
   // Store a pointer to the end of our path for easy appending.
 
553
   LPTSTR szEnd = szPath + _tcslen(szPath);
 
554
 
 
555
   BOOL fDoRegisterPUnZip = TRUE;
 
556
 
 
557
   // Associate "ZIP" file extensions to our application
 
558
   if (RegReadKey(HKEY_CLASSES_ROOT, TEXT(".zip"), szTstPath, sizeof(szTstPath)))
 
559
   {
 
560
      if (_tcscmp(szTstPath, TEXT("zipfile")) != 0)
 
561
         fDoRegisterPUnZip = FALSE;
 
562
      else if (RegReadKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\shell\\Open\\command"),
 
563
                          szTstPath, sizeof(szTstPath)) &&
 
564
               (_tcsncmp(szTstPath, szPath, _tcslen(szPath)) != 0))
 
565
         fDoRegisterPUnZip = FALSE;
 
566
 
 
567
      if (!fDoRegisterPUnZip)
 
568
      {
 
569
         fDoRegisterPUnZip =
 
570
            (IDOK == MessageBox(g_hWndMain,
 
571
                                TEXT("Currently, Pocket UnZip is not registered as default ")
 
572
                                TEXT("handler for Zip archives.\n\n")
 
573
                                TEXT("Please, confirm that Pocket UnZip should now register itself ")
 
574
                                TEXT("as default application for handling Zip archives (.zip files)"),
 
575
                                g_szAppName,
 
576
                                MB_ICONQUESTION | MB_OKCANCEL));
 
577
      }
 
578
   }
 
579
   if (fDoRegisterPUnZip) {
 
580
      RegWriteKey(HKEY_CLASSES_ROOT, TEXT(".zip"), TEXT("zipfile"));
 
581
      RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile"), TEXT("ZIP File"));
 
582
      RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\shell"), NULL);
 
583
      RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\shell\\Open"), NULL);
 
584
      _tcscpy(szEnd, TEXT(" %1"));
 
585
      RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\shell\\Open\\command"), szPath);
 
586
 
 
587
      // Register our program icon for all ZIP files.
 
588
      _stprintf(szEnd, TEXT(",-%u"), IDI_ZIPFILE);
 
589
      RegWriteKey(HKEY_CLASSES_ROOT, TEXT("zipfile\\DefaultIcon"), szPath);
 
590
   }
 
591
 
 
592
   // Create our application option location.
 
593
   RegWriteKey(HKEY_CURRENT_USER, TEXT("Software"), NULL);
 
594
   RegWriteKey(HKEY_CURRENT_USER, g_szRegKey, NULL);
 
595
}
 
596
 
 
597
//******************************************************************************
 
598
void BuildImageList() {
 
599
 
 
600
   // Create our global image list.
 
601
#ifdef _WIN32_WCE
 
602
 
 
603
   // On Windows CE, we can't spare a color for the mask, so we have to create
 
604
   // the mask in a separate monochrome bitmap.
 
605
 
 
606
   HIMAGELIST hil = ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 8, 8);
 
607
 
 
608
   // Load our default bitmaps into the image list.
 
609
   HBITMAP hBmpImageList = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST));
 
610
   HBITMAP hBmpMask = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST_MASK));
 
611
   ImageList_Add(hil, hBmpImageList, hBmpMask);
 
612
   DeleteObject(hBmpImageList);
 
613
   DeleteObject(hBmpMask);
 
614
 
 
615
#else
 
616
 
 
617
   // On Windows NT, we use magenta as a transparency mask color.
 
618
   HIMAGELIST hil = ImageList_LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST),
 
619
                                         16, 8, RGB(255, 0, 255));
 
620
#endif
 
621
 
 
622
   // Set up for our registry file type enumeration.
 
623
   FILE_TYPE_NODE *pftLast = NULL;
 
624
   TCHAR szExtension[128], szKey[128], szDescription[_MAX_PATH], szIconFile[_MAX_PATH + 16];
 
625
   DWORD dwIndex = 0, dwCount = countof(szExtension);
 
626
 
 
627
   // Enumerate all the keys immediately under HKEY_CLASSES_ROOT.
 
628
   while (ERROR_SUCCESS == RegEnumKeyEx(HKEY_CLASSES_ROOT, dwIndex++, szExtension,
 
629
                                        &dwCount, NULL, NULL, NULL, NULL))
 
630
   {
 
631
      dwCount = countof(szExtension);
 
632
 
 
633
      // Check to see if we read an extension key (starts with a period)
 
634
      if (*szExtension != TEXT('.')) {
 
635
         continue;
 
636
      }
 
637
 
 
638
      // Read the actual key name for this extension.
 
639
      if (!RegReadKey(HKEY_CLASSES_ROOT, szExtension, szKey, sizeof(szKey))) {
 
640
         continue;
 
641
      }
 
642
 
 
643
      // Read the Description for this extension.
 
644
      RegReadKey(HKEY_CLASSES_ROOT, szKey, szDescription, sizeof(szDescription));
 
645
 
 
646
      HICON hIcon = NULL;
 
647
      LPTSTR szEnd = szKey + _tcslen(szKey);
 
648
 
 
649
      // Attempt to get an icon for this extension from the "DefaultIcon" key.
 
650
      _tcscpy(szEnd, TEXT("\\DefaultIcon"));
 
651
      if (RegReadKey(HKEY_CLASSES_ROOT, szKey, szIconFile, sizeof(szIconFile))) {
 
652
 
 
653
         // Look for the comma between the file name and the image.
 
654
         LPTSTR szImageId = _tcschr(szIconFile, TEXT(','));
 
655
         if (szImageId) {
 
656
 
 
657
            // NULL terminate the file name portion of szIconFile.
 
658
            *(szImageId++) = TEXT('\0');
 
659
 
 
660
            // Get the image ID value from szIconFile.
 
661
            int imageId = _ttoi(szImageId);
 
662
 
 
663
            // Extract the icon from the module specified in szIconFile.
 
664
            ExtractIconEx(szIconFile, imageId, NULL, &hIcon, 1);
 
665
            if (hIcon == NULL) {
 
666
               ExtractIconEx(szIconFile, imageId, &hIcon, NULL, 1);
 
667
            }
 
668
         }
 
669
      }
 
670
 
 
671
      // If we failed to get the icon using the "DefaultIcon" key, then try
 
672
      // using the "shell\Open\command" key.
 
673
      if (hIcon == NULL) {
 
674
 
 
675
         _tcscpy(szEnd, TEXT("\\shell\\Open\\command"));
 
676
         if (RegReadKey(HKEY_CLASSES_ROOT, szKey, szIconFile, sizeof(szIconFile))) {
 
677
 
 
678
            // Get a pointer to just the binary - strip quotes and spaces.
 
679
            LPTSTR szPath;
 
680
            if (*szIconFile == TEXT('\"')) {
 
681
               szPath = szIconFile + 1;
 
682
               if (szEnd = _tcschr(szPath, TEXT('\"'))) {
 
683
                  *szEnd = TEXT('\0');
 
684
               }
 
685
            } else {
 
686
               szPath = szIconFile;
 
687
               if (szEnd = _tcschr(szPath, TEXT(' '))) {
 
688
                  *szEnd = TEXT('\0');
 
689
               }
 
690
            }
 
691
 
 
692
            // Extract the icon from the module specified in szIconFile.
 
693
            ExtractIconEx(szPath, 0, NULL, &hIcon, 1);
 
694
            if (hIcon == NULL) {
 
695
               ExtractIconEx(szPath, 0, &hIcon, NULL, 1);
 
696
            }
 
697
         }
 
698
      }
 
699
 
 
700
      // If we found an icon, add it to our image list.
 
701
      int image = -1;
 
702
      if (hIcon) {
 
703
         image = ImageList_AddIcon(hil, hIcon);
 
704
      }
 
705
 
 
706
      // If no icon could be found, then check to see if this is an executable.
 
707
      if ((image == -1) && (
 
708
#ifndef _WIN32_WCE // Windows CE only recognizes EXE's as executable.
 
709
         !_tcsicmp(szExtension + 1, TEXT("bat")) ||
 
710
         !_tcsicmp(szExtension + 1, TEXT("cmd")) ||
 
711
         !_tcsicmp(szExtension + 1, TEXT("com")) ||
 
712
#endif
 
713
         !_tcsicmp(szExtension + 1, TEXT("exe"))))
 
714
      {
 
715
         image = IMAGE_APPLICATION;
 
716
      }
 
717
 
 
718
      // If we don't have a description or a icon, then bail on this extension.
 
719
      if (!*szDescription && (image < 0)) {
 
720
         continue;
 
721
      }
 
722
 
 
723
      // Create our FILE_TYPE_NODE.
 
724
      size_t length = _tcslen(szExtension) - 1 + _tcslen(szDescription);
 
725
      FILE_TYPE_NODE *pft = (FILE_TYPE_NODE*) new BYTE[
 
726
         sizeof(FILE_TYPE_NODE) + (sizeof(TCHAR) * length)];
 
727
 
 
728
      // Bail out if we could not create our node.
 
729
      if (!pft) {
 
730
         DebugOut(TEXT("Not enough memory to create a FILE_TYPE_NODE."));
 
731
         continue;
 
732
      }
 
733
 
 
734
      // Fill in the node.
 
735
      pft->pNext = NULL;
 
736
      pft->image = (image >= 0) ? image : IMAGE_GENERIC;
 
737
      TSTRTOMBS(pft->szExtAndDesc, szExtension + 1, length + 2);
 
738
      size_t sizext = (strlen(pft->szExtAndDesc) + 1);
 
739
      TSTRTOMBS(pft->szExtAndDesc + sizext,
 
740
                szDescription, length - sizext + 2);
 
741
 
 
742
      // Add the node to our list.
 
743
      if (pftLast) {
 
744
         pftLast->pNext = pft;
 
745
      } else {
 
746
         g_pftHead = pft;
 
747
      }
 
748
      pftLast = pft;
 
749
   }
 
750
 
 
751
   // Assign this image list to our tree control.
 
752
   ListView_SetImageList(g_hWndList, hil, LVSIL_SMALL);
 
753
}
 
754
 
 
755
 
 
756
//******************************************************************************
 
757
//***** Our Main Window's Message Handler
 
758
//******************************************************************************
 
759
 
 
760
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
761
 
 
762
   switch(uMsg) {
 
763
      case WM_CREATE:
 
764
         g_hWndMain = hWnd;
 
765
         return OnCreate();
 
766
 
 
767
      case WM_ERASEBKGND:
 
768
         DrawBanner((HDC)wParam);
 
769
         return 0;
 
770
 
 
771
      case WM_SIZE:
 
772
         // Resize our list view control to match our client area.
 
773
         MoveWindow(g_hWndList, 0, g_cyCmdBar + 22, LOWORD(lParam),
 
774
                    HIWORD(lParam) - (g_cyCmdBar + 22), TRUE);
 
775
 
 
776
#ifndef _WIN32_WCE
 
777
         // On NT we have to resize our toolbar as well.
 
778
         MoveWindow(g_hWndCmdBar, 0, 0, LOWORD(lParam), g_cyCmdBar, TRUE);
 
779
#endif
 
780
         return 0;
 
781
 
 
782
      case WM_SETFOCUS:
 
783
         // Always direct focus to our list control.
 
784
         SetFocus(g_hWndList);
 
785
         return 0;
 
786
 
 
787
      case WM_DESTROY:
 
788
         PostQuitMessage(0);
 
789
         return 0;
 
790
 
 
791
      case WM_HELP:
 
792
         OnHelp();
 
793
         return 0;
 
794
 
 
795
      case WM_PRIVATE:
 
796
         switch (wParam) {
 
797
 
 
798
#ifdef _WIN32_WCE
 
799
            case MSG_SUBCLASS_DIALOG:
 
800
               SubclassSaveAsDlg();
 
801
               return 0;
 
802
#endif
 
803
            case MSG_ADD_TEXT_TO_EDIT:
 
804
               AddTextToEdit((LPCSTR)lParam);
 
805
               return 0;
 
806
 
 
807
            case MSG_PROMPT_TO_REPLACE:
 
808
               return PromptToReplace((LPCSTR)lParam);
 
809
 
 
810
#if CRYPT
 
811
            case MSG_PROMPT_FOR_PASSWORD:
 
812
               return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_PASSWORD),
 
813
                                     g_hDlgProgress, (DLGPROC)DlgProcPassword,
 
814
                                     lParam);
 
815
#endif
 
816
 
 
817
            case MSG_UPDATE_PROGRESS_PARTIAL:
 
818
               UpdateProgress((EXTRACT_INFO*)lParam, FALSE);
 
819
               return 0;
 
820
 
 
821
            case MSG_UPDATE_PROGRESS_COMPLETE:
 
822
               UpdateProgress((EXTRACT_INFO*)lParam, TRUE);
 
823
               return 0;
 
824
         }
 
825
         return 0;
 
826
 
 
827
      case WM_NOTIFY:
 
828
         switch (((LPNMHDR)lParam)->code) {
 
829
 
 
830
            case LVN_GETDISPINFO:
 
831
               OnGetDispInfo((LV_DISPINFO*)lParam);
 
832
               return 0;
 
833
 
 
834
            case LVN_DELETEITEM:
 
835
               OnDeleteItem((NM_LISTVIEW*)lParam);
 
836
               return 0;
 
837
 
 
838
            case LVN_COLUMNCLICK:
 
839
               Sort(((NM_LISTVIEW*)lParam)->iSubItem, FALSE);
 
840
               return 0;
 
841
 
 
842
            case LVN_ITEMCHANGED:
 
843
               OnItemChanged((NM_LISTVIEW*)lParam);
 
844
               return 0;
 
845
 
 
846
            case NM_DBLCLK:
 
847
            case NM_RETURN:
 
848
               OnActionView();
 
849
               return 0;
 
850
         }
 
851
 
 
852
         return 0;
 
853
 
 
854
      case WM_COMMAND:
 
855
         switch (LOWORD(wParam)) {
 
856
 
 
857
            case IDM_FILE_OPEN:
 
858
               OnFileOpen();
 
859
               return 0;
 
860
 
 
861
            case IDM_FILE_PROPERTIES:
 
862
               DialogBox(g_hInst, MAKEINTRESOURCE(IDD_PROPERTIES), hWnd, (DLGPROC)DlgProcProperties);
 
863
               return 0;
 
864
 
 
865
            case IDM_FILE_CLOSE:
 
866
               SendMessage(hWnd, WM_CLOSE, 0, 0);
 
867
               return 0;
 
868
 
 
869
            case IDM_ACTION_EXTRACT_ALL:
 
870
               OnActionSelectAll();
 
871
               // Fall through to IDM_ACTION_EXTRACT
 
872
 
 
873
            case IDM_ACTION_EXTRACT:
 
874
               ExtractOrTestFiles(TRUE);
 
875
               return 0;
 
876
 
 
877
            case IDM_ACTION_TEST_ALL:
 
878
               OnActionSelectAll();
 
879
               // Fall through to IDM_ACTION_TEST
 
880
 
 
881
            case IDM_ACTION_TEST:
 
882
               ExtractOrTestFiles(FALSE);
 
883
               return 0;
 
884
 
 
885
            case IDM_ACTION_VIEW:
 
886
               OnActionView();
 
887
               return 0;
 
888
 
 
889
            case IDM_ACTION_SELECT_ALL:
 
890
               OnActionSelectAll();
 
891
               return 0;
 
892
 
 
893
            case IDM_VIEW_EXPANDED_VIEW:
 
894
               OnViewExpandedView();
 
895
               return 0;
 
896
 
 
897
            case IDM_VIEW_COMMENT:
 
898
               DialogBox(g_hInst, MAKEINTRESOURCE(IDD_COMMENT), hWnd, (DLGPROC)DlgProcComment);
 
899
               return 0;
 
900
 
 
901
            case IDM_HELP_ABOUT:
 
902
               DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)DlgProcAbout);
 
903
               return 0;
 
904
 
 
905
            case IDHELP:
 
906
               return SendMessage(hWnd, WM_HELP, 0, 0);
 
907
 
 
908
            default:
 
909
               // Check to see if a MRU file was selected.
 
910
               if ((LOWORD(wParam) >= MRU_START_ID) &&
 
911
                   (LOWORD(wParam) < (MRU_START_ID + MRU_MAX_FILE)))
 
912
               {
 
913
                  ActivateMRU(LOWORD(wParam));
 
914
               }
 
915
         }
 
916
    }
 
917
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
 
918
}
 
919
 
 
920
//******************************************************************************
 
921
//***** Event Handlers for our Main Window
 
922
//******************************************************************************
 
923
 
 
924
int OnCreate() {
 
925
 
 
926
   // Our toolbar buttons.
 
927
   static TBBUTTON tbButton[] = {
 
928
      { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 
929
      { 0, IDM_FILE_OPEN,          0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 
930
      { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 
931
      { 1, IDM_FILE_PROPERTIES,    0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 
932
      { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 
933
      { 2, IDM_ACTION_EXTRACT,     0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 
934
      { 3, IDM_ACTION_EXTRACT_ALL, 0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 
935
      { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 
936
      { 4, IDM_ACTION_TEST,        0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 
937
      { 5, IDM_ACTION_TEST_ALL,    0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 
938
      { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 
939
      { 6, IDM_ACTION_VIEW,        0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 
940
      { 0, 0,                      0, TBSTYLE_SEP,    0, 0, 0, -1 },
 
941
      { 7, IDM_VIEW_EXPANDED_VIEW, 0, TBSTYLE_BUTTON, 0, 0, 0, -1 },
 
942
      { 8, IDM_VIEW_COMMENT,       0, TBSTYLE_BUTTON, 0, 0, 0, -1 }
 
943
   };
 
944
 
 
945
   // Our toolbar buttons' tool tip text.
 
946
   static LPTSTR szToolTips[] = {
 
947
       TEXT(""),  // Menu
 
948
       TEXT("Open (Ctrl+O)"),
 
949
       TEXT("Properties (Alt+Enter)"),
 
950
       TEXT("Extract Selected Files"),
 
951
       TEXT("Extract All Files"),
 
952
       TEXT("Test Selected Files"),
 
953
       TEXT("Test All Files"),
 
954
       TEXT("View Selected File"),
 
955
       TEXT("Expanded View"),
 
956
       TEXT("View Zip File Comment")
 
957
   };
 
958
 
 
959
   // Initialize the common controls.
 
960
   InitCommonControls();
 
961
 
 
962
   // Check to see if we have a help file.
 
963
   BOOL fHelp = (GetFileAttributes(g_szHelpFile) != 0xFFFFFFFF);
 
964
 
 
965
   // Set our window's icon so it can update the task bar.
 
966
   if (g_hIconMain) {
 
967
      SendMessage(g_hWndMain, WM_SETICON, FALSE, (LPARAM)g_hIconMain);
 
968
   }
 
969
 
 
970
   // Create the tree control.  Our main window will resize it to fit.
 
971
   g_hWndList = CreateWindow(WC_LISTVIEW, TEXT(""),
 
972
                             WS_VSCROLL | WS_CHILD | WS_VISIBLE |
 
973
                             LVS_REPORT | LVS_SHOWSELALWAYS,
 
974
                             0, 0, 0, 0, g_hWndMain, NULL, g_hInst, NULL);
 
975
 
 
976
#ifdef _WIN32_WCE
 
977
 
 
978
   // Create a command bar and add the toolbar bitmaps to it.
 
979
   g_hWndCmdBar = CommandBar_Create(g_hInst, g_hWndMain, 1);
 
980
   CommandBar_AddBitmap(g_hWndCmdBar, g_hInst, IDB_TOOLBAR, 9, 16, 16);
 
981
   CommandBar_InsertMenubar(g_hWndCmdBar, g_hInst, IDR_UNZIP, 0);
 
982
   CommandBar_AddButtons(g_hWndCmdBar, countof(tbButton), tbButton);
 
983
   CommandBar_AddAdornments(g_hWndCmdBar, fHelp ? CMDBAR_HELP : 0, 0);
 
984
 
 
985
   // Add tool tips to the tool bar.
 
986
   CommandBar_AddToolTips(g_hWndCmdBar, countof(szToolTips), szToolTips);
 
987
 
 
988
   // Store the height of the command bar for later calculations.
 
989
   g_cyCmdBar = CommandBar_Height(g_hWndCmdBar);
 
990
 
 
991
   // We set our wait window handle to our menu window within our command bar.
 
992
   // This is the last window that will be painted during startup of our app.
 
993
   g_hWndWaitFor = GetWindow(g_hWndCmdBar, GW_CHILD);
 
994
 
 
995
   // Add the help item to our help menu if we have a help file.
 
996
   if (fHelp) {
 
997
      HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 3);
 
998
      InsertMenu(hMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
 
999
      InsertMenu(hMenu, 0, MF_BYPOSITION | MF_ENABLED, IDHELP, TEXT("&Help"));
 
1000
   }
 
1001
 
 
1002
#else
 
1003
 
 
1004
   // Create a tool bar and add the toolbar bitmaps to it.
 
1005
   g_hWndCmdBar = CreateToolbarEx(g_hWndMain, WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS,
 
1006
                                  1, 9, g_hInst, IDB_TOOLBAR, tbButton,
 
1007
                                  countof(tbButton), 16, 16, 16, 16,
 
1008
                                  sizeof(TBBUTTON));
 
1009
 
 
1010
   // Get our tool tip control.
 
1011
   HWND hWndTT = (HWND)SendMessage(g_hWndCmdBar, TB_GETTOOLTIPS, 0, 0);
 
1012
 
 
1013
   // Set our tool tip strings.
 
1014
   TOOLINFO ti;
 
1015
   ti.cbSize = sizeof(ti);
 
1016
   int tip = 0, button;
 
1017
   while (SendMessage(hWndTT, TTM_ENUMTOOLS, tip++, (LPARAM)&ti)) {
 
1018
      for (button = 0; button < countof(tbButton); button++) {
 
1019
         if (tbButton[button].idCommand == (int)ti.uId) {
 
1020
            ti.lpszText = szToolTips[tbButton[button].iBitmap + 1];
 
1021
            SendMessage(hWndTT, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
 
1022
            break;
 
1023
         }
 
1024
      }
 
1025
   }
 
1026
 
 
1027
   // Store the height of the tool bar for later calculations.
 
1028
   RECT rc;
 
1029
   GetWindowRect(g_hWndCmdBar, &rc);
 
1030
   g_cyCmdBar = rc.bottom - rc.top;
 
1031
 
 
1032
   // We set our wait window handle to our toolbar.
 
1033
   // This is the last window that will be painted during the startup of our app.
 
1034
   g_hWndWaitFor = g_hWndCmdBar;
 
1035
 
 
1036
   // Add the help item to our help menu if we have a help file.
 
1037
   if (fHelp) {
 
1038
      HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 3);
 
1039
      InsertMenu(hMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
 
1040
      InsertMenu(hMenu, 0, MF_BYPOSITION | MF_ENABLED, IDHELP, TEXT("&Help\tF1"));
 
1041
   }
 
1042
 
 
1043
#endif // _WIN32_WCE
 
1044
 
 
1045
   // Enable Full Row Select - This feature is supported on Windows CE and was
 
1046
   // introduced to Win95/NT with IE 3.0.  If the user does not have a
 
1047
   // COMCTL32.DLL that supports this feature, then they will just see the
 
1048
   // old standard First Column Select.
 
1049
   SendMessage(g_hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT |
 
1050
               SendMessage(g_hWndList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0));
 
1051
 
 
1052
   // Get our expanded view option from the registry.
 
1053
   g_fExpandedView = GetOptionInt(TEXT("ExpandedView"), FALSE);
 
1054
 
 
1055
   // Show or remove menu check for expanded view option.
 
1056
   CheckAllMenuItems(IDM_VIEW_EXPANDED_VIEW, g_fExpandedView);
 
1057
 
 
1058
   // Create our columns.
 
1059
   AddDeleteColumns();
 
1060
 
 
1061
   // Set our current sort column to our name column
 
1062
   Sort(0, TRUE);
 
1063
 
 
1064
   return 0;
 
1065
}
 
1066
 
 
1067
//******************************************************************************
 
1068
void OnFileOpen() {
 
1069
 
 
1070
   TCHAR szPath[_MAX_PATH] = TEXT("");
 
1071
 
 
1072
   OPENFILENAME ofn;
 
1073
   ZeroMemory(&ofn, sizeof(ofn));
 
1074
 
 
1075
   ofn.lStructSize  = sizeof(ofn);
 
1076
   ofn.hwndOwner    = g_hWndMain;
 
1077
   ofn.hInstance    = g_hInst;
 
1078
   ofn.lpstrFilter  = TEXT("ZIP files (*.zip)\0*.zip\0SFX files (*.exe)\0*.exe\0All Files (*.*)\0*.*\0");
 
1079
   ofn.nFilterIndex = 1;
 
1080
   ofn.lpstrFile    = szPath;
 
1081
   ofn.nMaxFile     = countof(szPath);
 
1082
   ofn.Flags        = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
 
1083
   ofn.lpstrDefExt  = TEXT("zip");
 
1084
 
 
1085
   if (GetOpenFileName(&ofn)) {
 
1086
      ReadZipFileList(szPath);
 
1087
   }
 
1088
}
 
1089
 
 
1090
//******************************************************************************
 
1091
void OnActionView() {
 
1092
 
 
1093
   // We only allow a view if one item is selected.
 
1094
   int count = ListView_GetSelectedCount(g_hWndList);
 
1095
   if (count != 1) {
 
1096
      return;
 
1097
   }
 
1098
 
 
1099
   // Query the selected item for its FILE_NODE.
 
1100
   LV_ITEM lvi;
 
1101
   ZeroMemory(&lvi, sizeof(lvi));
 
1102
   lvi.mask = LVIF_IMAGE | LVIF_PARAM;
 
1103
   lvi.iItem = ListView_GetNextItem(g_hWndList, -1, LVNI_SELECTED);
 
1104
   ListView_GetItem(g_hWndList, &lvi);
 
1105
   FILE_NODE *pfn = (FILE_NODE*)lvi.lParam;
 
1106
 
 
1107
   // Bail out if the selected item is a folder or volume label.
 
1108
   if (pfn->dwAttributes & (FILE_ATTRIBUTE_DIRECTORY | ZFILE_ATTRIBUTE_VOLUME)) {
 
1109
      MessageBox(g_hWndMain, TEXT("You cannot view folders or volume labels."),
 
1110
                 g_szAppName, MB_ICONINFORMATION | MB_OK);
 
1111
      return;
 
1112
   }
 
1113
 
 
1114
   // Make sure our temporary directory exists.
 
1115
   CreateDirectory(g_szTempDir, NULL);
 
1116
 
 
1117
   TCHAR szPath[_MAX_PATH + 256];
 
1118
 
 
1119
   // Set our extraction directory to our temporary directory.
 
1120
   if (!SetExtractToDirectory((LPTSTR)g_szTempDir)) {
 
1121
 
 
1122
      // Create error message.  Use szPath buffer because it is handy.
 
1123
      _stprintf(szPath,
 
1124
         TEXT("Could not create \"%s\"\n\n")
 
1125
         TEXT("Most likely cause is that your drive is full."),
 
1126
         g_szTempDir);
 
1127
 
 
1128
      // Display error message.
 
1129
      MessageBox(g_hWndMain, szPath, g_szAppName, MB_ICONERROR | MB_OK);
 
1130
 
 
1131
      return;
 
1132
   }
 
1133
 
 
1134
   // Create our single item file array.
 
1135
   CHAR *argv[2] = { pfn->szPathAndMethod, NULL };
 
1136
 
 
1137
   // Create a buffer to store the mapped name of the file.  If the has to be
 
1138
   // renamed to be compatible with our file system, then we need to know that
 
1139
   // new name in order to open it correctly.
 
1140
   CHAR szMappedPath[_MAX_PATH];
 
1141
   *szMappedPath = '\0';
 
1142
 
 
1143
   // Configure our extract structure.
 
1144
   EXTRACT_INFO ei;
 
1145
   ZeroMemory(&ei, sizeof(ei));
 
1146
   ei.fExtract      = TRUE;
 
1147
   ei.dwFileCount   = 1;
 
1148
   ei.dwByteCount   = pfn->dwSize;
 
1149
   ei.szFileList    = argv;
 
1150
   ei.fRestorePaths = FALSE;
 
1151
   ei.overwriteMode = OM_PROMPT;
 
1152
   ei.szMappedPath  = szMappedPath;
 
1153
 
 
1154
   // Clear our skipped flag and set our viewing flag.
 
1155
   g_fSkipped = FALSE;
 
1156
   g_fViewing = TRUE;
 
1157
 
 
1158
   // Display our progress dialog and do the extraction.
 
1159
   DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_VIEW_PROGRESS), g_hWndMain,
 
1160
                  (DLGPROC)DlgProcViewProgress, (LPARAM)&ei);
 
1161
 
 
1162
   // Clear our viewing flag.
 
1163
   g_fViewing = FALSE;
 
1164
 
 
1165
   // Check to see if the user skipped the file by aborting the decryption or
 
1166
   // overwrite prompts.  The only other case that causes us to skip a file
 
1167
   // is when the user enters the incorrect password too many times.  In this
 
1168
   // case, IZ_BADPWD will be returned.
 
1169
   if (g_fSkipped) {
 
1170
      return;
 
1171
   }
 
1172
   if (ei.result == IZ_BADPWD) {
 
1173
      MessageBox(g_hWndMain, TEXT("Password was incorrect.  The file has been skipped."),
 
1174
                 g_szAppName, MB_ICONWARNING | MB_OK);
 
1175
      return;
 
1176
   }
 
1177
 
 
1178
   // Check to see if the extraction failed.
 
1179
   if (ei.result != PK_OK) {
 
1180
 
 
1181
      if (ei.result == PK_ABORTED) {
 
1182
         _tcscpy(szPath, GetZipErrorString(ei.result));
 
1183
 
 
1184
      } else {
 
1185
         // Create error message.  Use szPath buffer because it is handy.
 
1186
         _stprintf(szPath,
 
1187
#ifdef UNICODE
 
1188
            TEXT("Could not extract \"%S\".\n\n%s\n\nTry using the Test or ")
 
1189
#else
 
1190
            TEXT("Could not extract \"%s\".\n\n%s\n\nTry using the Test or ")
 
1191
#endif
 
1192
            TEXT("Extract action on the file for more details."),
 
1193
            *szMappedPath ? szMappedPath : pfn->szPathAndMethod,
 
1194
            GetZipErrorString(ei.result));
 
1195
      }
 
1196
 
 
1197
      // Display error message.
 
1198
      MessageBox(g_hWndMain, szPath, g_szAppName, MB_ICONERROR | MB_OK);
 
1199
 
 
1200
      // If we managed to create a bad file, then delete it.
 
1201
      if (*szMappedPath) {
 
1202
         MBSTOTSTR(szPath, szMappedPath, countof(szPath));
 
1203
         SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
 
1204
         if (!DeleteFile(szPath)) {
 
1205
            SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
 
1206
         }
 
1207
      }
 
1208
 
 
1209
      return;
 
1210
   }
 
1211
 
 
1212
   // Convert the file name to UNICODE.
 
1213
   MBSTOTSTR(szPath, szMappedPath, countof(szPath));
 
1214
 
 
1215
   // Prepare to launch the file.
 
1216
   SHELLEXECUTEINFO sei;
 
1217
   ZeroMemory(&sei, sizeof(sei));
 
1218
   sei.cbSize      = sizeof(sei);
 
1219
   sei.hwnd        = g_hWndMain;
 
1220
   sei.lpDirectory = g_szTempDir;
 
1221
   sei.nShow       = SW_SHOWNORMAL;
 
1222
 
 
1223
#ifdef _WIN32_WCE
 
1224
 
 
1225
   TCHAR szApp[_MAX_PATH];
 
1226
 
 
1227
   // On Windows CE, there is no default file association dialog that appears
 
1228
   // when ShellExecuteEx() is given an unknown file type.  We check to see if
 
1229
   // file is unknown, and display our own file association prompt.
 
1230
 
 
1231
   // Check our file image to see if this file has no associated viewer.
 
1232
   if (lvi.iImage == IMAGE_GENERIC) {
 
1233
 
 
1234
      // Display our file association prompt dialog.
 
1235
      if (IDOK != DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_VIEW_ASSOCIATION),
 
1236
                                 g_hWndMain, (DLGPROC)DlgProcViewAssociation,
 
1237
                                 (LPARAM)szApp))
 
1238
      {
 
1239
         // If the user aborted the association prompt, then delete file and exit.
 
1240
         SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
 
1241
         if (!DeleteFile(szPath)) {
 
1242
            SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
 
1243
         }
 
1244
         return;
 
1245
      }
 
1246
      // Set the file to be the viewer app and the parameters to be the file.
 
1247
      // Note: Some applications require that arguments with spaces be quoted,
 
1248
      // while other applications choked when quotes we part of the filename.
 
1249
      // In the end, it seems safer to leave the quotes off.
 
1250
      sei.lpFile = szApp;
 
1251
      sei.lpParameters = szPath;
 
1252
   } else {
 
1253
      sei.lpFile = szPath;
 
1254
   }
 
1255
 
 
1256
#else
 
1257
 
 
1258
   // On NT, ShellExecuteEx() will prompt user for association if needed.
 
1259
   sei.lpFile = szPath;
 
1260
 
 
1261
#endif
 
1262
 
 
1263
   // Launch the file.  All errors will be displayed by ShellExecuteEx().
 
1264
   ShellExecuteEx(&sei);
 
1265
}
 
1266
 
 
1267
//******************************************************************************
 
1268
void OnActionSelectAll() {
 
1269
   for (int i = ListView_GetItemCount(g_hWndList) - 1; i >= 0; i--) {
 
1270
      ListView_SetItemState(g_hWndList, i, LVIS_SELECTED, LVIS_SELECTED);
 
1271
   }
 
1272
}
 
1273
 
 
1274
//******************************************************************************
 
1275
void OnViewExpandedView() {
 
1276
 
 
1277
   // Toggle our expanded view option.
 
1278
   g_fExpandedView = !g_fExpandedView;
 
1279
 
 
1280
   // Show or remove menu check and toolbar button press.
 
1281
   CheckAllMenuItems(IDM_VIEW_EXPANDED_VIEW, g_fExpandedView);
 
1282
 
 
1283
   // Display the new columns.
 
1284
   AddDeleteColumns();
 
1285
 
 
1286
   // Re-sort if we just did away with out sort column.
 
1287
   if (!g_fExpandedView && (g_sortColumn > 3)) {
 
1288
      Sort(0, TRUE);
 
1289
   }
 
1290
 
 
1291
   // Write our expanded view option to the registry.
 
1292
   WriteOptionInt(TEXT("ExpandedView"), g_fExpandedView);
 
1293
}
 
1294
 
 
1295
//******************************************************************************
 
1296
void OnHelp() {
 
1297
 
 
1298
   // Prepare to launch the help file.
 
1299
   SHELLEXECUTEINFO sei;
 
1300
   ZeroMemory(&sei, sizeof(sei));
 
1301
   sei.cbSize      = sizeof(sei);
 
1302
   sei.hwnd        = g_hWndMain;
 
1303
   sei.lpFile      = g_szHelpFile;
 
1304
 
 
1305
   // Launch the file.
 
1306
   ShellExecuteEx(&sei);
 
1307
}
 
1308
 
 
1309
 
 
1310
//******************************************************************************
 
1311
//***** Event Handlers for our List View
 
1312
//******************************************************************************
 
1313
 
 
1314
void OnGetDispInfo(LV_DISPINFO *plvdi) {
 
1315
 
 
1316
   // Make sure we have the minimum amount of data to process this event.
 
1317
   if ((plvdi->item.iItem < 0) || !plvdi->item.lParam || !plvdi->item.pszText) {
 
1318
      return;
 
1319
   }
 
1320
 
 
1321
   // Get a pointer to the file node for this item.
 
1322
   FILE_NODE *pFile = (FILE_NODE*)plvdi->item.lParam;
 
1323
 
 
1324
   CHAR szBuffer[_MAX_PATH * 2];
 
1325
 
 
1326
   switch (plvdi->item.iSubItem) {
 
1327
 
 
1328
      case 0: // Name
 
1329
 
 
1330
         // Copy the string to a temporary buffer.
 
1331
         strcpy(szBuffer, pFile->szPathAndMethod);
 
1332
 
 
1333
         // Change all forward slashes to back slashes in the buffer
 
1334
         ForwardSlashesToBackSlashesA(szBuffer);
 
1335
 
 
1336
         // Convert the string to UNICODE and store it in our list control.
 
1337
         MBSTOTSTR(plvdi->item.pszText, szBuffer, plvdi->item.cchTextMax);
 
1338
 
 
1339
         return;
 
1340
 
 
1341
      case 1: // Size
 
1342
         FormatValue(plvdi->item.pszText, pFile->dwSize);
 
1343
         return;
 
1344
 
 
1345
      case 2: // Type
 
1346
         MBSTOTSTR(plvdi->item.pszText, BuildTypeString(pFile, szBuffer),
 
1347
                  plvdi->item.cchTextMax);
 
1348
         return;
 
1349
 
 
1350
      case 3: // Modified
 
1351
         int hour; hour = (pFile->dwModified >> 6) & 0x001F;
 
1352
         _stprintf(plvdi->item.pszText, TEXT("%u/%u/%u %u:%02u %cM"),
 
1353
                   (pFile->dwModified  >> 16) & 0x000F,
 
1354
                   (pFile->dwModified  >> 11) & 0x001F,
 
1355
                   ((pFile->dwModified >> 20) & 0x0FFF) % 100,
 
1356
                   (hour % 12) ? (hour % 12) : 12,
 
1357
                   pFile->dwModified & 0x003F,
 
1358
                   hour >= 12 ? 'P' : 'A');
 
1359
         return;
 
1360
 
 
1361
      case 4: // Attributes
 
1362
         BuildAttributesString(plvdi->item.pszText, pFile->dwAttributes);
 
1363
         return;
 
1364
 
 
1365
      case 5: // Compressed
 
1366
         FormatValue(plvdi->item.pszText, pFile->dwCompressedSize);
 
1367
         return;
 
1368
 
 
1369
      case 6: // Ratio
 
1370
         int factor; factor = ratio(pFile->dwSize, pFile->dwCompressedSize);
 
1371
         _stprintf(plvdi->item.pszText, TEXT("%d.%d%%"), factor / 10,
 
1372
                   ((factor < 0) ? -factor : factor) % 10);
 
1373
         return;
 
1374
 
 
1375
      case 7: // Method
 
1376
         MBSTOTSTR(plvdi->item.pszText, pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1,
 
1377
                  plvdi->item.cchTextMax);
 
1378
         return;
 
1379
 
 
1380
      case 8: // CRC
 
1381
         _stprintf(plvdi->item.pszText, TEXT("%08X"), pFile->dwCRC);
 
1382
         return;
 
1383
 
 
1384
      case 9: // Comment
 
1385
         MBSTOTSTR(plvdi->item.pszText, pFile->szComment ? pFile->szComment : "",
 
1386
                   plvdi->item.cchTextMax);
 
1387
         return;
 
1388
   }
 
1389
}
 
1390
 
 
1391
//******************************************************************************
 
1392
void OnDeleteItem(NM_LISTVIEW *pnmlv) {
 
1393
   if (pnmlv->lParam) {
 
1394
 
 
1395
      // Free any comment string associated with this item.
 
1396
      if (((FILE_NODE*)pnmlv->lParam)->szComment) {
 
1397
         delete[] (CHAR*)((FILE_NODE*)pnmlv->lParam)->szComment;
 
1398
      }
 
1399
 
 
1400
      // Free the item itself.
 
1401
      delete[] (LPBYTE)pnmlv->lParam;
 
1402
   }
 
1403
}
 
1404
 
 
1405
//******************************************************************************
 
1406
void OnItemChanged(NM_LISTVIEW *pnmlv) {
 
1407
   int count = ListView_GetSelectedCount(pnmlv->hdr.hwndFrom);
 
1408
   EnableAllMenuItems(IDM_FILE_PROPERTIES, count > 0);
 
1409
   EnableAllMenuItems(IDM_ACTION_EXTRACT,  count > 0);
 
1410
   EnableAllMenuItems(IDM_ACTION_TEST,     count > 0);
 
1411
   EnableAllMenuItems(IDM_ACTION_VIEW,     count == 1);
 
1412
}
 
1413
 
 
1414
//******************************************************************************
 
1415
//***** List View Sort Functions
 
1416
//******************************************************************************
 
1417
 
 
1418
void Sort(int sortColumn, BOOL fForce) {
 
1419
 
 
1420
   // Do not change the column header text if it is already correct.
 
1421
   if (sortColumn != g_sortColumn) {
 
1422
 
 
1423
      TCHAR szColumn[32];
 
1424
      LV_COLUMN lvc;
 
1425
      lvc.mask = LVCF_TEXT;
 
1426
      lvc.pszText = szColumn;
 
1427
 
 
1428
      // Remove the '^' from the current sort column.
 
1429
      if (g_sortColumn != -1) {
 
1430
         _stprintf(szColumn, (g_columns[g_sortColumn].format == LVCFMT_LEFT) ?
 
1431
                   TEXT("%s   ") : TEXT("   %s"), g_columns[g_sortColumn].szName);
 
1432
         ListView_SetColumn(g_hWndList, g_sortColumn, &lvc);
 
1433
      }
 
1434
 
 
1435
      // Set the new sort column.
 
1436
      g_sortColumn = sortColumn;
 
1437
 
 
1438
      // Add the '^' to the new sort column.
 
1439
      _stprintf(szColumn, (g_columns[g_sortColumn].format == LVCFMT_LEFT) ?
 
1440
                TEXT("%s ^") : TEXT("^ %s"), g_columns[g_sortColumn].szName);
 
1441
      ListView_SetColumn(g_hWndList, g_sortColumn, &lvc);
 
1442
 
 
1443
      // Sort the list by the new column.
 
1444
      ListView_SortItems(g_hWndList, CompareFunc, g_sortColumn);
 
1445
 
 
1446
   } else if (fForce) {
 
1447
      // Force the list to sort by the same column.
 
1448
      ListView_SortItems(g_hWndList, CompareFunc, g_sortColumn);
 
1449
   }
 
1450
}
 
1451
 
 
1452
//******************************************************************************
 
1453
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM sortColumn) {
 
1454
   FILE_NODE *pFile1 = (FILE_NODE*)lParam1, *pFile2 = (FILE_NODE*)lParam2;
 
1455
   TCHAR szBuffer1[8], szBuffer2[8];
 
1456
 
 
1457
   // Return Negative value if the first item should precede the second.
 
1458
   // Return Positive value if the first item should follow the second.
 
1459
   // Return Zero if the two items are equivalent.
 
1460
 
 
1461
   int result = 0;
 
1462
 
 
1463
   // Compute the relationship based on the current sort column
 
1464
   switch (sortColumn) {
 
1465
 
 
1466
      case 1: // Size - Smallest to Largest
 
1467
         if (pFile1->dwSize != pFile2->dwSize) {
 
1468
            result = ((pFile1->dwSize < pFile2->dwSize) ? -1 : 1);
 
1469
         }
 
1470
         break;
 
1471
 
 
1472
      case 2: { // Type - Volume Label's first, then directories, then files
 
1473
         int f1 = (pFile1->dwAttributes & ZFILE_ATTRIBUTE_VOLUME)   ? 1 :
 
1474
                  (pFile1->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 3;
 
1475
         int f2 = (pFile2->dwAttributes & ZFILE_ATTRIBUTE_VOLUME)   ? 1 :
 
1476
                  (pFile2->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 2 : 3;
 
1477
         if ((f1 == 3) && (f2 == 3)) {
 
1478
            CHAR szType1[128];
 
1479
            CHAR szType2[128];
 
1480
            result = _stricmp(BuildTypeString(pFile1, szType1),
 
1481
                              BuildTypeString(pFile2, szType2));
 
1482
         } else {
 
1483
            result = f1 - f2;
 
1484
         }
 
1485
         break;
 
1486
      }
 
1487
 
 
1488
      case 3: // Modified - Newest to Oldest
 
1489
         if (pFile1->dwModified != pFile2->dwModified) {
 
1490
            result = ((pFile1->dwModified > pFile2->dwModified) ? -1 : 1);
 
1491
         }
 
1492
         break;
 
1493
 
 
1494
      case 4: // Attributes - String Sort
 
1495
         result = _tcscmp(BuildAttributesString(szBuffer1, pFile1->dwAttributes),
 
1496
                          BuildAttributesString(szBuffer2, pFile2->dwAttributes));
 
1497
         break;
 
1498
 
 
1499
      case 5: // Compressed Size - Smallest to Largest
 
1500
         if (pFile1->dwCompressedSize != pFile2->dwCompressedSize) {
 
1501
            result = ((pFile1->dwCompressedSize < pFile2->dwCompressedSize) ? -1 : 1);
 
1502
         }
 
1503
         break;
 
1504
 
 
1505
      case 6: // Ratio - Smallest to Largest
 
1506
         int factor1, factor2;
 
1507
         factor1 = ratio(pFile1->dwSize, pFile1->dwCompressedSize);
 
1508
         factor2 = ratio(pFile2->dwSize, pFile2->dwCompressedSize);
 
1509
         result = factor1 - factor2;
 
1510
         break;
 
1511
 
 
1512
      case 7: // Method - String Sort
 
1513
         result = _stricmp(pFile1->szPathAndMethod + strlen(pFile1->szPathAndMethod) + 1,
 
1514
                           pFile2->szPathAndMethod + strlen(pFile2->szPathAndMethod) + 1);
 
1515
         break;
 
1516
 
 
1517
      case 8: // CRC - Smallest to Largest
 
1518
         if (pFile1->dwCRC != pFile2->dwCRC) {
 
1519
            result = ((pFile1->dwCRC < pFile2->dwCRC) ? -1 : 1);
 
1520
         }
 
1521
         break;
 
1522
 
 
1523
      case 9: // Comment - String Sort
 
1524
         result = _stricmp(pFile1->szComment ? pFile1->szComment : "",
 
1525
                           pFile2->szComment ? pFile2->szComment : "");
 
1526
         break;
 
1527
   }
 
1528
 
 
1529
   // If the sort resulted in a tie, we use the name to break the tie.
 
1530
   if (result == 0) {
 
1531
      result = _stricmp(pFile1->szPathAndMethod, pFile2->szPathAndMethod);
 
1532
   }
 
1533
 
 
1534
   return result;
 
1535
}
 
1536
 
 
1537
 
 
1538
//******************************************************************************
 
1539
//***** Helper/Utility Functions
 
1540
//******************************************************************************
 
1541
 
 
1542
void SetCaptionText(LPCTSTR szPrefix) {
 
1543
   TCHAR szCaption[_MAX_PATH + 32];
 
1544
   if (szPrefix) {
 
1545
      _stprintf(szCaption, TEXT("%s - "), szPrefix);
 
1546
   } else {
 
1547
      *szCaption = 0;
 
1548
   }
 
1549
   if (*g_szZipFile) {
 
1550
      size_t lenPrefix = _tcslen(szCaption);
 
1551
      MBSTOTSTR(szCaption + lenPrefix, GetFileFromPath(g_szZipFile),
 
1552
                countof(szCaption) - lenPrefix);
 
1553
   } else {
 
1554
      _tcscat(szCaption, TEXT("Pocket UnZip"));
 
1555
   }
 
1556
   SetWindowText(g_hWndMain, szCaption);
 
1557
}
 
1558
 
 
1559
//******************************************************************************
 
1560
void DrawBanner(HDC hdc) {
 
1561
 
 
1562
   // If we were not passed in a DC, then get one now.
 
1563
   BOOL fReleaseDC = FALSE;
 
1564
   if (!hdc) {
 
1565
      hdc = GetDC(g_hWndMain);
 
1566
      fReleaseDC = TRUE;
 
1567
   }
 
1568
 
 
1569
   // Compute the banner rectangle.
 
1570
   RECT rc;
 
1571
   GetClientRect(g_hWndMain, &rc);
 
1572
   rc.top += g_cyCmdBar;
 
1573
   rc.bottom = rc.top + 22;
 
1574
 
 
1575
   // Fill in the background with a light grey brush.
 
1576
   FillRect(hdc, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
 
1577
 
 
1578
   // Draw a highlight line across the top of our banner.
 
1579
   POINT pt[2] = { { rc.left, rc.top + 1 }, { rc.right, rc.top + 1 } };
 
1580
 
 
1581
   SelectObject(hdc, GetStockObject(WHITE_PEN));
 
1582
   Polyline(hdc, pt, 2);
 
1583
 
 
1584
   // Get the ZIP file image.  We do this only once and cache the result.
 
1585
   // Note that you do not need to free icons as they are a resource.
 
1586
   static HICON hIcon = NULL;
 
1587
   if (!hIcon) {
 
1588
      hIcon = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_ZIPFILE),
 
1589
                               IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
 
1590
   }
 
1591
 
 
1592
   // Draw the ZIP file image.
 
1593
   DrawIconEx(hdc, rc.left + 6, rc.top + 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
 
1594
 
 
1595
   // Set our font and colors.
 
1596
   HFONT hFontStock = (HFONT)SelectObject(hdc, g_hFontBanner);
 
1597
   SetTextColor(hdc, RGB(0, 0, 0));
 
1598
   SetBkMode(hdc, TRANSPARENT);
 
1599
 
 
1600
   rc.left   += 26;
 
1601
   rc.right  -= 48;
 
1602
   rc.bottom -=  2;
 
1603
 
 
1604
   // Decide what text to display.
 
1605
   TCHAR szPath[_MAX_PATH + 16];
 
1606
   if (g_hWndWaitFor) {
 
1607
      _tcscpy(szPath, TEXT("Initializing..."));
 
1608
   } else if (*g_szZipFile) {
 
1609
      if (g_fLoading) {
 
1610
#ifdef UNICODE
 
1611
         _stprintf(szPath, TEXT("Loading %S"), g_szZipFile);
 
1612
#else
 
1613
         _stprintf(szPath, TEXT("Loading %s"), g_szZipFile);
 
1614
#endif
 
1615
      } else {
 
1616
         MBSTOTSTR(szPath, g_szZipFile, countof(szPath));
 
1617
      }
 
1618
   } else {
 
1619
      _tcscpy(szPath, TEXT("No File Loaded"));
 
1620
   }
 
1621
 
 
1622
   // Draw the banner text.
 
1623
   DrawText(hdc, szPath, _tcslen(szPath), &rc,
 
1624
            DT_NOPREFIX | DT_SINGLELINE | DT_LEFT | DT_VCENTER);
 
1625
 
 
1626
   // Remove all non stock objects from the DC
 
1627
   SelectObject(hdc, hFontStock);
 
1628
 
 
1629
   // Free our DC if we created it.
 
1630
   if (fReleaseDC) {
 
1631
      ReleaseDC(g_hWndMain, hdc);
 
1632
   }
 
1633
}
 
1634
 
 
1635
//******************************************************************************
 
1636
void AddDeleteColumns() {
 
1637
 
 
1638
   static int curColumns = 0;
 
1639
   int column, newColumns = (g_fExpandedView ? countof(g_columns) : 4);
 
1640
 
 
1641
   // Are we adding columns?
 
1642
   if (newColumns > curColumns) {
 
1643
 
 
1644
      // Set up column structure.
 
1645
      TCHAR szColumn[32];
 
1646
      LV_COLUMN lvc;
 
1647
      lvc.mask = LVCF_TEXT | LVCF_FMT;
 
1648
      lvc.pszText = szColumn;
 
1649
 
 
1650
      // Loop through each column we need to add.
 
1651
      for (column = curColumns; column < newColumns; column++) {
 
1652
 
 
1653
         // Build the real column string.
 
1654
         _stprintf(szColumn, (g_columns[column].format == LVCFMT_LEFT) ?
 
1655
                   TEXT("%s   ") : TEXT("   %s"), g_columns[column].szName);
 
1656
 
 
1657
         // Insert the column with the correct format.
 
1658
         lvc.fmt = g_columns[column].format;
 
1659
         ListView_InsertColumn(g_hWndList, column, &lvc);
 
1660
      }
 
1661
 
 
1662
   // Otherwise, we are removing columns.
 
1663
   } else {
 
1664
 
 
1665
      // Loop through each column we need to delete and delete them.
 
1666
      for (column = curColumns - 1; column >= newColumns; column--) {
 
1667
         ListView_DeleteColumn(g_hWndList, column);
 
1668
      }
 
1669
   }
 
1670
 
 
1671
   // Store our new column count statically to help us with the next call to
 
1672
   // AddDeleteColumns().
 
1673
   curColumns = newColumns;
 
1674
 
 
1675
   // Re-calcualte our column widths.
 
1676
   ResizeColumns();
 
1677
}
 
1678
 
 
1679
//******************************************************************************
 
1680
void ResizeColumns() {
 
1681
 
 
1682
   // Hide the window since we are going to be doing some column shifting.
 
1683
   ShowWindow(g_hWndList, SW_HIDE);
 
1684
 
 
1685
   // Resize all the columns to best fit both the column data and the header.
 
1686
   for (int column = 0; column < countof(g_columns); column++) {
 
1687
      ListView_SetColumnWidth(g_hWndList, column, LVSCW_AUTOSIZE_USEHEADER);
 
1688
   }
 
1689
 
 
1690
   // Show the window again.
 
1691
   ShowWindow(g_hWndList, SW_SHOW);
 
1692
}
 
1693
 
 
1694
//******************************************************************************
 
1695
LPCTSTR GetZipErrorString(int error) {
 
1696
 
 
1697
   switch (error) {
 
1698
 
 
1699
      case PK_OK: // no error
 
1700
         return TEXT("Operation completed successfully.");
 
1701
 
 
1702
      case PK_WARN: // warning error
 
1703
         return TEXT("There were warnings during the operation.");
 
1704
 
 
1705
      case PK_ERR:    // error in zipfile
 
1706
      case PK_BADERR: // severe error in zipfile
 
1707
         return TEXT("The operation could not be successfully completed.  ")
 
1708
                TEXT("Possible causes are that the ZIP file contains errors, ")
 
1709
                TEXT("or that an error occurred while trying to create a ")
 
1710
                TEXT("directory or file.");
 
1711
 
 
1712
      case PK_MEM:  // insufficient memory
 
1713
      case PK_MEM2: // insufficient memory
 
1714
      case PK_MEM3: // insufficient memory
 
1715
      case PK_MEM4: // insufficient memory
 
1716
      case PK_MEM5: // insufficient memory
 
1717
         return TEXT("There is not enough memory to perform the operation.  ")
 
1718
                TEXT("Try closing other running applications or adjust your ")
 
1719
                TEXT("memory configuration.");
 
1720
 
 
1721
      case PK_NOZIP: // zipfile not found or corrupt.
 
1722
         return TEXT("The ZIP file either contains errors or could not be found.");
 
1723
 
 
1724
      case PK_PARAM: // bad or illegal parameters specified
 
1725
         break; // Not used in the Windows CE port.
 
1726
 
 
1727
      case PK_FIND: // no files found in ZIP file
 
1728
         return TEXT("The ZIP file contains errors that prevented the ")
 
1729
                TEXT("operation from completing successfully.  A possible ")
 
1730
                TEXT("cause is that one or more of the files listed as being ")
 
1731
                TEXT("in the ZIP file could not actually be found within the ")
 
1732
                TEXT("ZIP file itself.");
 
1733
 
 
1734
      case PK_DISK: // disk full or file locked
 
1735
         return TEXT("An error occurred while attempting to save a file.  ")
 
1736
                TEXT("Possible causes are that your file storage is full or ")
 
1737
                TEXT("read only, or that a file with the same name already ")
 
1738
                TEXT("exists and is locked by another application.");
 
1739
 
 
1740
      case PK_EOF: // unexpected end of file
 
1741
         return TEXT("The ZIP file contains errors that prevented the ")
 
1742
                TEXT("operation from completing successfully.  A possible ")
 
1743
                TEXT("cause is that your ZIP file is incomplete and might be ")
 
1744
                TEXT("truncated.");
 
1745
 
 
1746
      case IZ_UNSUP:  // no files found: all unsup. compr/encrypt.
 
1747
         return TEXT("None of the files could be processed because they were ")
 
1748
                TEXT("all compressed using an unsupported compression or ")
 
1749
                TEXT("encryption algorithm.");
 
1750
 
 
1751
      case IZ_BADPWD: // no files found: all had bad password.
 
1752
         return TEXT("None of the files could be processed because all the ")
 
1753
                TEXT("password(s) specified were incorrect.");
 
1754
 
 
1755
      case PK_EXCEPTION: // exception occurred
 
1756
         return TEXT("An internal error occurred.  Possible causes are that ")
 
1757
                TEXT("you are out of memory, you are out of file storage ")
 
1758
                TEXT("space, the ZIP file contains unexpected errors, or there ")
 
1759
                TEXT("is a bug in our program (that's why it's free).");
 
1760
 
 
1761
      case IZ_CTRLC:  // canceled by user's interaction
 
1762
      case PK_ABORTED: // user aborted
 
1763
         return TEXT("The operation was aborted.");
 
1764
   }
 
1765
 
 
1766
   return TEXT("An unknown error occurred while processing the ZIP file.");
 
1767
}
 
1768
 
 
1769
//******************************************************************************
 
1770
void AddFileToListView(FILE_NODE *pFile) {
 
1771
 
 
1772
   // Set up our List View Item structure.
 
1773
   LV_ITEM lvi;
 
1774
   ZeroMemory(&lvi, sizeof(lvi));
 
1775
   lvi.mask    = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
 
1776
   lvi.pszText = LPSTR_TEXTCALLBACK;
 
1777
   lvi.lParam  = (LPARAM)pFile;
 
1778
   lvi.iImage  = IMAGE_GENERIC;
 
1779
 
 
1780
   // Special case Volume Labels.
 
1781
   if (pFile->dwAttributes & ZFILE_ATTRIBUTE_VOLUME) {
 
1782
      pFile->szType = "Volume Label";
 
1783
      lvi.iImage = IMAGE_VOLUME;
 
1784
 
 
1785
   // Special case folders.
 
1786
   } else if (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
 
1787
      pFile->szType = "Folder";
 
1788
      lvi.iImage = IMAGE_FOLDER;
 
1789
 
 
1790
   // Do a lookup on the file extension.
 
1791
   } else {
 
1792
 
 
1793
      // Locate the file portion of our path.
 
1794
      LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
 
1795
 
 
1796
      // Find the extension portion of our file.
 
1797
      LPCSTR pszExt = MBSRCHR(pszFile, '.');
 
1798
 
 
1799
      // Search our known extension list for this extension.
 
1800
      if (pszExt && *(pszExt + 1)) {
 
1801
 
 
1802
         // Loop through our linked list
 
1803
         for (FILE_TYPE_NODE *pft = g_pftHead; pft; pft = pft->pNext) {
 
1804
 
 
1805
            // Check for a match.
 
1806
            if (!_stricmp(pszExt + 1, pft->szExtAndDesc)) {
 
1807
 
 
1808
               // We found a match, store the image and type string and exit loop.
 
1809
               lvi.iImage = pft->image;
 
1810
               pFile->szType = pft->szExtAndDesc + strlen(pft->szExtAndDesc) + 1;
 
1811
               if (!*pFile->szType) {
 
1812
                  pFile->szType = NULL;
 
1813
               }
 
1814
               break;
 
1815
            }
 
1816
         }
 
1817
      }
 
1818
   }
 
1819
 
 
1820
   // Add the item to our list.
 
1821
   ListView_InsertItem(g_hWndList, &lvi);
 
1822
}
 
1823
 
 
1824
//******************************************************************************
 
1825
void EnableAllMenuItems(UINT uMenuItem, BOOL fEnabled) {
 
1826
#ifdef _WIN32_WCE
 
1827
   HMENU hMenu = CommandBar_GetMenu(g_hWndCmdBar, 0);
 
1828
#else
 
1829
   HMENU hMenu = GetMenu(g_hWndMain);
 
1830
#endif
 
1831
   EnableMenuItem(hMenu, uMenuItem, fEnabled ? MF_ENABLED : MF_GRAYED);
 
1832
   SendMessage(g_hWndCmdBar, TB_ENABLEBUTTON, uMenuItem, MAKELONG(fEnabled, 0));
 
1833
}
 
1834
 
 
1835
//******************************************************************************
 
1836
void CheckAllMenuItems(UINT uMenuItem, BOOL fChecked) {
 
1837
#ifdef _WIN32_WCE
 
1838
   HMENU hMenu = CommandBar_GetMenu(g_hWndCmdBar, 0);
 
1839
#else
 
1840
   HMENU hMenu = GetMenu(g_hWndMain);
 
1841
#endif
 
1842
   CheckMenuItem(hMenu, uMenuItem, fChecked ? MF_CHECKED : MF_UNCHECKED);
 
1843
   SendMessage(g_hWndCmdBar, TB_PRESSBUTTON, uMenuItem, MAKELONG(fChecked, 0));
 
1844
}
 
1845
 
 
1846
//******************************************************************************
 
1847
void CenterWindow(HWND hWnd) {
 
1848
 
 
1849
   RECT rc, rcParent;
 
1850
 
 
1851
   // Get our window rectangle.
 
1852
   GetWindowRect(hWnd, &rc);
 
1853
 
 
1854
   // Get our parent's window rectangle.
 
1855
   GetWindowRect(GetParent(hWnd), &rcParent);
 
1856
 
 
1857
   // Center our window over our parent's window.
 
1858
   SetWindowPos(hWnd, NULL,
 
1859
      rcParent.left + ((rcParent.right  - rcParent.left) - (rc.right  - rc.left)) / 2,
 
1860
      rcParent.top  + ((rcParent.bottom - rcParent.top ) - (rc.bottom - rc.top )) / 2,
 
1861
      0, 0, SWP_NOZORDER | SWP_NOSIZE);
 
1862
}
 
1863
 
 
1864
//******************************************************************************
 
1865
void AddTextToEdit(LPCSTR szText) {
 
1866
 
 
1867
   if (!g_hWndEdit) {
 
1868
      return;
 
1869
   }
 
1870
 
 
1871
   // Add the characters one by one to our edit box while performing the
 
1872
   // the following newline conversions:
 
1873
   //    Single CR -> CR/LF
 
1874
   //    Single LF -> CR/LF
 
1875
   //    CR and LF -> CR/LF
 
1876
   //    LF and CR -> CR/LF
 
1877
   //    0 - 31    -> ^char
 
1878
 
 
1879
   TCHAR szOut[256], *pszOut = szOut;
 
1880
   CHAR *pszIn = (LPSTR)szText, cPrev = '\0';
 
1881
 
 
1882
   while (*pszIn) {
 
1883
 
 
1884
      if (*pszIn == '\n') {
 
1885
         if (cPrev == '\r') {
 
1886
            cPrev = '\0';
 
1887
         } else {
 
1888
            *(pszOut++) = TEXT('\r');
 
1889
            *(pszOut++) = TEXT('\n');
 
1890
            cPrev = '\n';
 
1891
         }
 
1892
 
 
1893
      } else if (*pszIn == '\r') {
 
1894
         if (cPrev == '\n') {
 
1895
            cPrev = '\0';
 
1896
         } else {
 
1897
            *(pszOut++) = TEXT('\r');
 
1898
            *(pszOut++) = TEXT('\n');
 
1899
            cPrev = '\r';
 
1900
         }
 
1901
 
 
1902
      } else if ((*pszIn < 32) && (*pszIn != '\t')) {
 
1903
         *(pszOut++) = (TCHAR)'^';
 
1904
         *(pszOut++) = (TCHAR)(64 + *pszIn);
 
1905
         cPrev = *pszIn;
 
1906
 
 
1907
      } else {
 
1908
         *(pszOut++) = (TCHAR)*pszIn;
 
1909
         cPrev = *pszIn;
 
1910
      }
 
1911
      pszIn++;
 
1912
 
 
1913
      // If our out buffer is full, then dump it to the edit box.
 
1914
      if ((pszOut - szOut) > 253) {
 
1915
         *pszOut = TEXT('\0');
 
1916
         SendMessage(g_hWndEdit, EM_SETSEL, -1, -1);
 
1917
         SendMessage(g_hWndEdit, EM_REPLACESEL, FALSE, (LPARAM)szOut);
 
1918
         pszOut = szOut;
 
1919
      }
 
1920
   }
 
1921
 
 
1922
   // One final flush of any partially full out buffer.
 
1923
   if (pszOut > szOut) {
 
1924
      *pszOut = TEXT('\0');
 
1925
      SendMessage(g_hWndEdit, EM_SETSEL, -1, -1);
 
1926
      SendMessage(g_hWndEdit, EM_REPLACESEL, FALSE, (LPARAM)szOut);
 
1927
   }
 
1928
}
 
1929
 
 
1930
//******************************************************************************
 
1931
LPTSTR FormatValue(LPTSTR szValue, DWORD dwValue) {
 
1932
   DWORD dw = 0, dwGroup[4] = { 0, 0, 0, 0 };
 
1933
   while (dwValue) {
 
1934
      dwGroup[dw++] = dwValue % 1000;
 
1935
      dwValue /= 1000;
 
1936
   }
 
1937
   switch (dw) {
 
1938
      case 2:  _stprintf(szValue, TEXT("%u,%03u"), dwGroup[1], dwGroup[0]); break;
 
1939
      case 3:  _stprintf(szValue, TEXT("%u,%03u,%03u"), dwGroup[2], dwGroup[1], dwGroup[0]); break;
 
1940
      case 4:  _stprintf(szValue, TEXT("%u,%03u,%03u,%03u"), dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]); break;
 
1941
      default: _stprintf(szValue, TEXT("%u"), dwGroup[0]);
 
1942
   }
 
1943
   return szValue;
 
1944
}
 
1945
 
 
1946
//******************************************************************************
 
1947
LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes) {
 
1948
   // Build the attribute string according to the flags specified for this file.
 
1949
   _stprintf(szBuffer, TEXT("%s%s%s%s%s%s%s%s"),
 
1950
             (dwAttributes & ZFILE_ATTRIBUTE_VOLUME)    ? TEXT("V") : TEXT(""),
 
1951
             (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)  ? TEXT("D") : TEXT(""),
 
1952
             (dwAttributes & FILE_ATTRIBUTE_READONLY)   ? TEXT("R") : TEXT(""),
 
1953
             (dwAttributes & FILE_ATTRIBUTE_ARCHIVE)    ? TEXT("A") : TEXT(""),
 
1954
             (dwAttributes & FILE_ATTRIBUTE_HIDDEN)     ? TEXT("H") : TEXT(""),
 
1955
             (dwAttributes & FILE_ATTRIBUTE_SYSTEM)     ? TEXT("S") : TEXT(""),
 
1956
             (dwAttributes & ZFILE_ATTRIBUTE_ENCRYPTED) ? TEXT("E") : TEXT(""),
 
1957
             (dwAttributes & ZFILE_ATTRIBUTE_COMMENT)   ? TEXT("C") : TEXT(""));
 
1958
   return szBuffer;
 
1959
}
 
1960
 
 
1961
//******************************************************************************
 
1962
LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType) {
 
1963
 
 
1964
   // First check to see if we have a known description.
 
1965
   if (pFile->szType) {
 
1966
      return pFile->szType;
 
1967
   }
 
1968
 
 
1969
   // Locate the file portion of our path.
 
1970
   LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
 
1971
 
 
1972
   // Get the extension portion of the file.
 
1973
   LPCSTR pszExt = MBSRCHR(pszFile, '.');
 
1974
 
 
1975
   // If we have an extension create a type name for this file.
 
1976
   if (pszExt && *(pszExt + 1)) {
 
1977
      strcpy(szType, pszExt + 1);
 
1978
      _strupr(szType);
 
1979
      strcat(szType, " File");
 
1980
      return szType;
 
1981
   }
 
1982
 
 
1983
   // If no extension, then use the default "File".
 
1984
   return "File";
 
1985
}
 
1986
 
 
1987
//******************************************************************************
 
1988
LPCSTR GetFileFromPath(LPCSTR szPath) {
 
1989
   LPCSTR p1 = MBSRCHR(szPath, '/'), p2 = MBSRCHR(szPath, '\\');
 
1990
   if (p1 && (p1 > p2)) {
 
1991
      return p1 + 1;
 
1992
   } else if (p2) {
 
1993
      return p2 + 1;
 
1994
   }
 
1995
   return szPath;
 
1996
}
 
1997
 
 
1998
//******************************************************************************
 
1999
void ForwardSlashesToBackSlashesA(LPSTR szBuffer) {
 
2000
   while (*szBuffer) {
 
2001
      if (*szBuffer == '/') {
 
2002
         *szBuffer = '\\';
 
2003
      }
 
2004
      INCSTR(szBuffer);
 
2005
   }
 
2006
}
 
2007
 
 
2008
//******************************************************************************
 
2009
void ForwardSlashesToBackSlashesW(LPWSTR szBuffer) {
 
2010
   while (*szBuffer) {
 
2011
      if (*szBuffer == L'/') {
 
2012
         *szBuffer = L'\\';
 
2013
      }
 
2014
      szBuffer++;
 
2015
   }
 
2016
}
 
2017
 
 
2018
//******************************************************************************
 
2019
void DeleteDirectory(LPTSTR szPath) {
 
2020
 
 
2021
   // Make note to where the end of our path is.
 
2022
   LPTSTR szEnd = szPath + _tcslen(szPath);
 
2023
 
 
2024
   // Add our search spec to the path.
 
2025
   _tcscpy(szEnd, TEXT("\\*.*"));
 
2026
 
 
2027
   // Start a directory search.
 
2028
   WIN32_FIND_DATA w32fd;
 
2029
   HANDLE hFind = FindFirstFile(szPath, &w32fd);
 
2030
 
 
2031
   // Loop through all entries in this directory.
 
2032
   if (hFind != INVALID_HANDLE_VALUE) {
 
2033
 
 
2034
      do {
 
2035
         // Append the file/directory name to the path.
 
2036
         _tcscpy(szEnd + 1, w32fd.cFileName);
 
2037
 
 
2038
         // Check to see if this entry is a subdirectory.
 
2039
         if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
 
2040
 
 
2041
            // Ignore current directory (.) and previous directory (..)
 
2042
            if (_tcscmp(w32fd.cFileName, TEXT("."))   &&
 
2043
                _tcscmp(w32fd.cFileName, TEXT("..")))
 
2044
            {
 
2045
               // Recurse into DeleteDirectory() to delete subdirectory.
 
2046
               DeleteDirectory(szPath);
 
2047
            }
 
2048
 
 
2049
         // Otherwise, it must be a file.
 
2050
         } else {
 
2051
 
 
2052
            // If the file is marked as read-only, then change to read/write.
 
2053
            if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
 
2054
               SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
 
2055
            }
 
2056
 
 
2057
            // Attempt to delete the file.  If we fail and the file used to be
 
2058
            // read-only, then set the read-only bit back on it.
 
2059
            if (!DeleteFile(szPath) &&
 
2060
                (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
 
2061
            {
 
2062
               SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
 
2063
            }
 
2064
         }
 
2065
 
 
2066
      // Get the next directory entry.
 
2067
      } while (FindNextFile(hFind, &w32fd));
 
2068
 
 
2069
      // Close the directory search.
 
2070
      FindClose(hFind);
 
2071
   }
 
2072
 
 
2073
   // Remove the directory.
 
2074
   *szEnd = TEXT('\0');
 
2075
   RemoveDirectory(szPath);
 
2076
}
 
2077
 
 
2078
 
 
2079
//******************************************************************************
 
2080
//***** Registry Functions
 
2081
//******************************************************************************
 
2082
 
 
2083
void RegWriteKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPCTSTR szValue) {
 
2084
   HKEY  hKey = NULL;
 
2085
   DWORD dwDisposition;
 
2086
 
 
2087
   if (RegCreateKeyEx(hKeyRoot, szSubKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) {
 
2088
      if (szValue) {
 
2089
         RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szValue,
 
2090
                       sizeof(TCHAR) * (_tcslen(szValue) + 1));
 
2091
      }
 
2092
      RegCloseKey(hKey);
 
2093
   }
 
2094
}
 
2095
 
 
2096
//******************************************************************************
 
2097
BOOL RegReadKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPTSTR szValue, DWORD cBytes) {
 
2098
   *szValue = TEXT('\0');
 
2099
   HKEY hKey = NULL;
 
2100
   LRESULT lResult = -1;
 
2101
 
 
2102
   if (RegOpenKeyEx(hKeyRoot, szSubKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
 
2103
      lResult = RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)szValue, &cBytes);
 
2104
      RegCloseKey(hKey);
 
2105
   }
 
2106
   return ((lResult == ERROR_SUCCESS) && *szValue);
 
2107
}
 
2108
 
 
2109
//******************************************************************************
 
2110
void WriteOptionString(LPCTSTR szOption, LPCTSTR szValue) {
 
2111
   HKEY hKey = NULL;
 
2112
 
 
2113
   if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
 
2114
      RegSetValueEx(hKey, szOption, 0, REG_SZ, (LPBYTE)szValue,
 
2115
                    sizeof(TCHAR) * (_tcslen(szValue) + 1));
 
2116
      RegCloseKey(hKey);
 
2117
   }
 
2118
}
 
2119
 
 
2120
//******************************************************************************
 
2121
void WriteOptionInt(LPCTSTR szOption, DWORD dwValue) {
 
2122
   HKEY hKey = NULL;
 
2123
 
 
2124
   if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
 
2125
      RegSetValueEx(hKey, szOption, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
 
2126
      RegCloseKey(hKey);
 
2127
   }
 
2128
}
 
2129
 
 
2130
//******************************************************************************
 
2131
LPTSTR GetOptionString(LPCTSTR szOption, LPCTSTR szDefault, LPTSTR szValue, DWORD nSize) {
 
2132
   HKEY hKey = NULL;
 
2133
   LONG lResult = -1;
 
2134
 
 
2135
   if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
 
2136
      lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)szValue, &nSize);
 
2137
      RegCloseKey(hKey);
 
2138
   }
 
2139
   if (lResult != ERROR_SUCCESS) {
 
2140
      _tcscpy(szValue, szDefault);
 
2141
   }
 
2142
   return szValue;
 
2143
}
 
2144
 
 
2145
//******************************************************************************
 
2146
DWORD GetOptionInt(LPCTSTR szOption, DWORD dwDefault) {
 
2147
   HKEY  hKey = NULL;
 
2148
   LONG  lResult = -1;
 
2149
   DWORD dwValue;
 
2150
   DWORD nSize = sizeof(dwValue);
 
2151
 
 
2152
   if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
 
2153
      lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)&dwValue, &nSize);
 
2154
      RegCloseKey(hKey);
 
2155
   }
 
2156
   return (lResult == ERROR_SUCCESS) ? dwValue : dwDefault;
 
2157
}
 
2158
 
 
2159
//******************************************************************************
 
2160
//***** EDIT Control Subclass Functions
 
2161
//******************************************************************************
 
2162
 
 
2163
void DisableEditing(HWND hWndEdit) {
 
2164
 
 
2165
   // Make sure the control does not have ES_READONLY or ES_WANTRETURN styles.
 
2166
   DWORD dwStyle = (DWORD)GetWindowLong(hWndEdit, GWL_STYLE);
 
2167
   if (dwStyle & (ES_READONLY | ES_WANTRETURN)) {
 
2168
      SetWindowLong(hWndEdit, GWL_STYLE, dwStyle & ~(ES_READONLY | ES_WANTRETURN));
 
2169
   }
 
2170
 
 
2171
   // Subclass the control so we can intercept certain keys.
 
2172
   g_wpEdit = (WNDPROC)GetWindowLong(hWndEdit, GWL_WNDPROC);
 
2173
   SetWindowLong(hWndEdit, GWL_WNDPROC, (LONG)EditSubclassProc);
 
2174
}
 
2175
 
 
2176
//******************************************************************************
 
2177
LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
2178
 
 
2179
   BOOL fCtrl, fShift;
 
2180
 
 
2181
   switch (uMsg) {
 
2182
      // For cut, paste, delete, and undo, the control post itself a message.
 
2183
      // we throw away that message.  This works as a fail-safe in case we miss
 
2184
      // some keystroke that causes one of these operations.  This also disables
 
2185
      // the context menu on NT from causing one of these actions to occur.
 
2186
      case WM_CUT:
 
2187
      case WM_PASTE:
 
2188
      case WM_CLEAR:
 
2189
      case WM_UNDO:
 
2190
         MessageBeep(0);
 
2191
         return 0;
 
2192
 
 
2193
      // WM_CHAR is used for normal characters. A-Z, numbers, symbols, enter,
 
2194
      // backspace, esc, and tab. In does not include del or movement keys.
 
2195
      case WM_CHAR:
 
2196
         fCtrl  = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
 
2197
 
 
2198
         // We only allow CTRL-C (copy), plain ESC, plain TAB, plain ENTER.
 
2199
         if (( fCtrl && (wParam == 3))         ||
 
2200
             (!fCtrl && (wParam == VK_ESCAPE)) ||
 
2201
             (!fCtrl && (wParam == VK_RETURN)) ||
 
2202
             (!fCtrl && (wParam == VK_TAB)))
 
2203
         {
 
2204
            break;
 
2205
         }
 
2206
         MessageBeep(0);
 
2207
         return 0;
 
2208
 
 
2209
      // WM_KEYDOWN handles del, insert, arrows, pg up/down, home/end.
 
2210
      case WM_KEYDOWN:
 
2211
         fCtrl  = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
 
2212
         fShift = (GetKeyState(VK_SHIFT)   & 0x8000) ? TRUE : FALSE;
 
2213
 
 
2214
         // Skip all forms of DELETE, SHIFT-INSERT (paste),
 
2215
         // CTRL-RETURN (hard-return), and CTRL-TAB (hard-tab).
 
2216
         if ((          (wParam == VK_DELETE)) ||
 
2217
             (fShift && (wParam == VK_INSERT)) ||
 
2218
             (fCtrl  && (wParam == VK_RETURN)) ||
 
2219
             (fCtrl  && (wParam == VK_TAB)))
 
2220
         {
 
2221
            MessageBeep(0);
 
2222
            return 0;
 
2223
         }
 
2224
         break;
 
2225
   }
 
2226
   return CallWindowProc(g_wpEdit, hWnd, uMsg, wParam, lParam);
 
2227
}
 
2228
 
 
2229
 
 
2230
//******************************************************************************
 
2231
//***** MRU Functions
 
2232
//******************************************************************************
 
2233
 
 
2234
#ifdef _WIN32_WCE
 
2235
int GetMenuString(HMENU hMenu, UINT uIDItem, LPTSTR lpString, int nMaxCount,
 
2236
                  UINT uFlag) {
 
2237
   MENUITEMINFO mii;
 
2238
   ZeroMemory(&mii, sizeof(mii));
 
2239
   mii.cbSize = sizeof(mii);
 
2240
   mii.fMask = MIIM_TYPE;
 
2241
   mii.dwTypeData = lpString;
 
2242
   mii.cch = nMaxCount;
 
2243
   return (GetMenuItemInfo(hMenu, uIDItem, uFlag == MF_BYPOSITION, &mii) ?
 
2244
           mii.cch : 0);
 
2245
}
 
2246
#endif
 
2247
 
 
2248
//******************************************************************************
 
2249
void InitializeMRU() {
 
2250
 
 
2251
   TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
 
2252
   int   i, j;
 
2253
 
 
2254
   // Get our menu handle.
 
2255
#ifdef _WIN32_WCE
 
2256
   HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
 
2257
#else
 
2258
   HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
 
2259
#endif
 
2260
 
 
2261
   // Read all our current MRUs from the registry.
 
2262
   for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
 
2263
 
 
2264
      // Build option name for current MRU and read from registry.
 
2265
      _stprintf(szOption, TEXT("MRU%d"), i+1);
 
2266
      GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
 
2267
 
 
2268
      // If this MRU exists, then add it.
 
2269
      if (szMRU[i][3]) {
 
2270
 
 
2271
         // Build the accelerator prefix for this menu item.
 
2272
         szMRU[i][0] = TEXT('&');
 
2273
         szMRU[i][1] = TEXT('1') + j;
 
2274
         szMRU[i][2] = TEXT(' ');
 
2275
 
 
2276
         // Add the item to our menu.
 
2277
         InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
 
2278
                    szMRU[i]);
 
2279
 
 
2280
         // Increment our actual MRU count.
 
2281
         j++;
 
2282
      }
 
2283
   }
 
2284
}
 
2285
 
 
2286
//******************************************************************************
 
2287
void AddFileToMRU(LPCSTR szFile) {
 
2288
 
 
2289
   TCHAR szMRU[MRU_MAX_FILE + 1][_MAX_PATH + 4], szOption[8];
 
2290
   int   i, j;
 
2291
 
 
2292
   // Store the new file in our first MRU index.
 
2293
   MBSTOTSTR(&szMRU[0][3], szFile, _MAX_PATH);
 
2294
 
 
2295
   //---------------------------------------------------------------------------
 
2296
   // We first read the current MRU list from the registry, merge in our new
 
2297
   // file at the top, and then write back to the registry.  The registry merge
 
2298
   // is done to allow multiple instances of Pocket UnZip to maintain a global
 
2299
   // MRU list independent to this current instance's MRU list.
 
2300
   //---------------------------------------------------------------------------
 
2301
 
 
2302
   // Read all our current MRUs from the registry.
 
2303
   for (i = 1; i <= MRU_MAX_FILE; i++) {
 
2304
 
 
2305
      // Build option name for current MRU and read from registry.
 
2306
      _stprintf(szOption, TEXT("MRU%d"), i);
 
2307
      GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
 
2308
   }
 
2309
 
 
2310
   // Write our new merged MRU list back to the registry.
 
2311
   for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
 
2312
 
 
2313
      // If this MRU exists and is different then our new file, then add it.
 
2314
      if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
 
2315
 
 
2316
         // Build option name for current MRU and write to registry.
 
2317
         _stprintf(szOption, TEXT("MRU%d"), ++j);
 
2318
         WriteOptionString(szOption, &szMRU[i][3]);
 
2319
      }
 
2320
   }
 
2321
 
 
2322
   //---------------------------------------------------------------------------
 
2323
   // The next thing we need to do is read our local MRU from our File menu,
 
2324
   // merge in our new file, and store the new list back to our File menu.
 
2325
   //---------------------------------------------------------------------------
 
2326
 
 
2327
   // Get our menu handle.
 
2328
#ifdef _WIN32_WCE
 
2329
   HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
 
2330
#else
 
2331
   HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
 
2332
#endif
 
2333
 
 
2334
   // Read all our current MRUs from our File Menu.
 
2335
   for (i = 1; i <= MRU_MAX_FILE; i++) {
 
2336
 
 
2337
      // Query our file Menu for a MRU file.
 
2338
      if (GetMenuString(hMenu, MRU_START_ID + i - 1, szMRU[i],
 
2339
                        countof(szMRU[0]), MF_BYCOMMAND))
 
2340
      {
 
2341
         // Delete this item from the menu for now.
 
2342
         DeleteMenu(hMenu, MRU_START_ID + i - 1, MF_BYCOMMAND);
 
2343
      } else {
 
2344
         szMRU[i][3] = TEXT('\0');
 
2345
      }
 
2346
   }
 
2347
 
 
2348
   // Write our new merged MRU list back to the File menu.
 
2349
   for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
 
2350
 
 
2351
      // If this MRU exists and is different then our new file, then add it.
 
2352
      if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
 
2353
 
 
2354
         // Build the accelerator prefix for this menu item.
 
2355
         szMRU[i][0] = TEXT('&');
 
2356
         szMRU[i][1] = TEXT('1') + j;
 
2357
         szMRU[i][2] = TEXT(' ');
 
2358
 
 
2359
         // Add the item to our menu.
 
2360
         InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
 
2361
                    szMRU[i]);
 
2362
 
 
2363
         // Increment our actual MRU count.
 
2364
         j++;
 
2365
      }
 
2366
   }
 
2367
}
 
2368
 
 
2369
//******************************************************************************
 
2370
void RemoveFileFromMRU(LPCTSTR szFile) {
 
2371
 
 
2372
   TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
 
2373
   int   i, j;
 
2374
   BOOL  fFound;
 
2375
 
 
2376
   //---------------------------------------------------------------------------
 
2377
   // We first look for this file in our global MRU stored in the registry.  We
 
2378
   // read the current MRU list from the registry, and then write it back while
 
2379
   // removing all occurrances of the file specified.
 
2380
   //---------------------------------------------------------------------------
 
2381
 
 
2382
   // Read all our current MRUs from the registry.
 
2383
   for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
 
2384
 
 
2385
      // Build option name for current MRU and read from registry.
 
2386
      _stprintf(szOption, TEXT("MRU%d"), i+1);
 
2387
      GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
 
2388
 
 
2389
      // Check for a match.
 
2390
      if (!_tcsicmp(szFile, &szMRU[i][3])) {
 
2391
         szMRU[i][3] = TEXT('\0');
 
2392
         fFound = TRUE;
 
2393
      }
 
2394
   }
 
2395
 
 
2396
   // Only write the MRU back to the registry if we found a file to remove.
 
2397
   if (fFound) {
 
2398
 
 
2399
      // Write the updated MRU list back to the registry.
 
2400
      for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
 
2401
 
 
2402
         // If this MRU still exists, then add it.
 
2403
         if (szMRU[i][3]) {
 
2404
 
 
2405
            // Build option name for current MRU and write to registry.
 
2406
            _stprintf(szOption, TEXT("MRU%d"), ++j);
 
2407
            WriteOptionString(szOption, &szMRU[i][3]);
 
2408
         }
 
2409
      }
 
2410
 
 
2411
      // If our list got smaller, clear the unused items in the registry.
 
2412
      while (j++ < MRU_MAX_FILE) {
 
2413
         _stprintf(szOption, TEXT("MRU%d"), j);
 
2414
         WriteOptionString(szOption, TEXT(""));
 
2415
      }
 
2416
   }
 
2417
 
 
2418
   //---------------------------------------------------------------------------
 
2419
   // We next thing we do is look for this file in our local MRU stored in our
 
2420
   // File menu.  We read the current MRU list from the menu, and then write it
 
2421
   // back while removing all occurrances of the file specified.
 
2422
   //---------------------------------------------------------------------------
 
2423
 
 
2424
   // Get our menu handle.
 
2425
#ifdef _WIN32_WCE
 
2426
   HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
 
2427
#else
 
2428
   HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
 
2429
#endif
 
2430
 
 
2431
   // Read all our current MRUs from our File Menu.
 
2432
   for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
 
2433
 
 
2434
      // Query our file Menu for a MRU file.
 
2435
      if (!GetMenuString(hMenu, MRU_START_ID + i, szMRU[i], countof(szMRU[0]),
 
2436
          MF_BYCOMMAND))
 
2437
      {
 
2438
         szMRU[i][3] = TEXT('\0');
 
2439
      }
 
2440
 
 
2441
      // Check for a match.
 
2442
      if (!_tcsicmp(szFile, &szMRU[i][3])) {
 
2443
         szMRU[i][3] = TEXT('\0');
 
2444
         fFound = TRUE;
 
2445
      }
 
2446
   }
 
2447
 
 
2448
   // Only update menu if we found a file to remove.
 
2449
   if (fFound) {
 
2450
 
 
2451
      // Clear out our menu's MRU list.
 
2452
      for (i = MRU_START_ID; i < (MRU_START_ID + MRU_MAX_FILE); i++) {
 
2453
         DeleteMenu(hMenu, i, MF_BYCOMMAND);
 
2454
      }
 
2455
 
 
2456
      // Write the rest of our MRU list back to the menu.
 
2457
      for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
 
2458
 
 
2459
         // If this MRU still exists, then add it.
 
2460
         if (szMRU[i][3]) {
 
2461
 
 
2462
            // Build the accelerator prefix for this menu item.
 
2463
            szMRU[i][0] = TEXT('&');
 
2464
            szMRU[i][1] = TEXT('1') + j;
 
2465
            szMRU[i][2] = TEXT(' ');
 
2466
 
 
2467
            // Add the item to our menu.
 
2468
            InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
 
2469
                       szMRU[i]);
 
2470
 
 
2471
            // Increment our actual MRU count.
 
2472
            j++;
 
2473
         }
 
2474
      }
 
2475
   }
 
2476
}
 
2477
 
 
2478
//******************************************************************************
 
2479
void ActivateMRU(UINT uIDItem) {
 
2480
   TCHAR szFile[_MAX_PATH + 4];
 
2481
 
 
2482
   // Get our menu handle.
 
2483
#ifdef _WIN32_WCE
 
2484
   HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
 
2485
#else
 
2486
   HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
 
2487
#endif
 
2488
 
 
2489
   // Query our menu for the selected MRU.
 
2490
   if (GetMenuString(hMenu, uIDItem, szFile, countof(szFile), MF_BYCOMMAND)) {
 
2491
 
 
2492
      // Move past 3 character accelerator prefix and open the file.
 
2493
      ReadZipFileList(&szFile[3]);
 
2494
   }
 
2495
}
 
2496
 
 
2497
 
 
2498
//******************************************************************************
 
2499
//***** Open Zip File Functions
 
2500
//******************************************************************************
 
2501
 
 
2502
void ReadZipFileList(LPCTSTR wszPath) {
 
2503
 
 
2504
   // Show wait cursor.
 
2505
   HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
 
2506
 
 
2507
   TSTRTOMBS(g_szZipFile, wszPath, countof(g_szZipFile));
 
2508
 
 
2509
   // Update our banner to show that we are loading.
 
2510
   g_fLoading = TRUE;
 
2511
   DrawBanner(NULL);
 
2512
 
 
2513
   // Update our caption to show that we are loading.
 
2514
   SetCaptionText(TEXT("Loading"));
 
2515
 
 
2516
   // Clear our list view.
 
2517
   ListView_DeleteAllItems(g_hWndList);
 
2518
 
 
2519
   // Ghost all our Unzip related menu items.
 
2520
   EnableAllMenuItems(IDM_FILE_PROPERTIES,    FALSE);
 
2521
   EnableAllMenuItems(IDM_ACTION_EXTRACT,     FALSE);
 
2522
   EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, FALSE);
 
2523
   EnableAllMenuItems(IDM_ACTION_TEST,        FALSE);
 
2524
   EnableAllMenuItems(IDM_ACTION_TEST_ALL,    FALSE);
 
2525
   EnableAllMenuItems(IDM_ACTION_VIEW,        FALSE);
 
2526
   EnableAllMenuItems(IDM_ACTION_SELECT_ALL,  FALSE);
 
2527
   EnableAllMenuItems(IDM_VIEW_COMMENT,       FALSE);
 
2528
 
 
2529
   // Let Info-ZIP and our callbacks do the work.
 
2530
   SendMessage(g_hWndList, WM_SETREDRAW, FALSE, 0);
 
2531
   int result = DoListFiles(g_szZipFile);
 
2532
   SendMessage(g_hWndList, WM_SETREDRAW, TRUE, 0);
 
2533
 
 
2534
   // Restore/remove cursor.
 
2535
   SetCursor(hCur);
 
2536
 
 
2537
   // Update our column widths
 
2538
   ResizeColumns();
 
2539
 
 
2540
   if ((result == PK_OK) || (result == PK_WARN)) {
 
2541
 
 
2542
      // Sort the items by name.
 
2543
      Sort(0, TRUE);
 
2544
 
 
2545
      // Update this file to our MRU list and menu.
 
2546
      AddFileToMRU(g_szZipFile);
 
2547
 
 
2548
      // Enabled the comment button if the zip file has a comment.
 
2549
      if (lpUserFunctions->cchComment) {
 
2550
         EnableAllMenuItems(IDM_VIEW_COMMENT, TRUE);
 
2551
      }
 
2552
 
 
2553
      // Update other items that are related to having a Zip file loaded.
 
2554
      EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, TRUE);
 
2555
      EnableAllMenuItems(IDM_ACTION_TEST_ALL,    TRUE);
 
2556
      EnableAllMenuItems(IDM_ACTION_SELECT_ALL,  TRUE);
 
2557
 
 
2558
   } else {
 
2559
 
 
2560
      // Make sure we didn't partially load and added a few files.
 
2561
      ListView_DeleteAllItems(g_hWndList);
 
2562
 
 
2563
      // If the file itself is bad or missing, then remove it from our MRU.
 
2564
      if ((result == PK_ERR) || (result == PK_BADERR) || (result == PK_NOZIP) ||
 
2565
          (result == PK_FIND) || (result == PK_EOF))
 
2566
      {
 
2567
         RemoveFileFromMRU(wszPath);
 
2568
      }
 
2569
 
 
2570
      // Display an error.
 
2571
      TCHAR szError[_MAX_PATH + 128];
 
2572
      _stprintf(szError, TEXT("Failure loading \"%s\".\n\n"), wszPath);
 
2573
      _tcscat(szError, GetZipErrorString(result));
 
2574
      MessageBox(g_hWndMain, szError, g_szAppName, MB_OK | MB_ICONERROR);
 
2575
 
 
2576
      // Clear our file status.
 
2577
      *g_szZipFile = '\0';
 
2578
   }
 
2579
 
 
2580
   // Update our caption to show that we are done loading.
 
2581
   SetCaptionText(NULL);
 
2582
 
 
2583
   // Update our banner to show that we are done loading.
 
2584
   g_fLoading = FALSE;
 
2585
   DrawBanner(NULL);
 
2586
}
 
2587
 
 
2588
 
 
2589
//******************************************************************************
 
2590
//***** Zip File Properties Dialog Functions
 
2591
//******************************************************************************
 
2592
 
 
2593
BOOL CALLBACK DlgProcProperties(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
2594
 
 
2595
   switch (uMsg) {
 
2596
 
 
2597
      case WM_INITDIALOG: {
 
2598
 
 
2599
         // Add "General" and "Comments" tabs to tab control.  We are using a
 
2600
         // poor man's version of a property sheet.  We display our 2 pages
 
2601
         // by showing and hiding controls as necessary.  For our purposes,
 
2602
         // this is much easier than dealing with separate property pages.
 
2603
 
 
2604
         TC_ITEM tci;
 
2605
         tci.mask = TCIF_TEXT;
 
2606
         tci.pszText = TEXT("General");
 
2607
         TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 0, &tci);
 
2608
         tci.pszText = TEXT("Comment");
 
2609
         TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 1, &tci);
 
2610
 
 
2611
#ifdef _WIN32_WCE
 
2612
         // Add "Ok" button to caption bar.
 
2613
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
 
2614
                       GetWindowLong(hDlg, GWL_EXSTYLE));
 
2615
#endif
 
2616
         // Center us over our parent.
 
2617
         CenterWindow(hDlg);
 
2618
 
 
2619
         int    directory = -1, readOnly = -1, archive = -1, hidden = -1;
 
2620
         int    system = -1, encrypted = -1;
 
2621
         int    year = -1, month = -1, day = -1, hour = -1, minute = -1, pm = -1;
 
2622
         DWORD  dwSize = 0, dwCompressedSize = 0;
 
2623
         LPCSTR szPath = NULL, szMethod = NULL, szComment = NULL;
 
2624
         DWORD  dwCRC = 0, dwCount = 0, dwCommentCount = 0;
 
2625
         TCHAR  szBuffer[MAX_PATH];
 
2626
 
 
2627
         // Loop through all selected items.
 
2628
         LV_ITEM lvi;
 
2629
         ZeroMemory(&lvi, sizeof(lvi));
 
2630
         lvi.mask = LVIF_PARAM;
 
2631
         lvi.iItem = -1;
 
2632
         while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) != -1) {
 
2633
 
 
2634
            // Get the FILE_NODE for the selected item.
 
2635
            ListView_GetItem(g_hWndList, &lvi);
 
2636
            FILE_NODE *pFile = (FILE_NODE*)lvi.lParam;
 
2637
 
 
2638
            // Merge this file's attributes into our accumulative attributes.
 
2639
            MergeValues(&directory, (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY)  != 0);
 
2640
            MergeValues(&readOnly,  (pFile->dwAttributes & FILE_ATTRIBUTE_READONLY)   != 0);
 
2641
            MergeValues(&archive,   (pFile->dwAttributes & FILE_ATTRIBUTE_ARCHIVE)    != 0);
 
2642
            MergeValues(&hidden,    (pFile->dwAttributes & FILE_ATTRIBUTE_HIDDEN)     != 0);
 
2643
            MergeValues(&system,    (pFile->dwAttributes & FILE_ATTRIBUTE_SYSTEM)     != 0);
 
2644
            MergeValues(&encrypted, (pFile->dwAttributes & ZFILE_ATTRIBUTE_ENCRYPTED) != 0);
 
2645
 
 
2646
            // Merge this file's date/time into our accumulative date/time.
 
2647
            int curHour = (pFile->dwModified >> 6) & 0x001F;
 
2648
            MergeValues(&year,   (pFile->dwModified >> 20) & 0x0FFF);
 
2649
            MergeValues(&month,  (pFile->dwModified >> 16) & 0x000F);
 
2650
            MergeValues(&day,    (pFile->dwModified >> 11) & 0x001F);
 
2651
            MergeValues(&hour,   (curHour % 12) ? (curHour % 12) : 12);
 
2652
            MergeValues(&minute, pFile->dwModified & 0x003F);
 
2653
            MergeValues(&pm,     curHour >= 12);
 
2654
 
 
2655
            // Store this file's name.
 
2656
            szPath = pFile->szPathAndMethod;
 
2657
 
 
2658
            // Store this file's CRC.
 
2659
            dwCRC = pFile->dwCRC;
 
2660
 
 
2661
            // Add the size and compressed size to our accumulative sizes.
 
2662
            dwSize += pFile->dwSize;
 
2663
            dwCompressedSize += pFile->dwCompressedSize;
 
2664
 
 
2665
            // Merge in our compression method.
 
2666
            LPCSTR szCurMethod = pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1;
 
2667
            if ((szMethod == NULL) || !strcmp(szMethod, szCurMethod)) {
 
2668
               szMethod = szCurMethod;
 
2669
            } else {
 
2670
               szMethod = "Multiple Methods";
 
2671
            }
 
2672
 
 
2673
            // Increment our file count.
 
2674
            dwCount++;
 
2675
 
 
2676
            // Increment our comment count if this file has a comment.
 
2677
            if (pFile->szComment) {
 
2678
               szComment = pFile->szComment;
 
2679
               dwCommentCount++;
 
2680
            }
 
2681
         };
 
2682
 
 
2683
         if (dwCount > 1) {
 
2684
 
 
2685
            // If multiple items selected, then display a selected count string
 
2686
            // in place of the file name.
 
2687
            _stprintf(szBuffer, TEXT("%u items selected."), dwCount);
 
2688
            SetDlgItemText(hDlg, IDC_FILE, szBuffer);
 
2689
 
 
2690
            // Display "Multiple" for CRC if multiple items selected.
 
2691
            SetDlgItemText(hDlg, IDC_CRC, TEXT("Multiple CRCs"));
 
2692
 
 
2693
         } else {
 
2694
 
 
2695
            // Set the file name text for the single item selected.
 
2696
            MBSTOTSTR(szBuffer, szPath, countof(szBuffer));
 
2697
            ForwardSlashesToBackSlashes(szBuffer);
 
2698
            SetDlgItemText(hDlg, IDC_FILE, szBuffer);
 
2699
 
 
2700
            // Set the CRC text for the single item selected.
 
2701
            _stprintf(szBuffer, TEXT("0x%08X"), dwCRC);
 
2702
            SetDlgItemText(hDlg, IDC_CRC, szBuffer);
 
2703
         }
 
2704
 
 
2705
         // Set the Size tally text.
 
2706
         FormatValue(szBuffer, dwSize);
 
2707
         _tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
 
2708
         SetDlgItemText(hDlg, IDC_FILE_SIZE, szBuffer);
 
2709
 
 
2710
         // Set the Compressed Size tally text.
 
2711
         FormatValue(szBuffer, dwCompressedSize);
 
2712
         _tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
 
2713
         SetDlgItemText(hDlg, IDC_COMPRESSED_SIZE, szBuffer);
 
2714
 
 
2715
         // Set the Compression Factor text.
 
2716
         int factor = ratio(dwSize, dwCompressedSize);
 
2717
         _stprintf(szBuffer, TEXT("%d.%d%%"), factor / 10,
 
2718
                   ((factor < 0) ? -factor : factor) % 10);
 
2719
         SetDlgItemText(hDlg, IDC_COMPRESSON_FACTOR, szBuffer);
 
2720
 
 
2721
         // Set the Compression Method text.
 
2722
         MBSTOTSTR(szBuffer, szMethod, countof(szBuffer));
 
2723
         SetDlgItemText(hDlg, IDC_COMPRESSION_METHOD, szBuffer);
 
2724
 
 
2725
         // Set the Attribute check boxes.
 
2726
         CheckThreeStateBox(hDlg, IDC_DIRECTORY, directory);
 
2727
         CheckThreeStateBox(hDlg, IDC_READONLY,  readOnly);
 
2728
         CheckThreeStateBox(hDlg, IDC_ARCHIVE,   archive);
 
2729
         CheckThreeStateBox(hDlg, IDC_HIDDEN,    hidden);
 
2730
         CheckThreeStateBox(hDlg, IDC_SYSTEM,    system);
 
2731
         CheckThreeStateBox(hDlg, IDC_ENCRYPTED, encrypted);
 
2732
 
 
2733
         // Build and set the Modified Date text.  The MS compiler does not
 
2734
         // consider "??/" to be a valid string.  "??/" is a trigraph that is
 
2735
         // turned into "\" by the preprocessor and causes grief for the compiler.
 
2736
         LPTSTR psz = szBuffer;
 
2737
         psz += ((month  < 0) ? _stprintf(psz, TEXT("?\?/")) :
 
2738
                                _stprintf(psz, TEXT("%u/"), month));
 
2739
         psz += ((day    < 0) ? _stprintf(psz, TEXT("?\?/")) :
 
2740
                                _stprintf(psz, TEXT("%u/"), day));
 
2741
         psz += ((year   < 0) ? _stprintf(psz, TEXT("?\? ")) :
 
2742
                                _stprintf(psz, TEXT("%u "), year % 100));
 
2743
         psz += ((hour   < 0) ? _stprintf(psz, TEXT("?\?:")) :
 
2744
                                _stprintf(psz, TEXT("%u:"), hour));
 
2745
         psz += ((minute < 0) ? _stprintf(psz, TEXT("?\? ")) :
 
2746
                                _stprintf(psz, TEXT("%02u "), minute));
 
2747
         psz += ((pm     < 0) ? _stprintf(psz, TEXT("?M")) :
 
2748
                                _stprintf(psz, TEXT("%cM"), pm ? TEXT('P') : TEXT('A')));
 
2749
         SetDlgItemText(hDlg, IDC_MODIFIED, szBuffer);
 
2750
 
 
2751
         // Store a global handle to our edit control.
 
2752
         g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
 
2753
 
 
2754
         // Disable our edit box from being edited.
 
2755
         DisableEditing(g_hWndEdit);
 
2756
 
 
2757
         // Stuff the appropriate message into the Comment edit control.
 
2758
         if (dwCommentCount == 0) {
 
2759
            if (dwCount == 1) {
 
2760
               AddTextToEdit("This file does not have a comment.");
 
2761
            } else {
 
2762
               AddTextToEdit("None of the selected files have a comment.");
 
2763
            }
 
2764
         } else if (dwCount == 1) {
 
2765
            AddTextToEdit(szComment);
 
2766
         } else {
 
2767
            CHAR szTemp[64];
 
2768
            _stprintf(szBuffer, TEXT("%u of the selected files %s a comment."),
 
2769
                      dwCommentCount, (dwCommentCount == 1)? TEXT("has") : TEXT("have"));
 
2770
            TSTRTOMBS(szTemp, szBuffer, countof(szTemp));
 
2771
            AddTextToEdit(szTemp);
 
2772
         }
 
2773
         g_hWndEdit = NULL;
 
2774
 
 
2775
 
 
2776
         // Whooh, done with WM_INITDIALOG
 
2777
         return TRUE;
 
2778
      }
 
2779
 
 
2780
      case WM_NOTIFY:
 
2781
         // Check to see if tab control was changed to new tab.
 
2782
         if (((NMHDR*)lParam)->code == TCN_SELCHANGE) {
 
2783
            HWND hWndTab     = ((NMHDR*)lParam)->hwndFrom;
 
2784
            HWND hWndComment = GetDlgItem(hDlg, IDC_COMMENT);
 
2785
            HWND hWnd        = GetWindow(hDlg, GW_CHILD);
 
2786
 
 
2787
            // If General tab selected, hide comment edit box and show all other controls.
 
2788
            if (TabCtrl_GetCurSel(hWndTab) == 0) {
 
2789
               while (hWnd) {
 
2790
                  ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd != hWndComment)) ?
 
2791
                             SW_SHOW : SW_HIDE);
 
2792
                  hWnd = GetWindow(hWnd, GW_HWNDNEXT);
 
2793
               }
 
2794
 
 
2795
            // If Comment tab selected, hide all controls except comment edit box.
 
2796
            } else {
 
2797
               while (hWnd) {
 
2798
                  ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd == hWndComment)) ?
 
2799
                             SW_SHOW : SW_HIDE);
 
2800
                  hWnd = GetWindow(hWnd, GW_HWNDNEXT);
 
2801
               }
 
2802
            }
 
2803
         }
 
2804
         return FALSE;
 
2805
 
 
2806
      case WM_COMMAND:
 
2807
         // Exit the dialog on OK (Enter) or CANCEL (Esc).
 
2808
         if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
 
2809
            EndDialog(hDlg, LOWORD(wParam));
 
2810
         }
 
2811
         return FALSE;
 
2812
   }
 
2813
   return FALSE;
 
2814
}
 
2815
 
 
2816
//******************************************************************************
 
2817
void MergeValues(int *p1, int p2) {
 
2818
   if ((*p1 == -1) || (*p1 == p2)) {
 
2819
      *p1 = p2;
 
2820
   } else {
 
2821
      *p1 = -2;
 
2822
   }
 
2823
}
 
2824
 
 
2825
//******************************************************************************
 
2826
void CheckThreeStateBox(HWND hDlg, int nIDButton, int state) {
 
2827
   CheckDlgButton(hDlg, nIDButton, (state == 0) ? BST_UNCHECKED :
 
2828
                                   (state == 1) ? BST_CHECKED :
 
2829
                                                  BST_INDETERMINATE);
 
2830
}
 
2831
 
 
2832
 
 
2833
//******************************************************************************
 
2834
//***** Extract/Test Dialog Functions
 
2835
//******************************************************************************
 
2836
 
 
2837
void ExtractOrTestFiles(BOOL fExtract) {
 
2838
 
 
2839
   EXTRACT_INFO ei;
 
2840
   ZeroMemory(&ei, sizeof(ei));
 
2841
 
 
2842
   // Set our Extract or Test flag.
 
2843
   ei.fExtract = fExtract;
 
2844
 
 
2845
   // Get the number of selected items and make sure we have at least one item.
 
2846
   if ((ei.dwFileCount = ListView_GetSelectedCount(g_hWndList)) <= 0) {
 
2847
      return;
 
2848
   }
 
2849
 
 
2850
   // If we are not extracting/testing all, then create and buffer large enough to
 
2851
   // hold the file list for all the selected files.
 
2852
   if ((int)ei.dwFileCount != ListView_GetItemCount(g_hWndList)) {
 
2853
      ei.szFileList = new LPSTR[ei.dwFileCount + 1];
 
2854
      if (!ei.szFileList) {
 
2855
         MessageBox(g_hWndMain, GetZipErrorString(PK_MEM), g_szAppName,
 
2856
                    MB_ICONERROR | MB_OK);
 
2857
         return;
 
2858
      }
 
2859
   }
 
2860
 
 
2861
   ei.dwFileCount = 0;
 
2862
   ei.dwByteCount = 0;
 
2863
 
 
2864
   LV_ITEM lvi;
 
2865
   ZeroMemory(&lvi, sizeof(lvi));
 
2866
   lvi.mask = LVIF_PARAM;
 
2867
   lvi.iItem = -1;
 
2868
 
 
2869
   // Walk through all the selected files to build our counts and set our file
 
2870
   // list pointers into our FILE_NODE paths for each selected item.
 
2871
   while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) >= 0) {
 
2872
      ListView_GetItem(g_hWndList, &lvi);
 
2873
      if (ei.szFileList) {
 
2874
         ei.szFileList[ei.dwFileCount] = ((FILE_NODE*)lvi.lParam)->szPathAndMethod;
 
2875
      }
 
2876
      ei.dwFileCount++;
 
2877
      ei.dwByteCount += ((FILE_NODE*)lvi.lParam)->dwSize;
 
2878
   }
 
2879
   if (ei.szFileList) {
 
2880
      ei.szFileList[ei.dwFileCount] = NULL;
 
2881
   }
 
2882
 
 
2883
   // If we are extracting, display the extract dialog to query for parameters.
 
2884
   if (!fExtract || (DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT), g_hWndMain,
 
2885
                                    (DLGPROC)DlgProcExtractOrTest, (LPARAM)&ei) == IDOK))
 
2886
   {
 
2887
      // Display our progress dialog and do the extraction/test.
 
2888
      DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT_PROGRESS), g_hWndMain,
 
2889
                     (DLGPROC)DlgProcExtractProgress, (LPARAM)&ei);
 
2890
   }
 
2891
 
 
2892
   // Free our file list buffer if we created one.
 
2893
   if (ei.szFileList) {
 
2894
      delete[] ei.szFileList;
 
2895
   }
 
2896
}
 
2897
 
 
2898
//******************************************************************************
 
2899
BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
2900
 
 
2901
   static EXTRACT_INFO *pei;
 
2902
   TCHAR  szPath[_MAX_PATH];
 
2903
 
 
2904
   switch (uMsg) {
 
2905
 
 
2906
      case WM_INITDIALOG:
 
2907
 
 
2908
         // Store our extract information structure.
 
2909
         pei = (EXTRACT_INFO*)lParam;
 
2910
 
 
2911
         // Load our settings.
 
2912
         pei->fRestorePaths = GetOptionInt(TEXT("RestorePaths"), TRUE);
 
2913
         pei->overwriteMode = (OVERWRITE_MODE)GetOptionInt(TEXT("OverwriteMode"), OM_PROMPT);
 
2914
 
 
2915
         // Load and set our path string.
 
2916
         GetOptionString(TEXT("ExtractToDirectory"), TEXT("\\"), szPath, sizeof(szPath));
 
2917
         SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
 
2918
 
 
2919
         // Set the state of all the controls.
 
2920
         SetDlgItemText(hDlg, IDC_FILE_COUNT, FormatValue(szPath, pei->dwFileCount));
 
2921
         SetDlgItemText(hDlg, IDC_BYTE_COUNT, FormatValue(szPath, pei->dwByteCount));
 
2922
         CheckDlgButton(hDlg, IDC_RESTORE_PATHS, pei->fRestorePaths);
 
2923
         CheckDlgButton(hDlg, IDC_OVERWRITE_PROMPT, pei->overwriteMode == OM_PROMPT);
 
2924
         CheckDlgButton(hDlg, IDC_OVERWRITE_NEWER,  pei->overwriteMode == OM_NEWER);
 
2925
         CheckDlgButton(hDlg, IDC_OVERWRITE_ALWAYS, pei->overwriteMode == OM_ALWAYS);
 
2926
         CheckDlgButton(hDlg, IDC_OVERWRITE_NEVER,  pei->overwriteMode == OM_NEVER);
 
2927
 
 
2928
         // Limit our edit control to max path.
 
2929
         SendDlgItemMessage(hDlg, IDC_EXTRACT_TO, EM_LIMITTEXT, sizeof(szPath) - 1, 0);
 
2930
 
 
2931
         // Center our dialog.
 
2932
         CenterWindow(hDlg);
 
2933
         return TRUE;
 
2934
 
 
2935
      case WM_COMMAND:
 
2936
         switch (LOWORD(wParam)) {
 
2937
 
 
2938
            case IDOK:
 
2939
 
 
2940
               // Force us to read and validate the extract to directory.
 
2941
               SendMessage(hDlg, WM_COMMAND, MAKELONG(IDC_EXTRACT_TO, EN_KILLFOCUS), 0);
 
2942
 
 
2943
               // Get our current path string.
 
2944
               GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
 
2945
 
 
2946
               // Verify our "extract to" path is valid.
 
2947
               if (!SetExtractToDirectory(szPath)) {
 
2948
                  MessageBox(hDlg, TEXT("The directory you entered is invalid or does not exist."),
 
2949
                             g_szAppName, MB_ICONERROR | MB_OK);
 
2950
                  SetFocus(GetDlgItem(hDlg, IDC_EXTRACT_TO));
 
2951
                  return FALSE;
 
2952
               }
 
2953
 
 
2954
               // Query other control values.
 
2955
               pei->fRestorePaths = IsDlgButtonChecked(hDlg, IDC_RESTORE_PATHS);
 
2956
               pei->overwriteMode =
 
2957
                  IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEWER)  ? OM_NEWER  :
 
2958
                  IsDlgButtonChecked(hDlg, IDC_OVERWRITE_ALWAYS) ? OM_ALWAYS :
 
2959
                  IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEVER)  ? OM_NEVER  : OM_PROMPT;
 
2960
 
 
2961
               // Write our settings.
 
2962
               WriteOptionInt(TEXT("RestorePaths"), pei->fRestorePaths);
 
2963
               WriteOptionInt(TEXT("OverwriteMode"), pei->overwriteMode);
 
2964
               WriteOptionString(TEXT("ExtractToDirectory"), szPath);
 
2965
 
 
2966
               // Fall through to IDCANCEL
 
2967
 
 
2968
            case IDCANCEL:
 
2969
               EndDialog(hDlg, LOWORD(wParam));
 
2970
               return FALSE;
 
2971
 
 
2972
            case IDC_EXTRACT_TO:
 
2973
 
 
2974
               // Make sure the path ends in a wack (\).
 
2975
               if (HIWORD(wParam) == EN_KILLFOCUS) {
 
2976
                  GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
 
2977
                  size_t length = _tcslen(szPath);
 
2978
                  if ((length == 0) || szPath[length - 1] != TEXT('\\')) {
 
2979
                     szPath[length    ] = TEXT('\\');
 
2980
                     szPath[length + 1] = TEXT('\0');
 
2981
                     SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
 
2982
                  }
 
2983
               }
 
2984
               return FALSE;
 
2985
 
 
2986
            case IDC_BROWSE:
 
2987
               GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
 
2988
               if (FolderBrowser(szPath, countof(szPath))) {
 
2989
                  SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
 
2990
               }
 
2991
               return FALSE;
 
2992
         }
 
2993
         return FALSE;
 
2994
   }
 
2995
   return FALSE;
 
2996
}
 
2997
 
 
2998
 
 
2999
//******************************************************************************
 
3000
//***** Folder Browsing Dialog Functions
 
3001
//******************************************************************************
 
3002
 
 
3003
BOOL FolderBrowser(LPTSTR szPath, DWORD dwLength) {
 
3004
 
 
3005
#ifdef _WIN32_WCE
 
3006
 
 
3007
   // On Windows CE, we use a common save-as dialog to query the diretory.  We
 
3008
   // display the dialog in this function, and then we sublass it.  Our subclass
 
3009
   // functions tweaks the dialog a bit and and returns the path.
 
3010
 
 
3011
   ForwardSlashesToBackSlashes(szPath);
 
3012
 
 
3013
   TCHAR szInitialDir[_MAX_PATH];
 
3014
   _tcscpy(szInitialDir, szPath);
 
3015
 
 
3016
   // Remove trailing wacks from path - The common dialog doesn't like them.
 
3017
   size_t length = _tcslen(szInitialDir);
 
3018
   while ((length > 0) && (szInitialDir[length - 1] == TEXT('\\'))) {
 
3019
      szInitialDir[--length] = TEXT('\0');
 
3020
   }
 
3021
 
 
3022
   // Set up the parameters for our save-as dialog.
 
3023
   OPENFILENAME ofn;
 
3024
   ZeroMemory(&ofn, sizeof(ofn));
 
3025
   ofn.lStructSize     = sizeof(ofn);
 
3026
   ofn.hwndOwner       = g_hWndMain;
 
3027
   ofn.hInstance       = g_hInst;
 
3028
   ofn.lpstrFilter     = TEXT(" \0!\0");
 
3029
   ofn.nFilterIndex    = 1;
 
3030
   ofn.lpstrFile       = szPath;
 
3031
   ofn.nMaxFile        = dwLength;
 
3032
   ofn.lpstrInitialDir = *szInitialDir ? szInitialDir : NULL;
 
3033
   ofn.lpstrTitle      = TEXT("Extract To");
 
3034
   ofn.Flags           = OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_NOTESTFILECREATE;
 
3035
 
 
3036
   // Post a message to our main window telling it that we are about to create
 
3037
   // a save as dialog.  Our main window will receive this message after the
 
3038
   // save as dialog is created.  This gives us a change to subclass the save as
 
3039
   // dialog.
 
3040
   PostMessage(g_hWndMain, WM_PRIVATE, MSG_SUBCLASS_DIALOG, 0);
 
3041
 
 
3042
   // Create and display the common save-as dialog.
 
3043
   if (GetSaveFileName(&ofn)) {
 
3044
 
 
3045
      // If success, then remove are special "!" filename from the end.
 
3046
      szPath[_tcslen(szPath) - 1] = TEXT('\0');
 
3047
      return TRUE;
 
3048
   }
 
3049
   return FALSE;
 
3050
 
 
3051
#else // !_WIN32_WCE
 
3052
 
 
3053
   // On Windows NT, the shell provides us with a nice folder browser dialog.
 
3054
   // We don't need to jump through any hoops to make it work like on Windows CE.
 
3055
   // The only problem is that on VC 4.0, the libraries don't export the UNICODE
 
3056
   // shell APIs because only Win95 had a shell library at the time.  The
 
3057
   // following code requires headers and libs from VC 4.2 or later.
 
3058
 
 
3059
   // Set up our BROWSEINFO structure.
 
3060
   BROWSEINFO bi;
 
3061
   ZeroMemory(&bi, sizeof(bi));
 
3062
   bi.hwndOwner = g_hWndMain;
 
3063
   bi.pszDisplayName = szPath;
 
3064
   bi.lpszTitle = TEXT("Extract To");
 
3065
   bi.ulFlags = BIF_RETURNONLYFSDIRS;
 
3066
 
 
3067
   // Prompt user for path.
 
3068
   LPITEMIDLIST piidl = SHBrowseForFolder(&bi);
 
3069
   if (!piidl) {
 
3070
      return FALSE;
 
3071
   }
 
3072
 
 
3073
   // Build path string.
 
3074
   SHGetPathFromIDList(piidl, szPath);
 
3075
 
 
3076
   // Free the PIDL returned by SHBrowseForFolder.
 
3077
   LPMALLOC pMalloc = NULL;
 
3078
   SHGetMalloc(&pMalloc);
 
3079
   pMalloc->Free(piidl);
 
3080
 
 
3081
   // Add trailing wack if one is not present.
 
3082
   size_t length = _tcslen(szPath);
 
3083
   if ((length > 0) && (szPath[length - 1] != TEXT('\\'))) {
 
3084
      szPath[length++] = TEXT('\\');
 
3085
      szPath[length]   = TEXT('\0');
 
3086
   }
 
3087
 
 
3088
   return TRUE;
 
3089
 
 
3090
#endif // _WIN32_WCE
 
3091
}
 
3092
 
 
3093
//******************************************************************************
 
3094
#ifdef _WIN32_WCE
 
3095
BOOL CALLBACK DlgProcBrowser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
3096
 
 
3097
   // This is our subclass of Windows CE's common save-as dialog.  We intercept
 
3098
   // the messages we care about and forward everything else to the original
 
3099
   // window procedure for the dialog.
 
3100
 
 
3101
   if (uMsg == WM_PRIVATE) { // wParam always equals MSG_INIT_DIALOG
 
3102
 
 
3103
      RECT rc1, rc2;
 
3104
 
 
3105
      // Get the window rectangle for the name edit control.
 
3106
      HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_NAME_EDIT);
 
3107
      GetWindowRect(hWnd, &rc1);
 
3108
      POINT pt1 = { rc1.left, rc1.top };
 
3109
      ScreenToClient(hDlg, &pt1);
 
3110
 
 
3111
      // Hide all the windows we don't want.
 
3112
      ShowWindow(hWnd, SW_HIDE);
 
3113
      ShowWindow(GetDlgItem(hDlg, IDC_SAVE_NAME_PROMPT), SW_HIDE);
 
3114
      ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_PROMPT), SW_HIDE);
 
3115
      ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_LIST), SW_HIDE);
 
3116
 
 
3117
      // Get the window rectangle for the file list.
 
3118
      hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
 
3119
      GetWindowRect(hWnd, &rc2);
 
3120
      POINT pt2 = { rc2.left, rc2.top };
 
3121
      ScreenToClient(hDlg, &pt2);
 
3122
 
 
3123
      // Resize the file list to fill the dialog.
 
3124
      MoveWindow(hWnd, pt2.x, pt2.y, rc2.right - rc2.left, rc1.bottom - rc2.top, TRUE);
 
3125
 
 
3126
   } else if ((uMsg == WM_COMMAND) && (LOWORD(wParam) == IDOK)) {
 
3127
 
 
3128
      // Get our file list window.
 
3129
      HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
 
3130
 
 
3131
      // Check to see if a directory is selected.
 
3132
      if (ListView_GetNextItem(hWnd, -1, LVNI_SELECTED) >= 0) {
 
3133
 
 
3134
         // If a directory is highlighted, then we post ourself a "Ok".  The "Ok"
 
3135
         // we are processing now will cause us to change into the highlighted
 
3136
         // directory, and our posted "Ok" will close the dialog in that directory.
 
3137
         PostMessage(hDlg, uMsg, wParam, lParam);
 
3138
 
 
3139
      } else {
 
3140
         // If no directory is selected, then enter the imaginary filename "!"
 
3141
         // into the name edit control and let the "Ok" end this dialog. The
 
3142
         // result will be the correct path with a "\!" at the end.
 
3143
         SetDlgItemText(hDlg, IDC_SAVE_NAME_EDIT, TEXT("!"));
 
3144
      }
 
3145
   }
 
3146
 
 
3147
   // Pass all messages to the base control's window proc.
 
3148
   return CallWindowProc(g_wpSaveAsDlg, hDlg, uMsg, wParam, lParam);
 
3149
}
 
3150
#endif // _WIN32_WCE
 
3151
 
 
3152
//******************************************************************************
 
3153
#ifdef _WIN32_WCE
 
3154
void SubclassSaveAsDlg() {
 
3155
 
 
3156
   // Get our current thread ID so we can compare it to other thread IDs.
 
3157
   DWORD dwThreadId = GetCurrentThreadId();
 
3158
 
 
3159
   // Get the the top window in the z-order that is a child of the desktop.
 
3160
   // Dialogs are always children of the desktop on CE.  This first window
 
3161
   // should be the dialog we are looking for, but we will walk the window list
 
3162
   // just in case.
 
3163
   HWND hWnd = GetWindow(g_hWndMain, GW_HWNDFIRST);
 
3164
 
 
3165
   // Walk the window list.
 
3166
   while (hWnd) {
 
3167
 
 
3168
      // Check to see if this window was created by us and has controls from a
 
3169
      // common "save as" dialog.
 
3170
      if ((GetWindowThreadProcessId(hWnd, NULL) == dwThreadId) &&
 
3171
           GetDlgItem(hWnd, IDC_SAVE_FILE_LIST) &&
 
3172
           GetDlgItem(hWnd, IDC_SAVE_NAME_EDIT))
 
3173
      {
 
3174
         // We found our dialog.  Subclass it.
 
3175
         g_wpSaveAsDlg = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
 
3176
         SetWindowLong(hWnd, GWL_WNDPROC, (LONG)DlgProcBrowser);
 
3177
 
 
3178
         // Send our new dialog a message so it can do its initialization.
 
3179
         SendMessage(hWnd, WM_PRIVATE, MSG_INIT_DIALOG, 0);
 
3180
      }
 
3181
 
 
3182
      // Get the next window in our window list.
 
3183
      hWnd = GetWindow(hWnd, GW_HWNDNEXT);
 
3184
   }
 
3185
}
 
3186
#endif // _WIN32_WCE
 
3187
 
 
3188
 
 
3189
//******************************************************************************
 
3190
//***** Extraction/Test/View Progress Dialog Functions
 
3191
//******************************************************************************
 
3192
 
 
3193
BOOL CALLBACK DlgProcExtractProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
3194
 
 
3195
   static EXTRACT_INFO *pei;
 
3196
   static BOOL fComplete;
 
3197
   static HWND hWndButton;
 
3198
   TCHAR szBuffer[32];
 
3199
 
 
3200
   switch (uMsg) {
 
3201
 
 
3202
      case WM_INITDIALOG:
 
3203
 
 
3204
         // Globally store our handle so our worker thread can post to us.
 
3205
         g_hDlgProgress = hDlg;
 
3206
 
 
3207
         // Get a pointer to our extract information structure.
 
3208
         pei = (EXTRACT_INFO*)lParam;
 
3209
 
 
3210
         // Clear our complete flag.  It will be set to TRUE when done.
 
3211
         fComplete = FALSE;
 
3212
 
 
3213
         // Get and store our edit control.
 
3214
         g_hWndEdit = GetDlgItem(hDlg, IDC_LOG);
 
3215
 
 
3216
         // Disable our edit box from being edited.
 
3217
         DisableEditing(g_hWndEdit);
 
3218
 
 
3219
         // Store a static handle for our Abort/Close button.
 
3220
         hWndButton = GetDlgItem(hDlg, IDCANCEL);
 
3221
 
 
3222
#ifdef _WIN32_WCE
 
3223
 
 
3224
         // Set our No-Drag style
 
3225
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_NODRAG |GetWindowLong(hDlg, GWL_EXSTYLE));
 
3226
 
 
3227
         RECT rc1, rc2, rcEdit;
 
3228
 
 
3229
         // Get our current client size.
 
3230
         GetClientRect(hDlg, &rc1);
 
3231
 
 
3232
         // Get the window rectangle for the edit control in client coordinates.
 
3233
         GetWindowRect(g_hWndEdit, &rcEdit);
 
3234
         ScreenToClient(hDlg, ((POINT*)&rcEdit));
 
3235
         ScreenToClient(hDlg, ((POINT*)&rcEdit) + 1);
 
3236
 
 
3237
         // Resize our dialog to be full screen (same size as parent).
 
3238
         GetWindowRect(g_hWndMain, &rc2);
 
3239
         MoveWindow(hDlg, rc2.left, rc2.top, rc2.right - rc2.left,
 
3240
                    rc2.bottom - rc2.top + 1, FALSE);
 
3241
 
 
3242
         // Get our new client size.
 
3243
         GetClientRect(hDlg, &rc2);
 
3244
 
 
3245
         // Resize our edit box to fill the client.
 
3246
         MoveWindow(g_hWndEdit, rcEdit.left, rcEdit.top,
 
3247
                    (rcEdit.right  - rcEdit.left) + (rc2.right  - rc1.right),
 
3248
                    (rcEdit.bottom - rcEdit.top)  + (rc2.bottom - rc1.bottom),
 
3249
                    FALSE);
 
3250
 
 
3251
#else
 
3252
         // On NT, we just center our dialog over our parent.
 
3253
         CenterWindow(hDlg);
 
3254
#endif
 
3255
 
 
3256
         // Store some globals until the extract/test finishes.
 
3257
         pei->hWndEditFile       = GetDlgItem(hDlg, IDC_FILE);
 
3258
         pei->hWndProgFile       = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
 
3259
         pei->hWndProgTotal      = GetDlgItem(hDlg, IDC_TOTAL_PROGRESS);
 
3260
         pei->hWndPercentage     = GetDlgItem(hDlg, IDC_PERCENTAGE);
 
3261
         pei->hWndFilesProcessed = GetDlgItem(hDlg, IDC_FILES_PROCESSED);
 
3262
         pei->hWndBytesProcessed = GetDlgItem(hDlg, IDC_BYTES_PROCESSED);
 
3263
 
 
3264
         if (pei->fExtract) {
 
3265
            // Set our main window's caption.
 
3266
            SetCaptionText(TEXT("Extracting"));
 
3267
 
 
3268
         } else {
 
3269
            // Set our main window's caption.
 
3270
            SetCaptionText(TEXT("Testing"));
 
3271
 
 
3272
            // Hide the current file progress for test since it never moves.
 
3273
            ShowWindow(pei->hWndProgFile, SW_HIDE);
 
3274
         }
 
3275
 
 
3276
         // Set the ranges on our progress bars.
 
3277
         SendMessage(pei->hWndProgFile,  PBM_SETRANGE, 0,
 
3278
                     MAKELPARAM(0, PROGRESS_MAX));
 
3279
         SendMessage(pei->hWndProgTotal, PBM_SETRANGE, 0,
 
3280
                     MAKELPARAM(0, PROGRESS_MAX));
 
3281
 
 
3282
         // Set our file and byte totals.
 
3283
         SetDlgItemText(hDlg, IDC_FILES_TOTAL,
 
3284
                        FormatValue(szBuffer, pei->dwFileCount));
 
3285
         SetDlgItemText(hDlg, IDC_BYTES_TOTAL,
 
3286
                        FormatValue(szBuffer, pei->dwByteCount));
 
3287
 
 
3288
         // Launch our Extract/Test thread and wait for WM_PRIVATE
 
3289
         DoExtractOrTestFiles(g_szZipFile, pei);
 
3290
 
 
3291
         return TRUE;
 
3292
 
 
3293
 
 
3294
      case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
 
3295
                       // test/extract is complete.
 
3296
 
 
3297
         // Check to see if the operation was a success
 
3298
         if ((pei->result == PK_OK) || (pei->result == PK_WARN)) {
 
3299
 
 
3300
            // Set all our fields to their "100%" settings.
 
3301
            SendMessage(pei->hWndProgFile,  PBM_SETPOS, PROGRESS_MAX, 0);
 
3302
            SendMessage(pei->hWndProgTotal, PBM_SETPOS, PROGRESS_MAX, 0);
 
3303
            SetWindowText(pei->hWndPercentage, TEXT("100%"));
 
3304
            SetDlgItemText(hDlg, IDC_FILES_PROCESSED,
 
3305
                           FormatValue(szBuffer, pei->dwFileCount));
 
3306
            SetDlgItemText(hDlg, IDC_BYTES_PROCESSED,
 
3307
                           FormatValue(szBuffer, pei->dwByteCount));
 
3308
         }
 
3309
 
 
3310
         // Update our status text.
 
3311
         SetWindowText(pei->hWndEditFile,
 
3312
            (pei->result == PK_OK)      ? TEXT("Completed.  There were no warnings or errors.") :
 
3313
            (pei->result == PK_WARN)    ? TEXT("Completed.  There was one or more warnings.") :
 
3314
            (pei->result == PK_ABORTED) ? TEXT("Aborted.  There may be warnings or errors.") :
 
3315
                                          TEXT("Completed.  There was one or more errors."));
 
3316
 
 
3317
         // Clear our global edit handle.
 
3318
         g_hWndEdit = NULL;
 
3319
 
 
3320
         // Update our caption to show that we are done extracting/testing.
 
3321
         SetCaptionText(NULL);
 
3322
 
 
3323
         // Change our abort button to now read "Close".
 
3324
         SetWindowText(hWndButton, TEXT("&Close"));
 
3325
         EnableWindow(hWndButton, TRUE);
 
3326
 
 
3327
         // Display an error dialog if an error occurred.
 
3328
         if ((pei->result != PK_OK) && (pei->result != PK_WARN)) {
 
3329
            MessageBox(hDlg, GetZipErrorString(pei->result),
 
3330
                       g_szAppName, MB_ICONERROR | MB_OK);
 
3331
         }
 
3332
 
 
3333
         // We are done.  Allow the user to close the dialog.
 
3334
         fComplete = TRUE;
 
3335
         return FALSE;
 
3336
 
 
3337
      case WM_COMMAND:
 
3338
         switch (LOWORD(wParam)) {
 
3339
            case IDCANCEL:
 
3340
               // If abort is pressed, then set a flag that our worker thread
 
3341
               // periodically checks to decide if it needs to bail out.
 
3342
               if (!fComplete && !pei->fAbort) {
 
3343
                  pei->fAbort = TRUE;
 
3344
                  SetWindowText(hWndButton, TEXT("Aborting..."));
 
3345
                  EnableWindow(hWndButton, FALSE);
 
3346
                  return FALSE;
 
3347
               }
 
3348
               // fall through to IDOK
 
3349
 
 
3350
            case IDOK:
 
3351
               // Don't allow dialog to close until extract/test is complete.
 
3352
               if (fComplete) {
 
3353
                  g_hDlgProgress = NULL;
 
3354
                  EndDialog(hDlg, LOWORD(wParam));
 
3355
               }
 
3356
               return FALSE;
 
3357
         }
 
3358
         return FALSE;
 
3359
   }
 
3360
   return FALSE;
 
3361
}
 
3362
 
 
3363
//******************************************************************************
 
3364
BOOL CALLBACK DlgProcViewProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
3365
 
 
3366
   static EXTRACT_INFO *pei;
 
3367
 
 
3368
   switch (uMsg) {
 
3369
 
 
3370
      case WM_INITDIALOG:
 
3371
 
 
3372
         // Globally store our handle so our worker thread can post to us.
 
3373
         g_hDlgProgress = hDlg;
 
3374
 
 
3375
         // Get a pointer to our extract information structure.
 
3376
         pei = (EXTRACT_INFO*)lParam;
 
3377
 
 
3378
         // Center our dialog over our parent.
 
3379
         CenterWindow(hDlg);
 
3380
 
 
3381
         // Store some globals until the extract finishes.
 
3382
         pei->hWndProgFile = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
 
3383
 
 
3384
         // Set the ranges on our progress bar.
 
3385
         SendDlgItemMessage(hDlg, IDC_FILE_PROGRESS, PBM_SETRANGE, 0,
 
3386
                            MAKELPARAM(0, PROGRESS_MAX));
 
3387
 
 
3388
         // Launch our Extract thread and wait for WM_PRIVATE message.
 
3389
         DoExtractOrTestFiles(g_szZipFile, pei);
 
3390
 
 
3391
         return TRUE;
 
3392
 
 
3393
      case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
 
3394
                       // test/extract is complete.
 
3395
 
 
3396
         // We are done.  Close our dialog.  Any errors will be reported by
 
3397
         // OnActionView().
 
3398
         g_hDlgProgress = NULL;
 
3399
         EndDialog(hDlg, LOWORD(wParam));
 
3400
         return FALSE;
 
3401
 
 
3402
      case WM_COMMAND:
 
3403
         // If abort is pressed, then set a flag that our worker thread
 
3404
         // periodically checks to decide if it needs to bail out.
 
3405
         if ((LOWORD(wParam) == IDCANCEL) && !pei->fAbort) {
 
3406
            pei->fAbort = TRUE;
 
3407
            SetWindowText(GetDlgItem(hDlg, IDCANCEL), TEXT("Aborting..."));
 
3408
            EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
 
3409
            return FALSE;
 
3410
         }
 
3411
   }
 
3412
 
 
3413
   return FALSE;
 
3414
}
 
3415
 
 
3416
//******************************************************************************
 
3417
void UpdateProgress(EXTRACT_INFO *pei, BOOL fFull) {
 
3418
 
 
3419
   DWORD dwFile, dwTotal, dwPercentage;
 
3420
   TCHAR szBuffer[_MAX_PATH + 32];
 
3421
 
 
3422
   // Compute our file progress bar position.
 
3423
   if (pei->dwBytesTotalThisFile) {
 
3424
      dwFile = (DWORD)(((DWORDLONG)PROGRESS_MAX *
 
3425
                        (DWORDLONG)pei->dwBytesWrittenThisFile) /
 
3426
                        (DWORDLONG)pei->dwBytesTotalThisFile);
 
3427
   } else {
 
3428
      dwFile = PROGRESS_MAX;
 
3429
   }
 
3430
 
 
3431
   // Set our file progress indicators.
 
3432
   SendMessage(pei->hWndProgFile,  PBM_SETPOS, dwFile,  0);
 
3433
 
 
3434
   // If we are only updating our View Progress dialog, then we are done.
 
3435
   if (!pei->hWndProgTotal) {
 
3436
      return;
 
3437
   }
 
3438
 
 
3439
   // Compute our total progress bar position.
 
3440
   dwTotal = (DWORD)(((DWORDLONG)PROGRESS_MAX *
 
3441
                      (DWORDLONG)(pei->dwBytesWrittenPreviousFiles +
 
3442
                                  pei->dwBytesWrittenThisFile +
 
3443
                                  pei->dwFile)) /
 
3444
                      (DWORDLONG)(pei->dwByteCount +
 
3445
                                  pei->dwFileCount));
 
3446
   dwPercentage = dwTotal / (PROGRESS_MAX / 100);
 
3447
 
 
3448
   // Set our total progress indicators.
 
3449
   SendMessage(pei->hWndProgTotal, PBM_SETPOS, dwTotal, 0);
 
3450
 
 
3451
   // Set our total percentage text.
 
3452
   _stprintf(szBuffer, TEXT("%u%%"), dwPercentage);
 
3453
   SetWindowText(pei->hWndPercentage, szBuffer);
 
3454
 
 
3455
   // Set our current file and byte process counts.
 
3456
   FormatValue(szBuffer, pei->dwFile - 1);
 
3457
   SetWindowText(pei->hWndFilesProcessed, szBuffer);
 
3458
   FormatValue(szBuffer, pei->dwBytesWrittenPreviousFiles +
 
3459
               pei->dwBytesWrittenThisFile);
 
3460
   SetWindowText(pei->hWndBytesProcessed, szBuffer);
 
3461
 
 
3462
 
 
3463
   if (fFull) {
 
3464
 
 
3465
      // Build our message string.
 
3466
      _tcscpy(szBuffer, pei->fExtract ? TEXT("Extract") : TEXT("Test"));
 
3467
      size_t preflen = _tcslen(szBuffer);
 
3468
      MBSTOTSTR(szBuffer+preflen, pei->szFile,countof(szBuffer)-preflen);
 
3469
 
 
3470
      // Change all forward slashes to back slashes in the buffer.
 
3471
      ForwardSlashesToBackSlashes(szBuffer);
 
3472
 
 
3473
      // Update the file name in our dialog.
 
3474
      SetWindowText(pei->hWndEditFile, szBuffer);
 
3475
   }
 
3476
}
 
3477
 
 
3478
 
 
3479
//******************************************************************************
 
3480
//***** Replace File Dialog Functions
 
3481
//******************************************************************************
 
3482
 
 
3483
int PromptToReplace(LPCSTR szPath) {
 
3484
 
 
3485
   // Check to see if we are extracting for view only.
 
3486
   if (g_fViewing) {
 
3487
 
 
3488
      // Build prompt.
 
3489
      TCHAR szMessage[_MAX_PATH + 128];
 
3490
      _stprintf(szMessage,
 
3491
#ifdef UNICODE
 
3492
         TEXT("A file named \"%S\" has already been extracted for viewing.  ")
 
3493
#else
 
3494
         TEXT("A file named \"%s\" has already been extracted for viewing.  ")
 
3495
#endif
 
3496
         TEXT("That file might be opened and locked for viewing by another application.\n\n")
 
3497
         TEXT("Would you like to attempt to overwrite it with the new file?"),
 
3498
         GetFileFromPath(szPath));
 
3499
 
 
3500
      // Display prompt.
 
3501
      if (IDYES == MessageBox(g_hDlgProgress, szMessage, g_szAppName,
 
3502
                              MB_ICONWARNING | MB_YESNO))
 
3503
      {
 
3504
         // Tell Info-ZIP to continue with extraction.
 
3505
         return IDM_REPLACE_YES;
 
3506
      }
 
3507
 
 
3508
      // Remember that the file was skipped and tell Info-ZIP to abort extraction.
 
3509
      g_fSkipped = TRUE;
 
3510
      return IDM_REPLACE_NO;
 
3511
   }
 
3512
 
 
3513
   // Otherwise, do the normal replace prompt dialog.
 
3514
   return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_REPLACE), g_hWndMain,
 
3515
                         (DLGPROC)DlgProcReplace, (LPARAM)szPath);
 
3516
}
 
3517
 
 
3518
//******************************************************************************
 
3519
BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
3520
   TCHAR szMessage[_MAX_PATH + 32];
 
3521
 
 
3522
   switch (uMsg) {
 
3523
 
 
3524
      case WM_INITDIALOG:
 
3525
 
 
3526
         // Play the question tone to alert the user.
 
3527
         MessageBeep(MB_ICONQUESTION);
 
3528
 
 
3529
         // Display a message with the file name.
 
3530
#ifdef UNICODE
 
3531
         _stprintf(szMessage, TEXT("\"%S\" already exists."), (LPCSTR)lParam);
 
3532
#else
 
3533
         _stprintf(szMessage, TEXT("\"%s\" already exists."), (LPCSTR)lParam);
 
3534
#endif
 
3535
 
 
3536
         // Change all forward slashes to back slashes in the buffer.
 
3537
         ForwardSlashesToBackSlashes(szMessage);
 
3538
 
 
3539
         // Display the file string.
 
3540
         SetDlgItemText(hDlg, IDC_FILE, szMessage);
 
3541
 
 
3542
         // Center our dialog over our parent.
 
3543
         CenterWindow(hDlg);
 
3544
         return TRUE;
 
3545
 
 
3546
      case WM_COMMAND:
 
3547
         switch (LOWORD(wParam)) {
 
3548
 
 
3549
            case IDCANCEL:
 
3550
            case IDOK:
 
3551
               EndDialog(hDlg, IDM_REPLACE_NO);
 
3552
               break;
 
3553
 
 
3554
            case IDM_REPLACE_ALL:
 
3555
            case IDM_REPLACE_NONE:
 
3556
            case IDM_REPLACE_YES:
 
3557
            case IDM_REPLACE_NO:
 
3558
               EndDialog(hDlg, wParam);
 
3559
               break;
 
3560
         }
 
3561
         return FALSE;
 
3562
   }
 
3563
   return FALSE;
 
3564
}
 
3565
 
 
3566
 
 
3567
//******************************************************************************
 
3568
//***** Password Dialog Functions
 
3569
//******************************************************************************
 
3570
 
 
3571
#if CRYPT
 
3572
 
 
3573
BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
3574
 
 
3575
   // Return Values:
 
3576
   //    IZ_PW_ENTERED    got some PWD string, use/try it
 
3577
   //    IZ_PW_CANCEL     no password available (for this entry)
 
3578
   //    IZ_PW_CANCELALL  no password, skip any further PWD request
 
3579
   //    IZ_PW_ERROR      failure (no mem, no tty, ...)
 
3580
 
 
3581
   static DECRYPT_INFO *pdi;
 
3582
   TCHAR szMessage[_MAX_PATH + 32];
 
3583
 
 
3584
   switch (uMsg) {
 
3585
 
 
3586
      case WM_INITDIALOG:
 
3587
 
 
3588
         // Play the question tone to alert the user.
 
3589
         MessageBeep(MB_ICONQUESTION);
 
3590
 
 
3591
#ifdef _WIN32_WCE
 
3592
         // Add "Ok" button to caption bar.
 
3593
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
 
3594
                       GetWindowLong(hDlg, GWL_EXSTYLE));
 
3595
#endif
 
3596
 
 
3597
         // Store our decrypt information structure.
 
3598
         pdi = (DECRYPT_INFO*)lParam;
 
3599
 
 
3600
         // Display a message with the file name.
 
3601
#ifdef UNICODE
 
3602
         _stprintf(szMessage, TEXT("\"%S\" is encrypted."), pdi->szFile);
 
3603
#else
 
3604
         _stprintf(szMessage, TEXT("\"%s\" is encrypted."), pdi->szFile);
 
3605
#endif
 
3606
 
 
3607
         // Change all forward slashes to back slashes in the buffer.
 
3608
         ForwardSlashesToBackSlashes(szMessage);
 
3609
 
 
3610
         // Display the message with the file name.
 
3611
         SetDlgItemText(hDlg, IDC_FILE, szMessage);
 
3612
 
 
3613
         // Display the appropriate prompt.
 
3614
         if (pdi->retry) {
 
3615
            _stprintf(szMessage, TEXT("Password was incorrect. Please re-enter (%d/%d)."),
 
3616
                     MAX_PASSWORD_RETRIES - pdi->retry + 2, MAX_PASSWORD_RETRIES + 1);
 
3617
            SetDlgItemText(hDlg, IDC_PROMPT, szMessage);
 
3618
         } else {
 
3619
            SetDlgItemText(hDlg, IDC_PROMPT, TEXT("Please enter the password."));
 
3620
         }
 
3621
 
 
3622
         // Limit the password to the size of the password buffer we have been given.
 
3623
         SendDlgItemMessage(hDlg, IDC_PASSWORD, EM_LIMITTEXT, pdi->nSize - 1, 0);
 
3624
 
 
3625
         // Center our dialog over our parent.
 
3626
         CenterWindow(hDlg);
 
3627
         return TRUE;
 
3628
 
 
3629
      case WM_COMMAND:
 
3630
         switch (LOWORD(wParam)) {
 
3631
 
 
3632
            case IDOK:
 
3633
 
 
3634
               // Store the password in our return password buffer.
 
3635
               GetDlgItemText(hDlg, IDC_PASSWORD, szMessage, countof(szMessage));
 
3636
               TSTRTOMBS(pdi->szPassword, szMessage, pdi->nSize);
 
3637
               EndDialog(hDlg, IZ_PW_ENTERED);
 
3638
               return FALSE;
 
3639
 
 
3640
            case IDCANCEL:
 
3641
               g_fSkipped = TRUE;
 
3642
               EndDialog(hDlg, IZ_PW_CANCEL);
 
3643
               return FALSE;
 
3644
 
 
3645
            case IDC_SKIP_ALL:
 
3646
               g_fSkipped = TRUE;
 
3647
               EndDialog(hDlg, IZ_PW_CANCELALL);
 
3648
               return FALSE;
 
3649
         }
 
3650
         return FALSE;
 
3651
   }
 
3652
   return FALSE;
 
3653
}
 
3654
 
 
3655
#endif // CRYPT
 
3656
 
 
3657
//******************************************************************************
 
3658
//***** View Association Dialog Functions
 
3659
//******************************************************************************
 
3660
 
 
3661
BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
3662
 
 
3663
   static LPTSTR szApp;
 
3664
 
 
3665
   switch (uMsg) {
 
3666
 
 
3667
      case WM_INITDIALOG:
 
3668
         // Store the path buffer for our application.
 
3669
         szApp = (LPTSTR)lParam;
 
3670
 
 
3671
         // Read our default viewer from the registry.
 
3672
#ifdef _WIN32_WCE
 
3673
         GetOptionString(TEXT("FileViewer"), TEXT("\\Windows\\PWord.exe"),
 
3674
                         szApp, sizeof(TCHAR) * _MAX_PATH);
 
3675
#else
 
3676
         GetOptionString(TEXT("FileViewer"), TEXT("notepad.exe"),
 
3677
                         szApp, sizeof(TCHAR) * _MAX_PATH);
 
3678
#endif
 
3679
 
 
3680
         // Limit our edit control to our buffer size.
 
3681
         SendDlgItemMessage(hDlg, IDC_PATH, EM_LIMITTEXT, _MAX_PATH - 1, 0);
 
3682
 
 
3683
         // Set our path string in our dialog.
 
3684
         SetDlgItemText(hDlg, IDC_PATH, szApp);
 
3685
 
 
3686
         // Center our dialog over our parent.
 
3687
         CenterWindow(hDlg);
 
3688
         return TRUE;
 
3689
 
 
3690
      case WM_COMMAND:
 
3691
         switch (LOWORD(wParam)) {
 
3692
 
 
3693
            case IDOK:
 
3694
               // Get the text currently in the path edit box and store it.
 
3695
               GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
 
3696
               WriteOptionString(TEXT("FileViewer"), szApp);
 
3697
               // Fall through
 
3698
 
 
3699
            case IDCANCEL:
 
3700
               EndDialog(hDlg, LOWORD(wParam));
 
3701
               break;
 
3702
 
 
3703
            case IDC_BROWSE:
 
3704
               // Get the text currently in the path edit box.
 
3705
               GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
 
3706
 
 
3707
               // Get the direcory from the path text.
 
3708
               ForwardSlashesToBackSlashes(szApp);
 
3709
               TCHAR szInitialDir[_MAX_PATH], *szFile;
 
3710
               _tcscpy(szInitialDir, szApp);
 
3711
               if (szFile = _tcsrchr(szInitialDir, TEXT('\\'))) {
 
3712
                  *szFile = TEXT('\0');
 
3713
               }
 
3714
 
 
3715
               // Prepare to display browse dialog.
 
3716
               OPENFILENAME ofn;
 
3717
               ZeroMemory(&ofn, sizeof(ofn));
 
3718
               ofn.lStructSize     = sizeof(ofn);
 
3719
               ofn.hwndOwner       = hDlg;
 
3720
               ofn.hInstance       = g_hInst;
 
3721
               ofn.lpstrFilter     = TEXT("Programs (*.exe)\0*.exe\0All Files (*.*)\0*.*\0");
 
3722
               ofn.nFilterIndex    = 1;
 
3723
               ofn.lpstrFile       = szApp;
 
3724
               ofn.nMaxFile        = _MAX_PATH;
 
3725
               ofn.lpstrInitialDir = szInitialDir;
 
3726
               ofn.lpstrTitle      = TEXT("Open With...");
 
3727
               ofn.Flags           = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
 
3728
               ofn.lpstrDefExt     = TEXT("exe");
 
3729
 
 
3730
               // Display the browse dialog and update our path edit box if neccessary.
 
3731
               if (GetOpenFileName(&ofn)) {
 
3732
                  SetDlgItemText(hDlg, IDC_PATH, szApp);
 
3733
               }
 
3734
               break;
 
3735
         }
 
3736
         return FALSE;
 
3737
   }
 
3738
   return FALSE;
 
3739
}
 
3740
 
 
3741
 
 
3742
//******************************************************************************
 
3743
//***** Comment Dialog Functions
 
3744
//******************************************************************************
 
3745
 
 
3746
BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
3747
   RECT    rc;
 
3748
   HCURSOR hCur;
 
3749
   int     result;
 
3750
 
 
3751
   switch (uMsg) {
 
3752
 
 
3753
      case WM_INITDIALOG:
 
3754
         // Get the handle to our edit box and store it globally.
 
3755
         g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
 
3756
 
 
3757
         // Disable our edit box from being edited.
 
3758
         DisableEditing(g_hWndEdit);
 
3759
 
 
3760
#ifdef _WIN32_WCE
 
3761
         // Add "Ok" button to caption bar and make window No-Drag.
 
3762
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | WS_EX_NODRAG |
 
3763
                       GetWindowLong(hDlg, GWL_EXSTYLE));
 
3764
 
 
3765
         // On CE, we resize our dialog to be full screen (same size as parent).
 
3766
         GetWindowRect(g_hWndMain, &rc);
 
3767
         MoveWindow(hDlg, rc.left, rc.top, rc.right - rc.left,
 
3768
                    rc.bottom - rc.top + 1, FALSE);
 
3769
#else
 
3770
         // On NT we just center the dialog.
 
3771
         CenterWindow(hDlg);
 
3772
#endif
 
3773
 
 
3774
         // Set our edit control to be the full size of our dialog.
 
3775
         GetClientRect(hDlg, &rc);
 
3776
         MoveWindow(g_hWndEdit, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
 
3777
 
 
3778
         // Show hour glass cursor while processing comment.
 
3779
         hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
 
3780
 
 
3781
         // Let Info-ZIP and our callbacks do the work.
 
3782
         result = DoGetComment(g_szZipFile);
 
3783
 
 
3784
         // Restore/remove our cursor.
 
3785
         SetCursor(hCur);
 
3786
 
 
3787
         // Display an error dialog if an error occurred.
 
3788
         if ((result != PK_OK) && (result != PK_WARN)) {
 
3789
            MessageBox(g_hWndMain, GetZipErrorString(result), g_szAppName,
 
3790
                       MB_ICONERROR | MB_OK);
 
3791
         }
 
3792
 
 
3793
         // Clear our global edit box handle as we are done with it.
 
3794
         g_hWndEdit = NULL;
 
3795
 
 
3796
         // Return FALSE to prevent edit box from gaining focus and showing highlight.
 
3797
         return FALSE;
 
3798
 
 
3799
      case WM_COMMAND:
 
3800
         if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
 
3801
            EndDialog(hDlg, LOWORD(wParam));
 
3802
         }
 
3803
         return FALSE;
 
3804
   }
 
3805
   return FALSE;
 
3806
}
 
3807
 
 
3808
 
 
3809
//******************************************************************************
 
3810
//***** About Dialog Functions
 
3811
//******************************************************************************
 
3812
 
 
3813
BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 
3814
 
 
3815
   switch (uMsg) {
 
3816
 
 
3817
      case WM_INITDIALOG:
 
3818
 
 
3819
#ifdef _WIN32_WCE
 
3820
         // Add "Ok" button to caption bar.
 
3821
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
 
3822
                       GetWindowLong(hDlg, GWL_EXSTYLE));
 
3823
#endif
 
3824
 
 
3825
         // Fill in a few static members.
 
3826
         // (For VER_FULLVERSION_STR and VER_COMMENT_STR, the TEXT() macro is
 
3827
         //  not applicable, because they are defined as a set of concatenated
 
3828
         //  string constants. These strings need to be converted to UNICODE
 
3829
         //  at runtime, sigh.)
 
3830
         TCHAR szBuffer[128];
 
3831
         SetDlgItemText(hDlg, IDC_PRODUCT, TEXT(VER_PRODUCT_STR));
 
3832
#ifdef UNICODE
 
3833
         _stprintf(szBuffer, TEXT("Freeware Version %S"), VER_FULLVERSION_STR);
 
3834
#else
 
3835
         _stprintf(szBuffer, TEXT("Freeware Version %s"), VER_FULLVERSION_STR);
 
3836
#endif
 
3837
         SetDlgItemText(hDlg, IDC_VERSION, szBuffer);
 
3838
         _stprintf(szBuffer, TEXT("Developed by %s"), TEXT(VER_DEVELOPER_STR));
 
3839
         SetDlgItemText(hDlg, IDC_DEVELOPER, szBuffer);
 
3840
         SetDlgItemText(hDlg, IDC_COPYRIGHT, TEXT(VER_COPYRIGHT_STR));
 
3841
#ifdef UNICODE
 
3842
         _stprintf(szBuffer, TEXT("%S"), VER_COMMENT_STR);
 
3843
         SetDlgItemText(hDlg, IDC_COMMENT, szBuffer);
 
3844
#else
 
3845
         SetDlgItemText(hDlg, IDC_COMMENT, VER_COMMENT_STR);
 
3846
#endif
 
3847
 
 
3848
         // Center the dialog over our parent.
 
3849
         CenterWindow(hDlg);
 
3850
         return TRUE;
 
3851
 
 
3852
      case WM_COMMAND:
 
3853
         if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
 
3854
            EndDialog(hDlg, 0);
 
3855
         }
 
3856
         return FALSE;
 
3857
   }
 
3858
   return FALSE;
 
3859
}