1 /* 7zipInstall.c - 7-Zip Installer
2 2024-04-05 : Igor Pavlov : Public domain */
3
4 #include "Precomp.h"
5
6 #define SZ_ERROR_ABORT 100
7
8 #include "../../7zWindows.h"
9
10 #if defined(_MSC_VER) && _MSC_VER < 1600
11 #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
12 #endif
13
14 Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
15
16 #ifdef Z7_OLD_WIN_SDK
17 struct IShellView;
18 #define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
19 SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
20 #define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
21 typedef enum {
22 SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists
23 SHGFP_TYPE_DEFAULT = 1, // default value, may not exist
24 } SHGFP_TYPE;
25 #endif
26 #if defined(__MINGW32__) || defined(__MINGW64__)
27 #include <shlobj.h>
28 #else
29 #include <ShlObj.h>
30 #endif
31
32 #include "../../7z.h"
33 #include "../../7zAlloc.h"
34 #include "../../7zCrc.h"
35 #include "../../7zFile.h"
36 #include "../../7zVersion.h"
37 #include "../../CpuArch.h"
38 #include "../../DllSecur.h"
39
40 #include "resource.h"
41
42 #if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__)
43 // #pragma GCC diagnostic ignored "-Wcast-function-type"
44 #endif
45
46 #define LLL_(quote) L##quote
47 #define LLL(quote) LLL_(quote)
48
49 #define wcscat lstrcatW
50 #define wcslen (size_t)lstrlenW
51 #define wcscpy lstrcpyW
52 // wcsncpy() and lstrcpynW() work differently. We don't use them.
53
54 #define kInputBufSize ((size_t)1 << 18)
55
56 #define Z7_7ZIP_CUR_VER ((MY_VER_MAJOR << 16) | MY_VER_MINOR)
57 #define Z7_7ZIP_DLL_VER_COMPAT ((16 << 16) | 3)
58
59 static LPCSTR const k_7zip = "7-Zip";
60
61 static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip";
62
63 // #define Z7_64BIT_INSTALLER 1
64
65 #ifdef _WIN64
66 #define Z7_64BIT_INSTALLER 1
67 #endif
68
69 #define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION)
70
71 #ifdef Z7_64BIT_INSTALLER
72
73 // #define USE_7ZIP_32_DLL
74
75 #if defined(_M_ARM64) || defined(_M_ARM)
76 #define k_Postfix L" (arm64)"
77 #else
78 #define k_Postfix L" (x64)"
79 #define USE_7ZIP_32_DLL
80 #endif
81 #else
82 #if defined(_M_ARM64) || defined(_M_ARM)
83 #define k_Postfix L" (arm)"
84 #else
85 // #define k_Postfix L" (x86)"
86 #define k_Postfix
87 #endif
88 #endif
89
90 #define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix
91
92
93 static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver;
94
95 static LPCWSTR const k_7zip_Setup = k_7zip_with_Ver L" Setup";
96
97 static LPCWSTR const k_Reg_Path = L"Path";
98
99 static LPCWSTR const k_Reg_Path32 = L"Path"
100 #ifdef Z7_64BIT_INSTALLER
101 L"64"
102 #else
103 L"32"
104 #endif
105 ;
106
107 #if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64)
108 #define k_Reg_WOW_Flag KEY_WOW64_64KEY
109 #else
110 #define k_Reg_WOW_Flag 0
111 #endif
112
113 #ifdef USE_7ZIP_32_DLL
114 #ifdef _WIN64
115 #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY
116 #else
117 #define k_Reg_WOW_Flag_32 0
118 #endif
119 #endif
120
121 #define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}"
122
123 static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID;
124 static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32";
125
126 #define g_AllUsers True
127
128 static BoolInt g_Install_was_Pressed;
129 static BoolInt g_Finished;
130 static BoolInt g_SilentMode;
131
132 static HWND g_HWND;
133 static HWND g_Path_HWND;
134 static HWND g_InfoLine_HWND;
135 static HWND g_Progress_HWND;
136
137 static DWORD g_TotalSize;
138
139 static WCHAR cmd[MAX_PATH + 4];
140 static WCHAR cmdError[MAX_PATH + 4];
141 static WCHAR path[MAX_PATH * 2 + 40];
142
143
144
CpyAscii(wchar_t * dest,const char * s)145 static void CpyAscii(wchar_t *dest, const char *s)
146 {
147 for (;;)
148 {
149 Byte b = (Byte)*s++;
150 *dest++ = b;
151 if (b == 0)
152 return;
153 }
154 }
155
CatAscii(wchar_t * dest,const char * s)156 static void CatAscii(wchar_t *dest, const char *s)
157 {
158 dest += wcslen(dest);
159 CpyAscii(dest, s);
160 }
161
PrintErrorMessage(const char * s1,const wchar_t * s2)162 static void PrintErrorMessage(const char *s1, const wchar_t *s2)
163 {
164 WCHAR m[MAX_PATH + 512];
165 m[0] = 0;
166 CatAscii(m, "ERROR:");
167 if (s1)
168 {
169 CatAscii(m, "\n");
170 CatAscii(m, s1);
171 }
172 if (s2)
173 {
174 CatAscii(m, "\n");
175 wcscat(m, s2);
176 }
177 MessageBoxW(g_HWND, m, k_7zip_with_Ver_str, MB_ICONERROR | MB_OK);
178 }
179
180
181 typedef DWORD (WINAPI * Func_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename, LPDWORD lpdwHandle);
182 typedef BOOL (WINAPI * Func_GetFileVersionInfoW)(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
183 typedef BOOL (WINAPI * Func_VerQueryValueW)(const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen);
184
185 static HMODULE g_version_dll_hModule;
186
GetFileVersion(LPCWSTR s)187 static DWORD GetFileVersion(LPCWSTR s)
188 {
189 DWORD size = 0;
190 void *vi = NULL;
191 DWORD version = 0;
192
193 Func_GetFileVersionInfoSizeW my_GetFileVersionInfoSizeW;
194 Func_GetFileVersionInfoW my_GetFileVersionInfoW;
195 Func_VerQueryValueW my_VerQueryValueW;
196
197 if (!g_version_dll_hModule)
198 {
199 wchar_t buf[MAX_PATH + 100];
200 {
201 unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2);
202 if (len == 0 || len > MAX_PATH)
203 return 0;
204 }
205 {
206 unsigned pos = (unsigned)lstrlenW(buf);
207 if (buf[pos - 1] != '\\')
208 buf[pos++] = '\\';
209 lstrcpyW(buf + pos, L"version.dll");
210 }
211 g_version_dll_hModule = LoadLibraryW(buf);
212 if (!g_version_dll_hModule)
213 return 0;
214 }
215
216 my_GetFileVersionInfoSizeW = (Func_GetFileVersionInfoSizeW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule,
217 "GetFileVersionInfoSizeW");
218 my_GetFileVersionInfoW = (Func_GetFileVersionInfoW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule,
219 "GetFileVersionInfoW");
220 my_VerQueryValueW = (Func_VerQueryValueW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule,
221 "VerQueryValueW");
222
223 if (!my_GetFileVersionInfoSizeW
224 || !my_GetFileVersionInfoW
225 || !my_VerQueryValueW)
226 return 0;
227
228 size = my_GetFileVersionInfoSizeW(s, NULL);
229 if (size == 0)
230 return 0;
231
232 vi = malloc(size);
233 if (!vi)
234 return 0;
235
236 if (my_GetFileVersionInfoW(s, 0, size, vi))
237 {
238 VS_FIXEDFILEINFO *fi = NULL;
239 UINT fiLen = 0;
240 if (my_VerQueryValueW(vi, L"\\", (LPVOID *)&fi, &fiLen))
241 version = fi->dwFileVersionMS;
242 }
243
244 free(vi);
245 return version;
246 }
247
248
MyCreateDir(LPCWSTR name)249 static WRes MyCreateDir(LPCWSTR name)
250 {
251 return CreateDirectoryW(name, NULL) ? 0 : GetLastError();
252 }
253
254 #define IS_SEPAR(c) (c == WCHAR_PATH_SEPARATOR)
255 #define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
256 #define IS_DRIVE_PATH(s) (IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]))
257
ReverseFind_PathSepar(const wchar_t * s)258 static int ReverseFind_PathSepar(const wchar_t *s)
259 {
260 int separ = -1;
261 int i;
262 for (i = 0;; i++)
263 {
264 wchar_t c = s[i];
265 if (c == 0)
266 return separ;
267 if (IS_SEPAR(c))
268 separ = i;
269 }
270 }
271
CreateComplexDir(void)272 static WRes CreateComplexDir(void)
273 {
274 WCHAR s[MAX_PATH + 10];
275
276 unsigned prefixSize = 0;
277 WRes wres;
278
279 {
280 size_t len = wcslen(path);
281 if (len > MAX_PATH)
282 return ERROR_INVALID_NAME;
283 wcscpy(s, path);
284 }
285
286 if (IS_DRIVE_PATH(s))
287 prefixSize = 3;
288 else if (IS_SEPAR(s[0]) && IS_SEPAR(s[1]))
289 prefixSize = 2;
290 else
291 return ERROR_INVALID_NAME;
292
293 {
294 DWORD attrib = GetFileAttributesW(s);
295 if (attrib != INVALID_FILE_ATTRIBUTES)
296 return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ? 0 : ERROR_ALREADY_EXISTS;
297 }
298
299 wres = MyCreateDir(s);
300 if (wres == 0 || wres == ERROR_ALREADY_EXISTS)
301 return 0;
302
303 {
304 size_t len = wcslen(s);
305 {
306 const int pos = ReverseFind_PathSepar(s);
307 if (pos < 0)
308 return wres;
309 if ((unsigned)pos < prefixSize)
310 return wres;
311 if ((unsigned)pos == len - 1)
312 {
313 if (len == 1)
314 return 0;
315 s[pos] = 0;
316 len = (unsigned)pos;
317 }
318 }
319
320 for (;;)
321 {
322 int pos;
323 wres = MyCreateDir(s);
324 if (wres == 0)
325 break;
326 if (wres == ERROR_ALREADY_EXISTS)
327 {
328 const DWORD attrib = GetFileAttributesW(s);
329 if (attrib != INVALID_FILE_ATTRIBUTES)
330 if ((attrib & FILE_ATTRIBUTE_DIRECTORY) == 0)
331 return ERROR_ALREADY_EXISTS;
332 break;
333 }
334 pos = ReverseFind_PathSepar(s);
335 if (pos < 0 || pos == 0 || (unsigned)pos < prefixSize)
336 return wres;
337 s[pos] = 0;
338 }
339
340 for (;;)
341 {
342 const size_t pos = wcslen(s);
343 if (pos >= len)
344 return 0;
345 s[pos] = CHAR_PATH_SEPARATOR;
346 wres = MyCreateDir(s);
347 if (wres != 0)
348 return wres;
349 }
350 }
351 }
352
353
MyRegistry_QueryString(HKEY hKey,LPCWSTR name,LPWSTR dest)354 static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest)
355 {
356 DWORD cnt = MAX_PATH * sizeof(name[0]);
357 DWORD type = 0;
358 const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt);
359 if (type != REG_SZ)
360 return False;
361 return res == ERROR_SUCCESS;
362 }
363
MyRegistry_QueryString2(HKEY hKey,LPCWSTR keyName,LPCWSTR valName,LPWSTR dest)364 static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest)
365 {
366 HKEY key = 0;
367 const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key);
368 if (res != ERROR_SUCCESS)
369 return False;
370 {
371 const BoolInt res2 = MyRegistry_QueryString(key, valName, dest);
372 RegCloseKey(key);
373 return res2;
374 }
375 }
376
MyRegistry_SetString(HKEY hKey,LPCWSTR name,LPCWSTR val)377 static LONG MyRegistry_SetString(HKEY hKey, LPCWSTR name, LPCWSTR val)
378 {
379 return RegSetValueExW(hKey, name, 0, REG_SZ,
380 (const BYTE *)val, (DWORD)(wcslen(val) + 1) * sizeof(val[0]));
381 }
382
MyRegistry_SetDWORD(HKEY hKey,LPCWSTR name,DWORD val)383 static LONG MyRegistry_SetDWORD(HKEY hKey, LPCWSTR name, DWORD val)
384 {
385 return RegSetValueExW(hKey, name, 0, REG_DWORD, (const BYTE *)&val, sizeof(DWORD));
386 }
387
388
MyRegistry_CreateKey(HKEY parentKey,LPCWSTR name,HKEY * destKey)389 static LONG MyRegistry_CreateKey(HKEY parentKey, LPCWSTR name, HKEY *destKey)
390 {
391 return RegCreateKeyExW(parentKey, name, 0, NULL,
392 REG_OPTION_NON_VOLATILE,
393 KEY_ALL_ACCESS | k_Reg_WOW_Flag,
394 NULL, destKey, NULL);
395 }
396
MyRegistry_CreateKeyAndVal(HKEY parentKey,LPCWSTR keyName,LPCWSTR valName,LPCWSTR val)397 static LONG MyRegistry_CreateKeyAndVal(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val)
398 {
399 HKEY destKey = 0;
400 LONG res = MyRegistry_CreateKey(parentKey, keyName, &destKey);
401 if (res == ERROR_SUCCESS)
402 {
403 res = MyRegistry_SetString(destKey, valName, val);
404 /* res = */ RegCloseKey(destKey);
405 }
406 return res;
407 }
408
409
410 #ifdef USE_7ZIP_32_DLL
411
MyRegistry_CreateKey_32(HKEY parentKey,LPCWSTR name,HKEY * destKey)412 static LONG MyRegistry_CreateKey_32(HKEY parentKey, LPCWSTR name, HKEY *destKey)
413 {
414 return RegCreateKeyExW(parentKey, name, 0, NULL,
415 REG_OPTION_NON_VOLATILE,
416 KEY_ALL_ACCESS | k_Reg_WOW_Flag_32,
417 NULL, destKey, NULL);
418 }
419
MyRegistry_CreateKeyAndVal_32(HKEY parentKey,LPCWSTR keyName,LPCWSTR valName,LPCWSTR val)420 static LONG MyRegistry_CreateKeyAndVal_32(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val)
421 {
422 HKEY destKey = 0;
423 LONG res = MyRegistry_CreateKey_32(parentKey, keyName, &destKey);
424 if (res == ERROR_SUCCESS)
425 {
426 res = MyRegistry_SetString(destKey, valName, val);
427 /* res = */ RegCloseKey(destKey);
428 }
429 return res;
430 }
431
432 #endif
433
434
435
436 #ifdef UNDER_CE
437 #define kBufSize (1 << 13)
438 #else
439 #define kBufSize (1 << 15)
440 #endif
441
442 #define kSignatureSearchLimit (1 << 22)
443
FindSignature(CSzFile * stream,UInt64 * resPos)444 static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos)
445 {
446 Byte buf[kBufSize];
447 size_t numPrevBytes = 0;
448 *resPos = 0;
449
450 for (;;)
451 {
452 size_t processed, pos;
453 if (*resPos > kSignatureSearchLimit)
454 return False;
455 processed = kBufSize - numPrevBytes;
456 if (File_Read(stream, buf + numPrevBytes, &processed) != 0)
457 return False;
458 processed += numPrevBytes;
459 if (processed < k7zStartHeaderSize ||
460 (processed == k7zStartHeaderSize && numPrevBytes != 0))
461 return False;
462 processed -= k7zStartHeaderSize;
463 for (pos = 0; pos <= processed; pos++)
464 {
465 for (; pos <= processed && buf[pos] != '7'; pos++);
466 if (pos > processed)
467 break;
468 if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0)
469 if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8))
470 {
471 *resPos += pos;
472 return True;
473 }
474 }
475 *resPos += processed;
476 numPrevBytes = k7zStartHeaderSize;
477 memmove(buf, buf + processed, k7zStartHeaderSize);
478 }
479 }
480
HexToString(UInt32 val,WCHAR * s)481 static void HexToString(UInt32 val, WCHAR *s)
482 {
483 UInt64 v = val;
484 unsigned i;
485 for (i = 1;; i++)
486 {
487 v >>= 4;
488 if (v == 0)
489 break;
490 }
491 s[i] = 0;
492 do
493 {
494 unsigned t = (unsigned)((val & 0xF));
495 val >>= 4;
496 s[--i] = (WCHAR)(unsigned)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
497 }
498 while (i);
499 }
500
501
502 #ifndef UNDER_CE
503
BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lp,LPARAM data)504 static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM data)
505 {
506 UNUSED_VAR(lp)
507 UNUSED_VAR(data)
508 UNUSED_VAR(hwnd)
509
510 switch (uMsg)
511 {
512 case BFFM_INITIALIZED:
513 {
514 SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, data);
515 break;
516 }
517 case BFFM_SELCHANGED:
518 {
519 // show selected path for BIF_STATUSTEXT
520 WCHAR dir[MAX_PATH];
521 if (!SHGetPathFromIDListW((LPITEMIDLIST)lp, dir))
522 dir[0] = 0;
523 SendMessage(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir);
524 break;
525 }
526 default:
527 break;
528 }
529 return 0;
530 }
531
MyBrowseForFolder(HWND owner,LPCWSTR title,UINT ulFlags,LPCWSTR initialFolder,LPWSTR resultPath)532 static BoolInt MyBrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags,
533 LPCWSTR initialFolder, LPWSTR resultPath)
534 {
535 WCHAR displayName[MAX_PATH];
536 BROWSEINFOW browseInfo;
537
538 displayName[0] = 0;
539 browseInfo.hwndOwner = owner;
540 browseInfo.pidlRoot = NULL;
541
542 // there are Unicode/Astring problems in some WinCE SDK ?
543 browseInfo.pszDisplayName = displayName;
544 browseInfo.lpszTitle = title;
545 browseInfo.ulFlags = ulFlags;
546 browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL;
547 browseInfo.lParam = (LPARAM)initialFolder;
548 {
549 LPITEMIDLIST idlist = SHBrowseForFolderW(&browseInfo);
550 if (idlist)
551 {
552 SHGetPathFromIDListW(idlist, resultPath);
553 // free idlist
554 // CoTaskMemFree(idlist);
555 return True;
556 }
557 return False;
558 }
559 }
560
561 #endif
562
NormalizePrefix(WCHAR * s)563 static void NormalizePrefix(WCHAR *s)
564 {
565 size_t i = 0;
566
567 for (;; i++)
568 {
569 const wchar_t c = s[i];
570 if (c == 0)
571 break;
572 if (c == '/')
573 s[i] = WCHAR_PATH_SEPARATOR;
574 }
575
576 if (i != 0 && s[i - 1] != WCHAR_PATH_SEPARATOR)
577 {
578 s[i] = WCHAR_PATH_SEPARATOR;
579 s[i + 1] = 0;
580 }
581 }
582
MyCharLower_Ascii(char c)583 static char MyCharLower_Ascii(char c)
584 {
585 if (c >= 'A' && c <= 'Z')
586 return (char)((unsigned char)c + 0x20);
587 return c;
588 }
589
MyWCharLower_Ascii(wchar_t c)590 static wchar_t MyWCharLower_Ascii(wchar_t c)
591 {
592 if (c >= 'A' && c <= 'Z')
593 return (wchar_t)(c + 0x20);
594 return c;
595 }
596
FindSubString(LPCWSTR s1,const char * s2)597 static LPCWSTR FindSubString(LPCWSTR s1, const char *s2)
598 {
599 for (;;)
600 {
601 unsigned i;
602 if (*s1 == 0)
603 return NULL;
604 for (i = 0;; i++)
605 {
606 const char b = s2[i];
607 if (b == 0)
608 return s1;
609 if (MyWCharLower_Ascii(s1[i]) != (Byte)MyCharLower_Ascii(b))
610 {
611 s1++;
612 break;
613 }
614 }
615 }
616 }
617
Set7zipPostfix(WCHAR * s)618 static void Set7zipPostfix(WCHAR *s)
619 {
620 NormalizePrefix(s);
621 if (FindSubString(s, "7-Zip"))
622 return;
623 CatAscii(s, "7-Zip\\");
624 }
625
626
627 static int Install(void);
628
OnClose(void)629 static void OnClose(void)
630 {
631 if (g_Install_was_Pressed && !g_Finished)
632 {
633 if (MessageBoxW(g_HWND,
634 L"Do you want to cancel " k_7zip_with_Ver L" installation?",
635 k_7zip_with_Ver,
636 MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
637 return;
638 }
639 DestroyWindow(g_HWND);
640 g_HWND = NULL;
641 }
642
643 static
644 #ifdef Z7_OLD_WIN_SDK
645 BOOL
646 #else
647 INT_PTR
648 #endif
MyDlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)649 CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
650 {
651 // UNUSED_VAR(hwnd)
652 UNUSED_VAR(lParam)
653
654 switch (message)
655 {
656 case WM_INITDIALOG:
657 g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH);
658 g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE);
659 g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS);
660
661 SetWindowTextW(hwnd, k_7zip_Setup);
662 SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path);
663
664 ShowWindow(g_Progress_HWND, SW_HIDE);
665 ShowWindow(g_InfoLine_HWND, SW_HIDE);
666
667 break;
668
669 case WM_COMMAND:
670 switch (LOWORD(wParam))
671 {
672 case IDOK:
673 {
674 if (g_Finished)
675 {
676 OnClose();
677 break;
678 }
679 if (!g_Install_was_Pressed)
680 {
681 SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE);
682
683 EnableWindow(g_Path_HWND, FALSE);
684 EnableWindow(GetDlgItem(hwnd, IDB_EXTRACT_SET_PATH), FALSE);
685 EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
686
687 g_Install_was_Pressed = True;
688 return TRUE;
689 }
690 break;
691 }
692
693 case IDCANCEL:
694 {
695 OnClose();
696 break;
697 }
698
699 case IDB_EXTRACT_SET_PATH:
700 {
701 #ifndef UNDER_CE
702
703 WCHAR s[MAX_PATH];
704 WCHAR s2[MAX_PATH];
705 GetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s, MAX_PATH);
706 if (MyBrowseForFolder(hwnd, L"Select the folder for installation:" ,
707 0
708 | BIF_NEWDIALOGSTYLE // 5.0 of ?.dll ?
709 | BIF_RETURNONLYFSDIRS
710 // | BIF_STATUSTEXT // doesn't work for BIF_NEWDIALOGSTYLE
711 , s, s2))
712 {
713 Set7zipPostfix(s2);
714 SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s2);
715 }
716
717 #endif
718 break;
719 }
720
721 default: return FALSE;
722 }
723 break;
724
725 case WM_CLOSE:
726 OnClose();
727 break;
728 /*
729 case WM_DESTROY:
730 PostQuitMessage(0);
731 return TRUE;
732 */
733 default:
734 return FALSE;
735 }
736
737 return TRUE;
738 }
739
740
741
SetRegKey_Path2(HKEY parentKey)742 static LONG SetRegKey_Path2(HKEY parentKey)
743 {
744 HKEY destKey = 0;
745 LONG res = MyRegistry_CreateKey(parentKey, k_Reg_Software_7zip, &destKey);
746 if (res == ERROR_SUCCESS)
747 {
748 res = MyRegistry_SetString(destKey, k_Reg_Path32, path);
749 /* res = */ MyRegistry_SetString(destKey, k_Reg_Path, path);
750 /* res = */ RegCloseKey(destKey);
751 }
752 return res;
753 }
754
SetRegKey_Path(void)755 static void SetRegKey_Path(void)
756 {
757 SetRegKey_Path2(HKEY_CURRENT_USER);
758 SetRegKey_Path2(HKEY_LOCAL_MACHINE);
759 }
760
761
CreateShellLink(LPCWSTR srcPath,LPCWSTR targetPath)762 static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath)
763 {
764 IShellLinkW* sl;
765
766 // CoInitialize has already been called.
767 HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl);
768
769 if (SUCCEEDED(hres))
770 {
771 IPersistFile* pf;
772
773 sl->lpVtbl->SetPath(sl, targetPath);
774 // sl->lpVtbl->SetDescription(sl, description);
775 hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
776
777 if (SUCCEEDED(hres))
778 {
779 hres = pf->lpVtbl->Save(pf, srcPath, TRUE);
780 pf->lpVtbl->Release(pf);
781 }
782 sl->lpVtbl->Release(sl);
783 }
784
785 return hres;
786 }
787
SetShellProgramsGroup(HWND hwndOwner)788 static void SetShellProgramsGroup(HWND hwndOwner)
789 {
790 #ifdef UNDER_CE
791
792 // CpyAscii(link, "\\Program Files\\");
793 UNUSED_VAR(hwndOwner)
794
795 #else
796
797 unsigned i = (g_AllUsers ? 0 : 2);
798
799 for (; i < 3; i++)
800 {
801 BoolInt isOK = True;
802 WCHAR link[MAX_PATH + 40];
803 WCHAR destPath[MAX_PATH + 40];
804
805 link[0] = 0;
806
807 if (SHGetFolderPathW(hwndOwner,
808 i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS,
809 NULL, SHGFP_TYPE_CURRENT, link) != S_OK)
810 continue;
811
812 NormalizePrefix(link);
813 CatAscii(link, k_7zip);
814 // CatAscii(link, "2");
815
816 if (i != 0)
817 MyCreateDir(link);
818
819 NormalizePrefix(link);
820
821 {
822 unsigned baseLen = (unsigned)wcslen(link);
823 unsigned k;
824
825 for (k = 0; k < 2; k++)
826 {
827 CpyAscii(link + baseLen, k == 0 ?
828 "7-Zip File Manager.lnk" :
829 "7-Zip Help.lnk"
830 );
831 wcscpy(destPath, path);
832 CatAscii(destPath, k == 0 ?
833 "7zFM.exe" :
834 "7-zip.chm");
835
836 if (i == 0)
837 DeleteFileW(link);
838 else if (CreateShellLink(link, destPath) != S_OK)
839 isOK = False;
840 }
841 }
842
843 if (i != 0 && isOK)
844 break;
845 }
846
847 #endif
848 }
849
850 static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
851 static LPCWSTR const k_7zip_ShellExtension = L"7-Zip Shell Extension";
852
WriteCLSID(void)853 static void WriteCLSID(void)
854 {
855 HKEY destKey;
856 LONG res;
857
858 #ifdef USE_7ZIP_32_DLL
859
860 MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension);
861
862 res = MyRegistry_CreateKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey);
863
864 if (res == ERROR_SUCCESS)
865 {
866 WCHAR destPath[MAX_PATH + 40];
867 wcscpy(destPath, path);
868 CatAscii(destPath, "7-zip32.dll");
869 /* res = */ MyRegistry_SetString(destKey, NULL, destPath);
870 /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment");
871 // DeleteRegValue(destKey, L"InprocServer32");
872 /* res = */ RegCloseKey(destKey);
873 }
874
875 #endif
876
877
878 MyRegistry_CreateKeyAndVal(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension);
879
880 destKey = 0;
881 res = MyRegistry_CreateKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey);
882
883 if (res == ERROR_SUCCESS)
884 {
885 WCHAR destPath[MAX_PATH + 40];
886 wcscpy(destPath, path);
887 CatAscii(destPath, "7-zip.dll");
888 /* res = */ MyRegistry_SetString(destKey, NULL, destPath);
889 /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment");
890 // DeleteRegValue(destKey, L"InprocServer32");
891 /* res = */ RegCloseKey(destKey);
892 }
893 }
894
895 static LPCSTR const k_ShellEx_Items[] =
896 {
897 "*\\shellex\\ContextMenuHandlers"
898 , "Directory\\shellex\\ContextMenuHandlers"
899 , "Folder\\shellex\\ContextMenuHandlers"
900 , "Directory\\shellex\\DragDropHandlers"
901 , "Drive\\shellex\\DragDropHandlers"
902 };
903
WriteShellEx(void)904 static void WriteShellEx(void)
905 {
906 unsigned i;
907 WCHAR destPath[MAX_PATH + 40];
908
909 for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++)
910 {
911 CpyAscii(destPath, k_ShellEx_Items[i]);
912 CatAscii(destPath, "\\7-Zip");
913
914 #ifdef USE_7ZIP_32_DLL
915 MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID);
916 #endif
917 MyRegistry_CreateKeyAndVal (HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID);
918 }
919
920 #ifdef USE_7ZIP_32_DLL
921 MyRegistry_CreateKeyAndVal_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension);
922 #endif
923 MyRegistry_CreateKeyAndVal (HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension);
924
925
926 wcscpy(destPath, path);
927 CatAscii(destPath, "7zFM.exe");
928
929 {
930 HKEY destKey = 0;
931 LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe", &destKey);
932 if (res == ERROR_SUCCESS)
933 {
934 MyRegistry_SetString(destKey, NULL, destPath);
935 MyRegistry_SetString(destKey, L"Path", path);
936 RegCloseKey(destKey);
937 }
938
939 }
940
941 {
942 HKEY destKey = 0;
943 LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\7-Zip", &destKey);
944 if (res == ERROR_SUCCESS)
945 {
946 MyRegistry_SetString(destKey, L"DisplayName", k_7zip_with_Ver_str);
947 MyRegistry_SetString(destKey, L"DisplayVersion", LLL(MY_VERSION_NUMBERS));
948 MyRegistry_SetString(destKey, L"DisplayIcon", destPath);
949 MyRegistry_SetString(destKey, L"InstallLocation", path);
950
951 destPath[0] = '\"';
952 wcscpy(destPath + 1, path);
953 CatAscii(destPath, "Uninstall.exe\"");
954 MyRegistry_SetString(destKey, L"UninstallString", destPath);
955
956 CatAscii(destPath, " /S");
957 MyRegistry_SetString(destKey, L"QuietUninstallString", destPath);
958
959 MyRegistry_SetDWORD(destKey, L"NoModify", 1);
960 MyRegistry_SetDWORD(destKey, L"NoRepair", 1);
961
962 MyRegistry_SetDWORD(destKey, L"EstimatedSize", g_TotalSize >> 10);
963
964 MyRegistry_SetDWORD(destKey, L"VersionMajor", MY_VER_MAJOR);
965 MyRegistry_SetDWORD(destKey, L"VersionMinor", MY_VER_MINOR);
966
967 MyRegistry_SetString(destKey, L"Publisher", LLL(MY_AUTHOR_NAME));
968
969 // MyRegistry_SetString(destKey, L"HelpLink", L"http://www.7-zip.org/support.html");
970 // MyRegistry_SetString(destKey, L"URLInfoAbout", L"http://www.7-zip.org/");
971 // MyRegistry_SetString(destKey, L"URLUpdateInfo", L"http://www.7-zip.org/");
972
973 RegCloseKey(destKey);
974 }
975 }
976 }
977
978
GetCmdParam(const wchar_t * s)979 static const wchar_t *GetCmdParam(const wchar_t *s)
980 {
981 unsigned pos = 0;
982 BoolInt quoteMode = False;
983 for (;; s++)
984 {
985 wchar_t c = *s;
986 if (c == 0 || (c == L' ' && !quoteMode))
987 break;
988 if (c == L'\"')
989 {
990 quoteMode = !quoteMode;
991 continue;
992 }
993 if (pos >= Z7_ARRAY_SIZE(cmd) - 1)
994 exit(1);
995 cmd[pos++] = c;
996 }
997 cmd[pos] = 0;
998 return s;
999 }
1000
1001
RemoveQuotes(wchar_t * s)1002 static void RemoveQuotes(wchar_t *s)
1003 {
1004 const wchar_t *src = s;
1005 for (;;)
1006 {
1007 wchar_t c = *src++;
1008 if (c == '\"')
1009 continue;
1010 *s++ = c;
1011 if (c == 0)
1012 return;
1013 }
1014 }
1015
1016 // #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ')
1017
1018
1019 typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL);
1020
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nCmdShow)1021 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
1022 #ifdef UNDER_CE
1023 LPWSTR
1024 #else
1025 LPSTR
1026 #endif
1027 lpCmdLine, int nCmdShow)
1028 {
1029
1030 UNUSED_VAR(hPrevInstance)
1031 UNUSED_VAR(lpCmdLine)
1032 UNUSED_VAR(nCmdShow)
1033
1034 #ifndef UNDER_CE
1035 LoadSecurityDlls();
1036 CoInitialize(NULL);
1037 #endif
1038
1039 CrcGenerateTable();
1040
1041 {
1042 const wchar_t *s = GetCommandLineW();
1043
1044 #ifndef UNDER_CE
1045 s = GetCmdParam(s);
1046 #endif
1047
1048 for (;;)
1049 {
1050 {
1051 const wchar_t c = *s;
1052 if (c == 0)
1053 break;
1054 if (c == ' ')
1055 {
1056 s++;
1057 continue;
1058 }
1059 }
1060
1061 {
1062 const wchar_t *s2 = GetCmdParam(s);
1063 BoolInt error = True;
1064 if (cmd[0] == '/')
1065 {
1066 if (cmd[1] == 'S')
1067 {
1068 if (cmd[2] == 0)
1069 {
1070 g_SilentMode = True;
1071 error = False;
1072 }
1073 }
1074 else if (cmd[1] == 'D' && cmd[2] == '=')
1075 {
1076 wcscpy(path, cmd + 3);
1077 // RemoveQuotes(path);
1078 error = False;
1079 }
1080 }
1081 s = s2;
1082 if (error && cmdError[0] == 0)
1083 wcscpy(cmdError, cmd);
1084 }
1085 }
1086
1087 if (cmdError[0] != 0)
1088 {
1089 if (!g_SilentMode)
1090 PrintErrorMessage("Unsupported command:", cmdError);
1091 return 1;
1092 }
1093 }
1094
1095 #if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64)
1096 {
1097 BOOL isWow64 = FALSE;
1098 const Func_IsWow64Process func_IsWow64Process = (Func_IsWow64Process)
1099 Z7_CAST_FUNC_C GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
1100 "IsWow64Process");
1101
1102 if (func_IsWow64Process)
1103 func_IsWow64Process(GetCurrentProcess(), &isWow64);
1104
1105 if (!isWow64)
1106 {
1107 if (!g_SilentMode)
1108 PrintErrorMessage("This installation requires Windows "
1109 #ifdef MY_CPU_X86_OR_AMD64
1110 "x64"
1111 #else
1112 "64-bit"
1113 #endif
1114 , NULL);
1115 return 1;
1116 }
1117 }
1118 #endif
1119
1120
1121 if (path[0] == 0)
1122 {
1123 HKEY key = 0;
1124 BoolInt ok = False;
1125 const LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key);
1126 if (res == ERROR_SUCCESS)
1127 {
1128 ok = MyRegistry_QueryString(key, k_Reg_Path32, path);
1129 // ok = MyRegistry_QueryString(key, k_Reg_Path, path);
1130 RegCloseKey(key);
1131 }
1132
1133 // ok = False;
1134 if (!ok)
1135 {
1136 /*
1137 #ifdef UNDER_CE
1138 CpyAscii(path, "\\Program Files\\");
1139 #else
1140
1141 #ifdef Z7_64BIT_INSTALLER
1142 {
1143 DWORD ttt = GetEnvironmentVariableW(L"ProgramW6432", path, MAX_PATH);
1144 if (ttt == 0 || ttt > MAX_PATH)
1145 CpyAscii(path, "C:\\");
1146 }
1147 #else
1148 if (!SHGetSpecialFolderPathW(0, path, CSIDL_PROGRAM_FILES, FALSE))
1149 CpyAscii(path, "C:\\");
1150 #endif
1151 #endif
1152 */
1153 if (!MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", L"ProgramFilesDir", path))
1154 CpyAscii(path,
1155 #ifdef UNDER_CE
1156 "\\Program Files\\"
1157 #else
1158 "C:\\"
1159 #endif
1160 );
1161
1162 Set7zipPostfix(path);
1163 }
1164 }
1165
1166 NormalizePrefix(path);
1167
1168 if (g_SilentMode)
1169 return Install();
1170
1171 {
1172 int retCode = 1;
1173 // INT_PTR res = DialogBox(
1174 g_HWND = CreateDialog(
1175 hInstance,
1176 // GetModuleHandle(NULL),
1177 MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc);
1178 if (!g_HWND)
1179 return 1;
1180
1181 {
1182 const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
1183 // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
1184 SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
1185 }
1186
1187
1188 {
1189 BOOL bRet;
1190 MSG msg;
1191
1192 // we need messages for all thread windows (including EDITTEXT window in dialog)
1193 while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
1194 {
1195 if (bRet == -1)
1196 return retCode;
1197 if (!g_HWND)
1198 return retCode;
1199
1200 if (!IsDialogMessage(g_HWND, &msg))
1201 {
1202 TranslateMessage(&msg);
1203 DispatchMessage(&msg);
1204 }
1205 if (!g_HWND)
1206 return retCode;
1207
1208 if (g_Install_was_Pressed && !g_Finished)
1209 {
1210 retCode = Install();
1211 g_Finished = True;
1212 if (retCode != 0)
1213 break;
1214 if (!g_HWND)
1215 break;
1216 {
1217 SetDlgItemTextW(g_HWND, IDOK, L"Close");
1218 EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE);
1219 EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE);
1220 SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE);
1221 }
1222 }
1223 }
1224
1225 if (g_HWND)
1226 {
1227 DestroyWindow(g_HWND);
1228 g_HWND = NULL;
1229 }
1230 }
1231
1232 return retCode;
1233 }
1234 }
1235
1236
GetErrorMessage(DWORD errorCode,WCHAR * message)1237 static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message)
1238 {
1239 LPWSTR msgBuf;
1240 if (FormatMessageW(
1241 FORMAT_MESSAGE_ALLOCATE_BUFFER
1242 | FORMAT_MESSAGE_FROM_SYSTEM
1243 | FORMAT_MESSAGE_IGNORE_INSERTS,
1244 NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
1245 return False;
1246 wcscpy(message, msgBuf);
1247 LocalFree(msgBuf);
1248 return True;
1249 }
1250
1251
1252
Install(void)1253 static int Install(void)
1254 {
1255 CFileInStream archiveStream;
1256 CLookToRead2 lookStream;
1257 CSzArEx db;
1258
1259 SRes res = SZ_OK;
1260 WRes winRes = 0;
1261 const char *errorMessage = NULL;
1262
1263 ISzAlloc allocImp;
1264 ISzAlloc allocTempImp;
1265 WCHAR sfxPath[MAX_PATH + 2];
1266
1267 int needRebootLevel = 0;
1268
1269 allocImp.Alloc = SzAlloc;
1270 allocImp.Free = SzFree;
1271
1272 allocTempImp.Alloc = SzAllocTemp;
1273 allocTempImp.Free = SzFreeTemp;
1274
1275 {
1276 const DWORD len = GetModuleFileNameW(NULL, sfxPath, MAX_PATH);
1277 if (len == 0 || len > MAX_PATH)
1278 return 1;
1279 }
1280
1281 winRes = InFile_OpenW(&archiveStream.file, sfxPath);
1282
1283 if (winRes == 0)
1284 {
1285 UInt64 pos = 0;
1286 if (!FindSignature(&archiveStream.file, &pos))
1287 errorMessage = "Can't find 7z archive";
1288 else
1289 winRes = File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET);
1290 }
1291
1292 if (winRes != 0)
1293 res = SZ_ERROR_FAIL;
1294
1295 if (errorMessage)
1296 res = SZ_ERROR_FAIL;
1297
1298 if (res == SZ_OK)
1299 {
1300 size_t pathLen;
1301 if (!g_SilentMode)
1302 {
1303 GetDlgItemTextW(g_HWND, IDE_EXTRACT_PATH, path, MAX_PATH);
1304 }
1305
1306 FileInStream_CreateVTable(&archiveStream);
1307 LookToRead2_CreateVTable(&lookStream, False);
1308 lookStream.buf = NULL;
1309
1310 RemoveQuotes(path);
1311 {
1312 // Remove post spaces
1313 unsigned endPos = 0;
1314 unsigned i = 0;
1315
1316 for (;;)
1317 {
1318 const wchar_t c = path[i++];
1319 if (c == 0)
1320 break;
1321 if (c != ' ')
1322 endPos = i;
1323 }
1324
1325 path[endPos] = 0;
1326 if (path[0] == 0)
1327 {
1328 PrintErrorMessage("Incorrect path", NULL);
1329 return 1;
1330 }
1331 }
1332
1333 NormalizePrefix(path);
1334 winRes = CreateComplexDir();
1335
1336 if (winRes != 0)
1337 res = SZ_ERROR_FAIL;
1338
1339 pathLen = wcslen(path);
1340
1341 if (res == SZ_OK)
1342 {
1343 lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
1344 if (!lookStream.buf)
1345 res = SZ_ERROR_MEM;
1346 else
1347 {
1348 lookStream.bufSize = kInputBufSize;
1349 lookStream.realStream = &archiveStream.vt;
1350 LookToRead2_INIT(&lookStream)
1351 }
1352 }
1353
1354 SzArEx_Init(&db);
1355
1356 if (res == SZ_OK)
1357 {
1358 res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
1359 }
1360
1361 if (res == SZ_OK)
1362 {
1363 UInt32 i;
1364 UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call, if (!outBuf) */
1365 Byte *outBuf = NULL; /* it must be NULL before first call for each new archive. */
1366 size_t outBufSize = 0; /* it can have any value before first call, if (!outBuf) */
1367
1368 g_TotalSize = 0;
1369
1370 if (!g_SilentMode)
1371 {
1372 ShowWindow(g_Progress_HWND, SW_SHOW);
1373 ShowWindow(g_InfoLine_HWND, SW_SHOW);
1374 SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, db.NumFiles);
1375 }
1376
1377 for (i = 0; i < db.NumFiles; i++)
1378 {
1379 size_t offset = 0;
1380 size_t outSizeProcessed = 0;
1381 WCHAR *temp;
1382
1383 if (!g_SilentMode)
1384 {
1385 MSG msg;
1386
1387 // g_HWND
1388 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1389 {
1390 if (!IsDialogMessage(g_HWND, &msg))
1391 {
1392 TranslateMessage(&msg);
1393 DispatchMessage(&msg);
1394 }
1395 if (!g_HWND)
1396 return 1;
1397 }
1398
1399 // Sleep(10);
1400 SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
1401 }
1402
1403 {
1404 const size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL);
1405 if (len >= MAX_PATH)
1406 {
1407 res = SZ_ERROR_FAIL;
1408 break;
1409 }
1410 }
1411
1412 temp = path + pathLen;
1413
1414 SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp);
1415
1416 if (!g_SilentMode)
1417 SetWindowTextW(g_InfoLine_HWND, temp);
1418
1419 {
1420 res = SzArEx_Extract(&db, &lookStream.vt, i,
1421 &blockIndex, &outBuf, &outBufSize,
1422 &offset, &outSizeProcessed,
1423 &allocImp, &allocTempImp);
1424 if (res != SZ_OK)
1425 break;
1426 }
1427
1428 {
1429 CSzFile outFile;
1430 size_t processedSize;
1431 size_t j;
1432 // size_t nameStartPos = 0;
1433 UInt32 tempIndex = 0;
1434 int fileLevel = 1 << 2;
1435 WCHAR origPath[MAX_PATH * 2 + 10];
1436
1437 for (j = 0; temp[j] != 0; j++)
1438 {
1439 if (temp[j] == '/')
1440 {
1441 temp[j] = 0;
1442 MyCreateDir(path);
1443 temp[j] = CHAR_PATH_SEPARATOR;
1444 // nameStartPos = j + 1;
1445 }
1446 }
1447
1448 if (SzArEx_IsDir(&db, i))
1449 {
1450 MyCreateDir(path);
1451 continue;
1452 }
1453
1454 {
1455 // BoolInt skipFile = False;
1456
1457 wcscpy(origPath, path);
1458
1459 for (;;)
1460 {
1461 WRes openRes;
1462
1463 if (tempIndex != 0)
1464 {
1465 if (tempIndex > 100)
1466 {
1467 res = SZ_ERROR_FAIL;
1468 break;
1469 }
1470 wcscpy(path, origPath);
1471 CatAscii(path, ".tmp");
1472 if (tempIndex > 1)
1473 HexToString(tempIndex, path + wcslen(path));
1474 if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1475 {
1476 tempIndex++;
1477 continue;
1478 }
1479 }
1480
1481 {
1482 SetFileAttributesW(path, 0);
1483 openRes = OutFile_OpenW(&outFile, path);
1484 if (openRes == 0)
1485 break;
1486 }
1487
1488 if (tempIndex != 0)
1489 {
1490 tempIndex++;
1491 continue;
1492 }
1493
1494 if (FindSubString(temp, "7-zip.dll")
1495 #ifdef USE_7ZIP_32_DLL
1496 || FindSubString(temp, "7-zip32.dll")
1497 #endif
1498 )
1499 {
1500 const DWORD ver = GetFileVersion(path);
1501 fileLevel = ((ver < Z7_7ZIP_DLL_VER_COMPAT || ver > Z7_7ZIP_CUR_VER) ? 2 : 1);
1502 tempIndex++;
1503 continue;
1504 }
1505
1506 if (g_SilentMode)
1507 {
1508 tempIndex++;
1509 continue;
1510 }
1511 {
1512 WCHAR message[MAX_PATH * 3 + 100];
1513 int mbRes;
1514
1515 CpyAscii(message, "Can't open file\n");
1516 wcscat(message, path);
1517 CatAscii(message, "\n");
1518
1519 GetErrorMessage(openRes, message + wcslen(message));
1520
1521 mbRes = MessageBoxW(g_HWND, message, L"Error", MB_ICONERROR | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3);
1522 if (mbRes == IDABORT)
1523 {
1524 res = SZ_ERROR_ABORT;
1525 tempIndex = 0;
1526 break;
1527 }
1528 if (mbRes == IDIGNORE)
1529 {
1530 // skipFile = True;
1531 tempIndex++;
1532 }
1533 }
1534 }
1535
1536 if (res != SZ_OK)
1537 break;
1538
1539 /*
1540 if (skipFile)
1541 continue;
1542 */
1543 }
1544
1545 // if (res == SZ_OK)
1546 {
1547 processedSize = outSizeProcessed;
1548 winRes = File_Write(&outFile, outBuf + offset, &processedSize);
1549 if (winRes != 0 || processedSize != outSizeProcessed)
1550 {
1551 errorMessage = "Can't write output file";
1552 res = SZ_ERROR_FAIL;
1553 }
1554
1555 g_TotalSize += (DWORD)outSizeProcessed;
1556
1557 #ifdef USE_WINDOWS_FILE
1558 if (SzBitWithVals_Check(&db.MTime, i))
1559 {
1560 const CNtfsFileTime *t = db.MTime.Vals + i;
1561 FILETIME mTime;
1562 mTime.dwLowDateTime = t->Low;
1563 mTime.dwHighDateTime = t->High;
1564 SetFileTime(outFile.handle, NULL, NULL, &mTime);
1565 }
1566 #endif
1567
1568 {
1569 const WRes winRes2 = File_Close(&outFile);
1570 if (res != SZ_OK)
1571 break;
1572 if (winRes2 != 0)
1573 {
1574 winRes = winRes2;
1575 break;
1576 }
1577 }
1578
1579 #ifdef USE_WINDOWS_FILE
1580 if (SzBitWithVals_Check(&db.Attribs, i))
1581 SetFileAttributesW(path, db.Attribs.Vals[i]);
1582 #endif
1583 }
1584
1585 if (tempIndex != 0)
1586 {
1587 // is it supported at win2000 ?
1588 #ifndef UNDER_CE
1589 if (!MoveFileExW(path, origPath, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING))
1590 {
1591 winRes = GetLastError();
1592 break;
1593 }
1594 needRebootLevel |= fileLevel;
1595 #endif
1596 }
1597
1598 }
1599 }
1600
1601 ISzAlloc_Free(&allocImp, outBuf);
1602
1603 if (!g_SilentMode)
1604 SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
1605
1606 path[pathLen] = 0;
1607
1608 if (i == db.NumFiles)
1609 {
1610 SetRegKey_Path();
1611 WriteCLSID();
1612 WriteShellEx();
1613
1614 SetShellProgramsGroup(g_HWND);
1615 if (!g_SilentMode)
1616 SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is installed");
1617 }
1618 }
1619
1620 SzArEx_Free(&db, &allocImp);
1621
1622 ISzAlloc_Free(&allocImp, lookStream.buf);
1623
1624 File_Close(&archiveStream.file);
1625
1626 }
1627
1628 if (winRes != 0)
1629 res = SZ_ERROR_FAIL;
1630
1631 if (res == SZ_OK)
1632 {
1633 if (!g_SilentMode && needRebootLevel > 1)
1634 {
1635 if (MessageBoxW(g_HWND, L"You must restart your system to complete the installation.\nRestart now?",
1636 k_7zip_Setup, MB_YESNO | MB_DEFBUTTON2) == IDYES)
1637 {
1638 #ifndef UNDER_CE
1639
1640 // Get a token for this process.
1641 HANDLE hToken;
1642
1643 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
1644 {
1645 TOKEN_PRIVILEGES tkp;
1646 // Get the LUID for the shutdown privilege.
1647 LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
1648 tkp.PrivilegeCount = 1; // one privilege to set
1649 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1650 // Get the shutdown privilege for this process.
1651 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
1652
1653 if (GetLastError() == ERROR_SUCCESS)
1654 {
1655 if (!ExitWindowsEx(EWX_REBOOT, 0))
1656 {
1657 }
1658 }
1659 }
1660
1661 #endif
1662 }
1663 }
1664
1665 if (res == SZ_OK)
1666 return 0;
1667 }
1668
1669 if (!g_SilentMode)
1670 {
1671 if (winRes != 0)
1672 {
1673 WCHAR m[MAX_PATH + 100];
1674 m[0] = 0;
1675 GetErrorMessage(winRes, m);
1676 PrintErrorMessage(NULL, m);
1677 }
1678 else
1679 {
1680 if (res == SZ_ERROR_ABORT)
1681 return 2;
1682
1683 if (res == SZ_ERROR_UNSUPPORTED)
1684 errorMessage = "Decoder doesn't support this archive";
1685 else if (res == SZ_ERROR_MEM)
1686 errorMessage = "Can't allocate required memory";
1687 else if (res == SZ_ERROR_CRC)
1688 errorMessage = "CRC error";
1689 else if (res == SZ_ERROR_DATA)
1690 errorMessage = "Data error";
1691
1692 if (!errorMessage)
1693 errorMessage = "ERROR";
1694 PrintErrorMessage(errorMessage, NULL);
1695 }
1696 }
1697
1698 return 1;
1699 }
1700