Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6725 siemargl 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   // Common controls - mainly ListView and ImageList
121
#include    // Common dialogs - OpenFile dialog
122
 
123
#ifndef _WIN32_WCE
124
#include     // On NT, we use the SHBrowseForFolder() stuff.
125
#include   // CommandLineToArgvW() and ExtractIconEx()
126
#endif
127
 
128
#include "intrface.h"  // Interface between Info-ZIP and us
129
#include "winmain.h"   // Us
130
}
131
#include      // 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, zusz_t uzValue);
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.uzByteCount   = pfn->uzSize;
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->uzSize);
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->uzCompressedSize);
1367
         return;
1368
 
1369
      case 6: // Ratio
1370
         int factor; factor = ratio(pFile->uzSize, pFile->uzCompressedSize);
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->uzSize != pFile2->uzSize) {
1468
            result = ((pFile1->uzSize < pFile2->uzSize) ? -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->uzCompressedSize != pFile2->uzCompressedSize) {
1501
            result = ((pFile1->uzCompressedSize < pFile2->uzCompressedSize) ? -1 : 1);
1502
         }
1503
         break;
1504
 
1505
      case 6: // Ratio - Smallest to Largest
1506
         int factor1, factor2;
1507
         factor1 = ratio(pFile1->uzSize, pFile1->uzCompressedSize);
1508
         factor2 = ratio(pFile2->uzSize, pFile2->uzCompressedSize);
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, zusz_t uzValue) {
1932
#ifdef ZIP64_SUPPORT
1933
    DWORD dw = 0, dwGroup[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1934
#else
1935
    DWORD dw = 0, dwGroup[4] = { 0, 0, 0, 0 };
1936
#endif
1937
   while (uzValue) {
1938
      dwGroup[dw++] = (DWORD)(uzValue % 1000);
1939
      uzValue /= 1000;
1940
   }
1941
   switch (dw) {
1942
      case 2:  _stprintf(szValue, TEXT("%u,%03u"), dwGroup[1], dwGroup[0]); break;
1943
      case 3:  _stprintf(szValue, TEXT("%u,%03u,%03u"), dwGroup[2], dwGroup[1], dwGroup[0]); break;
1944
      case 4:  _stprintf(szValue, TEXT("%u,%03u,%03u,%03u"), dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]); break;
1945
#ifdef ZIP64_SUPPORT
1946
      case 5:
1947
          _stprintf(szValue, TEXT("%u,%03u,%03u,%03u,%03u"),
1948
                    dwGroup[4], dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]);
1949
          break;
1950
      case 6:
1951
          _stprintf(szValue, TEXT("%u,%03u,%03u,%03u,%03u,%03u"), dwGroup[5],
1952
                    dwGroup[4], dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]);
1953
          break;
1954
      case 7:
1955
          _stprintf(szValue, TEXT("%u,%03u,%03u,%03u,%03u,%03u,%03u"), dwGroup[6], dwGroup[5],
1956
                    dwGroup[4], dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]);
1957
          break;
1958
      case 8:
1959
          _stprintf(szValue, TEXT("%u,%03u,%03u,%03u,%03u,%03u,%03u,%03u"), dwGroup[7], dwGroup[6], dwGroup[5],
1960
                    dwGroup[4], dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]);
1961
#endif
1962
      default: _stprintf(szValue, TEXT("%u"), dwGroup[0]);
1963
   }
1964
   return szValue;
1965
}
1966
 
1967
//******************************************************************************
1968
LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes) {
1969
   // Build the attribute string according to the flags specified for this file.
1970
   _stprintf(szBuffer, TEXT("%s%s%s%s%s%s%s%s"),
1971
             (dwAttributes & ZFILE_ATTRIBUTE_VOLUME)    ? TEXT("V") : TEXT(""),
1972
             (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)  ? TEXT("D") : TEXT(""),
1973
             (dwAttributes & FILE_ATTRIBUTE_READONLY)   ? TEXT("R") : TEXT(""),
1974
             (dwAttributes & FILE_ATTRIBUTE_ARCHIVE)    ? TEXT("A") : TEXT(""),
1975
             (dwAttributes & FILE_ATTRIBUTE_HIDDEN)     ? TEXT("H") : TEXT(""),
1976
             (dwAttributes & FILE_ATTRIBUTE_SYSTEM)     ? TEXT("S") : TEXT(""),
1977
             (dwAttributes & ZFILE_ATTRIBUTE_ENCRYPTED) ? TEXT("E") : TEXT(""),
1978
             (dwAttributes & ZFILE_ATTRIBUTE_COMMENT)   ? TEXT("C") : TEXT(""));
1979
   return szBuffer;
1980
}
1981
 
1982
//******************************************************************************
1983
LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType) {
1984
 
1985
   // First check to see if we have a known description.
1986
   if (pFile->szType) {
1987
      return pFile->szType;
1988
   }
1989
 
1990
   // Locate the file portion of our path.
1991
   LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
1992
 
1993
   // Get the extension portion of the file.
1994
   LPCSTR pszExt = MBSRCHR(pszFile, '.');
1995
 
1996
   // If we have an extension create a type name for this file.
1997
   if (pszExt && *(pszExt + 1)) {
1998
      strcpy(szType, pszExt + 1);
1999
      _strupr(szType);
2000
      strcat(szType, " File");
2001
      return szType;
2002
   }
2003
 
2004
   // If no extension, then use the default "File".
2005
   return "File";
2006
}
2007
 
2008
//******************************************************************************
2009
LPCSTR GetFileFromPath(LPCSTR szPath) {
2010
   LPCSTR p1 = MBSRCHR(szPath, '/'), p2 = MBSRCHR(szPath, '\\');
2011
   if (p1 && (p1 > p2)) {
2012
      return p1 + 1;
2013
   } else if (p2) {
2014
      return p2 + 1;
2015
   }
2016
   return szPath;
2017
}
2018
 
2019
//******************************************************************************
2020
void ForwardSlashesToBackSlashesA(LPSTR szBuffer) {
2021
   while (*szBuffer) {
2022
      if (*szBuffer == '/') {
2023
         *szBuffer = '\\';
2024
      }
2025
      INCSTR(szBuffer);
2026
   }
2027
}
2028
 
2029
//******************************************************************************
2030
void ForwardSlashesToBackSlashesW(LPWSTR szBuffer) {
2031
   while (*szBuffer) {
2032
      if (*szBuffer == L'/') {
2033
         *szBuffer = L'\\';
2034
      }
2035
      szBuffer++;
2036
   }
2037
}
2038
 
2039
//******************************************************************************
2040
void DeleteDirectory(LPTSTR szPath) {
2041
 
2042
   // Make note to where the end of our path is.
2043
   LPTSTR szEnd = szPath + _tcslen(szPath);
2044
 
2045
   // Add our search spec to the path.
2046
   _tcscpy(szEnd, TEXT("\\*.*"));
2047
 
2048
   // Start a directory search.
2049
   WIN32_FIND_DATA w32fd;
2050
   HANDLE hFind = FindFirstFile(szPath, &w32fd);
2051
 
2052
   // Loop through all entries in this directory.
2053
   if (hFind != INVALID_HANDLE_VALUE) {
2054
 
2055
      do {
2056
         // Append the file/directory name to the path.
2057
         _tcscpy(szEnd + 1, w32fd.cFileName);
2058
 
2059
         // Check to see if this entry is a subdirectory.
2060
         if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2061
 
2062
            // Ignore current directory (.) and previous directory (..)
2063
            if (_tcscmp(w32fd.cFileName, TEXT("."))   &&
2064
                _tcscmp(w32fd.cFileName, TEXT("..")))
2065
            {
2066
               // Recurse into DeleteDirectory() to delete subdirectory.
2067
               DeleteDirectory(szPath);
2068
            }
2069
 
2070
         // Otherwise, it must be a file.
2071
         } else {
2072
 
2073
            // If the file is marked as read-only, then change to read/write.
2074
            if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
2075
               SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
2076
            }
2077
 
2078
            // Attempt to delete the file.  If we fail and the file used to be
2079
            // read-only, then set the read-only bit back on it.
2080
            if (!DeleteFile(szPath) &&
2081
                (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
2082
            {
2083
               SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
2084
            }
2085
         }
2086
 
2087
      // Get the next directory entry.
2088
      } while (FindNextFile(hFind, &w32fd));
2089
 
2090
      // Close the directory search.
2091
      FindClose(hFind);
2092
   }
2093
 
2094
   // Remove the directory.
2095
   *szEnd = TEXT('\0');
2096
   RemoveDirectory(szPath);
2097
}
2098
 
2099
 
2100
//******************************************************************************
2101
//***** Registry Functions
2102
//******************************************************************************
2103
 
2104
void RegWriteKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPCTSTR szValue) {
2105
   HKEY  hKey = NULL;
2106
   DWORD dwDisposition;
2107
 
2108
   if (RegCreateKeyEx(hKeyRoot, szSubKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) {
2109
      if (szValue) {
2110
         RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szValue,
2111
                       sizeof(TCHAR) * (_tcslen(szValue) + 1));
2112
      }
2113
      RegCloseKey(hKey);
2114
   }
2115
}
2116
 
2117
//******************************************************************************
2118
BOOL RegReadKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPTSTR szValue, DWORD cBytes) {
2119
   *szValue = TEXT('\0');
2120
   HKEY hKey = NULL;
2121
   LRESULT lResult = -1;
2122
 
2123
   if (RegOpenKeyEx(hKeyRoot, szSubKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
2124
      lResult = RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)szValue, &cBytes);
2125
      RegCloseKey(hKey);
2126
   }
2127
   return ((lResult == ERROR_SUCCESS) && *szValue);
2128
}
2129
 
2130
//******************************************************************************
2131
void WriteOptionString(LPCTSTR szOption, LPCTSTR szValue) {
2132
   HKEY hKey = NULL;
2133
 
2134
   if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
2135
      RegSetValueEx(hKey, szOption, 0, REG_SZ, (LPBYTE)szValue,
2136
                    sizeof(TCHAR) * (_tcslen(szValue) + 1));
2137
      RegCloseKey(hKey);
2138
   }
2139
}
2140
 
2141
//******************************************************************************
2142
void WriteOptionInt(LPCTSTR szOption, DWORD dwValue) {
2143
   HKEY hKey = NULL;
2144
 
2145
   if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
2146
      RegSetValueEx(hKey, szOption, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
2147
      RegCloseKey(hKey);
2148
   }
2149
}
2150
 
2151
//******************************************************************************
2152
LPTSTR GetOptionString(LPCTSTR szOption, LPCTSTR szDefault, LPTSTR szValue, DWORD nSize) {
2153
   HKEY hKey = NULL;
2154
   LONG lResult = -1;
2155
 
2156
   if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
2157
      lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)szValue, &nSize);
