1 /* 7zipUninstall.c - 7-Zip Uninstaller
2 2024-03-21 : Igor Pavlov : Public domain */
3
4 #include "Precomp.h"
5
6 // #define SZ_ERROR_ABORT 100
7
8 #include "../../7zTypes.h"
9 #include "../../7zWindows.h"
10
11 #if defined(_MSC_VER) && _MSC_VER < 1600
12 #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
13 #endif
14
15 #ifdef Z7_OLD_WIN_SDK
16 struct IShellView;
17 #define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
18 SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
19 #define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
20 typedef enum {
21 SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists
22 SHGFP_TYPE_DEFAULT = 1, // default value, may not exist
23 } SHGFP_TYPE;
24 #endif
25 #if defined(__MINGW32__) || defined(__MINGW64__)
26 #include <shlobj.h>
27 #else
28 #include <ShlObj.h>
29 #endif
30
31 #include "../../7zVersion.h"
32
33 #include "resource.h"
34
35
36
37
38 #define LLL_(quote) L##quote
39 #define LLL(quote) LLL_(quote)
40
41 #define wcscat lstrcatW
42 #define wcslen (size_t)lstrlenW
43 #define wcscpy lstrcpyW
44
45 // static LPCWSTR const k_7zip = L"7-Zip";
46
47 // #define Z7_64BIT_INSTALLER 1
48
49 #ifdef _WIN64
50 #define Z7_64BIT_INSTALLER 1
51 #endif
52
53 #define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION)
54
55 #ifdef Z7_64BIT_INSTALLER
56
57 // #define USE_7ZIP_32_DLL
58
59 #if defined(_M_ARM64) || defined(_M_ARM)
60 #define k_Postfix L" (arm64)"
61 #else
62 #define k_Postfix L" (x64)"
63 #define USE_7ZIP_32_DLL
64 #endif
65 #else
66 #if defined(_M_ARM64) || defined(_M_ARM)
67 #define k_Postfix L" (arm)"
68 #else
69 // #define k_Postfix L" (x86)"
70 #define k_Postfix
71 #endif
72 #endif
73
74 #define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix
75
76 static LPCWSTR const k_7zip_with_Ver_Uninstall = k_7zip_with_Ver L" Uninstall";
77
78 static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip";
79
80 static LPCWSTR const k_Reg_Path = L"Path";
81
82 static LPCWSTR const k_Reg_Path32 = L"Path"
83 #ifdef Z7_64BIT_INSTALLER
84 L"64"
85 #else
86 L"32"
87 #endif
88 ;
89
90 #if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64)
91 #define k_Reg_WOW_Flag KEY_WOW64_64KEY
92 #else
93 #define k_Reg_WOW_Flag 0
94 #endif
95
96 #ifdef USE_7ZIP_32_DLL
97 #ifdef _WIN64
98 #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY
99 #else
100 #define k_Reg_WOW_Flag_32 0
101 #endif
102 #endif
103
104 #define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}"
105
106 static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID;
107 static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32";
108
109
110 #define g_AllUsers True
111
112 static BoolInt g_Install_was_Pressed;
113 static BoolInt g_Finished;
114 static BoolInt g_SilentMode;
115
116 static HWND g_HWND;
117 static HWND g_Path_HWND;
118 static HWND g_InfoLine_HWND;
119 static HWND g_Progress_HWND;
120
121 // RegDeleteKeyExW is supported starting from win2003sp1/xp-pro-x64
122 // Z7_WIN32_WINNT_MIN < 0x0600 // Vista
123 #if !defined(Z7_WIN32_WINNT_MIN) \
124 || Z7_WIN32_WINNT_MIN < 0x0502 /* < win2003 */ \
125 || Z7_WIN32_WINNT_MIN == 0x0502 && !defined(_M_AMD64)
126 #define Z7_USE_DYN_RegDeleteKeyExW
127 #endif
128
129 #ifdef Z7_USE_DYN_RegDeleteKeyExW
130 Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
131 typedef LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved);
132 static Func_RegDeleteKeyExW func_RegDeleteKeyExW;
133 #endif
134
135 static WCHAR cmd[MAX_PATH + 4];
136 static WCHAR cmdError[MAX_PATH + 4];
137 static WCHAR path[MAX_PATH * 2 + 40];
138 static WCHAR workDir[MAX_PATH + 10];
139 static WCHAR modulePath[MAX_PATH + 10];
140 static WCHAR modulePrefix[MAX_PATH + 10];
141 static WCHAR tempPath[MAX_PATH * 2 + 40];
142 static WCHAR cmdLine[MAX_PATH * 3 + 40];
143 static WCHAR copyPath[MAX_PATH * 2 + 40];
144
145 static LPCWSTR const kUninstallExe = L"Uninstall.exe";
146
147 #define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c)))
148
149
CpyAscii(wchar_t * dest,const char * s)150 static void CpyAscii(wchar_t *dest, const char *s)
151 {
152 for (;;)
153 {
154 const Byte b = (Byte)*s++;
155 *dest++ = b;
156 if (b == 0)
157 return;
158 }
159 }
160
CatAscii(wchar_t * dest,const char * s)161 static void CatAscii(wchar_t *dest, const char *s)
162 {
163 dest += wcslen(dest);
164 CpyAscii(dest, s);
165 }
166
PrintErrorMessage(const char * s1,const wchar_t * s2)167 static void PrintErrorMessage(const char *s1, const wchar_t *s2)
168 {
169 WCHAR m[MAX_PATH + 512];
170 m[0] = 0;
171 CatAscii(m, "ERROR:");
172 if (s1)
173 {
174 CatAscii(m, "\n");
175 CatAscii(m, s1);
176 }
177 if (s2)
178 {
179 CatAscii(m, "\n");
180 wcscat(m, s2);
181 }
182 MessageBoxW(g_HWND, m, k_7zip_with_Ver_Uninstall, MB_ICONERROR | MB_OK);
183 }
184
185
AreStringsEqual_NoCase(const wchar_t * s1,const wchar_t * s2)186 static BoolInt AreStringsEqual_NoCase(const wchar_t *s1, const wchar_t *s2)
187 {
188 for (;;)
189 {
190 wchar_t c1 = *s1++;
191 wchar_t c2 = *s2++;
192 if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2))
193 return False;
194 if (c2 == 0)
195 return True;
196 }
197 }
198
IsString1PrefixedByString2_NoCase(const wchar_t * s1,const wchar_t * s2)199 static BoolInt IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2)
200 {
201 for (;;)
202 {
203 wchar_t c1;
204 const wchar_t c2 = *s2++;
205 if (c2 == 0)
206 return True;
207 c1 = *s1++;
208 if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2))
209 return False;
210 }
211 }
212
NormalizePrefix(WCHAR * s)213 static void NormalizePrefix(WCHAR *s)
214 {
215 const size_t len = wcslen(s);
216 if (len != 0)
217 if (s[len - 1] != WCHAR_PATH_SEPARATOR)
218 {
219 s[len] = WCHAR_PATH_SEPARATOR;
220 s[len + 1] = 0;
221 }
222 }
223
MyRegistry_QueryString(HKEY hKey,LPCWSTR name,LPWSTR dest)224 static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest)
225 {
226 DWORD cnt = MAX_PATH * sizeof(name[0]);
227 DWORD type = 0;
228 const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt);
229 if (type != REG_SZ)
230 return False;
231 return res == ERROR_SUCCESS;
232 }
233
MyRegistry_QueryString2(HKEY hKey,LPCWSTR keyName,LPCWSTR valName,LPWSTR dest)234 static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest)
235 {
236 HKEY key = 0;
237 const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key);
238 if (res != ERROR_SUCCESS)
239 return False;
240 {
241 const BoolInt res2 = MyRegistry_QueryString(key, valName, dest);
242 RegCloseKey(key);
243 return res2;
244 }
245 }
246
MyRegistry_OpenKey_ReadWrite(HKEY parentKey,LPCWSTR name,HKEY * destKey)247 static LONG MyRegistry_OpenKey_ReadWrite(HKEY parentKey, LPCWSTR name, HKEY *destKey)
248 {
249 return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag, destKey);
250 }
251
MyRegistry_DeleteKey(HKEY parentKey,LPCWSTR name)252 static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCWSTR name)
253 {
254 #if k_Reg_WOW_Flag != 0
255 #ifdef Z7_USE_DYN_RegDeleteKeyExW
256 if (!func_RegDeleteKeyExW)
257 return E_FAIL;
258 return func_RegDeleteKeyExW
259 #else
260 return RegDeleteKeyExW
261 #endif
262 (parentKey, name, k_Reg_WOW_Flag, 0);
263 #else
264 return RegDeleteKeyW(parentKey, name);
265 #endif
266 }
267
268 #ifdef USE_7ZIP_32_DLL
269
MyRegistry_QueryString2_32(HKEY hKey,LPCWSTR keyName,LPCWSTR valName,LPWSTR dest)270 static int MyRegistry_QueryString2_32(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest)
271 {
272 HKEY key = 0;
273 const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag_32, &key);
274 if (res != ERROR_SUCCESS)
275 return False;
276 {
277 const BoolInt res2 = MyRegistry_QueryString(key, valName, dest);
278 RegCloseKey(key);
279 return res2;
280 }
281 }
282
MyRegistry_OpenKey_ReadWrite_32(HKEY parentKey,LPCWSTR name,HKEY * destKey)283 static LONG MyRegistry_OpenKey_ReadWrite_32(HKEY parentKey, LPCWSTR name, HKEY *destKey)
284 {
285 return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag_32, destKey);
286 }
287
MyRegistry_DeleteKey_32(HKEY parentKey,LPCWSTR name)288 static LONG MyRegistry_DeleteKey_32(HKEY parentKey, LPCWSTR name)
289 {
290 #if k_Reg_WOW_Flag_32 != 0
291 #ifdef Z7_USE_DYN_RegDeleteKeyExW
292 if (!func_RegDeleteKeyExW)
293 return E_FAIL;
294 return func_RegDeleteKeyExW
295 #else
296 return RegDeleteKeyExW
297 #endif
298 (parentKey, name, k_Reg_WOW_Flag_32, 0);
299 #else
300 return RegDeleteKeyW(parentKey, name);
301 #endif
302 }
303
304 #endif
305
306
307
308
MyReg_DeleteVal_Path_if_Equal(HKEY hKey,LPCWSTR name)309 static void MyReg_DeleteVal_Path_if_Equal(HKEY hKey, LPCWSTR name)
310 {
311 WCHAR s[MAX_PATH + 10];
312 if (MyRegistry_QueryString(hKey, name, s))
313 {
314 NormalizePrefix(s);
315 if (AreStringsEqual_NoCase(s, path))
316 RegDeleteValueW(hKey, name);
317 }
318 }
319
SetRegKey_Path2(HKEY parentKey)320 static void SetRegKey_Path2(HKEY parentKey)
321 {
322 HKEY key = 0;
323 const LONG res = MyRegistry_OpenKey_ReadWrite(parentKey, k_Reg_Software_7zip, &key);
324 if (res == ERROR_SUCCESS)
325 {
326 MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path32);
327 MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path);
328
329 RegCloseKey(key);
330 // MyRegistry_DeleteKey(parentKey, k_Reg_Software_7zip);
331 }
332 }
333
SetRegKey_Path(void)334 static void SetRegKey_Path(void)
335 {
336 SetRegKey_Path2(HKEY_CURRENT_USER);
337 SetRegKey_Path2(HKEY_LOCAL_MACHINE);
338 }
339
CreateShellLink(LPCWSTR srcPath,LPCWSTR targetPath)340 static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath)
341 {
342 IShellLinkW *sl;
343
344 // CoInitialize has already been called.
345 HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl);
346
347 if (SUCCEEDED(hres))
348 {
349 IPersistFile *pf;
350
351 hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID *)&pf);
352
353 if (SUCCEEDED(hres))
354 {
355 WCHAR s[MAX_PATH + 10];
356 hres = pf->lpVtbl->Load(pf, srcPath, TRUE);
357 pf->lpVtbl->Release(pf);
358
359 if (SUCCEEDED(hres))
360 {
361 hres = sl->lpVtbl->GetPath(sl, s, MAX_PATH, NULL, 0); // SLGP_RAWPATH
362 if (!AreStringsEqual_NoCase(s, targetPath))
363 hres = S_FALSE;
364 }
365 }
366
367 sl->lpVtbl->Release(sl);
368 }
369
370 return hres;
371 }
372
SetShellProgramsGroup(HWND hwndOwner)373 static void SetShellProgramsGroup(HWND hwndOwner)
374 {
375 #ifdef UNDER_CE
376
377 UNUSED_VAR(hwndOwner)
378
379 #else
380
381 unsigned i = (g_AllUsers ? 1 : 2);
382
383 for (; i < 3; i++)
384 {
385 // BoolInt isOK = True;
386 WCHAR link[MAX_PATH + 40];
387 WCHAR destPath[MAX_PATH + 40];
388
389 link[0] = 0;
390
391 if (SHGetFolderPathW(hwndOwner,
392 i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS,
393 NULL, SHGFP_TYPE_CURRENT, link) != S_OK)
394 continue;
395
396 NormalizePrefix(link);
397 CatAscii(link, "7-Zip\\");
398
399 {
400 const size_t baseLen = wcslen(link);
401 unsigned k;
402 BoolInt needDelete = False;
403
404 for (k = 0; k < 2; k++)
405 {
406 CpyAscii(link + baseLen, k == 0 ?
407 "7-Zip File Manager.lnk" :
408 "7-Zip Help.lnk");
409 wcscpy(destPath, path);
410 CatAscii(destPath, k == 0 ?
411 "7zFM.exe" :
412 "7-zip.chm");
413
414 if (CreateShellLink(link, destPath) == S_OK)
415 {
416 needDelete = True;
417 DeleteFileW(link);
418 }
419 }
420
421 if (needDelete)
422 {
423 link[baseLen] = 0;
424 RemoveDirectoryW(link);
425 }
426 }
427 }
428
429 #endif
430 }
431
432
433 static LPCSTR const k_ShellEx_Items[] =
434 {
435 "*\\shellex\\ContextMenuHandlers"
436 , "Directory\\shellex\\ContextMenuHandlers"
437 , "Folder\\shellex\\ContextMenuHandlers"
438 , "Directory\\shellex\\DragDropHandlers"
439 , "Drive\\shellex\\DragDropHandlers"
440 };
441
442 static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
443
444 static LPCWSTR const k_AppPaths_7zFm = L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe";
445 #define k_REG_Uninstall L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
446 static LPCWSTR const k_Uninstall_7zip = k_REG_Uninstall L"7-Zip";
447
448
RemoveQuotes(wchar_t * s)449 static void RemoveQuotes(wchar_t *s)
450 {
451 const size_t len = wcslen(s);
452 size_t i;
453 if (len == 0 || s[0] != '\"' || s[len - 1] != '\"')
454 return;
455 for (i = 0; i < len; i++)
456 s[i] = s[i + 1];
457 s[len - 2] = 0;
458 }
459
AreEqual_Path_PrefixName(const wchar_t * s,const wchar_t * prefix,const wchar_t * name)460 static BoolInt AreEqual_Path_PrefixName(const wchar_t *s, const wchar_t *prefix, const wchar_t *name)
461 {
462 if (!IsString1PrefixedByString2_NoCase(s, prefix))
463 return False;
464 return AreStringsEqual_NoCase(s + wcslen(prefix), name);
465 }
466
WriteCLSID(void)467 static void WriteCLSID(void)
468 {
469 WCHAR s[MAX_PATH + 30];
470
471 if (MyRegistry_QueryString2(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s))
472 {
473 if (AreEqual_Path_PrefixName(s, path, L"7-zip.dll"))
474 {
475 {
476 const LONG res = MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc);
477 if (res == ERROR_SUCCESS)
478 MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip);
479 }
480
481 {
482 unsigned i;
483 for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++)
484 {
485 WCHAR destPath[MAX_PATH];
486 CpyAscii(destPath, k_ShellEx_Items[i]);
487 CatAscii(destPath, "\\7-Zip");
488
489 MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, destPath);
490 }
491 }
492
493 {
494 HKEY destKey = 0;
495 const LONG res = MyRegistry_OpenKey_ReadWrite(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey);
496 if (res == ERROR_SUCCESS)
497 {
498 RegDeleteValueW(destKey, k_7zip_CLSID);
499 /* res = */ RegCloseKey(destKey);
500 }
501 }
502 }
503 }
504
505
506 #ifdef USE_7ZIP_32_DLL
507
508 if (MyRegistry_QueryString2_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s))
509 {
510 if (AreEqual_Path_PrefixName(s, path, L"7-zip32.dll"))
511 {
512 {
513 const LONG res = MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc);
514 if (res == ERROR_SUCCESS)
515 MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip);
516 }
517
518 {
519 unsigned i;
520 for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++)
521 {
522 WCHAR destPath[MAX_PATH];
523 CpyAscii(destPath, k_ShellEx_Items[i]);
524 CatAscii(destPath, "\\7-Zip");
525
526 MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, destPath);
527 }
528 }
529
530 {
531 HKEY destKey = 0;
532 const LONG res = MyRegistry_OpenKey_ReadWrite_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey);
533 if (res == ERROR_SUCCESS)
534 {
535 RegDeleteValueW(destKey, k_7zip_CLSID);
536 /* res = */ RegCloseKey(destKey);
537 }
538 }
539 }
540 }
541
542 #endif
543
544
545 if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm, NULL, s))
546 {
547 // RemoveQuotes(s);
548 if (AreEqual_Path_PrefixName(s, path, L"7zFM.exe"))
549 MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm);
550 }
551
552 if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_Uninstall_7zip, L"UninstallString", s))
553 {
554 RemoveQuotes(s);
555 if (AreEqual_Path_PrefixName(s, path, kUninstallExe))
556 MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_Uninstall_7zip);
557 }
558 }
559
560
GetCmdParam(const wchar_t * s)561 static const wchar_t *GetCmdParam(const wchar_t *s)
562 {
563 unsigned pos = 0;
564 BoolInt quoteMode = False;
565 for (;; s++)
566 {
567 const wchar_t c = *s;
568 if (c == 0 || (c == L' ' && !quoteMode))
569 break;
570 if (c == L'\"')
571 {
572 quoteMode = !quoteMode;
573 continue;
574 }
575 if (pos >= Z7_ARRAY_SIZE(cmd) - 1)
576 exit(1);
577 cmd[pos++] = c;
578 }
579 cmd[pos] = 0;
580 return s;
581 }
582
583 /*
584 static void RemoveQuotes(wchar_t *s)
585 {
586 const wchar_t *src = s;
587 for (;;)
588 {
589 wchar_t c = *src++;
590 if (c == '\"')
591 continue;
592 *s++ = c;
593 if (c == 0)
594 return;
595 }
596 }
597 */
598
DoesFileOrDirExist(void)599 static BoolInt DoesFileOrDirExist(void)
600 {
601 return (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES);
602 }
603
RemoveFileAfterReboot2(const WCHAR * s)604 static BOOL RemoveFileAfterReboot2(const WCHAR *s)
605 {
606 #ifndef UNDER_CE
607 return MoveFileExW(s, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
608 #else
609 UNUSED_VAR(s)
610 return TRUE;
611 #endif
612 }
613
RemoveFileAfterReboot(void)614 static BOOL RemoveFileAfterReboot(void)
615 {
616 return RemoveFileAfterReboot2(path);
617 }
618
619 // #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ')
620
IsThereSpace(const wchar_t * s)621 static BoolInt IsThereSpace(const wchar_t *s)
622 {
623 for (;;)
624 {
625 const wchar_t c = *s++;
626 if (c == 0)
627 return False;
628 if (c == ' ')
629 return True;
630 }
631 }
632
AddPathParam(wchar_t * dest,const wchar_t * src)633 static void AddPathParam(wchar_t *dest, const wchar_t *src)
634 {
635 const BoolInt needQuote = IsThereSpace(src);
636 if (needQuote)
637 CatAscii(dest, "\"");
638 wcscat(dest, src);
639 if (needQuote)
640 CatAscii(dest, "\"");
641 }
642
643
644
GetErrorMessage(DWORD errorCode,WCHAR * message)645 static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message)
646 {
647 LPWSTR msgBuf;
648 if (FormatMessageW(
649 FORMAT_MESSAGE_ALLOCATE_BUFFER
650 | FORMAT_MESSAGE_FROM_SYSTEM
651 | FORMAT_MESSAGE_IGNORE_INSERTS,
652 NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
653 return False;
654 wcscpy(message, msgBuf);
655 LocalFree(msgBuf);
656 return True;
657 }
658
RemoveDir(void)659 static BOOL RemoveDir(void)
660 {
661 const DWORD attrib = GetFileAttributesW(path);
662 if (attrib == INVALID_FILE_ATTRIBUTES)
663 return TRUE;
664 if (RemoveDirectoryW(path))
665 return TRUE;
666 return RemoveFileAfterReboot();
667 }
668
669
670
671
672
673 #define k_Lang "Lang"
674
675 // NUM_LANG_TXT_FILES files are placed before en.ttt
676 #define NUM_LANG_TXT_FILES 92
677
678 #ifdef USE_7ZIP_32_DLL
679 #define NUM_EXTRA_FILES_64BIT 1
680 #else
681 #define NUM_EXTRA_FILES_64BIT 0
682 #endif
683
684 #define NUM_FILES (NUM_LANG_TXT_FILES + 1 + 13 + NUM_EXTRA_FILES_64BIT)
685
686 static const char * const k_Names =
687 "af an ar ast az ba be bg bn br ca co cs cy da de el eo es et eu ext"
688 " fa fi fr fur fy ga gl gu he hi hr hu hy id io is it ja ka kaa kab kk ko ku ku-ckb ky"
689 " lij lt lv mk mn mng mng2 mr ms nb ne nl nn pa-in pl ps pt pt-br ro ru"
690 " sa si sk sl sq sr-spc sr-spl sv sw ta tg th tk tr tt ug uk uz uz-cyrl va vi yo zh-cn zh-tw"
691 " en.ttt"
692 " descript.ion"
693 " History.txt"
694 " License.txt"
695 " readme.txt"
696 " 7-zip.chm"
697 " 7z.sfx"
698 " 7zCon.sfx"
699 " 7z.exe"
700 " 7zG.exe"
701 " 7z.dll"
702 " 7zFM.exe"
703 #ifdef USE_7ZIP_32_DLL
704 " 7-zip32.dll"
705 #endif
706 " 7-zip.dll"
707 " Uninstall.exe";
708
709
710
Install(void)711 static int Install(void)
712 {
713 SRes res = SZ_OK;
714 WRes winRes = 0;
715
716 // BoolInt needReboot = False;
717 const size_t pathLen = wcslen(path);
718
719 if (!g_SilentMode)
720 {
721 ShowWindow(g_Progress_HWND, SW_SHOW);
722 ShowWindow(g_InfoLine_HWND, SW_SHOW);
723 SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, NUM_FILES);
724 }
725
726 {
727 unsigned i;
728 const char *curName = k_Names;
729
730 for (i = 0; *curName != 0; i++)
731 {
732 WCHAR *temp;
733
734 if (!g_SilentMode)
735 {
736 MSG msg;
737
738 // g_HWND
739 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
740 {
741 if (!IsDialogMessage(g_HWND, &msg))
742 {
743 TranslateMessage(&msg);
744 DispatchMessage(&msg);
745 }
746 if (!g_HWND)
747 return 1;
748 }
749
750 // Sleep(1);
751 SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
752 }
753
754 path[pathLen] = 0;
755 temp = path + pathLen;
756
757 if (i <= NUM_LANG_TXT_FILES)
758 CpyAscii(temp, k_Lang "\\");
759
760 {
761 WCHAR *dest = temp + wcslen(temp);
762
763 for (;;)
764 {
765 const char c = *curName;
766 if (c == 0)
767 break;
768 curName++;
769 if (c == ' ')
770 break;
771 *dest++ = (Byte)c;
772 }
773
774 *dest = 0;
775 }
776
777 if (i < NUM_LANG_TXT_FILES)
778 CatAscii(temp, ".txt");
779
780 if (!g_SilentMode)
781 SetWindowTextW(g_InfoLine_HWND, temp);
782
783 {
784 const DWORD attrib = GetFileAttributesW(path);
785 if (attrib == INVALID_FILE_ATTRIBUTES)
786 continue;
787 if (attrib & FILE_ATTRIBUTE_READONLY)
788 SetFileAttributesW(path, 0);
789 if (!DeleteFileW(path))
790 {
791 if (!RemoveFileAfterReboot())
792 {
793 winRes = GetLastError();
794 }
795 /*
796 else
797 needReboot = True;
798 */
799 }
800 }
801 }
802
803 CpyAscii(path + pathLen, k_Lang);
804 RemoveDir();
805
806 path[pathLen] = 0;
807 RemoveDir();
808
809 if (!g_SilentMode)
810 SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
811
812 if (*curName == 0)
813 {
814 SetRegKey_Path();
815 WriteCLSID();
816 SetShellProgramsGroup(g_HWND);
817 if (!g_SilentMode)
818 SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is uninstalled");
819 }
820 }
821
822 if (winRes != 0)
823 res = SZ_ERROR_FAIL;
824
825 if (res == SZ_OK)
826 {
827 // if (!g_SilentMode && needReboot);
828 return 0;
829 }
830
831 if (!g_SilentMode)
832 {
833 WCHAR m[MAX_PATH + 100];
834 m[0] = 0;
835 if (winRes == 0 || !GetErrorMessage(winRes, m))
836 CpyAscii(m, "ERROR");
837 PrintErrorMessage("System ERROR:", m);
838 }
839
840 return 1;
841 }
842
843
OnClose(void)844 static void OnClose(void)
845 {
846 if (g_Install_was_Pressed && !g_Finished)
847 {
848 if (MessageBoxW(g_HWND,
849 L"Do you want to cancel uninstallation?",
850 k_7zip_with_Ver_Uninstall,
851 MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
852 return;
853 }
854 DestroyWindow(g_HWND);
855 g_HWND = NULL;
856 }
857
858 static
859 #ifdef Z7_OLD_WIN_SDK
860 BOOL
861 #else
862 INT_PTR
863 #endif
MyDlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)864 CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
865 {
866 UNUSED_VAR(lParam)
867
868 switch (message)
869 {
870 case WM_INITDIALOG:
871 g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH);
872 g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE);
873 g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS);
874
875 SetWindowTextW(hwnd, k_7zip_with_Ver_Uninstall);
876 SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path);
877
878 ShowWindow(g_Progress_HWND, SW_HIDE);
879 ShowWindow(g_InfoLine_HWND, SW_HIDE);
880
881 break;
882
883 case WM_COMMAND:
884 switch (LOWORD(wParam))
885 {
886 case IDOK:
887 {
888 if (g_Finished)
889 {
890 OnClose();
891 break;
892 }
893 if (!g_Install_was_Pressed)
894 {
895 SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE);
896
897 EnableWindow(g_Path_HWND, FALSE);
898 EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
899
900 g_Install_was_Pressed = True;
901 return TRUE;
902 }
903 break;
904 }
905
906 case IDCANCEL:
907 {
908 OnClose();
909 break;
910 }
911
912 default: return FALSE;
913 }
914 break;
915
916 case WM_CLOSE:
917 OnClose();
918 break;
919 /*
920 case WM_DESTROY:
921 PostQuitMessage(0);
922 return TRUE;
923 */
924 default:
925 return FALSE;
926 }
927
928 return TRUE;
929 }
930
931
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nCmdShow)932 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
933 #ifdef UNDER_CE
934 LPWSTR
935 #else
936 LPSTR
937 #endif
938 lpCmdLine, int nCmdShow)
939 {
940 const wchar_t *cmdParams;
941 BoolInt useTemp = True;
942
943 UNUSED_VAR(hPrevInstance)
944 UNUSED_VAR(lpCmdLine)
945 UNUSED_VAR(nCmdShow)
946
947 #ifndef UNDER_CE
948 CoInitialize(NULL);
949 #endif
950
951 #ifndef UNDER_CE
952 #ifdef Z7_USE_DYN_RegDeleteKeyExW
953 func_RegDeleteKeyExW =
954 (Func_RegDeleteKeyExW) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandleW(L"advapi32.dll"),
955 "RegDeleteKeyExW");
956 #endif
957 #endif
958
959 {
960 const wchar_t *s = GetCommandLineW();
961
962 #ifndef UNDER_CE
963 s = GetCmdParam(s);
964 #endif
965
966 cmdParams = s;
967
968 for (;;)
969 {
970 {
971 wchar_t c = *s;
972 if (c == 0)
973 break;
974 if (c == ' ')
975 {
976 s++;
977 continue;
978 }
979 }
980
981 {
982 const wchar_t *s2 = GetCmdParam(s);
983 BoolInt error = True;
984 if (cmd[0] == '/')
985 {
986 if (cmd[1] == 'S')
987 {
988 if (cmd[2] == 0)
989 {
990 g_SilentMode = True;
991 error = False;
992 }
993 }
994 else if (cmd[1] == 'N')
995 {
996 if (cmd[2] == 0)
997 {
998 useTemp = False;
999 error = False;
1000 }
1001 }
1002 else if (cmd[1] == 'D' && cmd[2] == '=')
1003 {
1004 wcscpy(workDir, cmd + 3);
1005 // RemoveQuotes(workDir);
1006 useTemp = False;
1007 error = False;
1008 }
1009 }
1010 s = s2;
1011 if (error && cmdError[0] == 0)
1012 wcscpy(cmdError, cmd);
1013 }
1014 }
1015
1016 if (cmdError[0] != 0)
1017 {
1018 if (!g_SilentMode)
1019 PrintErrorMessage("Unsupported command:", cmdError);
1020 return 1;
1021 }
1022 }
1023
1024 {
1025 wchar_t *name;
1026 const DWORD len = GetModuleFileNameW(NULL, modulePath, MAX_PATH);
1027 if (len == 0 || len > MAX_PATH)
1028 return 1;
1029
1030 name = NULL;
1031 wcscpy(modulePrefix, modulePath);
1032
1033 {
1034 wchar_t *s = modulePrefix;
1035 for (;;)
1036 {
1037 const wchar_t c = *s++;
1038 if (c == 0)
1039 break;
1040 if (c == WCHAR_PATH_SEPARATOR)
1041 name = s;
1042 }
1043 }
1044
1045 if (!name)
1046 return 1;
1047
1048 if (!AreStringsEqual_NoCase(name, kUninstallExe))
1049 useTemp = False;
1050
1051 *name = 0; // keep only prefix for modulePrefix
1052 }
1053
1054
1055 if (useTemp)
1056 {
1057 DWORD winRes = GetTempPathW(MAX_PATH, path);
1058
1059 // GetTempPath: the returned string ends with a backslash
1060 /*
1061 {
1062 WCHAR s[MAX_PATH + 1];
1063 wcscpy(s, path);
1064 GetLongPathNameW(s, path, MAX_PATH);
1065 }
1066 */
1067
1068 if (winRes != 0 && winRes <= MAX_PATH + 1
1069 && !IsString1PrefixedByString2_NoCase(modulePrefix, path))
1070 {
1071 unsigned i;
1072 DWORD d;
1073
1074 const size_t pathLen = wcslen(path);
1075 d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
1076
1077 for (i = 0; i < 100; i++, d += GetTickCount())
1078 {
1079 CpyAscii(path + pathLen, "7z");
1080
1081 {
1082 wchar_t *s = path + wcslen(path);
1083 UInt32 value = d;
1084 unsigned k;
1085 for (k = 0; k < 8; k++)
1086 {
1087 const unsigned t = value & 0xF;
1088 value >>= 4;
1089 s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
1090 }
1091 s[k] = 0;
1092 }
1093
1094 if (DoesFileOrDirExist())
1095 continue;
1096 if (CreateDirectoryW(path, NULL))
1097 {
1098 CatAscii(path, STRING_PATH_SEPARATOR);
1099 wcscpy(tempPath, path);
1100 break;
1101 }
1102 if (GetLastError() != ERROR_ALREADY_EXISTS)
1103 break;
1104 }
1105
1106 if (tempPath[0] != 0)
1107 {
1108 wcscpy(copyPath, tempPath);
1109 CatAscii(copyPath, "Uninst.exe"); // we need not "Uninstall.exe" here
1110
1111 if (CopyFileW(modulePath, copyPath, TRUE))
1112 {
1113 RemoveFileAfterReboot2(copyPath);
1114 RemoveFileAfterReboot2(tempPath);
1115
1116 {
1117 STARTUPINFOW si;
1118 PROCESS_INFORMATION pi;
1119 cmdLine[0] = 0;
1120
1121 // maybe CreateProcess supports path with spaces even without quotes.
1122 AddPathParam(cmdLine, copyPath);
1123 CatAscii(cmdLine, " /N /D=");
1124 AddPathParam(cmdLine, modulePrefix);
1125
1126 if (cmdParams[0] != 0 && wcslen(cmdParams) < MAX_PATH * 2 + 10)
1127 wcscat(cmdLine, cmdParams);
1128
1129 memset(&si, 0, sizeof(si));
1130 si.cb = sizeof(si);
1131
1132 if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, tempPath, &si, &pi))
1133 {
1134 CloseHandle(pi.hThread);
1135 if (pi.hProcess)
1136 {
1137 CloseHandle(pi.hProcess);
1138 return 0;
1139 }
1140 }
1141 }
1142 }
1143 }
1144 }
1145 }
1146
1147 wcscpy(path, modulePrefix);
1148
1149 if (workDir[0] != 0)
1150 {
1151 wcscpy(path, workDir);
1152 NormalizePrefix(path);
1153 }
1154
1155 /*
1156 if (path[0] == 0)
1157 {
1158 HKEY key = 0;
1159 BoolInt ok = False;
1160 LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key);
1161 if (res == ERROR_SUCCESS)
1162 {
1163 ok = MyRegistry_QueryString(key, k_Reg_Path32, path);
1164 // ok = MyRegistry_QueryString(key, k_Reg_Path, path);
1165 RegCloseKey(key);
1166 }
1167 }
1168 */
1169
1170
1171 if (g_SilentMode)
1172 return Install();
1173
1174 {
1175 int retCode = 1;
1176 g_HWND = CreateDialog(
1177 hInstance,
1178 // GetModuleHandle(NULL),
1179 MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc);
1180 if (!g_HWND)
1181 return 1;
1182
1183 {
1184 const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
1185 // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
1186 SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
1187 }
1188
1189 {
1190 BOOL bRet;
1191 MSG msg;
1192
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