mirror of
https://github.com/ip7z/7zip.git
synced 2025-12-06 07:12:00 +01:00
1692 lines
39 KiB
C
1692 lines
39 KiB
C
/* 7zipInstall.c - 7-Zip Installer
|
|
2024-04-05 : Igor Pavlov : Public domain */
|
|
|
|
#include "Precomp.h"
|
|
|
|
#define SZ_ERROR_ABORT 100
|
|
|
|
#include "../../7zWindows.h"
|
|
|
|
#if defined(_MSC_VER) && _MSC_VER < 1600
|
|
#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
|
|
#endif
|
|
|
|
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
|
|
|
#ifdef Z7_OLD_WIN_SDK
|
|
struct IShellView;
|
|
#define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
|
|
SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
|
|
#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
|
|
typedef enum {
|
|
SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists
|
|
SHGFP_TYPE_DEFAULT = 1, // default value, may not exist
|
|
} SHGFP_TYPE;
|
|
#endif
|
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
|
#include <shlobj.h>
|
|
#else
|
|
#include <ShlObj.h>
|
|
#endif
|
|
|
|
#include "../../7z.h"
|
|
#include "../../7zAlloc.h"
|
|
#include "../../7zCrc.h"
|
|
#include "../../7zFile.h"
|
|
#include "../../7zVersion.h"
|
|
#include "../../CpuArch.h"
|
|
#include "../../DllSecur.h"
|
|
|
|
#include "resource.h"
|
|
|
|
#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__)
|
|
// #pragma GCC diagnostic ignored "-Wcast-function-type"
|
|
#endif
|
|
|
|
#define LLL_(quote) L##quote
|
|
#define LLL(quote) LLL_(quote)
|
|
|
|
#define wcscat lstrcatW
|
|
#define wcslen (size_t)lstrlenW
|
|
#define wcscpy lstrcpyW
|
|
// wcsncpy() and lstrcpynW() work differently. We don't use them.
|
|
|
|
#define kInputBufSize ((size_t)1 << 18)
|
|
|
|
#define Z7_7ZIP_CUR_VER ((MY_VER_MAJOR << 16) | MY_VER_MINOR)
|
|
#define Z7_7ZIP_DLL_VER_COMPAT ((16 << 16) | 3)
|
|
|
|
static LPCSTR const k_7zip = "7-Zip";
|
|
|
|
static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip";
|
|
|
|
// #define Z7_64BIT_INSTALLER 1
|
|
|
|
#ifdef _WIN64
|
|
#define Z7_64BIT_INSTALLER 1
|
|
#endif
|
|
|
|
#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION)
|
|
|
|
#ifdef Z7_64BIT_INSTALLER
|
|
|
|
// #define USE_7ZIP_32_DLL
|
|
|
|
#if defined(_M_ARM64) || defined(_M_ARM)
|
|
#define k_Postfix L" (arm64)"
|
|
#else
|
|
#define k_Postfix L" (x64)"
|
|
#define USE_7ZIP_32_DLL
|
|
#endif
|
|
#else
|
|
#if defined(_M_ARM64) || defined(_M_ARM)
|
|
#define k_Postfix L" (arm)"
|
|
#else
|
|
// #define k_Postfix L" (x86)"
|
|
#define k_Postfix
|
|
#endif
|
|
#endif
|
|
|
|
#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix
|
|
|
|
|
|
static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver;
|
|
|
|
static LPCWSTR const k_7zip_Setup = k_7zip_with_Ver L" Setup";
|
|
|
|
static LPCWSTR const k_Reg_Path = L"Path";
|
|
|
|
static LPCWSTR const k_Reg_Path32 = L"Path"
|
|
#ifdef Z7_64BIT_INSTALLER
|
|
L"64"
|
|
#else
|
|
L"32"
|
|
#endif
|
|
;
|
|
|
|
#if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64)
|
|
#define k_Reg_WOW_Flag KEY_WOW64_64KEY
|
|
#else
|
|
#define k_Reg_WOW_Flag 0
|
|
#endif
|
|
|
|
#ifdef USE_7ZIP_32_DLL
|
|
#ifdef _WIN64
|
|
#define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY
|
|
#else
|
|
#define k_Reg_WOW_Flag_32 0
|
|
#endif
|
|
#endif
|
|
|
|
#define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}"
|
|
|
|
static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID;
|
|
static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32";
|
|
|
|
#define g_AllUsers True
|
|
|
|
static BoolInt g_Install_was_Pressed;
|
|
static BoolInt g_Finished;
|
|
static BoolInt g_SilentMode;
|
|
|
|
static HWND g_HWND;
|
|
static HWND g_Path_HWND;
|
|
static HWND g_InfoLine_HWND;
|
|
static HWND g_Progress_HWND;
|
|
|
|
static DWORD g_TotalSize;
|
|
|
|
static WCHAR cmd[MAX_PATH + 4];
|
|
static WCHAR cmdError[MAX_PATH + 4];
|
|
static WCHAR path[MAX_PATH * 2 + 40];
|
|
|
|
|
|
|
|
static void CpyAscii(wchar_t *dest, const char *s)
|
|
{
|
|
for (;;)
|
|
{
|
|
Byte b = (Byte)*s++;
|
|
*dest++ = b;
|
|
if (b == 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void CatAscii(wchar_t *dest, const char *s)
|
|
{
|
|
dest += wcslen(dest);
|
|
CpyAscii(dest, s);
|
|
}
|
|
|
|
static void PrintErrorMessage(const char *s1, const wchar_t *s2)
|
|
{
|
|
WCHAR m[MAX_PATH + 512];
|
|
m[0] = 0;
|
|
CatAscii(m, "ERROR:");
|
|
if (s1)
|
|
{
|
|
CatAscii(m, "\n");
|
|
CatAscii(m, s1);
|
|
}
|
|
if (s2)
|
|
{
|
|
CatAscii(m, "\n");
|
|
wcscat(m, s2);
|
|
}
|
|
MessageBoxW(g_HWND, m, k_7zip_with_Ver_str, MB_ICONERROR | MB_OK);
|
|
}
|
|
|
|
|
|
typedef DWORD (WINAPI * Func_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename, LPDWORD lpdwHandle);
|
|
typedef BOOL (WINAPI * Func_GetFileVersionInfoW)(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
|
|
typedef BOOL (WINAPI * Func_VerQueryValueW)(const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen);
|
|
|
|
static HMODULE g_version_dll_hModule;
|
|
|
|
static DWORD GetFileVersion(LPCWSTR s)
|
|
{
|
|
DWORD size = 0;
|
|
void *vi = NULL;
|
|
DWORD version = 0;
|
|
|
|
Func_GetFileVersionInfoSizeW my_GetFileVersionInfoSizeW;
|
|
Func_GetFileVersionInfoW my_GetFileVersionInfoW;
|
|
Func_VerQueryValueW my_VerQueryValueW;
|
|
|
|
if (!g_version_dll_hModule)
|
|
{
|
|
wchar_t buf[MAX_PATH + 100];
|
|
{
|
|
unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2);
|
|
if (len == 0 || len > MAX_PATH)
|
|
return 0;
|
|
}
|
|
{
|
|
unsigned pos = (unsigned)lstrlenW(buf);
|
|
if (buf[pos - 1] != '\\')
|
|
buf[pos++] = '\\';
|
|
lstrcpyW(buf + pos, L"version.dll");
|
|
}
|
|
g_version_dll_hModule = LoadLibraryW(buf);
|
|
if (!g_version_dll_hModule)
|
|
return 0;
|
|
}
|
|
|
|
my_GetFileVersionInfoSizeW = (Func_GetFileVersionInfoSizeW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule,
|
|
"GetFileVersionInfoSizeW");
|
|
my_GetFileVersionInfoW = (Func_GetFileVersionInfoW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule,
|
|
"GetFileVersionInfoW");
|
|
my_VerQueryValueW = (Func_VerQueryValueW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule,
|
|
"VerQueryValueW");
|
|
|
|
if (!my_GetFileVersionInfoSizeW
|
|
|| !my_GetFileVersionInfoW
|
|
|| !my_VerQueryValueW)
|
|
return 0;
|
|
|
|
size = my_GetFileVersionInfoSizeW(s, NULL);
|
|
if (size == 0)
|
|
return 0;
|
|
|
|
vi = malloc(size);
|
|
if (!vi)
|
|
return 0;
|
|
|
|
if (my_GetFileVersionInfoW(s, 0, size, vi))
|
|
{
|
|
VS_FIXEDFILEINFO *fi = NULL;
|
|
UINT fiLen = 0;
|
|
if (my_VerQueryValueW(vi, L"\\", (LPVOID *)&fi, &fiLen))
|
|
version = fi->dwFileVersionMS;
|
|
}
|
|
|
|
free(vi);
|
|
return version;
|
|
}
|
|
|
|
|
|
static WRes MyCreateDir(LPCWSTR name)
|
|
{
|
|
return CreateDirectoryW(name, NULL) ? 0 : GetLastError();
|
|
}
|
|
|
|
#define IS_SEPAR(c) (c == WCHAR_PATH_SEPARATOR)
|
|
#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
|
#define IS_DRIVE_PATH(s) (IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]))
|
|
|
|
static int ReverseFind_PathSepar(const wchar_t *s)
|
|
{
|
|
int separ = -1;
|
|
int i;
|
|
for (i = 0;; i++)
|
|
{
|
|
wchar_t c = s[i];
|
|
if (c == 0)
|
|
return separ;
|
|
if (IS_SEPAR(c))
|
|
separ = i;
|
|
}
|
|
}
|
|
|
|
static WRes CreateComplexDir(void)
|
|
{
|
|
WCHAR s[MAX_PATH + 10];
|
|
|
|
unsigned prefixSize = 0;
|
|
WRes wres;
|
|
|
|
{
|
|
size_t len = wcslen(path);
|
|
if (len > MAX_PATH)
|
|
return ERROR_INVALID_NAME;
|
|
wcscpy(s, path);
|
|
}
|
|
|
|
if (IS_DRIVE_PATH(s))
|
|
prefixSize = 3;
|
|
else if (IS_SEPAR(s[0]) && IS_SEPAR(s[1]))
|
|
prefixSize = 2;
|
|
else
|
|
return ERROR_INVALID_NAME;
|
|
|
|
{
|
|
DWORD attrib = GetFileAttributesW(s);
|
|
if (attrib != INVALID_FILE_ATTRIBUTES)
|
|
return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ? 0 : ERROR_ALREADY_EXISTS;
|
|
}
|
|
|
|
wres = MyCreateDir(s);
|
|
if (wres == 0 || wres == ERROR_ALREADY_EXISTS)
|
|
return 0;
|
|
|
|
{
|
|
size_t len = wcslen(s);
|
|
{
|
|
const int pos = ReverseFind_PathSepar(s);
|
|
if (pos < 0)
|
|
return wres;
|
|
if ((unsigned)pos < prefixSize)
|
|
return wres;
|
|
if ((unsigned)pos == len - 1)
|
|
{
|
|
if (len == 1)
|
|
return 0;
|
|
s[pos] = 0;
|
|
len = (unsigned)pos;
|
|
}
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
int pos;
|
|
wres = MyCreateDir(s);
|
|
if (wres == 0)
|
|
break;
|
|
if (wres == ERROR_ALREADY_EXISTS)
|
|
{
|
|
const DWORD attrib = GetFileAttributesW(s);
|
|
if (attrib != INVALID_FILE_ATTRIBUTES)
|
|
if ((attrib & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
|
return ERROR_ALREADY_EXISTS;
|
|
break;
|
|
}
|
|
pos = ReverseFind_PathSepar(s);
|
|
if (pos < 0 || pos == 0 || (unsigned)pos < prefixSize)
|
|
return wres;
|
|
s[pos] = 0;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
const size_t pos = wcslen(s);
|
|
if (pos >= len)
|
|
return 0;
|
|
s[pos] = CHAR_PATH_SEPARATOR;
|
|
wres = MyCreateDir(s);
|
|
if (wres != 0)
|
|
return wres;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest)
|
|
{
|
|
DWORD cnt = MAX_PATH * sizeof(name[0]);
|
|
DWORD type = 0;
|
|
const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt);
|
|
if (type != REG_SZ)
|
|
return False;
|
|
return res == ERROR_SUCCESS;
|
|
}
|
|
|
|
static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest)
|
|
{
|
|
HKEY key = 0;
|
|
const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key);
|
|
if (res != ERROR_SUCCESS)
|
|
return False;
|
|
{
|
|
const BoolInt res2 = MyRegistry_QueryString(key, valName, dest);
|
|
RegCloseKey(key);
|
|
return res2;
|
|
}
|
|
}
|
|
|
|
static LONG MyRegistry_SetString(HKEY hKey, LPCWSTR name, LPCWSTR val)
|
|
{
|
|
return RegSetValueExW(hKey, name, 0, REG_SZ,
|
|
(const BYTE *)val, (DWORD)(wcslen(val) + 1) * sizeof(val[0]));
|
|
}
|
|
|
|
static LONG MyRegistry_SetDWORD(HKEY hKey, LPCWSTR name, DWORD val)
|
|
{
|
|
return RegSetValueExW(hKey, name, 0, REG_DWORD, (const BYTE *)&val, sizeof(DWORD));
|
|
}
|
|
|
|
|
|
static LONG MyRegistry_CreateKey(HKEY parentKey, LPCWSTR name, HKEY *destKey)
|
|
{
|
|
return RegCreateKeyExW(parentKey, name, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS | k_Reg_WOW_Flag,
|
|
NULL, destKey, NULL);
|
|
}
|
|
|
|
static LONG MyRegistry_CreateKeyAndVal(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val)
|
|
{
|
|
HKEY destKey = 0;
|
|
LONG res = MyRegistry_CreateKey(parentKey, keyName, &destKey);
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
res = MyRegistry_SetString(destKey, valName, val);
|
|
/* res = */ RegCloseKey(destKey);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
#ifdef USE_7ZIP_32_DLL
|
|
|
|
static LONG MyRegistry_CreateKey_32(HKEY parentKey, LPCWSTR name, HKEY *destKey)
|
|
{
|
|
return RegCreateKeyExW(parentKey, name, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS | k_Reg_WOW_Flag_32,
|
|
NULL, destKey, NULL);
|
|
}
|
|
|
|
static LONG MyRegistry_CreateKeyAndVal_32(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val)
|
|
{
|
|
HKEY destKey = 0;
|
|
LONG res = MyRegistry_CreateKey_32(parentKey, keyName, &destKey);
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
res = MyRegistry_SetString(destKey, valName, val);
|
|
/* res = */ RegCloseKey(destKey);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UNDER_CE
|
|
#define kBufSize (1 << 13)
|
|
#else
|
|
#define kBufSize (1 << 15)
|
|
#endif
|
|
|
|
#define kSignatureSearchLimit (1 << 22)
|
|
|
|
static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos)
|
|
{
|
|
Byte buf[kBufSize];
|
|
size_t numPrevBytes = 0;
|
|
*resPos = 0;
|
|
|
|
for (;;)
|
|
{
|
|
size_t processed, pos;
|
|
if (*resPos > kSignatureSearchLimit)
|
|
return False;
|
|
processed = kBufSize - numPrevBytes;
|
|
if (File_Read(stream, buf + numPrevBytes, &processed) != 0)
|
|
return False;
|
|
processed += numPrevBytes;
|
|
if (processed < k7zStartHeaderSize ||
|
|
(processed == k7zStartHeaderSize && numPrevBytes != 0))
|
|
return False;
|
|
processed -= k7zStartHeaderSize;
|
|
for (pos = 0; pos <= processed; pos++)
|
|
{
|
|
for (; pos <= processed && buf[pos] != '7'; pos++);
|
|
if (pos > processed)
|
|
break;
|
|
if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0)
|
|
if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8))
|
|
{
|
|
*resPos += pos;
|
|
return True;
|
|
}
|
|
}
|
|
*resPos += processed;
|
|
numPrevBytes = k7zStartHeaderSize;
|
|
memmove(buf, buf + processed, k7zStartHeaderSize);
|
|
}
|
|
}
|
|
|
|
static void HexToString(UInt32 val, WCHAR *s)
|
|
{
|
|
UInt64 v = val;
|
|
unsigned i;
|
|
for (i = 1;; i++)
|
|
{
|
|
v >>= 4;
|
|
if (v == 0)
|
|
break;
|
|
}
|
|
s[i] = 0;
|
|
do
|
|
{
|
|
unsigned t = (unsigned)((val & 0xF));
|
|
val >>= 4;
|
|
s[--i] = (WCHAR)(unsigned)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
|
|
}
|
|
while (i);
|
|
}
|
|
|
|
|
|
#ifndef UNDER_CE
|
|
|
|
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM data)
|
|
{
|
|
UNUSED_VAR(lp)
|
|
UNUSED_VAR(data)
|
|
UNUSED_VAR(hwnd)
|
|
|
|
switch (uMsg)
|
|
{
|
|
case BFFM_INITIALIZED:
|
|
{
|
|
SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, data);
|
|
break;
|
|
}
|
|
case BFFM_SELCHANGED:
|
|
{
|
|
// show selected path for BIF_STATUSTEXT
|
|
WCHAR dir[MAX_PATH];
|
|
if (!SHGetPathFromIDListW((LPITEMIDLIST)lp, dir))
|
|
dir[0] = 0;
|
|
SendMessage(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static BoolInt MyBrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags,
|
|
LPCWSTR initialFolder, LPWSTR resultPath)
|
|
{
|
|
WCHAR displayName[MAX_PATH];
|
|
BROWSEINFOW browseInfo;
|
|
|
|
displayName[0] = 0;
|
|
browseInfo.hwndOwner = owner;
|
|
browseInfo.pidlRoot = NULL;
|
|
|
|
// there are Unicode/Astring problems in some WinCE SDK ?
|
|
browseInfo.pszDisplayName = displayName;
|
|
browseInfo.lpszTitle = title;
|
|
browseInfo.ulFlags = ulFlags;
|
|
browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL;
|
|
browseInfo.lParam = (LPARAM)initialFolder;
|
|
{
|
|
LPITEMIDLIST idlist = SHBrowseForFolderW(&browseInfo);
|
|
if (idlist)
|
|
{
|
|
SHGetPathFromIDListW(idlist, resultPath);
|
|
// free idlist
|
|
// CoTaskMemFree(idlist);
|
|
return True;
|
|
}
|
|
return False;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
static void NormalizePrefix(WCHAR *s)
|
|
{
|
|
size_t i = 0;
|
|
|
|
for (;; i++)
|
|
{
|
|
const wchar_t c = s[i];
|
|
if (c == 0)
|
|
break;
|
|
if (c == '/')
|
|
s[i] = WCHAR_PATH_SEPARATOR;
|
|
}
|
|
|
|
if (i != 0 && s[i - 1] != WCHAR_PATH_SEPARATOR)
|
|
{
|
|
s[i] = WCHAR_PATH_SEPARATOR;
|
|
s[i + 1] = 0;
|
|
}
|
|
}
|
|
|
|
static char MyCharLower_Ascii(char c)
|
|
{
|
|
if (c >= 'A' && c <= 'Z')
|
|
return (char)((unsigned char)c + 0x20);
|
|
return c;
|
|
}
|
|
|
|
static wchar_t MyWCharLower_Ascii(wchar_t c)
|
|
{
|
|
if (c >= 'A' && c <= 'Z')
|
|
return (wchar_t)(c + 0x20);
|
|
return c;
|
|
}
|
|
|
|
static LPCWSTR FindSubString(LPCWSTR s1, const char *s2)
|
|
{
|
|
for (;;)
|
|
{
|
|
unsigned i;
|
|
if (*s1 == 0)
|
|
return NULL;
|
|
for (i = 0;; i++)
|
|
{
|
|
const char b = s2[i];
|
|
if (b == 0)
|
|
return s1;
|
|
if (MyWCharLower_Ascii(s1[i]) != (Byte)MyCharLower_Ascii(b))
|
|
{
|
|
s1++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Set7zipPostfix(WCHAR *s)
|
|
{
|
|
NormalizePrefix(s);
|
|
if (FindSubString(s, "7-Zip"))
|
|
return;
|
|
CatAscii(s, "7-Zip\\");
|
|
}
|
|
|
|
|
|
static int Install(void);
|
|
|
|
static void OnClose(void)
|
|
{
|
|
if (g_Install_was_Pressed && !g_Finished)
|
|
{
|
|
if (MessageBoxW(g_HWND,
|
|
L"Do you want to cancel " k_7zip_with_Ver L" installation?",
|
|
k_7zip_with_Ver,
|
|
MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
|
|
return;
|
|
}
|
|
DestroyWindow(g_HWND);
|
|
g_HWND = NULL;
|
|
}
|
|
|
|
static
|
|
#ifdef Z7_OLD_WIN_SDK
|
|
BOOL
|
|
#else
|
|
INT_PTR
|
|
#endif
|
|
CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// UNUSED_VAR(hwnd)
|
|
UNUSED_VAR(lParam)
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH);
|
|
g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE);
|
|
g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS);
|
|
|
|
SetWindowTextW(hwnd, k_7zip_Setup);
|
|
SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path);
|
|
|
|
ShowWindow(g_Progress_HWND, SW_HIDE);
|
|
ShowWindow(g_InfoLine_HWND, SW_HIDE);
|
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
{
|
|
if (g_Finished)
|
|
{
|
|
OnClose();
|
|
break;
|
|
}
|
|
if (!g_Install_was_Pressed)
|
|
{
|
|
SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE);
|
|
|
|
EnableWindow(g_Path_HWND, FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDB_EXTRACT_SET_PATH), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
|
|
|
|
g_Install_was_Pressed = True;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDCANCEL:
|
|
{
|
|
OnClose();
|
|
break;
|
|
}
|
|
|
|
case IDB_EXTRACT_SET_PATH:
|
|
{
|
|
#ifndef UNDER_CE
|
|
|
|
WCHAR s[MAX_PATH];
|
|
WCHAR s2[MAX_PATH];
|
|
GetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s, MAX_PATH);
|
|
if (MyBrowseForFolder(hwnd, L"Select the folder for installation:" ,
|
|
0
|
|
| BIF_NEWDIALOGSTYLE // 5.0 of ?.dll ?
|
|
| BIF_RETURNONLYFSDIRS
|
|
// | BIF_STATUSTEXT // doesn't work for BIF_NEWDIALOGSTYLE
|
|
, s, s2))
|
|
{
|
|
Set7zipPostfix(s2);
|
|
SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s2);
|
|
}
|
|
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
default: return FALSE;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
OnClose();
|
|
break;
|
|
/*
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
return TRUE;
|
|
*/
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
static LONG SetRegKey_Path2(HKEY parentKey)
|
|
{
|
|
HKEY destKey = 0;
|
|
LONG res = MyRegistry_CreateKey(parentKey, k_Reg_Software_7zip, &destKey);
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
res = MyRegistry_SetString(destKey, k_Reg_Path32, path);
|
|
/* res = */ MyRegistry_SetString(destKey, k_Reg_Path, path);
|
|
/* res = */ RegCloseKey(destKey);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static void SetRegKey_Path(void)
|
|
{
|
|
SetRegKey_Path2(HKEY_CURRENT_USER);
|
|
SetRegKey_Path2(HKEY_LOCAL_MACHINE);
|
|
}
|
|
|
|
|
|
static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath)
|
|
{
|
|
IShellLinkW* sl;
|
|
|
|
// CoInitialize has already been called.
|
|
HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IPersistFile* pf;
|
|
|
|
sl->lpVtbl->SetPath(sl, targetPath);
|
|
// sl->lpVtbl->SetDescription(sl, description);
|
|
hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pf->lpVtbl->Save(pf, srcPath, TRUE);
|
|
pf->lpVtbl->Release(pf);
|
|
}
|
|
sl->lpVtbl->Release(sl);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
static void SetShellProgramsGroup(HWND hwndOwner)
|
|
{
|
|
#ifdef UNDER_CE
|
|
|
|
// CpyAscii(link, "\\Program Files\\");
|
|
UNUSED_VAR(hwndOwner)
|
|
|
|
#else
|
|
|
|
unsigned i = (g_AllUsers ? 0 : 2);
|
|
|
|
for (; i < 3; i++)
|
|
{
|
|
BoolInt isOK = True;
|
|
WCHAR link[MAX_PATH + 40];
|
|
WCHAR destPath[MAX_PATH + 40];
|
|
|
|
link[0] = 0;
|
|
|
|
if (SHGetFolderPathW(hwndOwner,
|
|
i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS,
|
|
NULL, SHGFP_TYPE_CURRENT, link) != S_OK)
|
|
continue;
|
|
|
|
NormalizePrefix(link);
|
|
|
|
{
|
|
unsigned baseLen = (unsigned)wcslen(link);
|
|
unsigned k;
|
|
|
|
for (k = 0; k < 2; k++)
|
|
{
|
|
CpyAscii(link + baseLen, k == 0 ?
|
|
"7-Zip File Manager.lnk" :
|
|
);
|
|
wcscpy(destPath, path);
|
|
CatAscii(destPath, k == 0 ?
|
|
"7zFM.exe" :
|
|
"7-zip.chm");
|
|
|
|
if (i == 0)
|
|
DeleteFileW(link);
|
|
else if (CreateShellLink(link, destPath) != S_OK)
|
|
isOK = False;
|
|
}
|
|
}
|
|
|
|
if (i != 0 && isOK)
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
|
|
static LPCWSTR const k_7zip_ShellExtension = L"7-Zip Shell Extension";
|
|
|
|
static void WriteCLSID(void)
|
|
{
|
|
HKEY destKey;
|
|
LONG res;
|
|
|
|
#ifdef USE_7ZIP_32_DLL
|
|
|
|
MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension);
|
|
|
|
res = MyRegistry_CreateKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey);
|
|
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
WCHAR destPath[MAX_PATH + 40];
|
|
wcscpy(destPath, path);
|
|
CatAscii(destPath, "7-zip32.dll");
|
|
/* res = */ MyRegistry_SetString(destKey, NULL, destPath);
|
|
/* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment");
|
|
// DeleteRegValue(destKey, L"InprocServer32");
|
|
/* res = */ RegCloseKey(destKey);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
MyRegistry_CreateKeyAndVal(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension);
|
|
|
|
destKey = 0;
|
|
res = MyRegistry_CreateKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey);
|
|
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
WCHAR destPath[MAX_PATH + 40];
|
|
wcscpy(destPath, path);
|
|
CatAscii(destPath, "7-zip.dll");
|
|
/* res = */ MyRegistry_SetString(destKey, NULL, destPath);
|
|
/* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment");
|
|
// DeleteRegValue(destKey, L"InprocServer32");
|
|
/* res = */ RegCloseKey(destKey);
|
|
}
|
|
}
|
|
|
|
static LPCSTR const k_ShellEx_Items[] =
|
|
{
|
|
"*\\shellex\\ContextMenuHandlers"
|
|
, "Directory\\shellex\\ContextMenuHandlers"
|
|
, "Folder\\shellex\\ContextMenuHandlers"
|
|
, "Directory\\shellex\\DragDropHandlers"
|
|
, "Drive\\shellex\\DragDropHandlers"
|
|
};
|
|
|
|
static void WriteShellEx(void)
|
|
{
|
|
unsigned i;
|
|
WCHAR destPath[MAX_PATH + 40];
|
|
|
|
for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++)
|
|
{
|
|
CpyAscii(destPath, k_ShellEx_Items[i]);
|
|
CatAscii(destPath, "\\7-Zip");
|
|
|
|
#ifdef USE_7ZIP_32_DLL
|
|
MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID);
|
|
#endif
|
|
MyRegistry_CreateKeyAndVal (HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID);
|
|
}
|
|
|
|
#ifdef USE_7ZIP_32_DLL
|
|
MyRegistry_CreateKeyAndVal_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension);
|
|
#endif
|
|
MyRegistry_CreateKeyAndVal (HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension);
|
|
|
|
|
|
wcscpy(destPath, path);
|
|
CatAscii(destPath, "7zFM.exe");
|
|
|
|
{
|
|
HKEY destKey = 0;
|
|
LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe", &destKey);
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
MyRegistry_SetString(destKey, NULL, destPath);
|
|
MyRegistry_SetString(destKey, L"Path", path);
|
|
RegCloseKey(destKey);
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
HKEY destKey = 0;
|
|
LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\7-Zip", &destKey);
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
MyRegistry_SetString(destKey, L"DisplayName", k_7zip_with_Ver_str);
|
|
MyRegistry_SetString(destKey, L"DisplayVersion", LLL(MY_VERSION_NUMBERS));
|
|
MyRegistry_SetString(destKey, L"DisplayIcon", destPath);
|
|
MyRegistry_SetString(destKey, L"InstallLocation", path);
|
|
|
|
destPath[0] = '\"';
|
|
wcscpy(destPath + 1, path);
|
|
CatAscii(destPath, "Uninstall.exe\"");
|
|
MyRegistry_SetString(destKey, L"UninstallString", destPath);
|
|
|
|
CatAscii(destPath, " /S");
|
|
MyRegistry_SetString(destKey, L"QuietUninstallString", destPath);
|
|
|
|
MyRegistry_SetDWORD(destKey, L"NoModify", 1);
|
|
MyRegistry_SetDWORD(destKey, L"NoRepair", 1);
|
|
|
|
MyRegistry_SetDWORD(destKey, L"EstimatedSize", g_TotalSize >> 10);
|
|
|
|
MyRegistry_SetDWORD(destKey, L"VersionMajor", MY_VER_MAJOR);
|
|
MyRegistry_SetDWORD(destKey, L"VersionMinor", MY_VER_MINOR);
|
|
|
|
MyRegistry_SetString(destKey, L"Publisher", LLL(MY_AUTHOR_NAME));
|
|
|
|
// MyRegistry_SetString(destKey, L"HelpLink", L"http://www.7-zip.org/support.html");
|
|
// MyRegistry_SetString(destKey, L"URLInfoAbout", L"http://www.7-zip.org/");
|
|
// MyRegistry_SetString(destKey, L"URLUpdateInfo", L"http://www.7-zip.org/");
|
|
|
|
RegCloseKey(destKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static const wchar_t *GetCmdParam(const wchar_t *s)
|
|
{
|
|
unsigned pos = 0;
|
|
BoolInt quoteMode = False;
|
|
for (;; s++)
|
|
{
|
|
wchar_t c = *s;
|
|
if (c == 0 || (c == L' ' && !quoteMode))
|
|
break;
|
|
if (c == L'\"')
|
|
{
|
|
quoteMode = !quoteMode;
|
|
continue;
|
|
}
|
|
if (pos >= Z7_ARRAY_SIZE(cmd) - 1)
|
|
exit(1);
|
|
cmd[pos++] = c;
|
|
}
|
|
cmd[pos] = 0;
|
|
return s;
|
|
}
|
|
|
|
|
|
static void RemoveQuotes(wchar_t *s)
|
|
{
|
|
const wchar_t *src = s;
|
|
for (;;)
|
|
{
|
|
wchar_t c = *src++;
|
|
if (c == '\"')
|
|
continue;
|
|
*s++ = c;
|
|
if (c == 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
// #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ')
|
|
|
|
|
|
typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL);
|
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
#ifdef UNDER_CE
|
|
LPWSTR
|
|
#else
|
|
LPSTR
|
|
#endif
|
|
lpCmdLine, int nCmdShow)
|
|
{
|
|
|
|
UNUSED_VAR(hPrevInstance)
|
|
UNUSED_VAR(lpCmdLine)
|
|
UNUSED_VAR(nCmdShow)
|
|
|
|
#ifndef UNDER_CE
|
|
LoadSecurityDlls();
|
|
CoInitialize(NULL);
|
|
#endif
|
|
|
|
CrcGenerateTable();
|
|
|
|
{
|
|
const wchar_t *s = GetCommandLineW();
|
|
|
|
#ifndef UNDER_CE
|
|
s = GetCmdParam(s);
|
|
#endif
|
|
|
|
for (;;)
|
|
{
|
|
{
|
|
const wchar_t c = *s;
|
|
if (c == 0)
|
|
break;
|
|
if (c == ' ')
|
|
{
|
|
s++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
{
|
|
const wchar_t *s2 = GetCmdParam(s);
|
|
BoolInt error = True;
|
|
if (cmd[0] == '/')
|
|
{
|
|
if (cmd[1] == 'S')
|
|
{
|
|
if (cmd[2] == 0)
|
|
{
|
|
g_SilentMode = True;
|
|
error = False;
|
|
}
|
|
}
|
|
else if (cmd[1] == 'D' && cmd[2] == '=')
|
|
{
|
|
wcscpy(path, cmd + 3);
|
|
// RemoveQuotes(path);
|
|
error = False;
|
|
}
|
|
}
|
|
s = s2;
|
|
if (error && cmdError[0] == 0)
|
|
wcscpy(cmdError, cmd);
|
|
}
|
|
}
|
|
|
|
if (cmdError[0] != 0)
|
|
{
|
|
if (!g_SilentMode)
|
|
PrintErrorMessage("Unsupported command:", cmdError);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64)
|
|
{
|
|
BOOL isWow64 = FALSE;
|
|
const Func_IsWow64Process func_IsWow64Process = (Func_IsWow64Process)
|
|
Z7_CAST_FUNC_C GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
|
|
"IsWow64Process");
|
|
|
|
if (func_IsWow64Process)
|
|
func_IsWow64Process(GetCurrentProcess(), &isWow64);
|
|
|
|
if (!isWow64)
|
|
{
|
|
if (!g_SilentMode)
|
|
PrintErrorMessage("This installation requires Windows "
|
|
#ifdef MY_CPU_X86_OR_AMD64
|
|
"x64"
|
|
#else
|
|
"64-bit"
|
|
#endif
|
|
, NULL);
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
if (path[0] == 0)
|
|
{
|
|
HKEY key = 0;
|
|
BoolInt ok = False;
|
|
const LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key);
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
ok = MyRegistry_QueryString(key, k_Reg_Path32, path);
|
|
// ok = MyRegistry_QueryString(key, k_Reg_Path, path);
|
|
RegCloseKey(key);
|
|
}
|
|
|
|
// ok = False;
|
|
if (!ok)
|
|
{
|
|
/*
|
|
#ifdef UNDER_CE
|
|
CpyAscii(path, "\\Program Files\\");
|
|
#else
|
|
|
|
#ifdef Z7_64BIT_INSTALLER
|
|
{
|
|
DWORD ttt = GetEnvironmentVariableW(L"ProgramW6432", path, MAX_PATH);
|
|
if (ttt == 0 || ttt > MAX_PATH)
|
|
CpyAscii(path, "C:\\");
|
|
}
|
|
#else
|
|
if (!SHGetSpecialFolderPathW(0, path, CSIDL_PROGRAM_FILES, FALSE))
|
|
CpyAscii(path, "C:\\");
|
|
#endif
|
|
#endif
|
|
*/
|
|
if (!MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", L"ProgramFilesDir", path))
|
|
CpyAscii(path,
|
|
#ifdef UNDER_CE
|
|
"\\Program Files\\"
|
|
#else
|
|
"C:\\"
|
|
#endif
|
|
);
|
|
|
|
Set7zipPostfix(path);
|
|
}
|
|
}
|
|
|
|
NormalizePrefix(path);
|
|
|
|
if (g_SilentMode)
|
|
return Install();
|
|
|
|
{
|
|
int retCode = 1;
|
|
// INT_PTR res = DialogBox(
|
|
g_HWND = CreateDialog(
|
|
hInstance,
|
|
// GetModuleHandle(NULL),
|
|
MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc);
|
|
if (!g_HWND)
|
|
return 1;
|
|
|
|
{
|
|
const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
|
|
// SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
|
|
SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
|
|
}
|
|
|
|
|
|
{
|
|
BOOL bRet;
|
|
MSG msg;
|
|
|
|
// we need messages for all thread windows (including EDITTEXT window in dialog)
|
|
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
|
|
{
|
|
if (bRet == -1)
|
|
return retCode;
|
|
if (!g_HWND)
|
|
return retCode;
|
|
|
|
if (!IsDialogMessage(g_HWND, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
if (!g_HWND)
|
|
return retCode;
|
|
|
|
if (g_Install_was_Pressed && !g_Finished)
|
|
{
|
|
retCode = Install();
|
|
g_Finished = True;
|
|
if (retCode != 0)
|
|
break;
|
|
if (!g_HWND)
|
|
break;
|
|
{
|
|
SetDlgItemTextW(g_HWND, IDOK, L"Close");
|
|
EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE);
|
|
EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE);
|
|
SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_HWND)
|
|
{
|
|
DestroyWindow(g_HWND);
|
|
g_HWND = NULL;
|
|
}
|
|
}
|
|
|
|
return retCode;
|
|
}
|
|
}
|
|
|
|
|
|
static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message)
|
|
{
|
|
LPWSTR msgBuf;
|
|
if (FormatMessageW(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
| FORMAT_MESSAGE_FROM_SYSTEM
|
|
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
|
|
return False;
|
|
wcscpy(message, msgBuf);
|
|
LocalFree(msgBuf);
|
|
return True;
|
|
}
|
|
|
|
|
|
|
|
static int Install(void)
|
|
{
|
|
CFileInStream archiveStream;
|
|
CLookToRead2 lookStream;
|
|
CSzArEx db;
|
|
|
|
SRes res = SZ_OK;
|
|
WRes winRes = 0;
|
|
const char *errorMessage = NULL;
|
|
|
|
ISzAlloc allocImp;
|
|
ISzAlloc allocTempImp;
|
|
WCHAR sfxPath[MAX_PATH + 2];
|
|
|
|
int needRebootLevel = 0;
|
|
|
|
allocImp.Alloc = SzAlloc;
|
|
allocImp.Free = SzFree;
|
|
|
|
allocTempImp.Alloc = SzAllocTemp;
|
|
allocTempImp.Free = SzFreeTemp;
|
|
|
|
{
|
|
const DWORD len = GetModuleFileNameW(NULL, sfxPath, MAX_PATH);
|
|
if (len == 0 || len > MAX_PATH)
|
|
return 1;
|
|
}
|
|
|
|
winRes = InFile_OpenW(&archiveStream.file, sfxPath);
|
|
|
|
if (winRes == 0)
|
|
{
|
|
UInt64 pos = 0;
|
|
if (!FindSignature(&archiveStream.file, &pos))
|
|
errorMessage = "Can't find 7z archive";
|
|
else
|
|
winRes = File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET);
|
|
}
|
|
|
|
if (winRes != 0)
|
|
res = SZ_ERROR_FAIL;
|
|
|
|
if (errorMessage)
|
|
res = SZ_ERROR_FAIL;
|
|
|
|
if (res == SZ_OK)
|
|
{
|
|
size_t pathLen;
|
|
if (!g_SilentMode)
|
|
{
|
|
GetDlgItemTextW(g_HWND, IDE_EXTRACT_PATH, path, MAX_PATH);
|
|
}
|
|
|
|
FileInStream_CreateVTable(&archiveStream);
|
|
LookToRead2_CreateVTable(&lookStream, False);
|
|
lookStream.buf = NULL;
|
|
|
|
RemoveQuotes(path);
|
|
{
|
|
// Remove post spaces
|
|
unsigned endPos = 0;
|
|
unsigned i = 0;
|
|
|
|
for (;;)
|
|
{
|
|
const wchar_t c = path[i++];
|
|
if (c == 0)
|
|
break;
|
|
if (c != ' ')
|
|
endPos = i;
|
|
}
|
|
|
|
path[endPos] = 0;
|
|
if (path[0] == 0)
|
|
{
|
|
PrintErrorMessage("Incorrect path", NULL);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
NormalizePrefix(path);
|
|
winRes = CreateComplexDir();
|
|
|
|
if (winRes != 0)
|
|
res = SZ_ERROR_FAIL;
|
|
|
|
pathLen = wcslen(path);
|
|
|
|
if (res == SZ_OK)
|
|
{
|
|
lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
|
|
if (!lookStream.buf)
|
|
res = SZ_ERROR_MEM;
|
|
else
|
|
{
|
|
lookStream.bufSize = kInputBufSize;
|
|
lookStream.realStream = &archiveStream.vt;
|
|
LookToRead2_INIT(&lookStream)
|
|
}
|
|
}
|
|
|
|
SzArEx_Init(&db);
|
|
|
|
if (res == SZ_OK)
|
|
{
|
|
res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
|
|
}
|
|
|
|
if (res == SZ_OK)
|
|
{
|
|
UInt32 i;
|
|
UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call, if (!outBuf) */
|
|
Byte *outBuf = NULL; /* it must be NULL before first call for each new archive. */
|
|
size_t outBufSize = 0; /* it can have any value before first call, if (!outBuf) */
|
|
|
|
g_TotalSize = 0;
|
|
|
|
if (!g_SilentMode)
|
|
{
|
|
ShowWindow(g_Progress_HWND, SW_SHOW);
|
|
ShowWindow(g_InfoLine_HWND, SW_SHOW);
|
|
SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, db.NumFiles);
|
|
}
|
|
|
|
for (i = 0; i < db.NumFiles; i++)
|
|
{
|
|
size_t offset = 0;
|
|
size_t outSizeProcessed = 0;
|
|
WCHAR *temp;
|
|
|
|
if (!g_SilentMode)
|
|
{
|
|
MSG msg;
|
|
|
|
// g_HWND
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (!IsDialogMessage(g_HWND, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
if (!g_HWND)
|
|
return 1;
|
|
}
|
|
|
|
// Sleep(10);
|
|
SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
|
|
}
|
|
|
|
{
|
|
const size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL);
|
|
if (len >= MAX_PATH)
|
|
{
|
|
res = SZ_ERROR_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
temp = path + pathLen;
|
|
|
|
SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp);
|
|
|
|
if (!g_SilentMode)
|
|
SetWindowTextW(g_InfoLine_HWND, temp);
|
|
|
|
{
|
|
res = SzArEx_Extract(&db, &lookStream.vt, i,
|
|
&blockIndex, &outBuf, &outBufSize,
|
|
&offset, &outSizeProcessed,
|
|
&allocImp, &allocTempImp);
|
|
if (res != SZ_OK)
|
|
break;
|
|
}
|
|
|
|
{
|
|
CSzFile outFile;
|
|
size_t processedSize;
|
|
size_t j;
|
|
// size_t nameStartPos = 0;
|
|
UInt32 tempIndex = 0;
|
|
int fileLevel = 1 << 2;
|
|
WCHAR origPath[MAX_PATH * 2 + 10];
|
|
|
|
for (j = 0; temp[j] != 0; j++)
|
|
{
|
|
if (temp[j] == '/')
|
|
{
|
|
temp[j] = 0;
|
|
MyCreateDir(path);
|
|
temp[j] = CHAR_PATH_SEPARATOR;
|
|
// nameStartPos = j + 1;
|
|
}
|
|
}
|
|
|
|
if (SzArEx_IsDir(&db, i))
|
|
{
|
|
MyCreateDir(path);
|
|
continue;
|
|
}
|
|
|
|
{
|
|
// BoolInt skipFile = False;
|
|
|
|
wcscpy(origPath, path);
|
|
|
|
for (;;)
|
|
{
|
|
WRes openRes;
|
|
|
|
if (tempIndex != 0)
|
|
{
|
|
if (tempIndex > 100)
|
|
{
|
|
res = SZ_ERROR_FAIL;
|
|
break;
|
|
}
|
|
wcscpy(path, origPath);
|
|
CatAscii(path, ".tmp");
|
|
if (tempIndex > 1)
|
|
HexToString(tempIndex, path + wcslen(path));
|
|
if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
tempIndex++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
{
|
|
SetFileAttributesW(path, 0);
|
|
openRes = OutFile_OpenW(&outFile, path);
|
|
if (openRes == 0)
|
|
break;
|
|
}
|
|
|
|
if (tempIndex != 0)
|
|
{
|
|
tempIndex++;
|
|
continue;
|
|
}
|
|
|
|
if (FindSubString(temp, "7-zip.dll")
|
|
#ifdef USE_7ZIP_32_DLL
|
|
|| FindSubString(temp, "7-zip32.dll")
|
|
#endif
|
|
)
|
|
{
|
|
const DWORD ver = GetFileVersion(path);
|
|
fileLevel = ((ver < Z7_7ZIP_DLL_VER_COMPAT || ver > Z7_7ZIP_CUR_VER) ? 2 : 1);
|
|
tempIndex++;
|
|
continue;
|
|
}
|
|
|
|
if (g_SilentMode)
|
|
{
|
|
tempIndex++;
|
|
continue;
|
|
}
|
|
{
|
|
WCHAR message[MAX_PATH * 3 + 100];
|
|
int mbRes;
|
|
|
|
CpyAscii(message, "Can't open file\n");
|
|
wcscat(message, path);
|
|
CatAscii(message, "\n");
|
|
|
|
GetErrorMessage(openRes, message + wcslen(message));
|
|
|
|
mbRes = MessageBoxW(g_HWND, message, L"Error", MB_ICONERROR | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3);
|
|
if (mbRes == IDABORT)
|
|
{
|
|
res = SZ_ERROR_ABORT;
|
|
tempIndex = 0;
|
|
break;
|
|
}
|
|
if (mbRes == IDIGNORE)
|
|
{
|
|
// skipFile = True;
|
|
tempIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (res != SZ_OK)
|
|
break;
|
|
|
|
/*
|
|
if (skipFile)
|
|
continue;
|
|
*/
|
|
}
|
|
|
|
// if (res == SZ_OK)
|
|
{
|
|
processedSize = outSizeProcessed;
|
|
winRes = File_Write(&outFile, outBuf + offset, &processedSize);
|
|
if (winRes != 0 || processedSize != outSizeProcessed)
|
|
{
|
|
errorMessage = "Can't write output file";
|
|
res = SZ_ERROR_FAIL;
|
|
}
|
|
|
|
g_TotalSize += (DWORD)outSizeProcessed;
|
|
|
|
#ifdef USE_WINDOWS_FILE
|
|
if (SzBitWithVals_Check(&db.MTime, i))
|
|
{
|
|
const CNtfsFileTime *t = db.MTime.Vals + i;
|
|
FILETIME mTime;
|
|
mTime.dwLowDateTime = t->Low;
|
|
mTime.dwHighDateTime = t->High;
|
|
SetFileTime(outFile.handle, NULL, NULL, &mTime);
|
|
}
|
|
#endif
|
|
|
|
{
|
|
const WRes winRes2 = File_Close(&outFile);
|
|
if (res != SZ_OK)
|
|
break;
|
|
if (winRes2 != 0)
|
|
{
|
|
winRes = winRes2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef USE_WINDOWS_FILE
|
|
if (SzBitWithVals_Check(&db.Attribs, i))
|
|
SetFileAttributesW(path, db.Attribs.Vals[i]);
|
|
#endif
|
|
}
|
|
|
|
if (tempIndex != 0)
|
|
{
|
|
// is it supported at win2000 ?
|
|
#ifndef UNDER_CE
|
|
if (!MoveFileExW(path, origPath, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING))
|
|
{
|
|
winRes = GetLastError();
|
|
break;
|
|
}
|
|
needRebootLevel |= fileLevel;
|
|
#endif
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
ISzAlloc_Free(&allocImp, outBuf);
|
|
|
|
if (!g_SilentMode)
|
|
SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
|
|
|
|
path[pathLen] = 0;
|
|
|
|
if (i == db.NumFiles)
|
|
{
|
|
SetRegKey_Path();
|
|
WriteCLSID();
|
|
WriteShellEx();
|
|
|
|
SetShellProgramsGroup(g_HWND);
|
|
if (!g_SilentMode)
|
|
SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is installed");
|
|
}
|
|
}
|
|
|
|
SzArEx_Free(&db, &allocImp);
|
|
|
|
ISzAlloc_Free(&allocImp, lookStream.buf);
|
|
|
|
File_Close(&archiveStream.file);
|
|
|
|
}
|
|
|
|
if (winRes != 0)
|
|
res = SZ_ERROR_FAIL;
|
|
|
|
if (res == SZ_OK)
|
|
{
|
|
if (!g_SilentMode && needRebootLevel > 1)
|
|
{
|
|
if (MessageBoxW(g_HWND, L"You must restart your system to complete the installation.\nRestart now?",
|
|
k_7zip_Setup, MB_YESNO | MB_DEFBUTTON2) == IDYES)
|
|
{
|
|
#ifndef UNDER_CE
|
|
|
|
// Get a token for this process.
|
|
HANDLE hToken;
|
|
|
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
|
{
|
|
TOKEN_PRIVILEGES tkp;
|
|
// Get the LUID for the shutdown privilege.
|
|
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
|
|
tkp.PrivilegeCount = 1; // one privilege to set
|
|
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
// Get the shutdown privilege for this process.
|
|
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
|
|
|
|
if (GetLastError() == ERROR_SUCCESS)
|
|
{
|
|
if (!ExitWindowsEx(EWX_REBOOT, 0))
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (res == SZ_OK)
|
|
return 0;
|
|
}
|
|
|
|
if (!g_SilentMode)
|
|
{
|
|
if (winRes != 0)
|
|
{
|
|
WCHAR m[MAX_PATH + 100];
|
|
m[0] = 0;
|
|
GetErrorMessage(winRes, m);
|
|
PrintErrorMessage(NULL, m);
|
|
}
|
|
else
|
|
{
|
|
if (res == SZ_ERROR_ABORT)
|
|
return 2;
|
|
|
|
if (res == SZ_ERROR_UNSUPPORTED)
|
|
errorMessage = "Decoder doesn't support this archive";
|
|
else if (res == SZ_ERROR_MEM)
|
|
errorMessage = "Can't allocate required memory";
|
|
else if (res == SZ_ERROR_CRC)
|
|
errorMessage = "CRC error";
|
|
else if (res == SZ_ERROR_DATA)
|
|
errorMessage = "Data error";
|
|
|
|
if (!errorMessage)
|
|
errorMessage = "ERROR";
|
|
PrintErrorMessage(errorMessage, NULL);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|