2158
      RegCloseKey(hKey);
2159
   }
2160
   if (lResult != ERROR_SUCCESS) {
2161
      _tcscpy(szValue, szDefault);
2162
   }
2163
   return szValue;
2164
}
2165
 
2166
//******************************************************************************
2167
DWORD GetOptionInt(LPCTSTR szOption, DWORD dwDefault) {
2168
   HKEY  hKey = NULL;
2169
   LONG  lResult = -1;
2170
   DWORD dwValue;
2171
   DWORD nSize = sizeof(dwValue);
2172
 
2173
   if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
2174
      lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)&dwValue, &nSize);
2175
      RegCloseKey(hKey);
2176
   }
2177
   return (lResult == ERROR_SUCCESS) ? dwValue : dwDefault;
2178
}
2179
 
2180
//******************************************************************************
2181
//***** EDIT Control Subclass Functions
2182
//******************************************************************************
2183
 
2184
void DisableEditing(HWND hWndEdit) {
2185
 
2186
   // Make sure the control does not have ES_READONLY or ES_WANTRETURN styles.
2187
   DWORD dwStyle = (DWORD)GetWindowLong(hWndEdit, GWL_STYLE);
2188
   if (dwStyle & (ES_READONLY | ES_WANTRETURN)) {
2189
      SetWindowLong(hWndEdit, GWL_STYLE, dwStyle & ~(ES_READONLY | ES_WANTRETURN));
2190
   }
2191
 
2192
   // Subclass the control so we can intercept certain keys.
2193
   g_wpEdit = (WNDPROC)GetWindowLong(hWndEdit, GWL_WNDPROC);
2194
   SetWindowLong(hWndEdit, GWL_WNDPROC, (LONG)EditSubclassProc);
2195
}
2196
 
2197
//******************************************************************************
2198
LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2199
 
2200
   BOOL fCtrl, fShift;
2201
 
2202
   switch (uMsg) {
2203
      // For cut, paste, delete, and undo, the control post itself a message.
2204
      // we throw away that message.  This works as a fail-safe in case we miss
2205
      // some keystroke that causes one of these operations.  This also disables
2206
      // the context menu on NT from causing one of these actions to occur.
2207
      case WM_CUT:
2208
      case WM_PASTE:
2209
      case WM_CLEAR:
2210
      case WM_UNDO:
2211
         MessageBeep(0);
2212
         return 0;
2213
 
2214
      // WM_CHAR is used for normal characters. A-Z, numbers, symbols, enter,
2215
      // backspace, esc, and tab. In does not include del or movement keys.
2216
      case WM_CHAR:
2217
         fCtrl  = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
2218
 
2219
         // We only allow CTRL-C (copy), plain ESC, plain TAB, plain ENTER.
2220
         if (( fCtrl && (wParam == 3))         ||
2221
             (!fCtrl && (wParam == VK_ESCAPE)) ||
2222
             (!fCtrl && (wParam == VK_RETURN)) ||
2223
             (!fCtrl && (wParam == VK_TAB)))
2224
         {
2225
            break;
2226
         }
2227
         MessageBeep(0);
2228
         return 0;
2229
 
2230
      // WM_KEYDOWN handles del, insert, arrows, pg up/down, home/end.
2231
      case WM_KEYDOWN:
2232
         fCtrl  = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
2233
         fShift = (GetKeyState(VK_SHIFT)   & 0x8000) ? TRUE : FALSE;
2234
 
2235
         // Skip all forms of DELETE, SHIFT-INSERT (paste),
2236
         // CTRL-RETURN (hard-return), and CTRL-TAB (hard-tab).
2237
         if ((          (wParam == VK_DELETE)) ||
2238
             (fShift && (wParam == VK_INSERT)) ||
2239
             (fCtrl  && (wParam == VK_RETURN)) ||
2240
             (fCtrl  && (wParam == VK_TAB)))
2241
         {
2242
            MessageBeep(0);
2243
            return 0;
2244
         }
2245
         break;
2246
   }
2247
   return CallWindowProc(g_wpEdit, hWnd, uMsg, wParam, lParam);
2248
}
2249
 
2250
 
2251
//******************************************************************************
2252
//***** MRU Functions
2253
//******************************************************************************
2254
 
2255
#ifdef _WIN32_WCE
2256
int GetMenuString(HMENU hMenu, UINT uIDItem, LPTSTR lpString, int nMaxCount,
2257
                  UINT uFlag) {
2258
   MENUITEMINFO mii;
2259
   ZeroMemory(&mii, sizeof(mii));
2260
   mii.cbSize = sizeof(mii);
2261
   mii.fMask = MIIM_TYPE;
2262
   mii.dwTypeData = lpString;
2263
   mii.cch = nMaxCount;
2264
   return (GetMenuItemInfo(hMenu, uIDItem, uFlag == MF_BYPOSITION, &mii) ?
2265
           mii.cch : 0);
2266
}
2267
#endif
2268
 
2269
//******************************************************************************
2270
void InitializeMRU() {
2271
 
2272
   TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
2273
   int   i, j;
2274
 
2275
   // Get our menu handle.
2276
#ifdef _WIN32_WCE
2277
   HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
2278
#else
2279
   HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
2280
#endif
2281
 
2282
   // Read all our current MRUs from the registry.
2283
   for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
2284
 
2285
      // Build option name for current MRU and read from registry.
2286
      _stprintf(szOption, TEXT("MRU%d"), i+1);
2287
      GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
2288
 
2289
      // If this MRU exists, then add it.
2290
      if (szMRU[i][3]) {
2291
 
2292
         // Build the accelerator prefix for this menu item.
2293
         szMRU[i][0] = TEXT('&');
2294
         szMRU[i][1] = TEXT('1') + j;
2295
         szMRU[i][2] = TEXT(' ');
2296
 
2297
         // Add the item to our menu.
2298
         InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
2299
                    szMRU[i]);
2300
 
2301
         // Increment our actual MRU count.
2302
         j++;
2303
      }
2304
   }
2305
}
2306
 
2307
//******************************************************************************
2308
void AddFileToMRU(LPCSTR szFile) {
2309
 
2310
   TCHAR szMRU[MRU_MAX_FILE + 1][_MAX_PATH + 4], szOption[8];
2311
   int   i, j;
2312
 
2313
   // Store the new file in our first MRU index.
2314
   MBSTOTSTR(&szMRU[0][3], szFile, _MAX_PATH);
2315
 
2316
   //---------------------------------------------------------------------------
2317
   // We first read the current MRU list from the registry, merge in our new
2318
   // file at the top, and then write back to the registry.  The registry merge
2319
   // is done to allow multiple instances of Pocket UnZip to maintain a global
2320
   // MRU list independent to this current instance's MRU list.
2321
   //---------------------------------------------------------------------------
2322
 
2323
   // Read all our current MRUs from the registry.
2324
   for (i = 1; i <= MRU_MAX_FILE; i++) {
2325
 
2326
      // Build option name for current MRU and read from registry.
2327
      _stprintf(szOption, TEXT("MRU%d"), i);
2328
      GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
2329
   }
2330
 
2331
   // Write our new merged MRU list back to the registry.
2332
   for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
2333
 
2334
      // If this MRU exists and is different then our new file, then add it.
2335
      if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
2336
 
2337
         // Build option name for current MRU and write to registry.
2338
         _stprintf(szOption, TEXT("MRU%d"), ++j);
2339
         WriteOptionString(szOption, &szMRU[i][3]);
2340
      }
2341
   }
2342
 
2343
   //---------------------------------------------------------------------------
2344
   // The next thing we need to do is read our local MRU from our File menu,
2345
   // merge in our new file, and store the new list back to our File menu.
2346
   //---------------------------------------------------------------------------
2347
 
2348
   // Get our menu handle.
2349
#ifdef _WIN32_WCE
2350
   HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
2351
#else
2352
   HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
2353
#endif
2354
 
2355
   // Read all our current MRUs from our File Menu.
2356
   for (i = 1; i <= MRU_MAX_FILE; i++) {
2357
 
2358
      // Query our file Menu for a MRU file.
2359
      if (GetMenuString(hMenu, MRU_START_ID + i - 1, szMRU[i],
2360
                        countof(szMRU[0]), MF_BYCOMMAND))
2361
      {
2362
         // Delete this item from the menu for now.
2363
         DeleteMenu(hMenu, MRU_START_ID + i - 1, MF_BYCOMMAND);
2364
      } else {
2365
         szMRU[i][3] = TEXT('\0');
2366
      }
2367
   }
2368
 
2369
   // Write our new merged MRU list back to the File menu.
2370
   for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
2371
 
2372
      // If this MRU exists and is different then our new file, then add it.
2373
      if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
2374
 
2375
         // Build the accelerator prefix for this menu item.
2376
         szMRU[i][0] = TEXT('&');
2377
         szMRU[i][1] = TEXT('1') + j;
2378
         szMRU[i][2] = TEXT(' ');
2379
 
2380
         // Add the item to our menu.
2381
         InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
2382
                    szMRU[i]);
2383
 
2384
         // Increment our actual MRU count.
2385
         j++;
2386
      }
2387
   }
2388
}
2389
 
2390
//******************************************************************************
2391
void RemoveFileFromMRU(LPCTSTR szFile) {
2392
 
2393
   TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
2394
   int   i, j;
2395
   BOOL  fFound;
2396
 
2397
   //---------------------------------------------------------------------------
2398
   // We first look for this file in our global MRU stored in the registry.  We
2399
   // read the current MRU list from the registry, and then write it back while
2400
   // removing all occurrances of the file specified.
2401
   //---------------------------------------------------------------------------
2402
 
2403
   // Read all our current MRUs from the registry.
2404
   for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
2405
 
2406
      // Build option name for current MRU and read from registry.
2407
      _stprintf(szOption, TEXT("MRU%d"), i+1);
2408
      GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
2409
 
2410
      // Check for a match.
2411
      if (!_tcsicmp(szFile, &szMRU[i][3])) {
2412
         szMRU[i][3] = TEXT('\0');
2413
         fFound = TRUE;
2414
      }
2415
   }
2416
 
2417
   // Only write the MRU back to the registry if we found a file to remove.
2418
   if (fFound) {
2419
 
2420
      // Write the updated MRU list back to the registry.
2421
      for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
2422
 
2423
         // If this MRU still exists, then add it.
2424
         if (szMRU[i][3]) {
2425
 
2426
            // Build option name for current MRU and write to registry.
2427
            _stprintf(szOption, TEXT("MRU%d"), ++j);
2428
            WriteOptionString(szOption, &szMRU[i][3]);
2429
         }
2430
      }
