2
Copyright (c) 1990-2003 Info-ZIP. All rights reserved.
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
9
//******************************************************************************
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
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.
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.
37
// InitializeApplication
38
// ShutdownApplication
64
// BuildAttributesString
67
// ForwardSlashesToBackSlashesA
68
// ForwardSlashesToBackSlashesW
69
// DeleteDirectory(LPTSTR szPath);
88
// DlgProcExtractOrTest
92
// DlgProcExtractProgress
93
// DlgProcViewProgress
98
// DlgProcViewAssociation
104
// -------- ------------ -----------------------------------------------------
105
// 02/01/97 Steve Miller Created (Version 1.0 using Info-ZIP UnZip 5.30)
107
//******************************************************************************
110
#define __WINMAIN_CPP__
111
#define UNZIP_INTERNAL
115
#include "crypt.h" // Needed to pick up CRYPT define setting and return values.
117
#include "unzvers.h" // Only needed by consts.h (VERSION_DATE & VersionDate)
118
#include "consts.h" // Only include once - defines constant string messages.
120
#include <commctrl.h> // Common controls - mainly ListView and ImageList
121
#include <commdlg.h> // Common dialogs - OpenFile dialog
124
#include <shlobj.h> // On NT, we use the SHBrowseForFolder() stuff.
125
#include <shellapi.h> // CommandLineToArgvW() and ExtractIconEx()
128
#include "intrface.h" // Interface between Info-ZIP and us
129
#include "winmain.h" // Us
131
#include <tchar.h> // Must be outside of extern "C" block
134
//******************************************************************************
135
//***** "Local" Global Variables
136
//******************************************************************************
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;
158
static LPCTSTR g_szHelpFile = TEXT("\\windows\\punzip.htp");
160
static TCHAR g_szTempDirPath[_MAX_PATH];
161
static LPCTSTR g_szHelpFile = TEXT("punzip.html");
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 }
178
//******************************************************************************
179
//***** Local Function Prototypes
180
//******************************************************************************
182
// Startup and Shutdown Functions
183
void InitializeApplication(LPCTSTR szZipFile);
184
void ShutdownApplication();
185
void RegisterUnzip();
186
void BuildImageList();
188
// Our Main Window's Message Handler
189
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
191
// Event Handlers for our Main Window
195
void OnActionSelectAll();
196
void OnViewExpandedView();
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);
204
// List View Sort Functions
205
void Sort(int sortColumn, BOOL fForce);
206
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM sortColumn);
208
// Helper/Utility Functions
209
void SetCaptionText(LPCTSTR szPrefix);
210
void DrawBanner(HDC hdc);
211
void AddDeleteColumns();
212
void ResizeColumns();
213
LPCTSTR GetZipErrorString(int error);
214
void AddFileToListView(FILE_NODE *pFile);
215
void EnableAllMenuItems(UINT uMenuItem, BOOL fEnabled);
216
void CheckAllMenuItems(UINT uMenuItem, BOOL fChecked);
217
void CenterWindow(HWND hWnd);
218
void AddTextToEdit(LPCSTR szText);
219
LPTSTR FormatValue(LPTSTR szValue, DWORD dwValue);
220
LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes);
221
LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType);
222
LPCSTR GetFileFromPath(LPCSTR szPath);
223
void ForwardSlashesToBackSlashesA(LPSTR szBuffer);
225
void ForwardSlashesToBackSlashesW(LPWSTR szBuffer);
226
# define ForwardSlashesToBackSlashes ForwardSlashesToBackSlashesW
228
# define ForwardSlashesToBackSlashes ForwardSlashesToBackSlashesA
230
void DeleteDirectory(LPTSTR szPath);
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);
240
// EDIT Control Subclass Functions
241
void DisableEditing(HWND hWndEdit);
242
LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
245
void InitializeMRU();
246
void AddFileToMRU(LPCSTR szFile);
247
void RemoveFileFromMRU(LPCTSTR szFile);
248
void ActivateMRU(UINT uIDItem);
250
// Open Zip File Functions
251
void ReadZipFileList(LPCTSTR wszPath);
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);
258
// Extract/Test Dialog Functions
259
void ExtractOrTestFiles(BOOL fExtract);
260
BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
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();
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);
272
// Replace File Dialog Functions
273
int PromptToReplace(LPCSTR szPath);
274
BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
276
// Password Dialog Functions
277
BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
279
// View Association Dialog Functions
280
BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
282
// Comment Dialog Functions
283
BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
285
// About Dialog Functions
286
BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
289
//******************************************************************************
290
//***** WinMain - Our one and only entry point
291
//******************************************************************************
293
// Entrypoint is a tiny bit different on Windows CE - UNICODE command line.
295
extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
296
LPTSTR lpCmdLine, int nCmdShow)
298
extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
299
LPSTR lpCmdLine, int nCmdShow)
302
// Wrap the whole ball of wax in a big exception handler.
305
// Store global instance handle.
308
// Create our banner font. We need to do this before creating our window.
309
// This font handle will be deleted in ShutdownApplication().
311
ZeroMemory(&lf, sizeof(lf));
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);
322
// Define the window class for our application's main window.
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);
330
TCHAR *szZipPath = NULL;
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;
340
// On Windows CE, we only need the WS_VISIBLE flag.
341
DWORD dwStyle = WS_VISIBLE;
343
// Get and store command line file (if any).
344
if (lpCmdLine && *lpCmdLine) {
345
szZipPath = lpCmdLine;
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);
355
// On Windows NT, we use the standard overlapped window style.
356
DWORD dwStyle = WS_OVERLAPPEDWINDOW;
358
TCHAR szBuffer[_MAX_PATH];
360
// Get and store command line file (if any).
361
if (lpCmdLine && *lpCmdLine) {
362
MBSTOTSTR(szBuffer, lpCmdLine, countof(szBuffer));
363
szZipPath = szBuffer;
368
// Register our window class with the OS.
369
if (!RegisterClass(&wc)) {
370
DebugOut(TEXT("RegisterClass() failed [%u]"), GetLastError());
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);
379
// Quit now if we failed to create our main window.
381
DebugOut(TEXT("CreateWindow() failed [%u]"), GetLastError());
382
ShutdownApplication();
386
// Make sure our window is visible. Really only needed for NT.
387
ShowWindow(g_hWndMain, nCmdShow);
389
// Load our keyboard accelerator shortcuts.
391
HACCEL hAccel = LoadAccelerators(g_hInst, MAKEINTRESOURCE(IDR_UNZIP));
392
DWORD dwPaintFlags = 0;
394
// The message pump. Loop until we get a WM_QUIT message.
395
while (GetMessage(&msg, NULL, 0, 0)) {
397
// Check to see if this is an accelerator and handle it if neccessary.
398
if (!TranslateAccelerator(g_hWndMain, hAccel, &msg)) {
400
// If a normal message, then dispatch it to the correct window.
401
TranslateMessage(&msg);
402
DispatchMessage(&msg);
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;
412
if (dwPaintFlags == 0x11) {
413
InitializeApplication((szZipPath && *szZipPath) ?
421
ShutdownApplication();
423
// Nice clean finish - were out of here.
427
} __except(EXCEPTION_EXECUTE_HANDLER) {
429
// Something very bad happened. Try our best to appear somewhat graceful.
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);
445
//******************************************************************************
446
//***** Startup and Shutdown Functions
447
//******************************************************************************
449
void InitializeApplication(LPCTSTR szZipFile) {
451
// This function is called after our class is registered and all our windows
452
// are created and visible to the user.
454
// Show hour glass cursor.
455
HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
457
// Register UnZip in the registry to handle ".ZIP" files.
460
// Enumerate the system file assoications and build an image list.
463
// Load our initial MRU into our menu.
466
// Restore/remove our cursor.
469
// Clear our initialization window handle.
470
g_hWndWaitFor = NULL;
472
// Load our command line file if one was specified. Otherwise, just update
473
// our banner to show that no file is loaded.
475
ReadZipFileList(szZipFile);
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);
486
// Set our temporary directory.
488
g_szTempDir = TEXT("\\Temporary Pocket UnZip Files");
490
g_szTempDir = TEXT("C:\\Temporary Pocket UnZip Files");
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;
500
//******************************************************************************
501
void ShutdownApplication() {
503
// Free our banner font.
505
DeleteObject(g_hFontBanner);
506
g_hFontBanner = NULL;
509
// Delete our FILE_TYPE_NODE linked list.
510
for (FILE_TYPE_NODE *pft = g_pftHead; pft; ) {
511
FILE_TYPE_NODE *pftNext = pft->pNext;
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);
527
//******************************************************************************
528
void RegisterUnzip() {
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
537
TCHAR szPath[32] = TEXT("punzip.exe");
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));
552
// Store a pointer to the end of our path for easy appending.
553
LPTSTR szEnd = szPath + _tcslen(szPath);
555
BOOL fDoRegisterPUnZip = TRUE;
557
// Associate "ZIP" file extensions to our application
558
if (RegReadKey(HKEY_CLASSES_ROOT, TEXT(".zip"), szTstPath, sizeof(szTstPath)))
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;
567
if (!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)"),
576
MB_ICONQUESTION | MB_OKCANCEL));
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);
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);
592
// Create our application option location.
593
RegWriteKey(HKEY_CURRENT_USER, TEXT("Software"), NULL);
594
RegWriteKey(HKEY_CURRENT_USER, g_szRegKey, NULL);
597
//******************************************************************************
598
void BuildImageList() {
600
// Create our global image list.
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.
606
HIMAGELIST hil = ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 8, 8);
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);
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));
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);
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))
631
dwCount = countof(szExtension);
633
// Check to see if we read an extension key (starts with a period)
634
if (*szExtension != TEXT('.')) {
638
// Read the actual key name for this extension.
639
if (!RegReadKey(HKEY_CLASSES_ROOT, szExtension, szKey, sizeof(szKey))) {
643
// Read the Description for this extension.
644
RegReadKey(HKEY_CLASSES_ROOT, szKey, szDescription, sizeof(szDescription));
647
LPTSTR szEnd = szKey + _tcslen(szKey);
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))) {
653
// Look for the comma between the file name and the image.
654
LPTSTR szImageId = _tcschr(szIconFile, TEXT(','));
657
// NULL terminate the file name portion of szIconFile.
658
*(szImageId++) = TEXT('\0');
660
// Get the image ID value from szIconFile.
661
int imageId = _ttoi(szImageId);
663
// Extract the icon from the module specified in szIconFile.
664
ExtractIconEx(szIconFile, imageId, NULL, &hIcon, 1);
666
ExtractIconEx(szIconFile, imageId, &hIcon, NULL, 1);
671
// If we failed to get the icon using the "DefaultIcon" key, then try
672
// using the "shell\Open\command" key.
675
_tcscpy(szEnd, TEXT("\\shell\\Open\\command"));
676
if (RegReadKey(HKEY_CLASSES_ROOT, szKey, szIconFile, sizeof(szIconFile))) {
678
// Get a pointer to just the binary - strip quotes and spaces.
680
if (*szIconFile == TEXT('\"')) {
681
szPath = szIconFile + 1;
682
if (szEnd = _tcschr(szPath, TEXT('\"'))) {
687
if (szEnd = _tcschr(szPath, TEXT(' '))) {
692
// Extract the icon from the module specified in szIconFile.
693
ExtractIconEx(szPath, 0, NULL, &hIcon, 1);
695
ExtractIconEx(szPath, 0, &hIcon, NULL, 1);
700
// If we found an icon, add it to our image list.
703
image = ImageList_AddIcon(hil, hIcon);
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")) ||
713
!_tcsicmp(szExtension + 1, TEXT("exe"))))
715
image = IMAGE_APPLICATION;
718
// If we don't have a description or a icon, then bail on this extension.
719
if (!*szDescription && (image < 0)) {
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)];
728
// Bail out if we could not create our node.
730
DebugOut(TEXT("Not enough memory to create a FILE_TYPE_NODE."));
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);
742
// Add the node to our list.
744
pftLast->pNext = pft;
751
// Assign this image list to our tree control.
752
ListView_SetImageList(g_hWndList, hil, LVSIL_SMALL);
756
//******************************************************************************
757
//***** Our Main Window's Message Handler
758
//******************************************************************************
760
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
768
DrawBanner((HDC)wParam);
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);
777
// On NT we have to resize our toolbar as well.
778
MoveWindow(g_hWndCmdBar, 0, 0, LOWORD(lParam), g_cyCmdBar, TRUE);
783
// Always direct focus to our list control.
784
SetFocus(g_hWndList);
799
case MSG_SUBCLASS_DIALOG:
803
case MSG_ADD_TEXT_TO_EDIT:
804
AddTextToEdit((LPCSTR)lParam);
807
case MSG_PROMPT_TO_REPLACE:
808
return PromptToReplace((LPCSTR)lParam);
811
case MSG_PROMPT_FOR_PASSWORD:
812
return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_PASSWORD),
813
g_hDlgProgress, (DLGPROC)DlgProcPassword,
817
case MSG_UPDATE_PROGRESS_PARTIAL:
818
UpdateProgress((EXTRACT_INFO*)lParam, FALSE);
821
case MSG_UPDATE_PROGRESS_COMPLETE:
822
UpdateProgress((EXTRACT_INFO*)lParam, TRUE);
828
switch (((LPNMHDR)lParam)->code) {
830
case LVN_GETDISPINFO:
831
OnGetDispInfo((LV_DISPINFO*)lParam);
835
OnDeleteItem((NM_LISTVIEW*)lParam);
838
case LVN_COLUMNCLICK:
839
Sort(((NM_LISTVIEW*)lParam)->iSubItem, FALSE);
842
case LVN_ITEMCHANGED:
843
OnItemChanged((NM_LISTVIEW*)lParam);
855
switch (LOWORD(wParam)) {
861
case IDM_FILE_PROPERTIES:
862
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_PROPERTIES), hWnd, (DLGPROC)DlgProcProperties);
866
SendMessage(hWnd, WM_CLOSE, 0, 0);
869
case IDM_ACTION_EXTRACT_ALL:
871
// Fall through to IDM_ACTION_EXTRACT
873
case IDM_ACTION_EXTRACT:
874
ExtractOrTestFiles(TRUE);
877
case IDM_ACTION_TEST_ALL:
879
// Fall through to IDM_ACTION_TEST
881
case IDM_ACTION_TEST:
882
ExtractOrTestFiles(FALSE);
885
case IDM_ACTION_VIEW:
889
case IDM_ACTION_SELECT_ALL:
893
case IDM_VIEW_EXPANDED_VIEW:
894
OnViewExpandedView();
897
case IDM_VIEW_COMMENT:
898
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_COMMENT), hWnd, (DLGPROC)DlgProcComment);
902
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)DlgProcAbout);
906
return SendMessage(hWnd, WM_HELP, 0, 0);
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)))
913
ActivateMRU(LOWORD(wParam));
917
return DefWindowProc(hWnd, uMsg, wParam, lParam);
920
//******************************************************************************
921
//***** Event Handlers for our Main Window
922
//******************************************************************************
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 }
945
// Our toolbar buttons' tool tip text.
946
static LPTSTR szToolTips[] = {
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")
959
// Initialize the common controls.
960
InitCommonControls();
962
// Check to see if we have a help file.
963
BOOL fHelp = (GetFileAttributes(g_szHelpFile) != 0xFFFFFFFF);
965
// Set our window's icon so it can update the task bar.
967
SendMessage(g_hWndMain, WM_SETICON, FALSE, (LPARAM)g_hIconMain);
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);
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);
985
// Add tool tips to the tool bar.
986
CommandBar_AddToolTips(g_hWndCmdBar, countof(szToolTips), szToolTips);
988
// Store the height of the command bar for later calculations.
989
g_cyCmdBar = CommandBar_Height(g_hWndCmdBar);
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);
995
// Add the help item to our help menu if we have a help file.
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"));
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,
1010
// Get our tool tip control.
1011
HWND hWndTT = (HWND)SendMessage(g_hWndCmdBar, TB_GETTOOLTIPS, 0, 0);
1013
// Set our tool tip strings.
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);
1027
// Store the height of the tool bar for later calculations.
1029
GetWindowRect(g_hWndCmdBar, &rc);
1030
g_cyCmdBar = rc.bottom - rc.top;
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;
1036
// Add the help item to our help menu if we have a help file.
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"));
1043
#endif // _WIN32_WCE
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));
1052
// Get our expanded view option from the registry.
1053
g_fExpandedView = GetOptionInt(TEXT("ExpandedView"), FALSE);
1055
// Show or remove menu check for expanded view option.
1056
CheckAllMenuItems(IDM_VIEW_EXPANDED_VIEW, g_fExpandedView);
1058
// Create our columns.
1061
// Set our current sort column to our name column
1067
//******************************************************************************
1070
TCHAR szPath[_MAX_PATH] = TEXT("");
1073
ZeroMemory(&ofn, sizeof(ofn));
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");
1085
if (GetOpenFileName(&ofn)) {
1086
ReadZipFileList(szPath);
1090
//******************************************************************************
1091
void OnActionView() {
1093
// We only allow a view if one item is selected.
1094
int count = ListView_GetSelectedCount(g_hWndList);
1099
// Query the selected item for its FILE_NODE.
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;
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);
1114
// Make sure our temporary directory exists.
1115
CreateDirectory(g_szTempDir, NULL);
1117
TCHAR szPath[_MAX_PATH + 256];
1119
// Set our extraction directory to our temporary directory.
1120
if (!SetExtractToDirectory((LPTSTR)g_szTempDir)) {
1122
// Create error message. Use szPath buffer because it is handy.
1124
TEXT("Could not create \"%s\"\n\n")
1125
TEXT("Most likely cause is that your drive is full."),
1128
// Display error message.
1129
MessageBox(g_hWndMain, szPath, g_szAppName, MB_ICONERROR | MB_OK);
1134
// Create our single item file array.
1135
CHAR *argv[2] = { pfn->szPathAndMethod, NULL };
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';
1143
// Configure our extract structure.
1145
ZeroMemory(&ei, sizeof(ei));
1148
ei.dwByteCount = pfn->dwSize;
1149
ei.szFileList = argv;
1150
ei.fRestorePaths = FALSE;
1151
ei.overwriteMode = OM_PROMPT;
1152
ei.szMappedPath = szMappedPath;
1154
// Clear our skipped flag and set our viewing flag.
1158
// Display our progress dialog and do the extraction.
1159
DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_VIEW_PROGRESS), g_hWndMain,
1160
(DLGPROC)DlgProcViewProgress, (LPARAM)&ei);
1162
// Clear our viewing flag.
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.
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);
1178
// Check to see if the extraction failed.
1179
if (ei.result != PK_OK) {
1181
if (ei.result == PK_ABORTED) {
1182
_tcscpy(szPath, GetZipErrorString(ei.result));
1185
// Create error message. Use szPath buffer because it is handy.
1188
TEXT("Could not extract \"%S\".\n\n%s\n\nTry using the Test or ")
1190
TEXT("Could not extract \"%s\".\n\n%s\n\nTry using the Test or ")
1192
TEXT("Extract action on the file for more details."),
1193
*szMappedPath ? szMappedPath : pfn->szPathAndMethod,
1194
GetZipErrorString(ei.result));
1197
// Display error message.
1198
MessageBox(g_hWndMain, szPath, g_szAppName, MB_ICONERROR | MB_OK);
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);
1212
// Convert the file name to UNICODE.
1213
MBSTOTSTR(szPath, szMappedPath, countof(szPath));
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;
1225
TCHAR szApp[_MAX_PATH];
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.
1231
// Check our file image to see if this file has no associated viewer.
1232
if (lvi.iImage == IMAGE_GENERIC) {
1234
// Display our file association prompt dialog.
1235
if (IDOK != DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_VIEW_ASSOCIATION),
1236
g_hWndMain, (DLGPROC)DlgProcViewAssociation,
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);
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.
1251
sei.lpParameters = szPath;
1253
sei.lpFile = szPath;
1258
// On NT, ShellExecuteEx() will prompt user for association if needed.
1259
sei.lpFile = szPath;
1263
// Launch the file. All errors will be displayed by ShellExecuteEx().
1264
ShellExecuteEx(&sei);
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);
1274
//******************************************************************************
1275
void OnViewExpandedView() {
1277
// Toggle our expanded view option.
1278
g_fExpandedView = !g_fExpandedView;
1280
// Show or remove menu check and toolbar button press.
1281
CheckAllMenuItems(IDM_VIEW_EXPANDED_VIEW, g_fExpandedView);
1283
// Display the new columns.
1286
// Re-sort if we just did away with out sort column.
1287
if (!g_fExpandedView && (g_sortColumn > 3)) {
1291
// Write our expanded view option to the registry.
1292
WriteOptionInt(TEXT("ExpandedView"), g_fExpandedView);
1295
//******************************************************************************
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;
1306
ShellExecuteEx(&sei);
1310
//******************************************************************************
1311
//***** Event Handlers for our List View
1312
//******************************************************************************
1314
void OnGetDispInfo(LV_DISPINFO *plvdi) {
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) {
1321
// Get a pointer to the file node for this item.
1322
FILE_NODE *pFile = (FILE_NODE*)plvdi->item.lParam;
1324
CHAR szBuffer[_MAX_PATH * 2];
1326
switch (plvdi->item.iSubItem) {
1330
// Copy the string to a temporary buffer.
1331
strcpy(szBuffer, pFile->szPathAndMethod);
1333
// Change all forward slashes to back slashes in the buffer
1334
ForwardSlashesToBackSlashesA(szBuffer);
1336
// Convert the string to UNICODE and store it in our list control.
1337
MBSTOTSTR(plvdi->item.pszText, szBuffer, plvdi->item.cchTextMax);
1342
FormatValue(plvdi->item.pszText, pFile->dwSize);
1346
MBSTOTSTR(plvdi->item.pszText, BuildTypeString(pFile, szBuffer),
1347
plvdi->item.cchTextMax);
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');
1361
case 4: // Attributes
1362
BuildAttributesString(plvdi->item.pszText, pFile->dwAttributes);
1365
case 5: // Compressed
1366
FormatValue(plvdi->item.pszText, pFile->dwCompressedSize);
1370
int factor; factor = ratio(pFile->dwSize, pFile->dwCompressedSize);
1371
_stprintf(plvdi->item.pszText, TEXT("%d.%d%%"), factor / 10,
1372
((factor < 0) ? -factor : factor) % 10);
1376
MBSTOTSTR(plvdi->item.pszText, pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1,
1377
plvdi->item.cchTextMax);
1381
_stprintf(plvdi->item.pszText, TEXT("%08X"), pFile->dwCRC);
1385
MBSTOTSTR(plvdi->item.pszText, pFile->szComment ? pFile->szComment : "",
1386
plvdi->item.cchTextMax);
1391
//******************************************************************************
1392
void OnDeleteItem(NM_LISTVIEW *pnmlv) {
1393
if (pnmlv->lParam) {
1395
// Free any comment string associated with this item.
1396
if (((FILE_NODE*)pnmlv->lParam)->szComment) {
1397
delete[] (CHAR*)((FILE_NODE*)pnmlv->lParam)->szComment;
1400
// Free the item itself.
1401
delete[] (LPBYTE)pnmlv->lParam;
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);
1414
//******************************************************************************
1415
//***** List View Sort Functions
1416
//******************************************************************************
1418
void Sort(int sortColumn, BOOL fForce) {
1420
// Do not change the column header text if it is already correct.
1421
if (sortColumn != g_sortColumn) {
1425
lvc.mask = LVCF_TEXT;
1426
lvc.pszText = szColumn;
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);
1435
// Set the new sort column.
1436
g_sortColumn = sortColumn;
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);
1443
// Sort the list by the new column.
1444
ListView_SortItems(g_hWndList, CompareFunc, g_sortColumn);
1446
} else if (fForce) {
1447
// Force the list to sort by the same column.
1448
ListView_SortItems(g_hWndList, CompareFunc, g_sortColumn);
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];
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.
1463
// Compute the relationship based on the current sort column
1464
switch (sortColumn) {
1466
case 1: // Size - Smallest to Largest
1467
if (pFile1->dwSize != pFile2->dwSize) {
1468
result = ((pFile1->dwSize < pFile2->dwSize) ? -1 : 1);
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)) {
1480
result = _stricmp(BuildTypeString(pFile1, szType1),
1481
BuildTypeString(pFile2, szType2));
1488
case 3: // Modified - Newest to Oldest
1489
if (pFile1->dwModified != pFile2->dwModified) {
1490
result = ((pFile1->dwModified > pFile2->dwModified) ? -1 : 1);
1494
case 4: // Attributes - String Sort
1495
result = _tcscmp(BuildAttributesString(szBuffer1, pFile1->dwAttributes),
1496
BuildAttributesString(szBuffer2, pFile2->dwAttributes));
1499
case 5: // Compressed Size - Smallest to Largest
1500
if (pFile1->dwCompressedSize != pFile2->dwCompressedSize) {
1501
result = ((pFile1->dwCompressedSize < pFile2->dwCompressedSize) ? -1 : 1);
1505
case 6: // Ratio - Smallest to Largest
1506
int factor1, factor2;
1507
factor1 = ratio(pFile1->dwSize, pFile1->dwCompressedSize);
1508
factor2 = ratio(pFile2->dwSize, pFile2->dwCompressedSize);
1509
result = factor1 - factor2;
1512
case 7: // Method - String Sort
1513
result = _stricmp(pFile1->szPathAndMethod + strlen(pFile1->szPathAndMethod) + 1,
1514
pFile2->szPathAndMethod + strlen(pFile2->szPathAndMethod) + 1);
1517
case 8: // CRC - Smallest to Largest
1518
if (pFile1->dwCRC != pFile2->dwCRC) {
1519
result = ((pFile1->dwCRC < pFile2->dwCRC) ? -1 : 1);
1523
case 9: // Comment - String Sort
1524
result = _stricmp(pFile1->szComment ? pFile1->szComment : "",
1525
pFile2->szComment ? pFile2->szComment : "");
1529
// If the sort resulted in a tie, we use the name to break the tie.
1531
result = _stricmp(pFile1->szPathAndMethod, pFile2->szPathAndMethod);
1538
//******************************************************************************
1539
//***** Helper/Utility Functions
1540
//******************************************************************************
1542
void SetCaptionText(LPCTSTR szPrefix) {
1543
TCHAR szCaption[_MAX_PATH + 32];
1545
_stprintf(szCaption, TEXT("%s - "), szPrefix);
1550
size_t lenPrefix = _tcslen(szCaption);
1551
MBSTOTSTR(szCaption + lenPrefix, GetFileFromPath(g_szZipFile),
1552
countof(szCaption) - lenPrefix);
1554
_tcscat(szCaption, TEXT("Pocket UnZip"));
1556
SetWindowText(g_hWndMain, szCaption);
1559
//******************************************************************************
1560
void DrawBanner(HDC hdc) {
1562
// If we were not passed in a DC, then get one now.
1563
BOOL fReleaseDC = FALSE;
1565
hdc = GetDC(g_hWndMain);
1569
// Compute the banner rectangle.
1571
GetClientRect(g_hWndMain, &rc);
1572
rc.top += g_cyCmdBar;
1573
rc.bottom = rc.top + 22;
1575
// Fill in the background with a light grey brush.
1576
FillRect(hdc, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
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 } };
1581
SelectObject(hdc, GetStockObject(WHITE_PEN));
1582
Polyline(hdc, pt, 2);
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;
1588
hIcon = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_ZIPFILE),
1589
IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1592
// Draw the ZIP file image.
1593
DrawIconEx(hdc, rc.left + 6, rc.top + 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
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);
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) {
1611
_stprintf(szPath, TEXT("Loading %S"), g_szZipFile);
1613
_stprintf(szPath, TEXT("Loading %s"), g_szZipFile);
1616
MBSTOTSTR(szPath, g_szZipFile, countof(szPath));
1619
_tcscpy(szPath, TEXT("No File Loaded"));
1622
// Draw the banner text.
1623
DrawText(hdc, szPath, _tcslen(szPath), &rc,
1624
DT_NOPREFIX | DT_SINGLELINE | DT_LEFT | DT_VCENTER);
1626
// Remove all non stock objects from the DC
1627
SelectObject(hdc, hFontStock);
1629
// Free our DC if we created it.
1631
ReleaseDC(g_hWndMain, hdc);
1635
//******************************************************************************
1636
void AddDeleteColumns() {
1638
static int curColumns = 0;
1639
int column, newColumns = (g_fExpandedView ? countof(g_columns) : 4);
1641
// Are we adding columns?
1642
if (newColumns > curColumns) {
1644
// Set up column structure.
1647
lvc.mask = LVCF_TEXT | LVCF_FMT;
1648
lvc.pszText = szColumn;
1650
// Loop through each column we need to add.
1651
for (column = curColumns; column < newColumns; column++) {
1653
// Build the real column string.
1654
_stprintf(szColumn, (g_columns[column].format == LVCFMT_LEFT) ?
1655
TEXT("%s ") : TEXT(" %s"), g_columns[column].szName);
1657
// Insert the column with the correct format.
1658
lvc.fmt = g_columns[column].format;
1659
ListView_InsertColumn(g_hWndList, column, &lvc);
1662
// Otherwise, we are removing columns.
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);
1671
// Store our new column count statically to help us with the next call to
1672
// AddDeleteColumns().
1673
curColumns = newColumns;
1675
// Re-calcualte our column widths.
1679
//******************************************************************************
1680
void ResizeColumns() {
1682
// Hide the window since we are going to be doing some column shifting.
1683
ShowWindow(g_hWndList, SW_HIDE);
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);
1690
// Show the window again.
1691
ShowWindow(g_hWndList, SW_SHOW);
1694
//******************************************************************************
1695
LPCTSTR GetZipErrorString(int error) {
1699
case PK_OK: // no error
1700
return TEXT("Operation completed successfully.");
1702
case PK_WARN: // warning error
1703
return TEXT("There were warnings during the operation.");
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.");
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.");
1721
case PK_NOZIP: // zipfile not found or corrupt.
1722
return TEXT("The ZIP file either contains errors or could not be found.");
1724
case PK_PARAM: // bad or illegal parameters specified
1725
break; // Not used in the Windows CE port.
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.");
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.");
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 ")
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.");
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.");
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).");
1761
case IZ_CTRLC: // canceled by user's interaction
1762
case PK_ABORTED: // user aborted
1763
return TEXT("The operation was aborted.");
1766
return TEXT("An unknown error occurred while processing the ZIP file.");
1769
//******************************************************************************
1770
void AddFileToListView(FILE_NODE *pFile) {
1772
// Set up our List View Item structure.
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;
1780
// Special case Volume Labels.
1781
if (pFile->dwAttributes & ZFILE_ATTRIBUTE_VOLUME) {
1782
pFile->szType = "Volume Label";
1783
lvi.iImage = IMAGE_VOLUME;
1785
// Special case folders.
1786
} else if (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1787
pFile->szType = "Folder";
1788
lvi.iImage = IMAGE_FOLDER;
1790
// Do a lookup on the file extension.
1793
// Locate the file portion of our path.
1794
LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
1796
// Find the extension portion of our file.
1797
LPCSTR pszExt = MBSRCHR(pszFile, '.');
1799
// Search our known extension list for this extension.
1800
if (pszExt && *(pszExt + 1)) {
1802
// Loop through our linked list
1803
for (FILE_TYPE_NODE *pft = g_pftHead; pft; pft = pft->pNext) {
1805
// Check for a match.
1806
if (!_stricmp(pszExt + 1, pft->szExtAndDesc)) {
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;
1820
// Add the item to our list.
1821
ListView_InsertItem(g_hWndList, &lvi);
1824
//******************************************************************************
1825
void EnableAllMenuItems(UINT uMenuItem, BOOL fEnabled) {
1827
HMENU hMenu = CommandBar_GetMenu(g_hWndCmdBar, 0);
1829
HMENU hMenu = GetMenu(g_hWndMain);
1831
EnableMenuItem(hMenu, uMenuItem, fEnabled ? MF_ENABLED : MF_GRAYED);
1832
SendMessage(g_hWndCmdBar, TB_ENABLEBUTTON, uMenuItem, MAKELONG(fEnabled, 0));
1835
//******************************************************************************
1836
void CheckAllMenuItems(UINT uMenuItem, BOOL fChecked) {
1838
HMENU hMenu = CommandBar_GetMenu(g_hWndCmdBar, 0);
1840
HMENU hMenu = GetMenu(g_hWndMain);
1842
CheckMenuItem(hMenu, uMenuItem, fChecked ? MF_CHECKED : MF_UNCHECKED);
1843
SendMessage(g_hWndCmdBar, TB_PRESSBUTTON, uMenuItem, MAKELONG(fChecked, 0));
1846
//******************************************************************************
1847
void CenterWindow(HWND hWnd) {
1851
// Get our window rectangle.
1852
GetWindowRect(hWnd, &rc);
1854
// Get our parent's window rectangle.
1855
GetWindowRect(GetParent(hWnd), &rcParent);
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);
1864
//******************************************************************************
1865
void AddTextToEdit(LPCSTR szText) {
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
1879
TCHAR szOut[256], *pszOut = szOut;
1880
CHAR *pszIn = (LPSTR)szText, cPrev = '\0';
1884
if (*pszIn == '\n') {
1885
if (cPrev == '\r') {
1888
*(pszOut++) = TEXT('\r');
1889
*(pszOut++) = TEXT('\n');
1893
} else if (*pszIn == '\r') {
1894
if (cPrev == '\n') {
1897
*(pszOut++) = TEXT('\r');
1898
*(pszOut++) = TEXT('\n');
1902
} else if ((*pszIn < 32) && (*pszIn != '\t')) {
1903
*(pszOut++) = (TCHAR)'^';
1904
*(pszOut++) = (TCHAR)(64 + *pszIn);
1908
*(pszOut++) = (TCHAR)*pszIn;
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);
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);
1930
//******************************************************************************
1931
LPTSTR FormatValue(LPTSTR szValue, DWORD dwValue) {
1932
DWORD dw = 0, dwGroup[4] = { 0, 0, 0, 0 };
1934
dwGroup[dw++] = dwValue % 1000;
1938
case 2: _stprintf(szValue, TEXT("%u,%03u"), dwGroup[1], dwGroup[0]); break;
1939
case 3: _stprintf(szValue, TEXT("%u,%03u,%03u"), dwGroup[2], dwGroup[1], dwGroup[0]); break;
1940
case 4: _stprintf(szValue, TEXT("%u,%03u,%03u,%03u"), dwGroup[3], dwGroup[2], dwGroup[1], dwGroup[0]); break;
1941
default: _stprintf(szValue, TEXT("%u"), dwGroup[0]);
1946
//******************************************************************************
1947
LPTSTR BuildAttributesString(LPTSTR szBuffer, DWORD dwAttributes) {
1948
// Build the attribute string according to the flags specified for this file.
1949
_stprintf(szBuffer, TEXT("%s%s%s%s%s%s%s%s"),
1950
(dwAttributes & ZFILE_ATTRIBUTE_VOLUME) ? TEXT("V") : TEXT(""),
1951
(dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? TEXT("D") : TEXT(""),
1952
(dwAttributes & FILE_ATTRIBUTE_READONLY) ? TEXT("R") : TEXT(""),
1953
(dwAttributes & FILE_ATTRIBUTE_ARCHIVE) ? TEXT("A") : TEXT(""),
1954
(dwAttributes & FILE_ATTRIBUTE_HIDDEN) ? TEXT("H") : TEXT(""),
1955
(dwAttributes & FILE_ATTRIBUTE_SYSTEM) ? TEXT("S") : TEXT(""),
1956
(dwAttributes & ZFILE_ATTRIBUTE_ENCRYPTED) ? TEXT("E") : TEXT(""),
1957
(dwAttributes & ZFILE_ATTRIBUTE_COMMENT) ? TEXT("C") : TEXT(""));
1961
//******************************************************************************
1962
LPCSTR BuildTypeString(FILE_NODE *pFile, LPSTR szType) {
1964
// First check to see if we have a known description.
1965
if (pFile->szType) {
1966
return pFile->szType;
1969
// Locate the file portion of our path.
1970
LPCSTR pszFile = GetFileFromPath(pFile->szPathAndMethod);
1972
// Get the extension portion of the file.
1973
LPCSTR pszExt = MBSRCHR(pszFile, '.');
1975
// If we have an extension create a type name for this file.
1976
if (pszExt && *(pszExt + 1)) {
1977
strcpy(szType, pszExt + 1);
1979
strcat(szType, " File");
1983
// If no extension, then use the default "File".
1987
//******************************************************************************
1988
LPCSTR GetFileFromPath(LPCSTR szPath) {
1989
LPCSTR p1 = MBSRCHR(szPath, '/'), p2 = MBSRCHR(szPath, '\\');
1990
if (p1 && (p1 > p2)) {
1998
//******************************************************************************
1999
void ForwardSlashesToBackSlashesA(LPSTR szBuffer) {
2001
if (*szBuffer == '/') {
2008
//******************************************************************************
2009
void ForwardSlashesToBackSlashesW(LPWSTR szBuffer) {
2011
if (*szBuffer == L'/') {
2018
//******************************************************************************
2019
void DeleteDirectory(LPTSTR szPath) {
2021
// Make note to where the end of our path is.
2022
LPTSTR szEnd = szPath + _tcslen(szPath);
2024
// Add our search spec to the path.
2025
_tcscpy(szEnd, TEXT("\\*.*"));
2027
// Start a directory search.
2028
WIN32_FIND_DATA w32fd;
2029
HANDLE hFind = FindFirstFile(szPath, &w32fd);
2031
// Loop through all entries in this directory.
2032
if (hFind != INVALID_HANDLE_VALUE) {
2035
// Append the file/directory name to the path.
2036
_tcscpy(szEnd + 1, w32fd.cFileName);
2038
// Check to see if this entry is a subdirectory.
2039
if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2041
// Ignore current directory (.) and previous directory (..)
2042
if (_tcscmp(w32fd.cFileName, TEXT(".")) &&
2043
_tcscmp(w32fd.cFileName, TEXT("..")))
2045
// Recurse into DeleteDirectory() to delete subdirectory.
2046
DeleteDirectory(szPath);
2049
// Otherwise, it must be a file.
2052
// If the file is marked as read-only, then change to read/write.
2053
if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
2054
SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
2057
// Attempt to delete the file. If we fail and the file used to be
2058
// read-only, then set the read-only bit back on it.
2059
if (!DeleteFile(szPath) &&
2060
(w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
2062
SetFileAttributes(szPath, FILE_ATTRIBUTE_READONLY);
2066
// Get the next directory entry.
2067
} while (FindNextFile(hFind, &w32fd));
2069
// Close the directory search.
2073
// Remove the directory.
2074
*szEnd = TEXT('\0');
2075
RemoveDirectory(szPath);
2079
//******************************************************************************
2080
//***** Registry Functions
2081
//******************************************************************************
2083
void RegWriteKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPCTSTR szValue) {
2085
DWORD dwDisposition;
2087
if (RegCreateKeyEx(hKeyRoot, szSubKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) {
2089
RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szValue,
2090
sizeof(TCHAR) * (_tcslen(szValue) + 1));
2096
//******************************************************************************
2097
BOOL RegReadKey(HKEY hKeyRoot, LPCTSTR szSubKey, LPTSTR szValue, DWORD cBytes) {
2098
*szValue = TEXT('\0');
2100
LRESULT lResult = -1;
2102
if (RegOpenKeyEx(hKeyRoot, szSubKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
2103
lResult = RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)szValue, &cBytes);
2106
return ((lResult == ERROR_SUCCESS) && *szValue);
2109
//******************************************************************************
2110
void WriteOptionString(LPCTSTR szOption, LPCTSTR szValue) {
2113
if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
2114
RegSetValueEx(hKey, szOption, 0, REG_SZ, (LPBYTE)szValue,
2115
sizeof(TCHAR) * (_tcslen(szValue) + 1));
2120
//******************************************************************************
2121
void WriteOptionInt(LPCTSTR szOption, DWORD dwValue) {
2124
if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS) {
2125
RegSetValueEx(hKey, szOption, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
2130
//******************************************************************************
2131
LPTSTR GetOptionString(LPCTSTR szOption, LPCTSTR szDefault, LPTSTR szValue, DWORD nSize) {
2135
if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
2136
lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)szValue, &nSize);
2139
if (lResult != ERROR_SUCCESS) {
2140
_tcscpy(szValue, szDefault);
2145
//******************************************************************************
2146
DWORD GetOptionInt(LPCTSTR szOption, DWORD dwDefault) {
2150
DWORD nSize = sizeof(dwValue);
2152
if (RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
2153
lResult = RegQueryValueEx(hKey, szOption, NULL, NULL, (LPBYTE)&dwValue, &nSize);
2156
return (lResult == ERROR_SUCCESS) ? dwValue : dwDefault;
2159
//******************************************************************************
2160
//***** EDIT Control Subclass Functions
2161
//******************************************************************************
2163
void DisableEditing(HWND hWndEdit) {
2165
// Make sure the control does not have ES_READONLY or ES_WANTRETURN styles.
2166
DWORD dwStyle = (DWORD)GetWindowLong(hWndEdit, GWL_STYLE);
2167
if (dwStyle & (ES_READONLY | ES_WANTRETURN)) {
2168
SetWindowLong(hWndEdit, GWL_STYLE, dwStyle & ~(ES_READONLY | ES_WANTRETURN));
2171
// Subclass the control so we can intercept certain keys.
2172
g_wpEdit = (WNDPROC)GetWindowLong(hWndEdit, GWL_WNDPROC);
2173
SetWindowLong(hWndEdit, GWL_WNDPROC, (LONG)EditSubclassProc);
2176
//******************************************************************************
2177
LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2182
// For cut, paste, delete, and undo, the control post itself a message.
2183
// we throw away that message. This works as a fail-safe in case we miss
2184
// some keystroke that causes one of these operations. This also disables
2185
// the context menu on NT from causing one of these actions to occur.
2193
// WM_CHAR is used for normal characters. A-Z, numbers, symbols, enter,
2194
// backspace, esc, and tab. In does not include del or movement keys.
2196
fCtrl = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
2198
// We only allow CTRL-C (copy), plain ESC, plain TAB, plain ENTER.
2199
if (( fCtrl && (wParam == 3)) ||
2200
(!fCtrl && (wParam == VK_ESCAPE)) ||
2201
(!fCtrl && (wParam == VK_RETURN)) ||
2202
(!fCtrl && (wParam == VK_TAB)))
2209
// WM_KEYDOWN handles del, insert, arrows, pg up/down, home/end.
2211
fCtrl = (GetKeyState(VK_CONTROL) & 0x8000) ? TRUE : FALSE;
2212
fShift = (GetKeyState(VK_SHIFT) & 0x8000) ? TRUE : FALSE;
2214
// Skip all forms of DELETE, SHIFT-INSERT (paste),
2215
// CTRL-RETURN (hard-return), and CTRL-TAB (hard-tab).
2216
if (( (wParam == VK_DELETE)) ||
2217
(fShift && (wParam == VK_INSERT)) ||
2218
(fCtrl && (wParam == VK_RETURN)) ||
2219
(fCtrl && (wParam == VK_TAB)))
2226
return CallWindowProc(g_wpEdit, hWnd, uMsg, wParam, lParam);
2230
//******************************************************************************
2231
//***** MRU Functions
2232
//******************************************************************************
2235
int GetMenuString(HMENU hMenu, UINT uIDItem, LPTSTR lpString, int nMaxCount,
2238
ZeroMemory(&mii, sizeof(mii));
2239
mii.cbSize = sizeof(mii);
2240
mii.fMask = MIIM_TYPE;
2241
mii.dwTypeData = lpString;
2242
mii.cch = nMaxCount;
2243
return (GetMenuItemInfo(hMenu, uIDItem, uFlag == MF_BYPOSITION, &mii) ?
2248
//******************************************************************************
2249
void InitializeMRU() {
2251
TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
2254
// Get our menu handle.
2256
HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
2258
HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
2261
// Read all our current MRUs from the registry.
2262
for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
2264
// Build option name for current MRU and read from registry.
2265
_stprintf(szOption, TEXT("MRU%d"), i+1);
2266
GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
2268
// If this MRU exists, then add it.
2271
// Build the accelerator prefix for this menu item.
2272
szMRU[i][0] = TEXT('&');
2273
szMRU[i][1] = TEXT('1') + j;
2274
szMRU[i][2] = TEXT(' ');
2276
// Add the item to our menu.
2277
InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
2280
// Increment our actual MRU count.
2286
//******************************************************************************
2287
void AddFileToMRU(LPCSTR szFile) {
2289
TCHAR szMRU[MRU_MAX_FILE + 1][_MAX_PATH + 4], szOption[8];
2292
// Store the new file in our first MRU index.
2293
MBSTOTSTR(&szMRU[0][3], szFile, _MAX_PATH);
2295
//---------------------------------------------------------------------------
2296
// We first read the current MRU list from the registry, merge in our new
2297
// file at the top, and then write back to the registry. The registry merge
2298
// is done to allow multiple instances of Pocket UnZip to maintain a global
2299
// MRU list independent to this current instance's MRU list.
2300
//---------------------------------------------------------------------------
2302
// Read all our current MRUs from the registry.
2303
for (i = 1; i <= MRU_MAX_FILE; i++) {
2305
// Build option name for current MRU and read from registry.
2306
_stprintf(szOption, TEXT("MRU%d"), i);
2307
GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
2310
// Write our new merged MRU list back to the registry.
2311
for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
2313
// If this MRU exists and is different then our new file, then add it.
2314
if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
2316
// Build option name for current MRU and write to registry.
2317
_stprintf(szOption, TEXT("MRU%d"), ++j);
2318
WriteOptionString(szOption, &szMRU[i][3]);
2322
//---------------------------------------------------------------------------
2323
// The next thing we need to do is read our local MRU from our File menu,
2324
// merge in our new file, and store the new list back to our File menu.
2325
//---------------------------------------------------------------------------
2327
// Get our menu handle.
2329
HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
2331
HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
2334
// Read all our current MRUs from our File Menu.
2335
for (i = 1; i <= MRU_MAX_FILE; i++) {
2337
// Query our file Menu for a MRU file.
2338
if (GetMenuString(hMenu, MRU_START_ID + i - 1, szMRU[i],
2339
countof(szMRU[0]), MF_BYCOMMAND))
2341
// Delete this item from the menu for now.
2342
DeleteMenu(hMenu, MRU_START_ID + i - 1, MF_BYCOMMAND);
2344
szMRU[i][3] = TEXT('\0');
2348
// Write our new merged MRU list back to the File menu.
2349
for (i = 0, j = 0; (i <= MRU_MAX_FILE) && (j < MRU_MAX_FILE); i++) {
2351
// If this MRU exists and is different then our new file, then add it.
2352
if ((i == 0) || (szMRU[i][3] && _tcsicmp(&szMRU[0][3], &szMRU[i][3]))) {
2354
// Build the accelerator prefix for this menu item.
2355
szMRU[i][0] = TEXT('&');
2356
szMRU[i][1] = TEXT('1') + j;
2357
szMRU[i][2] = TEXT(' ');
2359
// Add the item to our menu.
2360
InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
2363
// Increment our actual MRU count.
2369
//******************************************************************************
2370
void RemoveFileFromMRU(LPCTSTR szFile) {
2372
TCHAR szMRU[MRU_MAX_FILE][_MAX_PATH + 4], szOption[8];
2376
//---------------------------------------------------------------------------
2377
// We first look for this file in our global MRU stored in the registry. We
2378
// read the current MRU list from the registry, and then write it back while
2379
// removing all occurrances of the file specified.
2380
//---------------------------------------------------------------------------
2382
// Read all our current MRUs from the registry.
2383
for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
2385
// Build option name for current MRU and read from registry.
2386
_stprintf(szOption, TEXT("MRU%d"), i+1);
2387
GetOptionString(szOption, TEXT(""), &szMRU[i][3], sizeof(TCHAR) * _MAX_PATH);
2389
// Check for a match.
2390
if (!_tcsicmp(szFile, &szMRU[i][3])) {
2391
szMRU[i][3] = TEXT('\0');
2396
// Only write the MRU back to the registry if we found a file to remove.
2399
// Write the updated MRU list back to the registry.
2400
for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
2402
// If this MRU still exists, then add it.
2405
// Build option name for current MRU and write to registry.
2406
_stprintf(szOption, TEXT("MRU%d"), ++j);
2407
WriteOptionString(szOption, &szMRU[i][3]);
2411
// If our list got smaller, clear the unused items in the registry.
2412
while (j++ < MRU_MAX_FILE) {
2413
_stprintf(szOption, TEXT("MRU%d"), j);
2414
WriteOptionString(szOption, TEXT(""));
2418
//---------------------------------------------------------------------------
2419
// We next thing we do is look for this file in our local MRU stored in our
2420
// File menu. We read the current MRU list from the menu, and then write it
2421
// back while removing all occurrances of the file specified.
2422
//---------------------------------------------------------------------------
2424
// Get our menu handle.
2426
HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
2428
HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
2431
// Read all our current MRUs from our File Menu.
2432
for (i = 0, fFound = FALSE; i < MRU_MAX_FILE; i++) {
2434
// Query our file Menu for a MRU file.
2435
if (!GetMenuString(hMenu, MRU_START_ID + i, szMRU[i], countof(szMRU[0]),
2438
szMRU[i][3] = TEXT('\0');
2441
// Check for a match.
2442
if (!_tcsicmp(szFile, &szMRU[i][3])) {
2443
szMRU[i][3] = TEXT('\0');
2448
// Only update menu if we found a file to remove.
2451
// Clear out our menu's MRU list.
2452
for (i = MRU_START_ID; i < (MRU_START_ID + MRU_MAX_FILE); i++) {
2453
DeleteMenu(hMenu, i, MF_BYCOMMAND);
2456
// Write the rest of our MRU list back to the menu.
2457
for (i = 0, j = 0; i < MRU_MAX_FILE; i++) {
2459
// If this MRU still exists, then add it.
2462
// Build the accelerator prefix for this menu item.
2463
szMRU[i][0] = TEXT('&');
2464
szMRU[i][1] = TEXT('1') + j;
2465
szMRU[i][2] = TEXT(' ');
2467
// Add the item to our menu.
2468
InsertMenu(hMenu, 4 + j, MF_BYPOSITION | MF_STRING, MRU_START_ID + j,
2471
// Increment our actual MRU count.
2478
//******************************************************************************
2479
void ActivateMRU(UINT uIDItem) {
2480
TCHAR szFile[_MAX_PATH + 4];
2482
// Get our menu handle.
2484
HMENU hMenu = GetSubMenu(CommandBar_GetMenu(g_hWndCmdBar, 0), 0);
2486
HMENU hMenu = GetSubMenu(GetMenu(g_hWndMain), 0);
2489
// Query our menu for the selected MRU.
2490
if (GetMenuString(hMenu, uIDItem, szFile, countof(szFile), MF_BYCOMMAND)) {
2492
// Move past 3 character accelerator prefix and open the file.
2493
ReadZipFileList(&szFile[3]);
2498
//******************************************************************************
2499
//***** Open Zip File Functions
2500
//******************************************************************************
2502
void ReadZipFileList(LPCTSTR wszPath) {
2504
// Show wait cursor.
2505
HCURSOR hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
2507
TSTRTOMBS(g_szZipFile, wszPath, countof(g_szZipFile));
2509
// Update our banner to show that we are loading.
2513
// Update our caption to show that we are loading.
2514
SetCaptionText(TEXT("Loading"));
2516
// Clear our list view.
2517
ListView_DeleteAllItems(g_hWndList);
2519
// Ghost all our Unzip related menu items.
2520
EnableAllMenuItems(IDM_FILE_PROPERTIES, FALSE);
2521
EnableAllMenuItems(IDM_ACTION_EXTRACT, FALSE);
2522
EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, FALSE);
2523
EnableAllMenuItems(IDM_ACTION_TEST, FALSE);
2524
EnableAllMenuItems(IDM_ACTION_TEST_ALL, FALSE);
2525
EnableAllMenuItems(IDM_ACTION_VIEW, FALSE);
2526
EnableAllMenuItems(IDM_ACTION_SELECT_ALL, FALSE);
2527
EnableAllMenuItems(IDM_VIEW_COMMENT, FALSE);
2529
// Let Info-ZIP and our callbacks do the work.
2530
SendMessage(g_hWndList, WM_SETREDRAW, FALSE, 0);
2531
int result = DoListFiles(g_szZipFile);
2532
SendMessage(g_hWndList, WM_SETREDRAW, TRUE, 0);
2534
// Restore/remove cursor.
2537
// Update our column widths
2540
if ((result == PK_OK) || (result == PK_WARN)) {
2542
// Sort the items by name.
2545
// Update this file to our MRU list and menu.
2546
AddFileToMRU(g_szZipFile);
2548
// Enabled the comment button if the zip file has a comment.
2549
if (lpUserFunctions->cchComment) {
2550
EnableAllMenuItems(IDM_VIEW_COMMENT, TRUE);
2553
// Update other items that are related to having a Zip file loaded.
2554
EnableAllMenuItems(IDM_ACTION_EXTRACT_ALL, TRUE);
2555
EnableAllMenuItems(IDM_ACTION_TEST_ALL, TRUE);
2556
EnableAllMenuItems(IDM_ACTION_SELECT_ALL, TRUE);
2560
// Make sure we didn't partially load and added a few files.
2561
ListView_DeleteAllItems(g_hWndList);
2563
// If the file itself is bad or missing, then remove it from our MRU.
2564
if ((result == PK_ERR) || (result == PK_BADERR) || (result == PK_NOZIP) ||
2565
(result == PK_FIND) || (result == PK_EOF))
2567
RemoveFileFromMRU(wszPath);
2570
// Display an error.
2571
TCHAR szError[_MAX_PATH + 128];
2572
_stprintf(szError, TEXT("Failure loading \"%s\".\n\n"), wszPath);
2573
_tcscat(szError, GetZipErrorString(result));
2574
MessageBox(g_hWndMain, szError, g_szAppName, MB_OK | MB_ICONERROR);
2576
// Clear our file status.
2577
*g_szZipFile = '\0';
2580
// Update our caption to show that we are done loading.
2581
SetCaptionText(NULL);
2583
// Update our banner to show that we are done loading.
2589
//******************************************************************************
2590
//***** Zip File Properties Dialog Functions
2591
//******************************************************************************
2593
BOOL CALLBACK DlgProcProperties(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2597
case WM_INITDIALOG: {
2599
// Add "General" and "Comments" tabs to tab control. We are using a
2600
// poor man's version of a property sheet. We display our 2 pages
2601
// by showing and hiding controls as necessary. For our purposes,
2602
// this is much easier than dealing with separate property pages.
2605
tci.mask = TCIF_TEXT;
2606
tci.pszText = TEXT("General");
2607
TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 0, &tci);
2608
tci.pszText = TEXT("Comment");
2609
TabCtrl_InsertItem(GetDlgItem(hDlg, IDC_TAB), 1, &tci);
2612
// Add "Ok" button to caption bar.
2613
SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
2614
GetWindowLong(hDlg, GWL_EXSTYLE));
2616
// Center us over our parent.
2619
int directory = -1, readOnly = -1, archive = -1, hidden = -1;
2620
int system = -1, encrypted = -1;
2621
int year = -1, month = -1, day = -1, hour = -1, minute = -1, pm = -1;
2622
DWORD dwSize = 0, dwCompressedSize = 0;
2623
LPCSTR szPath = NULL, szMethod = NULL, szComment = NULL;
2624
DWORD dwCRC = 0, dwCount = 0, dwCommentCount = 0;
2625
TCHAR szBuffer[MAX_PATH];
2627
// Loop through all selected items.
2629
ZeroMemory(&lvi, sizeof(lvi));
2630
lvi.mask = LVIF_PARAM;
2632
while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) != -1) {
2634
// Get the FILE_NODE for the selected item.
2635
ListView_GetItem(g_hWndList, &lvi);
2636
FILE_NODE *pFile = (FILE_NODE*)lvi.lParam;
2638
// Merge this file's attributes into our accumulative attributes.
2639
MergeValues(&directory, (pFile->dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
2640
MergeValues(&readOnly, (pFile->dwAttributes & FILE_ATTRIBUTE_READONLY) != 0);
2641
MergeValues(&archive, (pFile->dwAttributes & FILE_ATTRIBUTE_ARCHIVE) != 0);
2642
MergeValues(&hidden, (pFile->dwAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
2643
MergeValues(&system, (pFile->dwAttributes & FILE_ATTRIBUTE_SYSTEM) != 0);
2644
MergeValues(&encrypted, (pFile->dwAttributes & ZFILE_ATTRIBUTE_ENCRYPTED) != 0);
2646
// Merge this file's date/time into our accumulative date/time.
2647
int curHour = (pFile->dwModified >> 6) & 0x001F;
2648
MergeValues(&year, (pFile->dwModified >> 20) & 0x0FFF);
2649
MergeValues(&month, (pFile->dwModified >> 16) & 0x000F);
2650
MergeValues(&day, (pFile->dwModified >> 11) & 0x001F);
2651
MergeValues(&hour, (curHour % 12) ? (curHour % 12) : 12);
2652
MergeValues(&minute, pFile->dwModified & 0x003F);
2653
MergeValues(&pm, curHour >= 12);
2655
// Store this file's name.
2656
szPath = pFile->szPathAndMethod;
2658
// Store this file's CRC.
2659
dwCRC = pFile->dwCRC;
2661
// Add the size and compressed size to our accumulative sizes.
2662
dwSize += pFile->dwSize;
2663
dwCompressedSize += pFile->dwCompressedSize;
2665
// Merge in our compression method.
2666
LPCSTR szCurMethod = pFile->szPathAndMethod + strlen(pFile->szPathAndMethod) + 1;
2667
if ((szMethod == NULL) || !strcmp(szMethod, szCurMethod)) {
2668
szMethod = szCurMethod;
2670
szMethod = "Multiple Methods";
2673
// Increment our file count.
2676
// Increment our comment count if this file has a comment.
2677
if (pFile->szComment) {
2678
szComment = pFile->szComment;
2685
// If multiple items selected, then display a selected count string
2686
// in place of the file name.
2687
_stprintf(szBuffer, TEXT("%u items selected."), dwCount);
2688
SetDlgItemText(hDlg, IDC_FILE, szBuffer);
2690
// Display "Multiple" for CRC if multiple items selected.
2691
SetDlgItemText(hDlg, IDC_CRC, TEXT("Multiple CRCs"));
2695
// Set the file name text for the single item selected.
2696
MBSTOTSTR(szBuffer, szPath, countof(szBuffer));
2697
ForwardSlashesToBackSlashes(szBuffer);
2698
SetDlgItemText(hDlg, IDC_FILE, szBuffer);
2700
// Set the CRC text for the single item selected.
2701
_stprintf(szBuffer, TEXT("0x%08X"), dwCRC);
2702
SetDlgItemText(hDlg, IDC_CRC, szBuffer);
2705
// Set the Size tally text.
2706
FormatValue(szBuffer, dwSize);
2707
_tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
2708
SetDlgItemText(hDlg, IDC_FILE_SIZE, szBuffer);
2710
// Set the Compressed Size tally text.
2711
FormatValue(szBuffer, dwCompressedSize);
2712
_tcscat(szBuffer, (dwCount > 1) ? TEXT(" bytes total") : TEXT(" bytes"));
2713
SetDlgItemText(hDlg, IDC_COMPRESSED_SIZE, szBuffer);
2715
// Set the Compression Factor text.
2716
int factor = ratio(dwSize, dwCompressedSize);
2717
_stprintf(szBuffer, TEXT("%d.%d%%"), factor / 10,
2718
((factor < 0) ? -factor : factor) % 10);
2719
SetDlgItemText(hDlg, IDC_COMPRESSON_FACTOR, szBuffer);
2721
// Set the Compression Method text.
2722
MBSTOTSTR(szBuffer, szMethod, countof(szBuffer));
2723
SetDlgItemText(hDlg, IDC_COMPRESSION_METHOD, szBuffer);
2725
// Set the Attribute check boxes.
2726
CheckThreeStateBox(hDlg, IDC_DIRECTORY, directory);
2727
CheckThreeStateBox(hDlg, IDC_READONLY, readOnly);
2728
CheckThreeStateBox(hDlg, IDC_ARCHIVE, archive);
2729
CheckThreeStateBox(hDlg, IDC_HIDDEN, hidden);
2730
CheckThreeStateBox(hDlg, IDC_SYSTEM, system);
2731
CheckThreeStateBox(hDlg, IDC_ENCRYPTED, encrypted);
2733
// Build and set the Modified Date text. The MS compiler does not
2734
// consider "??/" to be a valid string. "??/" is a trigraph that is
2735
// turned into "\" by the preprocessor and causes grief for the compiler.
2736
LPTSTR psz = szBuffer;
2737
psz += ((month < 0) ? _stprintf(psz, TEXT("?\?/")) :
2738
_stprintf(psz, TEXT("%u/"), month));
2739
psz += ((day < 0) ? _stprintf(psz, TEXT("?\?/")) :
2740
_stprintf(psz, TEXT("%u/"), day));
2741
psz += ((year < 0) ? _stprintf(psz, TEXT("?\? ")) :
2742
_stprintf(psz, TEXT("%u "), year % 100));
2743
psz += ((hour < 0) ? _stprintf(psz, TEXT("?\?:")) :
2744
_stprintf(psz, TEXT("%u:"), hour));
2745
psz += ((minute < 0) ? _stprintf(psz, TEXT("?\? ")) :
2746
_stprintf(psz, TEXT("%02u "), minute));
2747
psz += ((pm < 0) ? _stprintf(psz, TEXT("?M")) :
2748
_stprintf(psz, TEXT("%cM"), pm ? TEXT('P') : TEXT('A')));
2749
SetDlgItemText(hDlg, IDC_MODIFIED, szBuffer);
2751
// Store a global handle to our edit control.
2752
g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
2754
// Disable our edit box from being edited.
2755
DisableEditing(g_hWndEdit);
2757
// Stuff the appropriate message into the Comment edit control.
2758
if (dwCommentCount == 0) {
2760
AddTextToEdit("This file does not have a comment.");
2762
AddTextToEdit("None of the selected files have a comment.");
2764
} else if (dwCount == 1) {
2765
AddTextToEdit(szComment);
2768
_stprintf(szBuffer, TEXT("%u of the selected files %s a comment."),
2769
dwCommentCount, (dwCommentCount == 1)? TEXT("has") : TEXT("have"));
2770
TSTRTOMBS(szTemp, szBuffer, countof(szTemp));
2771
AddTextToEdit(szTemp);
2776
// Whooh, done with WM_INITDIALOG
2781
// Check to see if tab control was changed to new tab.
2782
if (((NMHDR*)lParam)->code == TCN_SELCHANGE) {
2783
HWND hWndTab = ((NMHDR*)lParam)->hwndFrom;
2784
HWND hWndComment = GetDlgItem(hDlg, IDC_COMMENT);
2785
HWND hWnd = GetWindow(hDlg, GW_CHILD);
2787
// If General tab selected, hide comment edit box and show all other controls.
2788
if (TabCtrl_GetCurSel(hWndTab) == 0) {
2790
ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd != hWndComment)) ?
2792
hWnd = GetWindow(hWnd, GW_HWNDNEXT);
2795
// If Comment tab selected, hide all controls except comment edit box.
2798
ShowWindow(hWnd, ((hWnd == hWndTab) || (hWnd == hWndComment)) ?
2800
hWnd = GetWindow(hWnd, GW_HWNDNEXT);
2807
// Exit the dialog on OK (Enter) or CANCEL (Esc).
2808
if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
2809
EndDialog(hDlg, LOWORD(wParam));
2816
//******************************************************************************
2817
void MergeValues(int *p1, int p2) {
2818
if ((*p1 == -1) || (*p1 == p2)) {
2825
//******************************************************************************
2826
void CheckThreeStateBox(HWND hDlg, int nIDButton, int state) {
2827
CheckDlgButton(hDlg, nIDButton, (state == 0) ? BST_UNCHECKED :
2828
(state == 1) ? BST_CHECKED :
2833
//******************************************************************************
2834
//***** Extract/Test Dialog Functions
2835
//******************************************************************************
2837
void ExtractOrTestFiles(BOOL fExtract) {
2840
ZeroMemory(&ei, sizeof(ei));
2842
// Set our Extract or Test flag.
2843
ei.fExtract = fExtract;
2845
// Get the number of selected items and make sure we have at least one item.
2846
if ((ei.dwFileCount = ListView_GetSelectedCount(g_hWndList)) <= 0) {
2850
// If we are not extracting/testing all, then create and buffer large enough to
2851
// hold the file list for all the selected files.
2852
if ((int)ei.dwFileCount != ListView_GetItemCount(g_hWndList)) {
2853
ei.szFileList = new LPSTR[ei.dwFileCount + 1];
2854
if (!ei.szFileList) {
2855
MessageBox(g_hWndMain, GetZipErrorString(PK_MEM), g_szAppName,
2856
MB_ICONERROR | MB_OK);
2865
ZeroMemory(&lvi, sizeof(lvi));
2866
lvi.mask = LVIF_PARAM;
2869
// Walk through all the selected files to build our counts and set our file
2870
// list pointers into our FILE_NODE paths for each selected item.
2871
while ((lvi.iItem = ListView_GetNextItem(g_hWndList, lvi.iItem, LVNI_SELECTED)) >= 0) {
2872
ListView_GetItem(g_hWndList, &lvi);
2873
if (ei.szFileList) {
2874
ei.szFileList[ei.dwFileCount] = ((FILE_NODE*)lvi.lParam)->szPathAndMethod;
2877
ei.dwByteCount += ((FILE_NODE*)lvi.lParam)->dwSize;
2879
if (ei.szFileList) {
2880
ei.szFileList[ei.dwFileCount] = NULL;
2883
// If we are extracting, display the extract dialog to query for parameters.
2884
if (!fExtract || (DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT), g_hWndMain,
2885
(DLGPROC)DlgProcExtractOrTest, (LPARAM)&ei) == IDOK))
2887
// Display our progress dialog and do the extraction/test.
2888
DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXTRACT_PROGRESS), g_hWndMain,
2889
(DLGPROC)DlgProcExtractProgress, (LPARAM)&ei);
2892
// Free our file list buffer if we created one.
2893
if (ei.szFileList) {
2894
delete[] ei.szFileList;
2898
//******************************************************************************
2899
BOOL CALLBACK DlgProcExtractOrTest(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2901
static EXTRACT_INFO *pei;
2902
TCHAR szPath[_MAX_PATH];
2908
// Store our extract information structure.
2909
pei = (EXTRACT_INFO*)lParam;
2911
// Load our settings.
2912
pei->fRestorePaths = GetOptionInt(TEXT("RestorePaths"), TRUE);
2913
pei->overwriteMode = (OVERWRITE_MODE)GetOptionInt(TEXT("OverwriteMode"), OM_PROMPT);
2915
// Load and set our path string.
2916
GetOptionString(TEXT("ExtractToDirectory"), TEXT("\\"), szPath, sizeof(szPath));
2917
SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
2919
// Set the state of all the controls.
2920
SetDlgItemText(hDlg, IDC_FILE_COUNT, FormatValue(szPath, pei->dwFileCount));
2921
SetDlgItemText(hDlg, IDC_BYTE_COUNT, FormatValue(szPath, pei->dwByteCount));
2922
CheckDlgButton(hDlg, IDC_RESTORE_PATHS, pei->fRestorePaths);
2923
CheckDlgButton(hDlg, IDC_OVERWRITE_PROMPT, pei->overwriteMode == OM_PROMPT);
2924
CheckDlgButton(hDlg, IDC_OVERWRITE_NEWER, pei->overwriteMode == OM_NEWER);
2925
CheckDlgButton(hDlg, IDC_OVERWRITE_ALWAYS, pei->overwriteMode == OM_ALWAYS);
2926
CheckDlgButton(hDlg, IDC_OVERWRITE_NEVER, pei->overwriteMode == OM_NEVER);
2928
// Limit our edit control to max path.
2929
SendDlgItemMessage(hDlg, IDC_EXTRACT_TO, EM_LIMITTEXT, sizeof(szPath) - 1, 0);
2931
// Center our dialog.
2936
switch (LOWORD(wParam)) {
2940
// Force us to read and validate the extract to directory.
2941
SendMessage(hDlg, WM_COMMAND, MAKELONG(IDC_EXTRACT_TO, EN_KILLFOCUS), 0);
2943
// Get our current path string.
2944
GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
2946
// Verify our "extract to" path is valid.
2947
if (!SetExtractToDirectory(szPath)) {
2948
MessageBox(hDlg, TEXT("The directory you entered is invalid or does not exist."),
2949
g_szAppName, MB_ICONERROR | MB_OK);
2950
SetFocus(GetDlgItem(hDlg, IDC_EXTRACT_TO));
2954
// Query other control values.
2955
pei->fRestorePaths = IsDlgButtonChecked(hDlg, IDC_RESTORE_PATHS);
2956
pei->overwriteMode =
2957
IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEWER) ? OM_NEWER :
2958
IsDlgButtonChecked(hDlg, IDC_OVERWRITE_ALWAYS) ? OM_ALWAYS :
2959
IsDlgButtonChecked(hDlg, IDC_OVERWRITE_NEVER) ? OM_NEVER : OM_PROMPT;
2961
// Write our settings.
2962
WriteOptionInt(TEXT("RestorePaths"), pei->fRestorePaths);
2963
WriteOptionInt(TEXT("OverwriteMode"), pei->overwriteMode);
2964
WriteOptionString(TEXT("ExtractToDirectory"), szPath);
2966
// Fall through to IDCANCEL
2969
EndDialog(hDlg, LOWORD(wParam));
2972
case IDC_EXTRACT_TO:
2974
// Make sure the path ends in a wack (\).
2975
if (HIWORD(wParam) == EN_KILLFOCUS) {
2976
GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
2977
size_t length = _tcslen(szPath);
2978
if ((length == 0) || szPath[length - 1] != TEXT('\\')) {
2979
szPath[length ] = TEXT('\\');
2980
szPath[length + 1] = TEXT('\0');
2981
SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
2987
GetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath, countof(szPath));
2988
if (FolderBrowser(szPath, countof(szPath))) {
2989
SetDlgItemText(hDlg, IDC_EXTRACT_TO, szPath);
2999
//******************************************************************************
3000
//***** Folder Browsing Dialog Functions
3001
//******************************************************************************
3003
BOOL FolderBrowser(LPTSTR szPath, DWORD dwLength) {
3007
// On Windows CE, we use a common save-as dialog to query the diretory. We
3008
// display the dialog in this function, and then we sublass it. Our subclass
3009
// functions tweaks the dialog a bit and and returns the path.
3011
ForwardSlashesToBackSlashes(szPath);
3013
TCHAR szInitialDir[_MAX_PATH];
3014
_tcscpy(szInitialDir, szPath);
3016
// Remove trailing wacks from path - The common dialog doesn't like them.
3017
size_t length = _tcslen(szInitialDir);
3018
while ((length > 0) && (szInitialDir[length - 1] == TEXT('\\'))) {
3019
szInitialDir[--length] = TEXT('\0');
3022
// Set up the parameters for our save-as dialog.
3024
ZeroMemory(&ofn, sizeof(ofn));
3025
ofn.lStructSize = sizeof(ofn);
3026
ofn.hwndOwner = g_hWndMain;
3027
ofn.hInstance = g_hInst;
3028
ofn.lpstrFilter = TEXT(" \0!\0");
3029
ofn.nFilterIndex = 1;
3030
ofn.lpstrFile = szPath;
3031
ofn.nMaxFile = dwLength;
3032
ofn.lpstrInitialDir = *szInitialDir ? szInitialDir : NULL;
3033
ofn.lpstrTitle = TEXT("Extract To");
3034
ofn.Flags = OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_NOTESTFILECREATE;
3036
// Post a message to our main window telling it that we are about to create
3037
// a save as dialog. Our main window will receive this message after the
3038
// save as dialog is created. This gives us a change to subclass the save as
3040
PostMessage(g_hWndMain, WM_PRIVATE, MSG_SUBCLASS_DIALOG, 0);
3042
// Create and display the common save-as dialog.
3043
if (GetSaveFileName(&ofn)) {
3045
// If success, then remove are special "!" filename from the end.
3046
szPath[_tcslen(szPath) - 1] = TEXT('\0');
3051
#else // !_WIN32_WCE
3053
// On Windows NT, the shell provides us with a nice folder browser dialog.
3054
// We don't need to jump through any hoops to make it work like on Windows CE.
3055
// The only problem is that on VC 4.0, the libraries don't export the UNICODE
3056
// shell APIs because only Win95 had a shell library at the time. The
3057
// following code requires headers and libs from VC 4.2 or later.
3059
// Set up our BROWSEINFO structure.
3061
ZeroMemory(&bi, sizeof(bi));
3062
bi.hwndOwner = g_hWndMain;
3063
bi.pszDisplayName = szPath;
3064
bi.lpszTitle = TEXT("Extract To");
3065
bi.ulFlags = BIF_RETURNONLYFSDIRS;
3067
// Prompt user for path.
3068
LPITEMIDLIST piidl = SHBrowseForFolder(&bi);
3073
// Build path string.
3074
SHGetPathFromIDList(piidl, szPath);
3076
// Free the PIDL returned by SHBrowseForFolder.
3077
LPMALLOC pMalloc = NULL;
3078
SHGetMalloc(&pMalloc);
3079
pMalloc->Free(piidl);
3081
// Add trailing wack if one is not present.
3082
size_t length = _tcslen(szPath);
3083
if ((length > 0) && (szPath[length - 1] != TEXT('\\'))) {
3084
szPath[length++] = TEXT('\\');
3085
szPath[length] = TEXT('\0');
3090
#endif // _WIN32_WCE
3093
//******************************************************************************
3095
BOOL CALLBACK DlgProcBrowser(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3097
// This is our subclass of Windows CE's common save-as dialog. We intercept
3098
// the messages we care about and forward everything else to the original
3099
// window procedure for the dialog.
3101
if (uMsg == WM_PRIVATE) { // wParam always equals MSG_INIT_DIALOG
3105
// Get the window rectangle for the name edit control.
3106
HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_NAME_EDIT);
3107
GetWindowRect(hWnd, &rc1);
3108
POINT pt1 = { rc1.left, rc1.top };
3109
ScreenToClient(hDlg, &pt1);
3111
// Hide all the windows we don't want.
3112
ShowWindow(hWnd, SW_HIDE);
3113
ShowWindow(GetDlgItem(hDlg, IDC_SAVE_NAME_PROMPT), SW_HIDE);
3114
ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_PROMPT), SW_HIDE);
3115
ShowWindow(GetDlgItem(hDlg, IDC_SAVE_TYPE_LIST), SW_HIDE);
3117
// Get the window rectangle for the file list.
3118
hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
3119
GetWindowRect(hWnd, &rc2);
3120
POINT pt2 = { rc2.left, rc2.top };
3121
ScreenToClient(hDlg, &pt2);
3123
// Resize the file list to fill the dialog.
3124
MoveWindow(hWnd, pt2.x, pt2.y, rc2.right - rc2.left, rc1.bottom - rc2.top, TRUE);
3126
} else if ((uMsg == WM_COMMAND) && (LOWORD(wParam) == IDOK)) {
3128
// Get our file list window.
3129
HWND hWnd = GetDlgItem(hDlg, IDC_SAVE_FILE_LIST);
3131
// Check to see if a directory is selected.
3132
if (ListView_GetNextItem(hWnd, -1, LVNI_SELECTED) >= 0) {
3134
// If a directory is highlighted, then we post ourself a "Ok". The "Ok"
3135
// we are processing now will cause us to change into the highlighted
3136
// directory, and our posted "Ok" will close the dialog in that directory.
3137
PostMessage(hDlg, uMsg, wParam, lParam);
3140
// If no directory is selected, then enter the imaginary filename "!"
3141
// into the name edit control and let the "Ok" end this dialog. The
3142
// result will be the correct path with a "\!" at the end.
3143
SetDlgItemText(hDlg, IDC_SAVE_NAME_EDIT, TEXT("!"));
3147
// Pass all messages to the base control's window proc.
3148
return CallWindowProc(g_wpSaveAsDlg, hDlg, uMsg, wParam, lParam);
3150
#endif // _WIN32_WCE
3152
//******************************************************************************
3154
void SubclassSaveAsDlg() {
3156
// Get our current thread ID so we can compare it to other thread IDs.
3157
DWORD dwThreadId = GetCurrentThreadId();
3159
// Get the the top window in the z-order that is a child of the desktop.
3160
// Dialogs are always children of the desktop on CE. This first window
3161
// should be the dialog we are looking for, but we will walk the window list
3163
HWND hWnd = GetWindow(g_hWndMain, GW_HWNDFIRST);
3165
// Walk the window list.
3168
// Check to see if this window was created by us and has controls from a
3169
// common "save as" dialog.
3170
if ((GetWindowThreadProcessId(hWnd, NULL) == dwThreadId) &&
3171
GetDlgItem(hWnd, IDC_SAVE_FILE_LIST) &&
3172
GetDlgItem(hWnd, IDC_SAVE_NAME_EDIT))
3174
// We found our dialog. Subclass it.
3175
g_wpSaveAsDlg = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
3176
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)DlgProcBrowser);
3178
// Send our new dialog a message so it can do its initialization.
3179
SendMessage(hWnd, WM_PRIVATE, MSG_INIT_DIALOG, 0);
3182
// Get the next window in our window list.
3183
hWnd = GetWindow(hWnd, GW_HWNDNEXT);
3186
#endif // _WIN32_WCE
3189
//******************************************************************************
3190
//***** Extraction/Test/View Progress Dialog Functions
3191
//******************************************************************************
3193
BOOL CALLBACK DlgProcExtractProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3195
static EXTRACT_INFO *pei;
3196
static BOOL fComplete;
3197
static HWND hWndButton;
3204
// Globally store our handle so our worker thread can post to us.
3205
g_hDlgProgress = hDlg;
3207
// Get a pointer to our extract information structure.
3208
pei = (EXTRACT_INFO*)lParam;
3210
// Clear our complete flag. It will be set to TRUE when done.
3213
// Get and store our edit control.
3214
g_hWndEdit = GetDlgItem(hDlg, IDC_LOG);
3216
// Disable our edit box from being edited.
3217
DisableEditing(g_hWndEdit);
3219
// Store a static handle for our Abort/Close button.
3220
hWndButton = GetDlgItem(hDlg, IDCANCEL);
3224
// Set our No-Drag style
3225
SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_NODRAG |GetWindowLong(hDlg, GWL_EXSTYLE));
3227
RECT rc1, rc2, rcEdit;
3229
// Get our current client size.
3230
GetClientRect(hDlg, &rc1);
3232
// Get the window rectangle for the edit control in client coordinates.
3233
GetWindowRect(g_hWndEdit, &rcEdit);
3234
ScreenToClient(hDlg, ((POINT*)&rcEdit));
3235
ScreenToClient(hDlg, ((POINT*)&rcEdit) + 1);
3237
// Resize our dialog to be full screen (same size as parent).
3238
GetWindowRect(g_hWndMain, &rc2);
3239
MoveWindow(hDlg, rc2.left, rc2.top, rc2.right - rc2.left,
3240
rc2.bottom - rc2.top + 1, FALSE);
3242
// Get our new client size.
3243
GetClientRect(hDlg, &rc2);
3245
// Resize our edit box to fill the client.
3246
MoveWindow(g_hWndEdit, rcEdit.left, rcEdit.top,
3247
(rcEdit.right - rcEdit.left) + (rc2.right - rc1.right),
3248
(rcEdit.bottom - rcEdit.top) + (rc2.bottom - rc1.bottom),
3252
// On NT, we just center our dialog over our parent.
3256
// Store some globals until the extract/test finishes.
3257
pei->hWndEditFile = GetDlgItem(hDlg, IDC_FILE);
3258
pei->hWndProgFile = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
3259
pei->hWndProgTotal = GetDlgItem(hDlg, IDC_TOTAL_PROGRESS);
3260
pei->hWndPercentage = GetDlgItem(hDlg, IDC_PERCENTAGE);
3261
pei->hWndFilesProcessed = GetDlgItem(hDlg, IDC_FILES_PROCESSED);
3262
pei->hWndBytesProcessed = GetDlgItem(hDlg, IDC_BYTES_PROCESSED);
3264
if (pei->fExtract) {
3265
// Set our main window's caption.
3266
SetCaptionText(TEXT("Extracting"));
3269
// Set our main window's caption.
3270
SetCaptionText(TEXT("Testing"));
3272
// Hide the current file progress for test since it never moves.
3273
ShowWindow(pei->hWndProgFile, SW_HIDE);
3276
// Set the ranges on our progress bars.
3277
SendMessage(pei->hWndProgFile, PBM_SETRANGE, 0,
3278
MAKELPARAM(0, PROGRESS_MAX));
3279
SendMessage(pei->hWndProgTotal, PBM_SETRANGE, 0,
3280
MAKELPARAM(0, PROGRESS_MAX));
3282
// Set our file and byte totals.
3283
SetDlgItemText(hDlg, IDC_FILES_TOTAL,
3284
FormatValue(szBuffer, pei->dwFileCount));
3285
SetDlgItemText(hDlg, IDC_BYTES_TOTAL,
3286
FormatValue(szBuffer, pei->dwByteCount));
3288
// Launch our Extract/Test thread and wait for WM_PRIVATE
3289
DoExtractOrTestFiles(g_szZipFile, pei);
3294
case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
3295
// test/extract is complete.
3297
// Check to see if the operation was a success
3298
if ((pei->result == PK_OK) || (pei->result == PK_WARN)) {
3300
// Set all our fields to their "100%" settings.
3301
SendMessage(pei->hWndProgFile, PBM_SETPOS, PROGRESS_MAX, 0);
3302
SendMessage(pei->hWndProgTotal, PBM_SETPOS, PROGRESS_MAX, 0);
3303
SetWindowText(pei->hWndPercentage, TEXT("100%"));
3304
SetDlgItemText(hDlg, IDC_FILES_PROCESSED,
3305
FormatValue(szBuffer, pei->dwFileCount));
3306
SetDlgItemText(hDlg, IDC_BYTES_PROCESSED,
3307
FormatValue(szBuffer, pei->dwByteCount));
3310
// Update our status text.
3311
SetWindowText(pei->hWndEditFile,
3312
(pei->result == PK_OK) ? TEXT("Completed. There were no warnings or errors.") :
3313
(pei->result == PK_WARN) ? TEXT("Completed. There was one or more warnings.") :
3314
(pei->result == PK_ABORTED) ? TEXT("Aborted. There may be warnings or errors.") :
3315
TEXT("Completed. There was one or more errors."));
3317
// Clear our global edit handle.
3320
// Update our caption to show that we are done extracting/testing.
3321
SetCaptionText(NULL);
3323
// Change our abort button to now read "Close".
3324
SetWindowText(hWndButton, TEXT("&Close"));
3325
EnableWindow(hWndButton, TRUE);
3327
// Display an error dialog if an error occurred.
3328
if ((pei->result != PK_OK) && (pei->result != PK_WARN)) {
3329
MessageBox(hDlg, GetZipErrorString(pei->result),
3330
g_szAppName, MB_ICONERROR | MB_OK);
3333
// We are done. Allow the user to close the dialog.
3338
switch (LOWORD(wParam)) {
3340
// If abort is pressed, then set a flag that our worker thread
3341
// periodically checks to decide if it needs to bail out.
3342
if (!fComplete && !pei->fAbort) {
3344
SetWindowText(hWndButton, TEXT("Aborting..."));
3345
EnableWindow(hWndButton, FALSE);
3348
// fall through to IDOK
3351
// Don't allow dialog to close until extract/test is complete.
3353
g_hDlgProgress = NULL;
3354
EndDialog(hDlg, LOWORD(wParam));
3363
//******************************************************************************
3364
BOOL CALLBACK DlgProcViewProgress(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3366
static EXTRACT_INFO *pei;
3372
// Globally store our handle so our worker thread can post to us.
3373
g_hDlgProgress = hDlg;
3375
// Get a pointer to our extract information structure.
3376
pei = (EXTRACT_INFO*)lParam;
3378
// Center our dialog over our parent.
3381
// Store some globals until the extract finishes.
3382
pei->hWndProgFile = GetDlgItem(hDlg, IDC_FILE_PROGRESS);
3384
// Set the ranges on our progress bar.
3385
SendDlgItemMessage(hDlg, IDC_FILE_PROGRESS, PBM_SETRANGE, 0,
3386
MAKELPARAM(0, PROGRESS_MAX));
3388
// Launch our Extract thread and wait for WM_PRIVATE message.
3389
DoExtractOrTestFiles(g_szZipFile, pei);
3393
case WM_PRIVATE: // Sent with wParam equal to MSG_OPERATION_COMPLETE when
3394
// test/extract is complete.
3396
// We are done. Close our dialog. Any errors will be reported by
3398
g_hDlgProgress = NULL;
3399
EndDialog(hDlg, LOWORD(wParam));
3403
// If abort is pressed, then set a flag that our worker thread
3404
// periodically checks to decide if it needs to bail out.
3405
if ((LOWORD(wParam) == IDCANCEL) && !pei->fAbort) {
3407
SetWindowText(GetDlgItem(hDlg, IDCANCEL), TEXT("Aborting..."));
3408
EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
3416
//******************************************************************************
3417
void UpdateProgress(EXTRACT_INFO *pei, BOOL fFull) {
3419
DWORD dwFile, dwTotal, dwPercentage;
3420
TCHAR szBuffer[_MAX_PATH + 32];
3422
// Compute our file progress bar position.
3423
if (pei->dwBytesTotalThisFile) {
3424
dwFile = (DWORD)(((DWORDLONG)PROGRESS_MAX *
3425
(DWORDLONG)pei->dwBytesWrittenThisFile) /
3426
(DWORDLONG)pei->dwBytesTotalThisFile);
3428
dwFile = PROGRESS_MAX;
3431
// Set our file progress indicators.
3432
SendMessage(pei->hWndProgFile, PBM_SETPOS, dwFile, 0);
3434
// If we are only updating our View Progress dialog, then we are done.
3435
if (!pei->hWndProgTotal) {
3439
// Compute our total progress bar position.
3440
dwTotal = (DWORD)(((DWORDLONG)PROGRESS_MAX *
3441
(DWORDLONG)(pei->dwBytesWrittenPreviousFiles +
3442
pei->dwBytesWrittenThisFile +
3444
(DWORDLONG)(pei->dwByteCount +
3446
dwPercentage = dwTotal / (PROGRESS_MAX / 100);
3448
// Set our total progress indicators.
3449
SendMessage(pei->hWndProgTotal, PBM_SETPOS, dwTotal, 0);
3451
// Set our total percentage text.
3452
_stprintf(szBuffer, TEXT("%u%%"), dwPercentage);
3453
SetWindowText(pei->hWndPercentage, szBuffer);
3455
// Set our current file and byte process counts.
3456
FormatValue(szBuffer, pei->dwFile - 1);
3457
SetWindowText(pei->hWndFilesProcessed, szBuffer);
3458
FormatValue(szBuffer, pei->dwBytesWrittenPreviousFiles +
3459
pei->dwBytesWrittenThisFile);
3460
SetWindowText(pei->hWndBytesProcessed, szBuffer);
3465
// Build our message string.
3466
_tcscpy(szBuffer, pei->fExtract ? TEXT("Extract") : TEXT("Test"));
3467
size_t preflen = _tcslen(szBuffer);
3468
MBSTOTSTR(szBuffer+preflen, pei->szFile,countof(szBuffer)-preflen);
3470
// Change all forward slashes to back slashes in the buffer.
3471
ForwardSlashesToBackSlashes(szBuffer);
3473
// Update the file name in our dialog.
3474
SetWindowText(pei->hWndEditFile, szBuffer);
3479
//******************************************************************************
3480
//***** Replace File Dialog Functions
3481
//******************************************************************************
3483
int PromptToReplace(LPCSTR szPath) {
3485
// Check to see if we are extracting for view only.
3489
TCHAR szMessage[_MAX_PATH + 128];
3490
_stprintf(szMessage,
3492
TEXT("A file named \"%S\" has already been extracted for viewing. ")
3494
TEXT("A file named \"%s\" has already been extracted for viewing. ")
3496
TEXT("That file might be opened and locked for viewing by another application.\n\n")
3497
TEXT("Would you like to attempt to overwrite it with the new file?"),
3498
GetFileFromPath(szPath));
3501
if (IDYES == MessageBox(g_hDlgProgress, szMessage, g_szAppName,
3502
MB_ICONWARNING | MB_YESNO))
3504
// Tell Info-ZIP to continue with extraction.
3505
return IDM_REPLACE_YES;
3508
// Remember that the file was skipped and tell Info-ZIP to abort extraction.
3510
return IDM_REPLACE_NO;
3513
// Otherwise, do the normal replace prompt dialog.
3514
return DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_REPLACE), g_hWndMain,
3515
(DLGPROC)DlgProcReplace, (LPARAM)szPath);
3518
//******************************************************************************
3519
BOOL CALLBACK DlgProcReplace(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3520
TCHAR szMessage[_MAX_PATH + 32];
3526
// Play the question tone to alert the user.
3527
MessageBeep(MB_ICONQUESTION);
3529
// Display a message with the file name.
3531
_stprintf(szMessage, TEXT("\"%S\" already exists."), (LPCSTR)lParam);
3533
_stprintf(szMessage, TEXT("\"%s\" already exists."), (LPCSTR)lParam);
3536
// Change all forward slashes to back slashes in the buffer.
3537
ForwardSlashesToBackSlashes(szMessage);
3539
// Display the file string.
3540
SetDlgItemText(hDlg, IDC_FILE, szMessage);
3542
// Center our dialog over our parent.
3547
switch (LOWORD(wParam)) {
3551
EndDialog(hDlg, IDM_REPLACE_NO);
3554
case IDM_REPLACE_ALL:
3555
case IDM_REPLACE_NONE:
3556
case IDM_REPLACE_YES:
3557
case IDM_REPLACE_NO:
3558
EndDialog(hDlg, wParam);
3567
//******************************************************************************
3568
//***** Password Dialog Functions
3569
//******************************************************************************
3573
BOOL CALLBACK DlgProcPassword(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3576
// IZ_PW_ENTERED got some PWD string, use/try it
3577
// IZ_PW_CANCEL no password available (for this entry)
3578
// IZ_PW_CANCELALL no password, skip any further PWD request
3579
// IZ_PW_ERROR failure (no mem, no tty, ...)
3581
static DECRYPT_INFO *pdi;
3582
TCHAR szMessage[_MAX_PATH + 32];
3588
// Play the question tone to alert the user.
3589
MessageBeep(MB_ICONQUESTION);
3592
// Add "Ok" button to caption bar.
3593
SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
3594
GetWindowLong(hDlg, GWL_EXSTYLE));
3597
// Store our decrypt information structure.
3598
pdi = (DECRYPT_INFO*)lParam;
3600
// Display a message with the file name.
3602
_stprintf(szMessage, TEXT("\"%S\" is encrypted."), pdi->szFile);
3604
_stprintf(szMessage, TEXT("\"%s\" is encrypted."), pdi->szFile);
3607
// Change all forward slashes to back slashes in the buffer.
3608
ForwardSlashesToBackSlashes(szMessage);
3610
// Display the message with the file name.
3611
SetDlgItemText(hDlg, IDC_FILE, szMessage);
3613
// Display the appropriate prompt.
3615
_stprintf(szMessage, TEXT("Password was incorrect. Please re-enter (%d/%d)."),
3616
MAX_PASSWORD_RETRIES - pdi->retry + 2, MAX_PASSWORD_RETRIES + 1);
3617
SetDlgItemText(hDlg, IDC_PROMPT, szMessage);
3619
SetDlgItemText(hDlg, IDC_PROMPT, TEXT("Please enter the password."));
3622
// Limit the password to the size of the password buffer we have been given.
3623
SendDlgItemMessage(hDlg, IDC_PASSWORD, EM_LIMITTEXT, pdi->nSize - 1, 0);
3625
// Center our dialog over our parent.
3630
switch (LOWORD(wParam)) {
3634
// Store the password in our return password buffer.
3635
GetDlgItemText(hDlg, IDC_PASSWORD, szMessage, countof(szMessage));
3636
TSTRTOMBS(pdi->szPassword, szMessage, pdi->nSize);
3637
EndDialog(hDlg, IZ_PW_ENTERED);
3642
EndDialog(hDlg, IZ_PW_CANCEL);
3647
EndDialog(hDlg, IZ_PW_CANCELALL);
3657
//******************************************************************************
3658
//***** View Association Dialog Functions
3659
//******************************************************************************
3661
BOOL CALLBACK DlgProcViewAssociation(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3663
static LPTSTR szApp;
3668
// Store the path buffer for our application.
3669
szApp = (LPTSTR)lParam;
3671
// Read our default viewer from the registry.
3673
GetOptionString(TEXT("FileViewer"), TEXT("\\Windows\\PWord.exe"),
3674
szApp, sizeof(TCHAR) * _MAX_PATH);
3676
GetOptionString(TEXT("FileViewer"), TEXT("notepad.exe"),
3677
szApp, sizeof(TCHAR) * _MAX_PATH);
3680
// Limit our edit control to our buffer size.
3681
SendDlgItemMessage(hDlg, IDC_PATH, EM_LIMITTEXT, _MAX_PATH - 1, 0);
3683
// Set our path string in our dialog.
3684
SetDlgItemText(hDlg, IDC_PATH, szApp);
3686
// Center our dialog over our parent.
3691
switch (LOWORD(wParam)) {
3694
// Get the text currently in the path edit box and store it.
3695
GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
3696
WriteOptionString(TEXT("FileViewer"), szApp);
3700
EndDialog(hDlg, LOWORD(wParam));
3704
// Get the text currently in the path edit box.
3705
GetDlgItemText(hDlg, IDC_PATH, szApp, _MAX_PATH);
3707
// Get the direcory from the path text.
3708
ForwardSlashesToBackSlashes(szApp);
3709
TCHAR szInitialDir[_MAX_PATH], *szFile;
3710
_tcscpy(szInitialDir, szApp);
3711
if (szFile = _tcsrchr(szInitialDir, TEXT('\\'))) {
3712
*szFile = TEXT('\0');
3715
// Prepare to display browse dialog.
3717
ZeroMemory(&ofn, sizeof(ofn));
3718
ofn.lStructSize = sizeof(ofn);
3719
ofn.hwndOwner = hDlg;
3720
ofn.hInstance = g_hInst;
3721
ofn.lpstrFilter = TEXT("Programs (*.exe)\0*.exe\0All Files (*.*)\0*.*\0");
3722
ofn.nFilterIndex = 1;
3723
ofn.lpstrFile = szApp;
3724
ofn.nMaxFile = _MAX_PATH;
3725
ofn.lpstrInitialDir = szInitialDir;
3726
ofn.lpstrTitle = TEXT("Open With...");
3727
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
3728
ofn.lpstrDefExt = TEXT("exe");
3730
// Display the browse dialog and update our path edit box if neccessary.
3731
if (GetOpenFileName(&ofn)) {
3732
SetDlgItemText(hDlg, IDC_PATH, szApp);
3742
//******************************************************************************
3743
//***** Comment Dialog Functions
3744
//******************************************************************************
3746
BOOL CALLBACK DlgProcComment(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3754
// Get the handle to our edit box and store it globally.
3755
g_hWndEdit = GetDlgItem(hDlg, IDC_COMMENT);
3757
// Disable our edit box from being edited.
3758
DisableEditing(g_hWndEdit);
3761
// Add "Ok" button to caption bar and make window No-Drag.
3762
SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN | WS_EX_NODRAG |
3763
GetWindowLong(hDlg, GWL_EXSTYLE));
3765
// On CE, we resize our dialog to be full screen (same size as parent).
3766
GetWindowRect(g_hWndMain, &rc);
3767
MoveWindow(hDlg, rc.left, rc.top, rc.right - rc.left,
3768
rc.bottom - rc.top + 1, FALSE);
3770
// On NT we just center the dialog.
3774
// Set our edit control to be the full size of our dialog.
3775
GetClientRect(hDlg, &rc);
3776
MoveWindow(g_hWndEdit, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
3778
// Show hour glass cursor while processing comment.
3779
hCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
3781
// Let Info-ZIP and our callbacks do the work.
3782
result = DoGetComment(g_szZipFile);
3784
// Restore/remove our cursor.
3787
// Display an error dialog if an error occurred.
3788
if ((result != PK_OK) && (result != PK_WARN)) {
3789
MessageBox(g_hWndMain, GetZipErrorString(result), g_szAppName,
3790
MB_ICONERROR | MB_OK);
3793
// Clear our global edit box handle as we are done with it.
3796
// Return FALSE to prevent edit box from gaining focus and showing highlight.
3800
if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {
3801
EndDialog(hDlg, LOWORD(wParam));
3809
//******************************************************************************
3810
//***** About Dialog Functions
3811
//******************************************************************************
3813
BOOL CALLBACK DlgProcAbout(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
3820
// Add "Ok" button to caption bar.
3821
SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_CAPTIONOKBTN |
3822
GetWindowLong(hDlg, GWL_EXSTYLE));
3825
// Fill in a few static members.
3826
// (For VER_FULLVERSION_STR and VER_COMMENT_STR, the TEXT() macro is
3827
// not applicable, because they are defined as a set of concatenated
3828
// string constants. These strings need to be converted to UNICODE
3829
// at runtime, sigh.)
3830
TCHAR szBuffer[128];
3831
SetDlgItemText(hDlg, IDC_PRODUCT, TEXT(VER_PRODUCT_STR));
3833
_stprintf(szBuffer, TEXT("Freeware Version %S"), VER_FULLVERSION_STR);
3835
_stprintf(szBuffer, TEXT("Freeware Version %s"), VER_FULLVERSION_STR);
3837
SetDlgItemText(hDlg, IDC_VERSION, szBuffer);
3838
_stprintf(szBuffer, TEXT("Developed by %s"), TEXT(VER_DEVELOPER_STR));
3839
SetDlgItemText(hDlg, IDC_DEVELOPER, szBuffer);
3840
SetDlgItemText(hDlg, IDC_COPYRIGHT, TEXT(VER_COPYRIGHT_STR));
3842
_stprintf(szBuffer, TEXT("%S"), VER_COMMENT_STR);
3843
SetDlgItemText(hDlg, IDC_COMMENT, szBuffer);
3845
SetDlgItemText(hDlg, IDC_COMMENT, VER_COMMENT_STR);
3848
// Center the dialog over our parent.
3853
if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL)) {