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