2431
 
2432
      // If our list got smaller, clear the unused items in the registry.
2433
      while (j++ < MRU_MAX_FILE) {
2434
         _stprintf(szOption, TEXT("MRU%d"), j);
2435
         WriteOptionString(szOption, TEXT(""));
2436
      }
2437
   }
2438
 
2439
   //---------------------------------------------------------------------------
2440
   // We next thing we do is look for this file in our local MRU stored in our
2441
   // File menu.  We read the current MRU list from the menu, and then write it
2442
   // back while removing all occurrances of the file specified.
2443
   //---------------------------------------------------------------------------
2444
 
2445
   // Get our menu handle.
2446
#ifdef _WIN32_WCE
2447
   HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
2448
#else
2449
   HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
2450
#endif
2451
 
2452
   // Read all our current MRUs from our File Menu.
2453
   for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
2454
 
2455
      // Query our file Menu for a MRU file.
2456
      if (!GetMenuString(hMenu, MRU_START_ID + i, szMRU[i], countof(szMRU[0]),
2457
          MF_BYCOMMAND))
2458
      {
2459
         szMRU[i][3] = TEXT('\0');
2460
      }
2461
 
2462
      // Check for a match.
2463
      if (!_tcsicmp(szFile, &szMRU[i][3])) {
2464
         szMRU[i][3] = TEXT('\0');
2465
         fFound = TRUE;
2466
      }
2467
   }
2468
 
2469
   // Only update menu if we found a file to remove.
2470
   if (fFound) {
2471
 
2472
      // Clear out our menu's MRU list.
2473
      for (i = MRU_START_ID; i < (MRU_START_ID + MRU_MAX_FILE); i++) {
2474
         DeleteMenu(hMenu, i, MF_BYCOMMAND);
2475
      }
2476
 
2477
      // Write the rest of our MRU list back to the menu.
2478
      for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
2479
 
2480
         // If this MRU still exists, then add it.
2481
         if (szMRU[i][3]) {
2482
 
2483
            // Build the accelerator prefix for this menu item.
2484
            szMRU[i][0] = TEXT('&');
2485
            szMRU[i][1] = TEXT('1') + j;
2486
            szMRU[i][2] = TEXT(' ');
2487
 
2488
            // Add the item to our menu.
2489
            InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
2490
                       szMRU[i]);
2491
 
2492
            // Increment our actual MRU count.
2493
            j++;
2494
         }
2495
      }
2496
   }
2497
}
2498
 
2499
//******************************************************************************
2500
void ActivateMRU(UINT uIDItem) {
2501
   TCHAR szFile[_MAX_PATH + 4];
2502
 
2503
   // Get our menu handle.
2504
#ifdef _WIN32_WCE
2505
   HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
2506
#else
2507
   HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
2508
#endif
2509
 
2510
   // Query our menu for the selected MRU.
2511
   if (GetMenuString(hMenu, uIDItem, szFile, countof(szFile), MF_BYCOMMAND)) {
2512
 
2513
      // Move past 3 character accelerator prefix and open the file.
2514
      ReadZipFileList(&szFile[3]);
2515
   }
2516
}
2517
 
2518
 
2519
//******************************************************************************
2520
//***** Open Zip File Functions
2521
//******************************************************************************
2522
 
2523
void ReadZipFileList(LPCTSTR wszPath) {
2524
 
2525
   // Show wait cursor.
2526
   HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
2527
 
2528
   TSTRTOMBS(g_szZipFile, wszPath, countof(g_szZipFile));
2529
 
2530
   // Update our banner to show that we are loading.
2531
   g_fLoading = TRUE;
2532
   DrawBanner(NULL);
2533
 
2534
   // Update our caption to show that we are loading.
2535
   SetCaptionText(TEXT("Loading"));
2536
 
2537
   // Clear our list view.
2538
   ListView_DeleteAllItems(g_hWndList);
2539
 
2540
   // Ghost all our Unzip related menu items.
2541
   EnableAllMenuItems(IDM_FILE_PROPERTIES,    FALSE);
2542
   EnableAllMenuItems(IDM_ACTION_EXTRACT,     FALSE);
2543
   EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, FALSE);
2544
   EnableAllMenuItems(IDM_ACTION_TEST,        FALSE);
2545
   EnableAllMenuItems(IDM_ACTION_TEST_ALL,    FALSE);
2546
   EnableAllMenuItems(IDM_ACTION_VIEW,        FALSE);
2547
   EnableAllMenuItems(IDM_ACTION_SELECT_ALL,  FALSE);
2548
   EnableAllMenuItems(IDM_VIEW_COMMENT,       FALSE);
2549
 
2550
   // Let Info-ZIP and our callbacks do the work.
2551
   SendMessage(g_hWndList, WM_SETREDRAW, FALSE, 0);
2552
   int result = DoListFiles(g_szZipFile);
2553
   SendMessage(g_hWndList, WM_SETREDRAW, TRUE, 0);
2554
 
2555
   // Restore/remove cursor.
2556
   SetCursor(hCur);
2557
 
2558
   // Update our column widths
2559
   ResizeColumns();
2560
 
2561
   if ((result == PK_OK) || (result == PK_WARN)) {
2562
 
2563
      // Sort the items by name.
2564
      Sort(0, TRUE);
2565
 
2566
      // Update this file to our MRU list and menu.
2567
      AddFileToMRU(g_szZipFile);
2568
 
2569
      // Enabled the comment button if the zip file has a comment.
2570
      if (lpUserFunctions->cchComment) {
2571
         EnableAllMenuItems(IDM_VIEW_COMMENT, TRUE);
2572
      }
2573
 
2574
      // Update other items that are related to having a Zip file loaded.
2575
      EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, TRUE);
2576
      EnableAllMenuItems(IDM_ACTION_TEST_ALL,    TRUE);
2577
      EnableAllMenuItems(IDM_ACTION_SELECT_ALL,  TRUE);
2578
 
2579
   } else {
2580
 
2581
      // Make sure we didn't partially load and added a few files.
2582
      ListView_DeleteAllItems(g_hWndList);
2583
 
2584
      // If the file itself is bad or missing, then remove it from our MRU.
2585
      if ((result == PK_ERR) || (result == PK_BADERR) || (result == PK_NOZIP) ||
2586
          (result == PK_FIND) || (result == PK_EOF))
2587
      {
2588
         RemoveFileFromMRU(wszPath);
2589
      }
2590
 
2591
      // Display an error.
2592
      TCHAR szError[_MAX_PATH + 128];
2593
      _stprintf(szError, TEXT("Failure loading \"%s\".\n\n"), wszPath);
2594
      _tcscat(szError, GetZipErrorString(result));
2595
      MessageBox(g_hWndMain, szError, g_szAppName, MB_OK | MB_ICONERROR);
2596
 
2597
      // Clear our file status.
2598
      *g_szZipFile = '\0';
2599
   }
2600
 
2601
   // Update our caption to show that we are done loading.
2602
   SetCaptionText(NULL);
2603
 
2604
   // Update our banner to show that we are done loading.
2605
   g_fLoading = FALSE;
2606
   DrawBanner(NULL);
2607
}
2608
 
2609
 
2610
//******************************************************************************
2611
//***** Zip File Properties Dialog Functions
2612
//******************************************************************************
2613
 
2614
BOOL CALLBACK DlgProcProperties(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2615
 
2616
   switch (uMsg) {
2617
 
2618
      case WM_INITDIALOG: {
2619
 
2620
         // Add "General" and "Comments" tabs to tab control.  We are using a
2621
         // poor man's version of a property sheet.  We display our 2 pages
2622
         // by showing and hiding controls as necessary.  For our purposes,
2623
         // this is much easier than dealing with separate property pages.
2624
 
2625
         TC_ITEM tci;
2626
         tci.mask = TCIF_TEXT;
2627
         tci.pszText = TEXT("General");
2628
         TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 0, &tci);
2629
         tci.pszText = TEXT("Comment");
2630
         TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 1, &tci);
2631
 
2632
#ifdef _WIN32_WCE
2633
         // Add "Ok" button to caption bar.
2634
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
2635
                       GetWindowLong(hDlg, GWL_EXSTYLE));
2636
#endif
2637
         // Center us over our parent.
2638
         CenterWindow(hDlg);
2639
 
2640
         int    directory = -1, readOnly = -1, archive = -1, hidden = -1;
2641
         int    system = -1, encrypted = -1;
2642
         int    year = -1, month = -1, day = -1, hour = -1, minute = -1, pm = -1;
2643
         zusz_t uzSize = 0, uzCompressedSize = 0;
2644
         LPCSTR szPath = NULL, szMethod = NULL, szComment = NULL;
2645
         DWORD  dwCRC = 0, dwCount = 0, dwCommentCount = 0;
2646
         TCHAR  szBuffer[MAX_PATH];
2647
 
2648
         // Loop through all selected items.
2649
         LV_ITEM lvi;
2650
         ZeroMemory(&lvi, sizeof(lvi));
2651
         lvi.mask = LVIF_PARAM;
2652
         lvi.iItem = -1;
2653
         while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) != -1) {
2654
 
2655
            // Get the FILE_NODE for the selected item.
2656
            ListView_GetItem(g_hWndList, &lvi);
2657
            FILE_NODE *pFile = (FILE_NODE*)lvi.lParam;
2658
 
2659
            // Merge this file's attributes into our accumulative attributes.
2660
            MergeValues(&directory, (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY)  != 0);
2661
            MergeValues(&readOnly,  (pFile->dwAttributes & FILE_ATTRIBUTE_READONLY)   != 0);
2662
            MergeValues(&archive,   (pFile->dwAttributes & FILE_ATTRIBUTE_ARCHIVE)    != 0);
2663
            MergeValues(&hidden,    (pFile->dwAttributes & FILE_ATTRIBUTE_HIDDEN)     != 0);
2664
            MergeValues(&system,    (pFile->dwAttributes & FILE_ATTRIBUTE_SYSTEM)     != 0);
2665
            MergeValues(&encrypted, (pFile->dwAttributes & ZFILE_ATTRIBUTE_ENCRYPTED) != 0);
2666
 
2667
            // Merge this file's date/time into our accumulative date/time.
2668
            int curHour = (pFile->dwModified >> 6) & 0x001F;
2669
            MergeValues(&year,   (pFile->dwModified >> 20) & 0x0FFF);
2670
            MergeValues(&month,  (pFile->dwModified >> 16) & 0x000F);
2671
            MergeValues(&day,    (pFile->dwModified >> 11) & 0x001F);
2672
            MergeValues(&hour,   (curHour % 12) ? (curHour % 12) : 12);
2673
            MergeValues(&minute, pFile->dwModified & 0x003F);
2674
            MergeValues(&pm,     curHour >= 12);
2675
 
2676
            // Store this file's name.
2677
            szPath = pFile->szPathAndMethod;
2678
 
2679
            // Store this file's CRC.
2680
            dwCRC = pFile->dwCRC;
2681
 
2682
            // Add the size and compressed size to our accumulative sizes.
2683
            uzSize += pFile->uzSize;
2684
            uzCompressedSize += pFile->uzCompressedSize;
2685
 
2686
            // Merge in our compression method.
2687
            LPCSTR szCurMethod = pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1;
2688
            if ((szMethod == NULL) || !strcmp(szMethod, szCurMethod)) {
2689
               szMethod = szCurMethod;
2690
            } else {
2691
               szMethod = "Multiple Methods";
2692
            }
2693
 
2694
            // Increment our file count.
2695
            dwCount++;
2696
 
2697
            // Increment our comment count if this file has a comment.
2698
            if (pFile->szComment) {
2699
               szComment = pFile->szComment;
2700
               dwCommentCount++;
2701
            }
2702
         };
