xref: /aosp_15_r20/external/lzma/C/Util/7zipInstall/7zipInstall.c (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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