2703
 
2704
         if (dwCount > 1) {
2705
 
2706
            // If multiple items selected, then display a selected count string
2707
            // in place of the file name.
2708
            _stprintf(szBuffer, TEXT("%u items selected."), dwCount);
2709
            SetDlgItemText(hDlg, IDC_FILE, szBuffer);
2710
 
2711
            // Display "Multiple" for CRC if multiple items selected.
2712
            SetDlgItemText(hDlg, IDC_CRC, TEXT("Multiple CRCs"));
2713
 
2714
         } else {
2715
 
2716
            // Set the file name text for the single item selected.
2717
            MBSTOTSTR(szBuffer, szPath, countof(szBuffer));
2718
            ForwardSlashesToBackSlashes(szBuffer);
2719
            SetDlgItemText(hDlg, IDC_FILE, szBuffer);
2720
 
2721
            // Set the CRC text for the single item selected.
2722
            _stprintf(szBuffer, TEXT("0x%08X"), dwCRC);
2723
            SetDlgItemText(hDlg, IDC_CRC, szBuffer);
2724
         }
2725
 
2726
         // Set the Size tally text.
2727
         FormatValue(szBuffer, uzSize);
2728
         _tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
2729
         SetDlgItemText(hDlg, IDC_FILE_SIZE, szBuffer);
2730
 
2731
         // Set the Compressed Size tally text.
2732
         FormatValue(szBuffer, uzCompressedSize);
2733
         _tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
2734
         SetDlgItemText(hDlg, IDC_COMPRESSED_SIZE, szBuffer);
2735
 
2736
         // Set the Compression Factor text.
2737
         int factor = ratio(uzSize, uzCompressedSize);
2738
         _stprintf(szBuffer, TEXT("%d.%d%%"), factor / 10,
2739
                   ((factor < 0) ? -factor : factor) % 10);
2740
         SetDlgItemText(hDlg, IDC_COMPRESSON_FACTOR, szBuffer);
2741
 
2742
         // Set the Compression Method text.
2743
         MBSTOTSTR(szBuffer, szMethod, countof(szBuffer));
2744
         SetDlgItemText(hDlg, IDC_COMPRESSION_METHOD, szBuffer);
2745
 
2746
         // Set the Attribute check boxes.
2747
         CheckThreeStateBox(hDlg, IDC_DIRECTORY, directory);
2748
         CheckThreeStateBox(hDlg, IDC_READONLY,  readOnly);
2749
         CheckThreeStateBox(hDlg, IDC_ARCHIVE,   archive);
2750
         CheckThreeStateBox(hDlg, IDC_HIDDEN,    hidden);
2751
         CheckThreeStateBox(hDlg, IDC_SYSTEM,    system);
2752
         CheckThreeStateBox(hDlg, IDC_ENCRYPTED, encrypted);
2753
 
2754
         // Build and set the Modified Date text.  The MS compiler does not
2755
         // consider "??/" to be a valid string.  "??/" is a trigraph that is
2756
         // turned into "\" by the preprocessor and causes grief for the compiler.
2757
         LPTSTR psz = szBuffer;
2758
         psz += ((month  < 0) ? _stprintf(psz, TEXT("?\?/")) :
2759
                                _stprintf(psz, TEXT("%u/"), month));
2760
         psz += ((day    < 0) ? _stprintf(psz, TEXT("?\?/")) :
2761
                                _stprintf(psz, TEXT("%u/"), day));
2762
         psz += ((year   < 0) ? _stprintf(psz, TEXT("?\? ")) :
2763
                                _stprintf(psz, TEXT("%u "), year % 100));
2764
         psz += ((hour   < 0) ? _stprintf(psz, TEXT("?\?:")) :
2765
                                _stprintf(psz, TEXT("%u:"), hour));
2766
         psz += ((minute < 0) ? _stprintf(psz, TEXT("?\? ")) :
2767
                                _stprintf(psz, TEXT("%02u "), minute));
2768
         psz += ((pm     < 0) ? _stprintf(psz, TEXT("?M")) :
2769
                                _stprintf(psz, TEXT("%cM"), pm ? TEXT('P') : TEXT('A')));
2770
         SetDlgItemText(hDlg, IDC_MODIFIED, szBuffer);
2771
 
2772
         // Store a global handle to our edit control.
2773
         g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
2774
 
2775
         // Disable our edit box from being edited.
2776
         DisableEditing(g_hWndEdit);
2777
 
2778
         // Stuff the appropriate message into the Comment edit control.
2779
         if (dwCommentCount == 0) {
2780
            if (dwCount == 1) {
2781
               AddTextToEdit("This file does not have a comment.");
2782
            } else {
2783
               AddTextToEdit("None of the selected files have a comment.");
2784
            }
2785
         } else if (dwCount == 1) {
2786
            AddTextToEdit(szComment);
2787
         } else {
2788
            CHAR szTemp[64];
2789
            _stprintf(szBuffer, TEXT("%u of the selected files %s a comment."),
2790
                      dwCommentCount, (dwCommentCount == 1)? TEXT("has") : TEXT("have"));
2791
            TSTRTOMBS(szTemp, szBuffer, countof(szTemp));
2792
            AddTextToEdit(szTemp);
2793
         }
2794
         g_hWndEdit = NULL;
2795
 
2796
 
2797
         // Whooh, done with WM_INITDIALOG
2798
         return TRUE;
2799
      }
2800
 
2801
      case WM_NOTIFY:
2802
         // Check to see if tab control was changed to new tab.
2803
         if (((NMHDR*)lParam)->code == TCN_SELCHANGE) {
2804
            HWND hWndTab     = ((NMHDR*)lParam)->hwndFrom;
2805
            HWND hWndComment = GetDlgItem(hDlg, IDC_COMMENT);
2806
            HWND hWnd        = GetWindow(hDlg, GW_CHILD);
2807
 
2808
            // If General tab selected, hide comment edit box and show all other controls.
2809
            if (TabCtrl_GetCurSel(hWndTab) == 0) {
2810
               while (hWnd) {
2811
                  ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd != hWndComment)) ?
2812
                             SW_SHOW : SW_HIDE);
2813
                  hWnd = GetWindow(hWnd, GW_HWNDNEXT);
2814
               }
2815
 
2816
            // If Comment tab selected, hide all controls except comment edit box.
2817
            } else {
2818
               while (hWnd) {
2819
                  ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd == hWndComment)) ?
2820
                             SW_SHOW : SW_HIDE);
2821
                  hWnd = GetWindow(hWnd, GW_HWNDNEXT);
2822
               }
2823
            }
2824
         }
2825
         return FALSE;
2826
 
2827
      case WM_COMMAND:
2828
         // Exit the dialog on OK (Enter) or CANCEL (Esc).
2829
         if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
2830
            EndDialog(hDlg, LOWORD(wParam));
2831
         }
2832
         return FALSE;
2833
   }
2834
   return FALSE;
2835
}
2836
 
2837
//******************************************************************************
2838
void MergeValues(int *p1, int p2) {
2839
   if ((*p1 == -1) || (*p1 == p2)) {
2840
      *p1 = p2;
2841
   } else {
2842
      *p1 = -2;
2843
   }
2844
}
2845
 
2846
//******************************************************************************
2847
void CheckThreeStateBox(HWND hDlg, int nIDButton, int state) {
2848
   CheckDlgButton(hDlg, nIDButton, (state == 0) ? BST_UNCHECKED :
2849
                                   (state == 1) ? BST_CHECKED :
2850
                                                  BST_INDETERMINATE);
2851
}
2852
 
2853
 
2854
//******************************************************************************
2855
//***** Extract/Test Dialog Functions
2856
//******************************************************************************
2857
 
2858
void ExtractOrTestFiles(BOOL fExtract) {
2859
 
2860
   EXTRACT_INFO ei;
2861
   ZeroMemory(&ei, sizeof(ei));
2862
 
2863
   // Set our Extract or Test flag.
2864
   ei.fExtract = fExtract;
2865
 
2866
   // Get the number of selected items and make sure we have at least one item.
2867
   if ((ei.dwFileCount = ListView_GetSelectedCount(g_hWndList)) <= 0) {
2868
      return;
2869
   }
2870
 
2871
   // If we are not extracting/testing all, then create and buffer large enough to
2872
   // hold the file list for all the selected files.
2873
   if ((int)ei.dwFileCount != ListView_GetItemCount(g_hWndList)) {
2874
      ei.szFileList = new LPSTR[ei.dwFileCount + 1];
2875
      if (!ei.szFileList) {
2876
         MessageBox(g_hWndMain, GetZipErrorString(PK_MEM), g_szAppName,
2877
                    MB_ICONERROR | MB_OK);
2878
         return;
2879
      }
2880
   }
2881
 
2882
   ei.dwFileCount = 0;
2883
   ei.uzByteCount = 0;
2884
 
2885
   LV_ITEM lvi;
2886
   ZeroMemory(&lvi, sizeof(lvi));
2887
   lvi.mask = LVIF_PARAM;
2888
   lvi.iItem = -1;
2889
 
2890
   // Walk through all the selected files to build our counts and set our file
2891
   // list pointers into our FILE_NODE paths for each selected item.
2892
   while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) >= 0) {
2893
      ListView_GetItem(g_hWndList, &lvi);
2894
      if (ei.szFileList) {
2895
         ei.szFileList[ei.dwFileCount] = ((FILE_NODE*)lvi.lParam)->szPathAndMethod;
2896
      }
2897
      ei.dwFileCount++;
2898
      ei.uzByteCount += ((FILE_NODE*)lvi.lParam)->uzSize;
2899
   }
2900
   if (ei.szFileList) {
2901
      ei.szFileList[ei.dwFileCount] = NULL;
2902
   }
2903
 
2904
   // If we are extracting, display the extract dialog to query for parameters.
2905
   if (!fExtract || (DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT), g_hWndMain,
2906
                                    (DLGPROC)DlgProcExtractOrTest, (LPARAM)&ei) == IDOK))
2907
   {
2908
      // Display our progress dialog and do the extraction/test.
2909
      DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT_PROGRESS), g_hWndMain,
2910
                     (DLGPROC)DlgProcExtractProgress, (LPARAM)&ei);
2911
   }
2912
 
2913
   // Free our file list buffer if we created one.
2914
   if (ei.szFileList) {
2915
      delete[] ei.szFileList;
2916
   }
2917
}
2918
 
2919
//******************************************************************************
2920
BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2921
 
2922
   static EXTRACT_INFO *pei;
2923
   TCHAR  szPath[_MAX_PATH];
2924
 
2925
   switch (uMsg) {
2926
 
2927
      case WM_INITDIALOG:
2928
 
2929
         // Store our extract information structure.
2930
         pei = (EXTRACT_INFO*)lParam;
2931
 
2932
         // Load our settings.
2933
         pei->fRestorePaths = GetOptionInt(TEXT("RestorePaths"), TRUE);
2934
         pei->overwriteMode = (OVERWRITE_MODE)GetOptionInt(TEXT("OverwriteMode"), OM_PROMPT);
2935
 
2936
         // Load and set our path string.
2937
         GetOptionString(TEXT("ExtractToDirectory"), TEXT("\\"), szPath, sizeof(szPath));
2938
         SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
2939
 
2940
         // Set the state of all the controls.
2941
         SetDlgItemText(hDlg, IDC_FILE_COUNT, FormatValue(szPath, pei->dwFileCount));
2942
         SetDlgItemText(hDlg, IDC_BYTE_COUNT, FormatValue(szPath, pei->uzByteCount));
2943
         CheckDlgButton(hDlg, IDC_RESTORE_PATHS, pei->fRestorePaths);
2944
         CheckDlgButton(hDlg, IDC_OVERWRITE_PROMPT, pei->overwriteMode == OM_PROMPT);
2945
         CheckDlgButton(hDlg, IDC_OVERWRITE_NEWER,  pei->overwriteMode == OM_NEWER);
2946
         CheckDlgButton(hDlg, IDC_OVERWRITE_ALWAYS, pei->overwriteMode == OM_ALWAYS);
2947
         CheckDlgButton(hDlg, IDC_OVERWRITE_NEVER,  pei->overwriteMode == OM_NEVER);
2948
 
2949
         // Limit our edit control to max path.
2950
         SendDlgItemMessage(hDlg, IDC_EXTRACT_TO, EM_LIMITTEXT, sizeof(szPath) - 1, 0);
2951
 
2952
         // Center our dialog.
2953
         CenterWindow(hDlg);
2954
         return TRUE;
2955
 
2956
      case WM_COMMAND:
2957
         switch (LOWORD(wParam)) {
2958
 
2959
            case IDOK:
2960
 
2961
               // Force us to read and validate the extract to directory.
2962
               SendMessage(hDlg, WM_COMMAND, MAKELONG(IDC_EXTRACT_TO, EN_KILLFOCUS), 0);
2963
 
2964
               // Get our current path string.
2965
               GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
2966
 
2967
               // Verify our "extract to" path is valid.
2968
               if (!SetExtractToDirectory(szPath)) {
2969
                  MessageBox(hDlg, TEXT("The directory you entered is invalid or does not exist."),
2970
                             g_szAppName, MB_ICONERROR | MB_OK);
2971
                  SetFocus(GetDlgItem(hDlg, IDC_EXTRACT_TO));
2972
                  return FALSE;
2973
               }
2974
 
2975
               // Query other control values.
2976
               pei->fRestorePaths = IsDlgButtonChecked(hDlg, IDC_RESTORE_PATHS);
2977
               pei->overwriteMode =
2978
                  IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEWER)  ? OM_NEWER  :
2979
                  IsDlgButtonChecked(hDlg, IDC_OVERWRITE_ALWAYS) ? OM_ALWAYS :
2980
                  IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEVER)  ? OM_NEVER  : OM_PROMPT;
2981
 
2982
               // Write our settings.
2983
               WriteOptionInt(TEXT("RestorePaths"), pei->fRestorePaths);
2984
               WriteOptionInt(TEXT("OverwriteMode"), pei->overwriteMode);
2985
               WriteOptionString(TEXT("ExtractToDirectory"), szPath);
2986
 
2987
               // Fall through to IDCANCEL
2988
 
2989
            case IDCANCEL:
2990
               EndDialog(hDlg, LOWORD(wParam));
2991
               return FALSE;
2992
 
2993
            case IDC_EXTRACT_TO:
2994
 
2995
               // Make sure the path ends in a wack (\).
2996
               if (HIWORD(wParam) == EN_KILLFOCUS) {
2997
                  GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
2998
                  size_t length = _tcslen(szPath);
2999
                  if ((length == 0) || szPath[length - 1] != TEXT('\\')) {
3000
                     szPath[length    ] = TEXT('\\');
3001
                     szPath[length + 1] = TEXT('\0');
3002
                     SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
3003
                  }
3004
               }
3005
               return FALSE;
3006
 
3007
            case IDC_BROWSE:
3008
               GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
3009
               if (FolderBrowser(szPath, countof(szPath))) {
3010
                  SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
3011
               }
3012
               return FALSE;
3013
         }
3014
         return FALSE;
3015
   }
3016
   return FALSE;
3017
}
3018
 
3019
 
3020
//******************************************************************************
3021
//***** Folder Browsing Dialog Functions
3022
//******************************************************************************
3023
 
3024
BOOL FolderBrowser(LPTSTR szPath, DWORD dwLength) {
3025
 
3026
#ifdef _WIN32_WCE
3027
 
3028
   // On Windows CE, we use a common save-as dialog to query the diretory.  We
3029
   // display the dialog in this function, and then we sublass it.  Our subclass
3030
   // functions tweaks the dialog a bit and and returns the path.
3031
 
3032
   ForwardSlashesToBackSlashes(szPath);
3033
 
3034
   TCHAR szInitialDir[_MAX_PATH];
3035
   _tcscpy(szInitialDir, szPath);
3036
 
3037
   // Remove trailing wacks from path - The common dialog doesn't like them.
3038
   size_t length = _tcslen(szInitialDir);
3039
   while ((length > 0) && (szInitialDir[length - 1] == TEXT('\\'))) {
3040
      szInitialDir[--length] = TEXT('\0');
3041
   }
3042
 
3043
   // Set up the parameters for our save-as dialog.
3044
   OPENFILENAME ofn;
3045
   ZeroMemory(&ofn, sizeof(ofn));
3046
   ofn.lStructSize     = sizeof(ofn);
3047
   ofn.hwndOwner       = g_hWndMain;
3048
   ofn.hInstance       = g_hInst;
3049
   ofn.lpstrFilter     = TEXT(" \0!\0");
3050
   ofn.nFilterIndex    = 1;
3051
   ofn.lpstrFile       = szPath;
3052
   ofn.nMaxFile        = dwLength;
3053
   ofn.lpstrInitialDir = *szInitialDir ? szInitialDir : NULL;
3054
   ofn.lpstrTitle      = TEXT("Extract To");
3055
   ofn.Flags           = OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_NOTESTFILECREATE;
3056
 
3057
   // Post a message to our main window telling it that we are about to create
3058
   // a save as dialog.  Our main window will receive this message after the
3059
   // save as dialog is created.  This gives us a change to subclass the save as
3060
   // dialog.
3061
   PostMessage(g_hWndMain, WM_PRIVATE, MSG_SUBCLASS_DIALOG, 0);
3062
 
3063
   // Create and display the common save-as dialog.
3064
   if (GetSaveFileName(&ofn)) {
3065
 
3066
      // If success, then remove are special "!" filename from the end.
3067
      szPath[_tcslen(szPath) - 1] = TEXT('\0');
3068
      return TRUE;
3069
   }
3070
   return FALSE;
3071
 
3072
#else // !_WIN32_WCE
3073
 
3074
   // On Windows NT, the shell provides us with a nice folder browser dialog.
3075
   // We don't need to jump through any hoops to make it work like on Windows CE.
3076
   // The only problem is that on VC 4.0, the libraries don't export the UNICODE
3077
   // shell APIs because only Win95 had a shell library at the time.  The
3078
   // following code requires headers and libs from VC 4.2 or later.
3079
 
3080
   // Set up our BROWSEINFO structure.
3081
   BROWSEINFO bi;
3082
   ZeroMemory(&bi, sizeof(bi));
3083
   bi.hwndOwner = g_hWndMain;
3084
   bi.pszDisplayName = szPath;
3085
   bi.lpszTitle = TEXT("Extract To");
3086
   bi.ulFlags = BIF_RETURNONLYFSDIRS;
3087
 
3088
   // Prompt user for path.
3089
   LPITEMIDLIST piidl = SHBrowseForFolder(&bi);
3090
   if (!piidl) {
3091
      return FALSE;
3092
   }
3093
 
3094
   // Build path string.
3095
   SHGetPathFromIDList(piidl, szPath);
3096
 
3097
   // Free the PIDL returned by SHBrowseForFolder.
3098
   LPMALLOC pMalloc = NULL;
3099
   SHGetMalloc(&pMalloc);
3100
   pMalloc->Free(piidl);
3101
 
3102
   // Add trailing wack if one is not present.
3103
   size_t length = _tcslen(szPath);
3104
   if ((length > 0) && (szPath[length - 1] != TEXT('\\'))) {
3105
      szPath[length++] = TEXT('\\');
3106
      szPath[length]   = TEXT('\0');
3107
   }
3108
 
3109
   return TRUE;
3110
 
3111
#endif // _WIN32_WCE
3112
}
3113
 
3114
//******************************************************************************
3115
#ifdef _WIN32_WCE
3116
BOOL CALLBACK DlgProcBrowser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3117
 
3118
   // This is our subclass of Windows CE's common save-as dialog.  We intercept
3119
   // the messages we care about and forward everything else to the original
3120
   // window procedure for the dialog.
3121
 
3122
   if (uMsg == WM_PRIVATE) { // wParam always equals MSG_INIT_DIALOG
3123
 
3124
      RECT rc1, rc2;
3125
 
3126
      // Get the window rectangle for the name edit control.
3127
      HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_NAME_EDIT);
3128
      GetWindowRect(hWnd, &rc1);
3129
      POINT pt1 = { rc1.left, rc1.top };
3130
      ScreenToClient(hDlg, &pt1);
3131
 
3132
      // Hide all the windows we don't want.
3133
      ShowWindow(hWnd, SW_HIDE);
3134
      ShowWindow(GetDlgItem(hDlg, IDC_SAVE_NAME_PROMPT), SW_HIDE);
3135
      ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_PROMPT), SW_HIDE);
3136
      ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_LIST), SW_HIDE);
3137
 
3138
      // Get the window rectangle for the file list.
3139
      hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
3140
      GetWindowRect(hWnd, &rc2);
3141
      POINT pt2 = { rc2.left, rc2.top };
3142
      ScreenToClient(hDlg, &pt2);
3143
 
3144
      // Resize the file list to fill the dialog.
3145
      MoveWindow(hWnd, pt2.x, pt2.y, rc2.right - rc2.left, rc1.bottom - rc2.top, TRUE);
3146
 
3147
   } else if ((uMsg == WM_COMMAND) && (LOWORD(wParam) == IDOK)) {
3148
 
3149
      // Get our file list window.
3150
      HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
3151
 
3152
      // Check to see if a directory is selected.
3153
      if (ListView_GetNextItem(hWnd, -1, LVNI_SELECTED) >= 0) {
3154
 
3155
         // If a directory is highlighted, then we post ourself a "Ok".  The "Ok"
3156
         // we are processing now will cause us to change into the highlighted
3157
         // directory, and our posted "Ok" will close the dialog in that directory.
3158
         PostMessage(hDlg, uMsg, wParam, lParam);
3159
 
3160
      } else {
3161
         // If no directory is selected, then enter the imaginary filename "!"
3162
         // into the name edit control and let the "Ok" end this dialog. The
3163
         // result will be the correct path with a "\!" at the end.
3164
         SetDlgItemText(hDlg, IDC_SAVE_NAME_EDIT, TEXT("!"));
3165
      }
3166
   }
3167
 
3168
   // Pass all messages to the base control's window proc.
3169
   return CallWindowProc(g_wpSaveAsDlg, hDlg, uMsg, wParam, lParam);
3170
}
3171
#endif // _WIN32_WCE
3172
 
3173
//******************************************************************************
3174
#ifdef _WIN32_WCE
3175
void SubclassSaveAsDlg() {
3176
 
3177
   // Get our current thread ID so we can compare it to other thread IDs.
3178
   DWORD dwThreadId = GetCurrentThreadId();
3179
 
3180
   // Get the the top window in the z-order that is a child of the desktop.
3181
   // Dialogs are always children of the desktop on CE.  This first window
3182
   // should be the dialog we are looking for, but we will walk the window list
3183
   // just in case.
3184
   HWND hWnd = GetWindow(g_hWndMain, GW_HWNDFIRST);
3185
 
3186
   // Walk the window list.
3187
   while (hWnd) {
3188
 
3189
      // Check to see if this window was created by us and has controls from a
3190
      // common "save as" dialog.
3191
      if ((GetWindowThreadProcessId(hWnd, NULL) == dwThreadId) &&
3192
           GetDlgItem(hWnd, IDC_SAVE_FILE_LIST) &&
3193
           GetDlgItem(hWnd, IDC_SAVE_NAME_EDIT))
3194
      {
3195
         // We found our dialog.  Subclass it.
3196
         g_wpSaveAsDlg = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
3197
         SetWindowLong(hWnd, GWL_WNDPROC, (LONG)DlgProcBrowser);
3198
 
3199
         // Send our new dialog a message so it can do its initialization.
3200
         SendMessage(hWnd, WM_PRIVATE, MSG_INIT_DIALOG, 0);
3201
      }
3202
 
3203
      // Get the next window in our window list.
3204
      hWnd = GetWindow(hWnd, GW_HWNDNEXT);
3205
   }
3206
}
3207
#endif // _WIN32_WCE
3208
 
3209
 
3210
//******************************************************************************
3211
//***** Extraction/Test/View Progress Dialog Functions
3212
//******************************************************************************
3213
 
3214
BOOL CALLBACK DlgProcExtractProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3215
 
3216
   static EXTRACT_INFO *pei;
3217
   static BOOL fComplete;
3218
   static HWND hWndButton;
3219
   TCHAR szBuffer[32];
3220
 
3221
   switch (uMsg) {
3222
 
3223
      case WM_INITDIALOG:
3224
 
3225
         // Globally store our handle so our worker thread can post to us.
3226
         g_hDlgProgress = hDlg;
3227
 
3228
         // Get a pointer to our extract information structure.
3229
         pei = (EXTRACT_INFO*)lParam;
3230
 
3231
         // Clear our complete flag.  It will be set to TRUE when done.
3232
         fComplete = FALSE;
3233
 
3234
         // Get and store our edit control.
3235
         g_hWndEdit = GetDlgItem(hDlg, IDC_LOG);
3236
 
3237
         // Disable our edit box from being edited.
3238
         DisableEditing(g_hWndEdit);
3239
 
3240
         // Store a static handle for our Abort/Close button.
3241
         hWndButton = GetDlgItem(hDlg, IDCANCEL);
3242
 
3243
#ifdef _WIN32_WCE
3244
 
3245
         // Set our No-Drag style
3246
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_NODRAG |GetWindowLong(hDlg, GWL_EXSTYLE));
3247
 
3248
         RECT rc1, rc2, rcEdit;
3249
 
3250
         // Get our current client size.
3251
         GetClientRect(hDlg, &rc1);
3252
 
3253
         // Get the window rectangle for the edit control in client coordinates.
3254
         GetWindowRect(g_hWndEdit, &rcEdit);
3255
         ScreenToClient(hDlg, ((POINT*)&rcEdit));
3256
         ScreenToClient(hDlg, ((POINT*)&rcEdit) + 1);
3257
 
3258
         // Resize our dialog to be full screen (same size as parent).
3259
         GetWindowRect(g_hWndMain, &rc2);
3260
         MoveWindow(hDlg, rc2.left, rc2.top, rc2.right - rc2.left,
3261
                    rc2.bottom - rc2.top + 1, FALSE);
3262
 
3263
         // Get our new client size.
3264
         GetClientRect(hDlg, &rc2);
3265
 
3266
         // Resize our edit box to fill the client.
3267
         MoveWindow(g_hWndEdit, rcEdit.left, rcEdit.top,
3268
                    (rcEdit.right  - rcEdit.left) + (rc2.right  - rc1.right),
3269
                    (rcEdit.bottom - rcEdit.top)  + (rc2.bottom - rc1.bottom),
3270
                    FALSE);
3271
 
3272
#else
3273
         // On NT, we just center our dialog over our parent.
3274
         CenterWindow(hDlg);
3275
#endif
3276
 
3277
         // Store some globals until the extract/test finishes.
3278
         pei->hWndEditFile       = GetDlgItem(hDlg, IDC_FILE);
3279
         pei->hWndProgFile       = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
3280
         pei->hWndProgTotal      = GetDlgItem(hDlg, IDC_TOTAL_PROGRESS);
3281
         pei->hWndPercentage     = GetDlgItem(hDlg, IDC_PERCENTAGE);
3282
         pei->hWndFilesProcessed = GetDlgItem(hDlg, IDC_FILES_PROCESSED);
3283
         pei->hWndBytesProcessed = GetDlgItem(hDlg, IDC_BYTES_PROCESSED);
3284
 
3285
         if (pei->fExtract) {
3286
            // Set our main window's caption.
3287
            SetCaptionText(TEXT("Extracting"));
3288
 
3289
         } else {
3290
            // Set our main window's caption.
3291
            SetCaptionText(TEXT("Testing"));
3292
 
3293
            // Hide the current file progress for test since it never moves.
3294
            ShowWindow(pei->hWndProgFile, SW_HIDE);
3295
         }
3296
 
3297
         // Set the ranges on our progress bars.
3298
         SendMessage(pei->hWndProgFile,  PBM_SETRANGE, 0,
3299
                     MAKELPARAM(0, PROGRESS_MAX));
3300
         SendMessage(pei->hWndProgTotal, PBM_SETRANGE, 0,
3301
                     MAKELPARAM(0, PROGRESS_MAX));
3302
 
3303
         // Set our file and byte totals.
3304
         SetDlgItemText(hDlg, IDC_FILES_TOTAL,
3305
                        FormatValue(szBuffer, pei->dwFileCount));
3306
         SetDlgItemText(hDlg, IDC_BYTES_TOTAL,
3307
                        FormatValue(szBuffer, pei->uzByteCount));
3308
 
3309
         // Launch our Extract/Test thread and wait for WM_PRIVATE
3310
         DoExtractOrTestFiles(g_szZipFile, pei);
3311
 
3312
         return TRUE;
3313
 
3314
 
3315
      case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
3316
                       // test/extract is complete.
3317
 
3318
         // Check to see if the operation was a success
3319
         if ((pei->result == PK_OK) || (pei->result == PK_WARN)) {
3320
 
3321
            // Set all our fields to their "100%" settings.
3322
            SendMessage(pei->hWndProgFile,  PBM_SETPOS, PROGRESS_MAX, 0);
3323
            SendMessage(pei->hWndProgTotal, PBM_SETPOS, PROGRESS_MAX, 0);
3324
            SetWindowText(pei->hWndPercentage, TEXT("100%"));
3325
            SetDlgItemText(hDlg, IDC_FILES_PROCESSED,
3326
                           FormatValue(szBuffer, pei->dwFileCount));
3327
            SetDlgItemText(hDlg, IDC_BYTES_PROCESSED,
3328
                           FormatValue(szBuffer, pei->uzByteCount));
3329
         }
3330
 
3331
         // Update our status text.
3332
         SetWindowText(pei->hWndEditFile,
3333
            (pei->result == PK_OK)      ? TEXT("Completed.  There were no warnings or errors.") :
3334
            (pei->result == PK_WARN)    ? TEXT("Completed.  There was one or more warnings.") :
3335
            (pei->result == PK_ABORTED) ? TEXT("Aborted.  There may be warnings or errors.") :
3336
                                          TEXT("Completed.  There was one or more errors."));
3337
 
3338
         // Clear our global edit handle.
3339
         g_hWndEdit = NULL;
3340
 
3341
         // Update our caption to show that we are done extracting/testing.
3342
         SetCaptionText(NULL);
3343
 
3344
         // Change our abort button to now read "Close".
3345
         SetWindowText(hWndButton, TEXT("&Close"));
3346
         EnableWindow(hWndButton, TRUE);
3347
 
3348
         // Display an error dialog if an error occurred.
3349
         if ((pei->result != PK_OK) && (pei->result != PK_WARN)) {
3350
            MessageBox(hDlg, GetZipErrorString(pei->result),
3351
                       g_szAppName, MB_ICONERROR | MB_OK);
3352
         }
3353
 
3354
         // We are done.  Allow the user to close the dialog.
3355
         fComplete = TRUE;
3356
         return FALSE;
3357
 
3358
      case WM_COMMAND:
3359
         switch (LOWORD(wParam)) {
3360
            case IDCANCEL:
3361
               // If abort is pressed, then set a flag that our worker thread
3362
               // periodically checks to decide if it needs to bail out.
3363
               if (!fComplete && !pei->fAbort) {
3364
                  pei->fAbort = TRUE;
3365
                  SetWindowText(hWndButton, TEXT("Aborting..."));
3366
                  EnableWindow(hWndButton, FALSE);
3367
                  return FALSE;
3368
               }
3369
               // fall through to IDOK
3370
 
3371
            case IDOK:
3372
               // Don't allow dialog to close until extract/test is complete.
3373
               if (fComplete) {
3374
                  g_hDlgProgress = NULL;
3375
                  EndDialog(hDlg, LOWORD(wParam));
3376
               }
3377
               return FALSE;
3378
         }
3379
         return FALSE;
3380
   }
3381
   return FALSE;
3382
}
3383
 
3384
//******************************************************************************
3385
BOOL CALLBACK DlgProcViewProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3386
 
3387
   static EXTRACT_INFO *pei;
3388
 
3389
   switch (uMsg) {
3390
 
3391
      case WM_INITDIALOG:
3392
 
3393
         // Globally store our handle so our worker thread can post to us.
3394
         g_hDlgProgress = hDlg;
3395
 
3396
         // Get a pointer to our extract information structure.
3397
         pei = (EXTRACT_INFO*)lParam;
3398
 
3399
         // Center our dialog over our parent.
3400
         CenterWindow(hDlg);
3401
 
3402
         // Store some globals until the extract finishes.
3403
         pei->hWndProgFile = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
3404
 
3405
         // Set the ranges on our progress bar.
3406
         SendDlgItemMessage(hDlg, IDC_FILE_PROGRESS, PBM_SETRANGE, 0,
3407
                            MAKELPARAM(0, PROGRESS_MAX));
3408
 
3409
         // Launch our Extract thread and wait for WM_PRIVATE message.
3410
         DoExtractOrTestFiles(g_szZipFile, pei);
3411
 
3412
         return TRUE;
3413
 
3414
      case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
3415
                       // test/extract is complete.
3416
 
3417
         // We are done.  Close our dialog.  Any errors will be reported by
3418
         // OnActionView().
3419
         g_hDlgProgress = NULL;
3420
         EndDialog(hDlg, LOWORD(wParam));
3421
         return FALSE;
3422
 
3423
      case WM_COMMAND:
3424
         // If abort is pressed, then set a flag that our worker thread
3425
         // periodically checks to decide if it needs to bail out.
3426
         if ((LOWORD(wParam) == IDCANCEL) && !pei->fAbort) {
3427
            pei->fAbort = TRUE;
3428
            SetWindowText(GetDlgItem(hDlg, IDCANCEL), TEXT("Aborting..."));
3429
            EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
3430
            return FALSE;
3431
         }
3432
   }
3433
 
3434
   return FALSE;
3435
}
3436
 
3437
//******************************************************************************
3438
void UpdateProgress(EXTRACT_INFO *pei, BOOL fFull) {
3439
 
3440
   DWORD dwFile, dwTotal, dwPercentage;
3441
   TCHAR szBuffer[_MAX_PATH + 32];
3442
 
3443
   // Compute our file progress bar position.
3444
   if (pei->uzBytesTotalThisFile) {
3445
      dwFile = (DWORD)(((DWORDLONG)PROGRESS_MAX *
3446
                        (DWORDLONG)pei->uzBytesWrittenThisFile) /
3447
                        (DWORDLONG)pei->uzBytesTotalThisFile);
3448
   } else {
3449
      dwFile = PROGRESS_MAX;
3450
   }
3451
 
3452
   // Set our file progress indicators.
3453
   SendMessage(pei->hWndProgFile,  PBM_SETPOS, dwFile,  0);
3454
 
3455
   // If we are only updating our View Progress dialog, then we are done.
3456
   if (!pei->hWndProgTotal) {
3457
      return;
3458
   }
3459
 
3460
   // Compute our total progress bar position.
3461
   dwTotal = (DWORD)(((DWORDLONG)PROGRESS_MAX *
3462
                      (DWORDLONG)(pei->uzBytesWrittenPreviousFiles +
3463
                                  pei->uzBytesWrittenThisFile +
3464
                                  pei->dwFile)) /
3465
                      (DWORDLONG)(pei->uzByteCount +
3466
                                  pei->dwFileCount));
3467
   dwPercentage = dwTotal / (PROGRESS_MAX / 100);
3468
 
3469
   // Set our total progress indicators.
3470
   SendMessage(pei->hWndProgTotal, PBM_SETPOS, dwTotal, 0);
3471
 
3472
   // Set our total percentage text.
3473
   _stprintf(szBuffer, TEXT("%u%%"), dwPercentage);
3474
   SetWindowText(pei->hWndPercentage, szBuffer);
3475
 
3476
   // Set our current file and byte process counts.
3477
   FormatValue(szBuffer, pei->dwFile - 1);
3478
   SetWindowText(pei->hWndFilesProcessed, szBuffer);
3479
   FormatValue(szBuffer, pei->uzBytesWrittenPreviousFiles +
3480
               pei->uzBytesWrittenThisFile);
3481
   SetWindowText(pei->hWndBytesProcessed, szBuffer);
3482
 
3483
 
3484
   if (fFull) {
3485
 
3486
      // Build our message string.
3487
      _tcscpy(szBuffer, pei->fExtract ? TEXT("Extract") : TEXT("Test"));
3488
      size_t preflen = _tcslen(szBuffer);
3489
      MBSTOTSTR(szBuffer+preflen, pei->szFile,countof(szBuffer)-preflen);
3490
 
3491
      // Change all forward slashes to back slashes in the buffer.
3492
      ForwardSlashesToBackSlashes(szBuffer);
3493
 
3494
      // Update the file name in our dialog.
3495
      SetWindowText(pei->hWndEditFile, szBuffer);
3496
   }
3497
}
3498
 
3499
 
3500
//******************************************************************************
3501
//***** Replace File Dialog Functions
3502
//******************************************************************************
3503
 
3504
int PromptToReplace(LPCSTR szPath) {
3505
 
3506
   // Check to see if we are extracting for view only.
3507
   if (g_fViewing) {
3508
 
3509
      // Build prompt.
3510
      TCHAR szMessage[_MAX_PATH + 128];
3511
      _stprintf(szMessage,
3512
#ifdef UNICODE
3513
         TEXT("A file named \"%S\" has already been extracted for viewing.  ")
3514
#else
3515
         TEXT("A file named \"%s\" has already been extracted for viewing.  ")
3516
#endif
3517
         TEXT("That file might be opened and locked for viewing by another application.\n\n")
3518
         TEXT("Would you like to attempt to overwrite it with the new file?"),
3519
         GetFileFromPath(szPath));
3520
 
3521
      // Display prompt.
3522
      if (IDYES == MessageBox(g_hDlgProgress, szMessage, g_szAppName,
3523
                              MB_ICONWARNING | MB_YESNO))
3524
      {
3525
         // Tell Info-ZIP to continue with extraction.
3526
         return IDM_REPLACE_YES;
3527
      }
3528
 
3529
      // Remember that the file was skipped and tell Info-ZIP to abort extraction.
3530
      g_fSkipped = TRUE;
3531
      return IDM_REPLACE_NO;
3532
   }
3533
 
3534
   // Otherwise, do the normal replace prompt dialog.
3535
   return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_REPLACE), g_hWndMain,
3536
                         (DLGPROC)DlgProcReplace, (LPARAM)szPath);
3537
}
3538
 
3539
//******************************************************************************
3540
BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3541
   TCHAR szMessage[_MAX_PATH + 32];
3542
 
3543
   switch (uMsg) {
3544
 
3545
      case WM_INITDIALOG:
3546
 
3547
         // Play the question tone to alert the user.
3548
         MessageBeep(MB_ICONQUESTION);
3549
 
3550
         // Display a message with the file name.
3551
#ifdef UNICODE
3552
         _stprintf(szMessage, TEXT("\"%S\" already exists."), (LPCSTR)lParam);
3553
#else
3554
         _stprintf(szMessage, TEXT("\"%s\" already exists."), (LPCSTR)lParam);
3555
#endif
3556
 
3557
         // Change all forward slashes to back slashes in the buffer.
3558
         ForwardSlashesToBackSlashes(szMessage);
3559
 
3560
         // Display the file string.
3561
         SetDlgItemText(hDlg, IDC_FILE, szMessage);
3562
 
3563
         // Center our dialog over our parent.
3564
         CenterWindow(hDlg);
3565
         return TRUE;
3566
 
3567
      case WM_COMMAND:
3568
         switch (LOWORD(wParam)) {
3569
 
3570
            case IDCANCEL:
3571
            case IDOK:
3572
               EndDialog(hDlg, IDM_REPLACE_NO);
3573
               break;
3574
 
3575
            case IDM_REPLACE_ALL:
3576
            case IDM_REPLACE_NONE:
3577
            case IDM_REPLACE_YES:
3578
            case IDM_REPLACE_NO:
3579
               EndDialog(hDlg, wParam);
3580
               break;
3581
         }
3582
         return FALSE;
3583
   }
3584
   return FALSE;
3585
}
3586
 
3587
 
3588
//******************************************************************************
3589
//***** Password Dialog Functions
3590
//******************************************************************************
3591
 
3592
#if CRYPT
3593
 
3594
BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3595
 
3596
   // Return Values:
3597
   //    IZ_PW_ENTERED    got some PWD string, use/try it
3598
   //    IZ_PW_CANCEL     no password available (for this entry)
3599
   //    IZ_PW_CANCELALL  no password, skip any further PWD request
3600
   //    IZ_PW_ERROR      failure (no mem, no tty, ...)
3601
 
3602
   static DECRYPT_INFO *pdi;
3603
   TCHAR szMessage[_MAX_PATH + 32];
3604
 
3605
   switch (uMsg) {
3606
 
3607
      case WM_INITDIALOG:
3608
 
3609
         // Play the question tone to alert the user.
3610
         MessageBeep(MB_ICONQUESTION);
3611
 
3612
#ifdef _WIN32_WCE
3613
         // Add "Ok" button to caption bar.
3614
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
3615
                       GetWindowLong(hDlg, GWL_EXSTYLE));
3616
#endif
3617
 
3618
         // Store our decrypt information structure.
3619
         pdi = (DECRYPT_INFO*)lParam;
3620
 
3621
         // Display a message with the file name.
3622
#ifdef UNICODE
3623
         _stprintf(szMessage, TEXT("\"%S\" is encrypted."), pdi->szFile);
3624
#else
3625
         _stprintf(szMessage, TEXT("\"%s\" is encrypted."), pdi->szFile);
3626
#endif
3627
 
3628
         // Change all forward slashes to back slashes in the buffer.
3629
         ForwardSlashesToBackSlashes(szMessage);
3630
 
3631
         // Display the message with the file name.
3632
         SetDlgItemText(hDlg, IDC_FILE, szMessage);
3633
 
3634
         // Display the appropriate prompt.
3635
         if (pdi->retry) {
3636
            _stprintf(szMessage, TEXT("Password was incorrect. Please re-enter (%d/%d)."),
3637
                     MAX_PASSWORD_RETRIES - pdi->retry + 2, MAX_PASSWORD_RETRIES + 1);
3638
            SetDlgItemText(hDlg, IDC_PROMPT, szMessage);
3639
         } else {
3640
            SetDlgItemText(hDlg, IDC_PROMPT, TEXT("Please enter the password."));
3641
         }
3642
 
3643
         // Limit the password to the size of the password buffer we have been given.
3644
         SendDlgItemMessage(hDlg, IDC_PASSWORD, EM_LIMITTEXT, pdi->nSize - 1, 0);
3645
 
3646
         // Center our dialog over our parent.
3647
         CenterWindow(hDlg);
3648
         return TRUE;
3649
 
3650
      case WM_COMMAND:
3651
         switch (LOWORD(wParam)) {
3652
 
3653
            case IDOK:
3654
 
3655
               // Store the password in our return password buffer.
3656
               GetDlgItemText(hDlg, IDC_PASSWORD, szMessage, countof(szMessage));
3657
               TSTRTOMBS(pdi->szPassword, szMessage, pdi->nSize);
3658
               EndDialog(hDlg, IZ_PW_ENTERED);
3659
               return FALSE;
3660
 
3661
            case IDCANCEL:
3662
               g_fSkipped = TRUE;
3663
               EndDialog(hDlg, IZ_PW_CANCEL);
3664
               return FALSE;
3665
 
3666
            case IDC_SKIP_ALL:
3667
               g_fSkipped = TRUE;
3668
               EndDialog(hDlg, IZ_PW_CANCELALL);
3669
               return FALSE;
3670
         }
3671
         return FALSE;
3672
   }
3673
   return FALSE;
3674
}
3675
 
3676
#endif // CRYPT
3677
 
3678
//******************************************************************************
3679
//***** View Association Dialog Functions
3680
//******************************************************************************
3681
 
3682
BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3683
 
3684
   static LPTSTR szApp;
3685
 
3686
   switch (uMsg) {
3687
 
3688
      case WM_INITDIALOG:
3689
         // Store the path buffer for our application.
3690
         szApp = (LPTSTR)lParam;
3691
 
3692
         // Read our default viewer from the registry.
3693
#ifdef _WIN32_WCE
3694
         GetOptionString(TEXT("FileViewer"), TEXT("\\Windows\\PWord.exe"),
3695
                         szApp, sizeof(TCHAR) * _MAX_PATH);
3696
#else
3697
         GetOptionString(TEXT("FileViewer"), TEXT("notepad.exe"),
3698
                         szApp, sizeof(TCHAR) * _MAX_PATH);
3699
#endif
3700
 
3701
         // Limit our edit control to our buffer size.
3702
         SendDlgItemMessage(hDlg, IDC_PATH, EM_LIMITTEXT, _MAX_PATH - 1, 0);
3703
 
3704
         // Set our path string in our dialog.
3705
         SetDlgItemText(hDlg, IDC_PATH, szApp);
3706
 
3707
         // Center our dialog over our parent.
3708
         CenterWindow(hDlg);
3709
         return TRUE;
3710
 
3711
      case WM_COMMAND:
3712
         switch (LOWORD(wParam)) {
3713
 
3714
            case IDOK:
3715
               // Get the text currently in the path edit box and store it.
3716
               GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
3717
               WriteOptionString(TEXT("FileViewer"), szApp);
3718
               // Fall through
3719
 
3720
            case IDCANCEL:
3721
               EndDialog(hDlg, LOWORD(wParam));
3722
               break;
3723
 
3724
            case IDC_BROWSE:
3725
               // Get the text currently in the path edit box.
3726
               GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
3727
 
3728
               // Get the direcory from the path text.
3729
               ForwardSlashesToBackSlashes(szApp);
3730
               TCHAR szInitialDir[_MAX_PATH], *szFile;
3731
               _tcscpy(szInitialDir, szApp);
3732
               if (szFile = _tcsrchr(szInitialDir, TEXT('\\'))) {
3733
                  *szFile = TEXT('\0');
3734
               }
3735
 
3736
               // Prepare to display browse dialog.
3737
               OPENFILENAME ofn;
3738
               ZeroMemory(&ofn, sizeof(ofn));
3739
               ofn.lStructSize     = sizeof(ofn);
3740
               ofn.hwndOwner       = hDlg;
3741
               ofn.hInstance       = g_hInst;
3742
               ofn.lpstrFilter     = TEXT("Programs (*.exe)\0*.exe\0All Files (*.*)\0*.*\0");
3743
               ofn.nFilterIndex    = 1;
3744
               ofn.lpstrFile       = szApp;
3745
               ofn.nMaxFile        = _MAX_PATH;
3746
               ofn.lpstrInitialDir = szInitialDir;
3747
               ofn.lpstrTitle      = TEXT("Open With...");
3748
               ofn.Flags           = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
3749
               ofn.lpstrDefExt     = TEXT("exe");
3750
 
3751
               // Display the browse dialog and update our path edit box if neccessary.
3752
               if (GetOpenFileName(&ofn)) {
3753
                  SetDlgItemText(hDlg, IDC_PATH, szApp);
3754
               }
3755
               break;
3756
         }
3757
         return FALSE;
3758
   }
3759
   return FALSE;
3760
}
3761
 
3762
 
3763
//******************************************************************************
3764
//***** Comment Dialog Functions
3765
//******************************************************************************
3766
 
3767
BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3768
   RECT    rc;
3769
   HCURSOR hCur;
3770
   int     result;
3771
 
3772
   switch (uMsg) {
3773
 
3774
      case WM_INITDIALOG:
3775
         // Get the handle to our edit box and store it globally.
3776
         g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
3777
 
3778
         // Disable our edit box from being edited.
3779
         DisableEditing(g_hWndEdit);
3780
 
3781
#ifdef _WIN32_WCE
3782
         // Add "Ok" button to caption bar and make window No-Drag.
3783
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | WS_EX_NODRAG |
3784
                       GetWindowLong(hDlg, GWL_EXSTYLE));
3785
 
3786
         // On CE, we resize our dialog to be full screen (same size as parent).
3787
         GetWindowRect(g_hWndMain, &rc);
3788
         MoveWindow(hDlg, rc.left, rc.top, rc.right - rc.left,
3789
                    rc.bottom - rc.top + 1, FALSE);
3790
#else
3791
         // On NT we just center the dialog.
3792
         CenterWindow(hDlg);
3793
#endif
3794
 
3795
         // Set our edit control to be the full size of our dialog.
3796
         GetClientRect(hDlg, &rc);
3797
         MoveWindow(g_hWndEdit, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
3798
 
3799
         // Show hour glass cursor while processing comment.
3800
         hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
3801
 
3802
         // Let Info-ZIP and our callbacks do the work.
3803
         result = DoGetComment(g_szZipFile);
3804
 
3805
         // Restore/remove our cursor.
3806
         SetCursor(hCur);
3807
 
3808
         // Display an error dialog if an error occurred.
3809
         if ((result != PK_OK) && (result != PK_WARN)) {
3810
            MessageBox(g_hWndMain, GetZipErrorString(result), g_szAppName,
3811
                       MB_ICONERROR | MB_OK);
3812
         }
3813
 
3814
         // Clear our global edit box handle as we are done with it.
3815
         g_hWndEdit = NULL;
3816
 
3817
         // Return FALSE to prevent edit box from gaining focus and showing highlight.
3818
         return FALSE;
3819
 
3820
      case WM_COMMAND:
3821
         if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
3822
            EndDialog(hDlg, LOWORD(wParam));
3823
         }
3824
         return FALSE;
3825
   }
3826
   return FALSE;
3827
}
3828
 
3829
 
3830
//******************************************************************************
3831
//***** About Dialog Functions
3832
//******************************************************************************
3833
 
3834
BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3835
 
3836
   switch (uMsg) {
3837
 
3838
      case WM_INITDIALOG:
3839
 
3840
#ifdef _WIN32_WCE
3841
         // Add "Ok" button to caption bar.
3842
         SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
3843
                       GetWindowLong(hDlg, GWL_EXSTYLE));
3844
#endif
3845
 
3846
         // Fill in a few static members.
3847
         // (For VER_FULLVERSION_STR and VER_COMMENT_STR, the TEXT() macro is
3848
         //  not applicable, because they are defined as a set of concatenated
3849
         //  string constants. These strings need to be converted to UNICODE
3850
         //  at runtime, sigh.)
3851
         TCHAR szBuffer[128];
3852
         SetDlgItemText(hDlg, IDC_PRODUCT, TEXT(VER_PRODUCT_STR));
3853
#ifdef UNICODE
3854
         _stprintf(szBuffer, TEXT("Freeware Version %S"), VER_FULLVERSION_STR);
3855
#else
3856
         _stprintf(szBuffer, TEXT("Freeware Version %s"), VER_FULLVERSION_STR);
3857
#endif
3858
         SetDlgItemText(hDlg, IDC_VERSION, szBuffer);
3859
         _stprintf(szBuffer, TEXT("Developed by %s"), TEXT(VER_DEVELOPER_STR));
3860
         SetDlgItemText(hDlg, IDC_DEVELOPER, szBuffer);
3861
         SetDlgItemText(hDlg, IDC_COPYRIGHT, TEXT(VER_COPYRIGHT_STR));
3862
#ifdef UNICODE
3863
         _stprintf(szBuffer, TEXT("%S"), VER_COMMENT_STR);
3864
         SetDlgItemText(hDlg, IDC_COMMENT, szBuffer);
3865
#else
3866
         SetDlgItemText(hDlg, IDC_COMMENT, VER_COMMENT_STR);
3867
#endif
3868
 
3869
         // Center the dialog over our parent.
3870
         CenterWindow(hDlg);
3871
         return TRUE;
3872
 
3873
      case WM_COMMAND:
3874
         if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
3875
            EndDialog(hDlg, 0);
3876
         }
3877
         return FALSE;
3878
   }
3879
   return FALSE;
3880
}