/src/native/windows/setup/setup.c
C | 2046 lines | 1804 code | 104 blank | 138 comment | 157 complexity | ad350b093c1d592ed4d8708bac909621 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
- /*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
- #include "lasterror.h"
- #include "nls.h"
- #include "registry.h"
- #include "setup.h"
-
- #include <ctype.h> /* isspace */
- #include <stdint.h> /* intptr_t */
- #include <stdlib.h>
- #include <string.h>
- #include <tchar.h>
-
- #include <objbase.h>
- #ifndef ERROR_RESOURCE_ENUM_USER_STOP
- #define ERROR_RESOURCE_ENUM_USER_STOP 0x3B02
- #endif /* #ifndef ERROR_RESOURCE_ENUM_USER_STOP */
- #include <shellapi.h>
- #ifndef SEE_MASK_NOASYNC
- #define SEE_MASK_NOASYNC 0x00000100
- #endif /* #ifndef SEE_MASK_NOASYNC */
- #include <tlhelp32.h> /* CreateToolhelp32Snapshot */
-
- #include <bspatch.h>
- #include <lzma.h>
-
- #define SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR_PROPERTY_BEGIN \
- L"SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR=\""
-
- static LPWSTR Setup_commandLine = NULL;
- static LPTSTR Setup_fileName = NULL;
-
- /**
- * The indicator which determines whether this setup is to execute as msiexec
- * only and is to just execute an MSI specified on the command line.
- */
- static BOOL Setup_msiexec_ = FALSE;
- static LPTSTR Setup_productName = NULL;
-
- /**
- * The indicator which determines whether this setup is to display no user
- * interface such as error message dialogs and the error status of the
- * application is to be reported as its exit code.
- */
- static BOOL Setup_quiet = FALSE;
- static BOOL Setup_waitForParentProcess_ = FALSE;
-
- /**
- * The indicator which determines whether this setup is to execute as xzdec only
- * and is to just extract its payload in the current directory.
- */
- static BOOL Setup_xzdec_ = FALSE;
-
- BOOL CALLBACK Setup_enumResNameProc(HMODULE module, LPCTSTR type, LPTSTR name, LONG_PTR param);
- static DWORD Setup_executeBspatch(LPCTSTR path);
- static DWORD Setup_executeMsiA(LPCSTR path);
- static DWORD Setup_executeMsiW(LPCWSTR path);
- static DWORD Setup_extractAndExecutePayload(LPVOID ptr, DWORD size);
- #ifdef PACKAGECODE
- static LONG Setup_findLocalPackageByProductId(LPCTSTR productId, LPTSTR *localPackage);
- static LONG Setup_findProductIdByPackageCode(LPCTSTR packageCode, LPTSTR *productId);
- #endif /* #ifdef PACKAGECODE */
- static void Setup_fixCommandLineQuotes();
- static LPWSTR Setup_getArgW(LPWSTR commandLine, LPWSTR *value);
- static LPSTR Setup_getBoolArgA(LPCSTR argName, LPSTR commandLine, BOOL *boolValue);
- static LPWSTR Setup_getBoolArgW(LPCWSTR argName, LPWSTR commandLine, BOOL *boolValue);
- static LPCTSTR Setup_getFileName();
- static DWORD Setup_getParentProcess(DWORD *ppid, LPTSTR *fileName);
- static LPCTSTR Setup_getProductName();
- static DWORD Setup_getWinMainCmdLine(LPTSTR *winMainCmdLine);
- static int Setup_isWow64Acceptable();
- LRESULT CALLBACK Setup_isWow64AcceptableMessageBoxCallWndRetProc(int code, WPARAM wParam, LPARAM lParam);
- static DWORD Setup_msiexec();
- static DWORD Setup_parseCommandLine(LPTSTR cmdLine);
- static LPSTR Setup_skipWhitespaceA(LPSTR str);
- static LPWSTR Setup_skipWhitespaceW(LPWSTR str);
- static DWORD Setup_terminateUp2DateExe();
- static DWORD Setup_waitForParentProcess();
- static DWORD Setup_xzdec(LPVOID ptr, DWORD size, HANDLE file);
-
- #ifdef _UNICODE
- #define Setup_executeMsi(path) \
- Setup_executeMsiW(path)
- #define Setup_getBoolArg(argName, commandLine, boolValue) \
- Setup_getBoolArgW(argName, commandLine, boolValue)
- #define Setup_skipWhitespace(str) \
- Setup_skipWhitespaceW(str)
- #else /* #ifdef _UNICODE */
- #define Setup_executeMsi(path) \
- Setup_executeMsiA(path)
- #define Setup_getBoolArg(argName, commandLine, boolValue) \
- Setup_getBoolArgA(argName, commandLine, boolValue)
- #define Setup_skipWhitespace(str) \
- Setup_skipWhitespaceA(str)
- #endif /* #ifdef _UNICODE */
-
- BOOL CALLBACK
- Setup_enumResNameProc(
- HMODULE module,
- LPCTSTR type, LPTSTR name,
- LONG_PTR param)
- {
- HRSRC rsrc = FindResource(module, name, type);
- BOOL proceed = TRUE;
- DWORD error = ERROR_SUCCESS;
-
- if (rsrc)
- {
- DWORD size = SizeofResource(module, rsrc);
-
- if (size)
- {
- HGLOBAL global = LoadResource(module, rsrc);
-
- if (global)
- {
- LPVOID ptr = LockResource(global);
-
- if (ptr)
- {
- proceed = FALSE;
- error = Setup_extractAndExecutePayload(ptr, size);
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- if (param)
- *((DWORD *) param) = error;
- return proceed;
- }
-
- static DWORD
- Setup_executeBspatch(LPCTSTR path)
- {
- DWORD error;
-
- #ifdef PACKAGECODE
- LPTSTR packageCode = _tcsdup(PACKAGECODE);
-
- if (packageCode)
- {
- /*
- * Strip the display characters from the GUID, only its bytes are
- * important.
- */
- size_t i;
- size_t j;
- size_t packageCodeLength = _tcslen(packageCode);
-
- for (i = 0, j = 0; i < packageCodeLength; i++)
- {
- TCHAR c = packageCode[i];
-
- if ((_T('{') != c) && (_T('}') != c) && (_T('-') != c))
- packageCode[j++] = c;
- }
- packageCode[j] = 0;
- packageCodeLength = j;
-
- if (32 == packageCodeLength)
- {
- TCHAR swap;
- LPTSTR pc = packageCode;
- LPTSTR productId;
-
- /* 8 */
- swap = pc[7]; pc[7] = pc[0]; pc[0] = swap;
- swap = pc[6]; pc[6] = pc[1]; pc[1] = swap;
- swap = pc[5]; pc[5] = pc[2]; pc[2] = swap;
- swap = pc[4]; pc[4] = pc[3]; pc[3] = swap;
- /* 4 */
- swap = pc[11]; pc[11] = pc[8]; pc[8] = swap;
- swap = pc[10]; pc[10] = pc[9]; pc[9] = swap;
- /* 4 */
- swap = pc[15]; pc[15] = pc[12]; pc[12] = swap;
- swap = pc[14]; pc[14] = pc[13]; pc[13] = swap;
- /* 4 */
- swap = pc[17]; pc[17] = pc[16]; pc[16] = swap;
- swap = pc[19]; pc[19] = pc[18]; pc[18] = swap;
- /* 12 */
- swap = pc[21]; pc[21] = pc[20]; pc[20] = swap;
- swap = pc[23]; pc[23] = pc[22]; pc[22] = swap;
- swap = pc[25]; pc[25] = pc[24]; pc[24] = swap;
- swap = pc[27]; pc[27] = pc[26]; pc[26] = swap;
- swap = pc[29]; pc[29] = pc[28]; pc[28] = swap;
- swap = pc[31]; pc[31] = pc[30]; pc[30] = swap;
-
- error = Setup_findProductIdByPackageCode(packageCode, &productId);
- if (ERROR_SUCCESS == error)
- {
- LPTSTR localPackage;
-
- error
- = Setup_findLocalPackageByProductId(
- productId,
- &localPackage);
- #ifdef PACKAGESIZE
- /*
- * Windows Installer on Windows XP caches the MSI database only
- * so the localPackage cannot really be used with bspatch as the
- * old file to produce the new file. Unfortunately, bspatch will
- * report that it has successfully produced the new file from
- * the old file in this scenario but the resulting MSI will be
- * malformed. As a workaround to detect this error, make sure
- * that the localPackage is with the expected size in bytes.
- */
- if (ERROR_SUCCESS == error)
- {
- HANDLE hLocalPackage
- = CreateFile(
- localPackage,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL);
-
- if (INVALID_HANDLE_VALUE == hLocalPackage)
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- else
- {
- LARGE_INTEGER packageSize;
-
- if (GetFileSizeEx(hLocalPackage, &packageSize))
- {
- if (PACKAGESIZE != packageSize.QuadPart)
- {
- error = ERROR_FILE_NOT_FOUND;
- LastError_setLastError(
- error,
- _T(__FILE__), __LINE__);
- }
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- CloseHandle(hLocalPackage);
- }
- }
- #endif /* #ifdef PACKAGESIZE */
- if (ERROR_SUCCESS == error)
- {
- /*
- * The path to the new file to be produced by bspatch.exe is
- * optional. If it is not specified on the command line,
- * default to a path derived from the path to the .bspatch
- * file.
- */
- LPWSTR wNewPath;
- LPTSTR newPath;
-
- Setup_commandLine
- = Setup_getArgW(Setup_commandLine, &wNewPath);
- if (wNewPath)
- {
- #ifdef _UNICODE
- newPath = wNewPath;
- #else /* #ifdef _UNICODE */
- newPath = NLS_wstr2str(wNewPath);
- #endif /* #ifdef _UNICODE */
- }
- else
- {
- size_t pathLength = _tcslen(path);
- LPCTSTR extension = _T(".msi");
- size_t extensionLength = _tcslen(extension);
-
- newPath
- = malloc(
- sizeof(TCHAR)
- * (pathLength + extensionLength + 1));
- if (newPath)
- {
- LPTSTR str;
-
- str = newPath;
- _tcsncpy(str, path, pathLength);
- str += pathLength;
- _tcsncpy(str, extension, extensionLength);
- str += extensionLength;
- *str = 0;
- }
- }
- /*
- * Execute bspatch.exe (or rather the function it has been
- * compiled into).
- */
- if (newPath)
- {
- LPCTSTR argv[]
- = {
- _T("bspatch.exe"),
- localPackage, newPath, path,
- NULL
- };
-
- if (bspatch_main(
- (sizeof(argv) / sizeof(LPCTSTR)) - 1,
- argv))
- {
- error = ERROR_GEN_FAILURE;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- if (((LPVOID) newPath) != ((LPVOID) wNewPath))
- free(newPath);
- }
- else
- {
- error = ERROR_NOT_ENOUGH_MEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- free(localPackage);
- }
- free(productId);
- }
- }
- else
- {
- error = ERROR_INVALID_PARAMETER;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- free(packageCode);
- }
- else
- {
- error = ERROR_NOT_ENOUGH_MEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- #else /* #ifdef PACKAGECODE */
- error = ERROR_CALL_NOT_IMPLEMENTED;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- #endif /* #ifdef PACKAGECODE */
- return error;
- }
-
- static DWORD
- Setup_executeMsiA(LPCSTR path)
- {
- LPWSTR wpath = NLS_str2wstr(path);
- DWORD error;
-
- if (wpath)
- {
- error = Setup_executeMsiW(wpath);
- free(wpath);
- }
- else
- {
- error = ERROR_OUTOFMEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- return error;
- }
-
- static DWORD
- Setup_executeMsiW(LPCWSTR path)
- {
- DWORD error = ERROR_SUCCESS;
- LPCWSTR p0, p1, p2, p3;
- size_t p0Length, p1Length, p2Length, p3Length;
- LPWSTR parameters;
-
- p0 = L"/i \"";
- p0Length = wcslen(p0);
- p1 = path;
- if (p1)
- p1Length = wcslen(p1);
- else
- {
- error = ERROR_INVALID_PARAMETER;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- return error;
- }
- p2 = L"\" REINSTALLMODE=amus ";
- p2Length = wcslen(p2);
- p3 = Setup_commandLine;
- p3Length = p3 ? wcslen(p3) : 0;
-
- parameters
- = (LPWSTR)
- malloc(
- sizeof(wchar_t)
- * (p0Length + p1Length + p2Length + p3Length + 1));
- if (parameters)
- {
- LPWSTR str = parameters;
- SHELLEXECUTEINFOW sei;
-
- wcsncpy(str, p0, p0Length);
- str += p0Length;
- wcsncpy(str, p1, p1Length);
- str += p1Length;
- wcsncpy(str, p2, p2Length);
- str += p2Length;
- if (p3Length)
- {
- wcsncpy(str, p3, p3Length);
- str += p3Length;
- }
- *str = 0;
-
- ZeroMemory(&sei, sizeof(sei));
- sei.cbSize = sizeof(sei);
- sei.fMask
- = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI;
- sei.lpVerb = L"open";
- sei.lpFile = L"msiexec.exe";
- sei.lpParameters = parameters;
- sei.nShow = SW_SHOWNORMAL;
-
- /*
- * MSDN says it is good practice to always initialize COM before using
- * ShellExecuteEx.
- */
- CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
-
- if (ShellExecuteExW(&sei) && (((intptr_t) (sei.hInstApp)) > 32))
- {
- if (sei.hProcess)
- {
- DWORD event;
-
- do
- {
- event = WaitForSingleObject(sei.hProcess, INFINITE);
- if (WAIT_FAILED == event)
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
- }
- while (WAIT_TIMEOUT == event);
- CloseHandle(sei.hProcess);
- }
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
-
- free(parameters);
- }
- else
- {
- error = ERROR_OUTOFMEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- return error;
- }
-
- static DWORD
- Setup_extractAndExecutePayload(LPVOID ptr, DWORD size)
- {
- TCHAR path[MAX_PATH + 1];
- DWORD pathSize = sizeof(path) / sizeof(TCHAR);
- DWORD tempPathLength;
- DWORD error = ERROR_SUCCESS;
-
- /*
- * When this application is to execute in the fashion of xzdec only, it does
- * not sound like a nice idea to extract its payload in the TEMP directory
- * and the current directory sounds like an acceptable compromise (given
- * that it is far more complex to accept the path to extract to as a command
- * line argument).
- */
- if (Setup_xzdec_)
- {
- path[0] = _T('.');
- path[1] = _T('\\');
- /*
- * It is not necessary to null-terminate path because it will
- * automatically be done later in accord with the value of
- * tempPathLength.
- */
- tempPathLength = 2;
- }
- else
- tempPathLength = GetTempPath(pathSize, path);
- if (tempPathLength)
- {
- if (tempPathLength > pathSize)
- {
- error = ERROR_NOT_ENOUGH_MEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- else
- {
- LPCTSTR fileName = Setup_getFileName();
- HANDLE file = INVALID_HANDLE_VALUE;
-
- if (fileName)
- {
- size_t fileNameLength = _tcslen(fileName);
- size_t freePathSize;
- #ifdef PACKAGECODE
- LPCTSTR fileType = _T("bspatch");
- BOOL xzdec = FALSE;
- #else /* #ifdef PACKAGECODE */
- LPCTSTR fileType = _T("msi");
- BOOL xzdec = TRUE;
- #endif /* #ifdef PACKAGECODE */
-
- if ((fileNameLength > 4 /* .exe */)
- && ((freePathSize
- = (pathSize
- - (tempPathLength
- + fileNameLength
- + 1)))
- >= 0))
- {
- LPTSTR str = path + tempPathLength;
- size_t fileTypeLength = _tcslen(fileType);
-
- _tcsncpy(str, fileName, fileNameLength - 4);
- str += (fileNameLength - 4);
- *str = _T('.');
- str++;
- _tcsncpy(str, fileType, 3);
- str += 3;
-
- /*
- * If possible, use the whole fileType for the extension and
- * not just its first 3 characters.
- */
- fileTypeLength -= 3;
- if ((fileTypeLength > 0)
- && (fileTypeLength <= freePathSize))
- {
- _tcsncpy(str, fileType + 3, fileTypeLength);
- str += fileTypeLength;
- }
-
- *str = 0;
-
- file
- = CreateFile(
- path,
- GENERIC_WRITE,
- 0,
- NULL,
- CREATE_NEW,
- FILE_ATTRIBUTE_TEMPORARY,
- NULL);
- }
-
- if (INVALID_HANDLE_VALUE == file)
- {
- LPTSTR tempPath;
-
- path[tempPathLength] = 0;
- tempPath = _tcsdup(path);
-
- if (tempPath)
- {
- if (0
- == GetTempFileName(
- tempPath,
- fileType,
- 0,
- path))
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- else
- {
- file
- = CreateFile(
- path,
- GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_TEMPORARY,
- NULL);
- if (INVALID_HANDLE_VALUE == file)
- {
- error = GetLastError();
- LastError_setLastError(
- error,
- _T(__FILE__), __LINE__);
- }
- }
- free(tempPath);
- }
- else
- {
- error = ERROR_OUTOFMEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
-
- if (INVALID_HANDLE_VALUE != file)
- {
- if (xzdec)
- error = Setup_xzdec(ptr, size, file);
- else
- {
- DWORD numberOfBytesWritten;
-
- if (!WriteFile(
- file,
- ptr, size,
- &numberOfBytesWritten,
- NULL))
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
-
- /* When executing as xzdec, do not execute the MSI. */
- if ((ERROR_SUCCESS == error) && !Setup_xzdec_)
- {
- if (Setup_waitForParentProcess_)
- Setup_waitForParentProcess();
-
- CloseHandle(file);
- if (_tcsnicmp(_T("bspatch"), fileType, 3) == 0)
- error = Setup_executeBspatch(path);
- else if (_tcsnicmp(_T("msi"), fileType, 3) == 0)
- error = Setup_executeMsi(path);
- else
- {
- error = ERROR_CALL_NOT_IMPLEMENTED;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- else
- CloseHandle(file);
- /*
- * Delete the MSI if executing as setup or if executing as
- * xzdec and the extraction has failed (in the fashion of
- * other popular decompressors).
- */
- if (!Setup_xzdec_ || (ERROR_SUCCESS != error))
- DeleteFile(path);
- }
- }
- }
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- return error;
- }
-
- #ifdef PACKAGECODE
- static LONG
- Setup_findLocalPackageByProductId(LPCTSTR productId, LPTSTR *localPackage)
- {
- HKEY userDataKey;
- LONG error
- = RegOpenKeyEx(
- HKEY_LOCAL_MACHINE,
- _T("Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData"),
- 0,
- KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY,
- &userDataKey);
-
- if (ERROR_SUCCESS == error)
- {
- TCHAR userDataSubKeyName[1024];
- const DWORD userDataSubKeyNameCapacity
- = sizeof(userDataSubKeyName) / sizeof(TCHAR);
- DWORD index = 0;
- LPCTSTR products = _T("\\Products\\");
- const DWORD productsLength = 10;
- const DWORD productIdLength = 32;
- LPCTSTR installProperties = _T("\\InstallProperties");
- const DWORD installPropertiesLength = 18;
- TCHAR installPropertiesKeyName[
- userDataSubKeyNameCapacity
- + productsLength
- + productIdLength
- + installPropertiesLength];
-
- *localPackage = NULL;
- do
- {
- DWORD userDataSubKeyNameLength = userDataSubKeyNameCapacity;
- LPTSTR str;
- HKEY installPropertiesKey;
-
- error
- = RegEnumKeyEx(
- userDataKey,
- index,
- userDataSubKeyName, &userDataSubKeyNameLength,
- NULL,
- NULL, NULL,
- NULL);
- index++;
- if (ERROR_MORE_DATA == error)
- continue;
- if (ERROR_SUCCESS != error)
- {
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
-
- str = installPropertiesKeyName;
- _tcsncpy(str, userDataSubKeyName, userDataSubKeyNameLength);
- str += userDataSubKeyNameLength;
- _tcsncpy(str, products, productsLength);
- str += productsLength;
- _tcsncpy(str, productId, productIdLength);
- str += productIdLength;
- _tcsncpy(str, installProperties, installPropertiesLength);
- str += installPropertiesLength;
- *str = 0;
-
- error
- = RegOpenKeyEx(
- userDataKey,
- installPropertiesKeyName,
- 0,
- KEY_QUERY_VALUE | KEY_WOW64_64KEY,
- &installPropertiesKey);
- if (ERROR_SUCCESS == error)
- {
- error
- = Run_getRegSzValue(
- installPropertiesKey,
- _T("LocalPackage"),
- localPackage);
- /*
- * Reset the value stored at localPackage to NULL in case
- * Run_getRegSzValue has failed but has assigned an invalid
- * value prior to the failure.
- */
- if (ERROR_SUCCESS != error)
- *localPackage = NULL;
- RegCloseKey(installPropertiesKey);
- }
- }
- while (!(*localPackage));
- RegCloseKey(userDataKey);
- if ((ERROR_SUCCESS == error) && !(*localPackage))
- {
- error = ERROR_FILE_NOT_FOUND;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- else
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- return error;
- }
- #endif /* #ifdef PACKAGECODE */
-
- #ifdef PACKAGECODE
- static LONG
- Setup_findProductIdByPackageCode(LPCTSTR packageCode, LPTSTR *productId)
- {
- HKEY key;
- LONG error
- = RegOpenKeyEx(
- HKEY_LOCAL_MACHINE,
- _T("Software\\Classes\\Installer\\Products"),
- 0,
- KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY,
- &key);
-
- if (ERROR_SUCCESS == error)
- {
- TCHAR subKeyName[33];
- const DWORD subKeyNameCapacity = sizeof(subKeyName) / sizeof(TCHAR);
- DWORD index = 0;
-
- *productId = NULL;
- do
- {
- DWORD subKeyNameLength = subKeyNameCapacity;
- HKEY subKey;
- LPTSTR packageCodeOfProductId;
-
- error
- = RegEnumKeyEx(
- key,
- index,
- subKeyName, &subKeyNameLength,
- NULL,
- NULL, NULL,
- NULL);
- index++;
- if (ERROR_MORE_DATA == error)
- continue;
- if (ERROR_SUCCESS != error)
- {
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
- if (32 != subKeyNameLength)
- continue;
- error
- = RegOpenKeyEx(
- key,
- subKeyName,
- 0,
- KEY_QUERY_VALUE | KEY_WOW64_64KEY,
- &subKey);
- if (ERROR_SUCCESS != error)
- {
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
- error
- = Run_getRegSzValue(
- subKey,
- _T("PackageCode"),
- &packageCodeOfProductId);
- if (ERROR_SUCCESS == error)
- {
- if (_tcsnicmp(
- packageCodeOfProductId, packageCode,
- subKeyNameLength)
- == 0)
- {
- *productId = _tcsdup(subKeyName);
- if (!(*productId))
- {
- error = ERROR_NOT_ENOUGH_MEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- free(packageCodeOfProductId);
- }
- else
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- RegCloseKey(subKey);
- if (ERROR_SUCCESS != error)
- break;
- }
- while (!(*productId));
- RegCloseKey(key);
- if ((ERROR_SUCCESS == error) && !(*productId))
- {
- error = ERROR_FILE_NOT_FOUND;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- else
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- return error;
- }
- #endif /* #ifdef PACKAGECODE */
-
- static void
- Setup_fixCommandLineQuotes()
- {
- LPWSTR readCmdLine = Setup_commandLine;
- LPWSTR writeCmdLine = Setup_commandLine;
-
- do
- {
- LPWSTR arg;
-
- readCmdLine = Setup_getArgW(readCmdLine, &arg);
- if (arg)
- {
- /*
- * If the argument has unquoted whitespace, quote the whole
- * argument.
- */
- wchar_t c;
- LPWSTR a = arg;
- BOOL quoted = FALSE;
- BOOL whitespace = FALSE;
- size_t argLength;
-
- while ((c = *a))
- {
- if (iswspace(c))
- {
- if (!quoted)
- {
- whitespace = TRUE;
- break;
- }
- }
- else if (L'\"' == c)
- quoted = quoted ? FALSE : TRUE;
- a++;
- }
-
- /*
- * If the argument is not the first one, separate it from the
- * previous one with a space.
- */
- if (writeCmdLine != Setup_commandLine)
- {
- *writeCmdLine = L' ';
- writeCmdLine++;
- }
- /* Append the argument to the command line. */
- argLength = wcslen(arg);
- if (whitespace
- && ((writeCmdLine + (argLength + 1)) < readCmdLine))
- {
- *writeCmdLine = L'\"';
- writeCmdLine++;
- wcsncpy(writeCmdLine, arg, argLength);
- writeCmdLine += argLength;
- *writeCmdLine = L'\"';
- writeCmdLine++;
- }
- else
- {
- wcsncpy(writeCmdLine, arg, argLength);
- writeCmdLine += argLength;
- }
- }
- else
- break;
- }
- while (1);
- /* At long last, terminate the command line. */
- *writeCmdLine = 0;
- }
-
- static LPWSTR
- Setup_getArgW(LPWSTR commandLine, LPWSTR *value)
- {
- if (commandLine)
- {
- LPWSTR v;
- size_t quoted;
- wchar_t prevC;
- wchar_t c;
-
- /* Obviously, any leading whitespace is not a part of an argument. */
- commandLine = Setup_skipWhitespaceW(commandLine);
- v = commandLine;
-
- quoted = 0;
- prevC = 0;
- while ((c = *commandLine))
- {
- if (iswspace(c))
- {
- if (!quoted)
- break;
- }
- else if (L'\"' == c)
- {
- if (quoted)
- {
- /*
- * Quotes cannot simply be nested but the Java
- * ProcessBuilder does nest them (in cases in which nesting
- * is not even necessary) so try to deal with them. Clearly,
- * the implementation will be heuristic in nature.
- */
- wchar_t nextC;
-
- if ((1 == quoted)
- && ((nextC = *(commandLine + 1)))
- && !iswspace(nextC)
- && ((L'=' == prevC)
- || ((L'\"' == prevC)
- && (v + 1 == commandLine))))
- quoted++;
- else
- quoted--;
- }
- else
- quoted = 1;
- }
- prevC = c;
- commandLine++;
- }
- /*
- * If there are more arguments, get rid of any whitespace before them.
- */
- if (c)
- {
- LPWSTR vEnd = commandLine;
-
- commandLine = Setup_skipWhitespaceW(commandLine);
- *vEnd = 0;
- }
- /*
- * If the argument is quoted, drop the quotes. Since the Java
- * ProcessBuilder will quote even the quoted command line arguments,
- * drop as many quotes as possible.
- */
- while (L'\"' == *v)
- {
- size_t vLength = wcslen(v);
-
- if (vLength > 1)
- {
- LPWSTR vEnd = v + (vLength - 1);
-
- if (L'\"' == *vEnd)
- {
- /*
- * Convert the opening quote to a whitespace character (just
- * in case) and the closing quote to the null character (in
- * order to terminate the argument).
- */
- *v = L' ';
- v++;
- *vEnd = 0;
- }
- }
- }
-
- if (value)
- *value = *v ? v : NULL;
- }
- else
- {
- if (value)
- *value = NULL;
- }
- return commandLine;
- }
-
- #define DEFINE_SETUP_GETBOOLARG(f, t, len, nicmp) \
- static LP ## t \
- Setup_getBoolArg ## f (LPC ## t argName, LP ## t commandLine, BOOL *boolValue) \
- { \
- size_t argNameLength; \
- BOOL argValue; \
- \
- argNameLength = len(argName); \
- commandLine = Setup_skipWhitespace ## f (commandLine); \
- if (0 == nicmp(commandLine, argName, argNameLength)) \
- { \
- argValue = TRUE; \
- commandLine = Setup_skipWhitespace ## f (commandLine + argNameLength); \
- } \
- else \
- argValue = FALSE; \
- if (boolValue) \
- *boolValue = argValue; \
- return commandLine; \
- }
- #ifdef _UNICODE
- #undef _UNICODE
- DEFINE_SETUP_GETBOOLARG(A, STR, strlen, _strnicmp)
- #define _UNICODE
- DEFINE_SETUP_GETBOOLARG(W, WSTR, wcslen, _wcsnicmp)
- #else /* #ifdef _UNICODE */
- DEFINE_SETUP_GETBOOLARG(A, STR, strlen, _strnicmp)
- #define _UNICODE
- DEFINE_SETUP_GETBOOLARG(W, WSTR, wcslen, _wcsnicmp)
- #undef _UNICODE
- #endif /* #ifdef _UNICODE */
-
- static LPCTSTR
- Setup_getFileName()
- {
- if (!Setup_fileName)
- {
- TCHAR moduleFileName[MAX_PATH + 1];
- DWORD moduleFileNameSize = sizeof(moduleFileName) / sizeof(TCHAR);
- DWORD moduleFileNameLength
- = GetModuleFileName(NULL, moduleFileName, moduleFileNameSize);
-
- if (moduleFileNameLength)
- {
- TCHAR *fileNameEnd = moduleFileName + moduleFileNameLength - 1;
- TCHAR *fileNameBegin = fileNameEnd;
- size_t fileNameLength;
- LPTSTR fileName;
-
- for (; fileNameBegin >= moduleFileName; fileNameBegin--)
- {
- TCHAR c = *fileNameBegin;
-
- if ((_T('\\') == c) || (_T('/') == c))
- break;
- }
- fileNameBegin
- = (fileNameBegin == fileNameEnd)
- ? moduleFileName
- : (fileNameBegin + 1);
-
- fileNameLength = (fileNameEnd - fileNameBegin) + 1;
- fileName = (LPTSTR) malloc((fileNameLength + 1) * sizeof(TCHAR));
- if (fileName)
- {
- _tcsncpy(fileName, fileNameBegin, fileNameLength);
- *(fileName + fileNameLength) = 0;
- Setup_fileName = fileName;
- }
- }
- }
- return Setup_fileName;
- }
-
- static DWORD
- Setup_getParentProcess(DWORD *ppid, LPTSTR *fileName)
- {
- HANDLE snapshot;
- DWORD error;
-
- snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if (snapshot == INVALID_HANDLE_VALUE)
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- else
- {
- PROCESSENTRY32 entry;
-
- entry.dwSize = sizeof(PROCESSENTRY32);
- if (Process32First(snapshot, &entry))
- {
- DWORD pid;
-
- error = ERROR_SUCCESS;
- pid = GetCurrentProcessId();
- if (ppid)
- *ppid = 0;
-
- do
- {
- if (entry.th32ProcessID == pid)
- {
- if (ppid)
- *ppid = entry.th32ParentProcessID;
- break;
- }
- if (!Process32Next(snapshot, &entry))
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
- }
- while (1);
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- if ((ERROR_SUCCESS == error) && fileName && ppid && *ppid)
- {
- if (Process32First(snapshot, &entry))
- {
- do
- {
- if (entry.th32ProcessID == *ppid)
- {
- *fileName = _tcsdup(entry.szExeFile);
- if (NULL == *fileName)
- {
- error = ERROR_OUTOFMEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- break;
- }
- if (!Process32Next(snapshot, &entry))
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
- }
- while (1);
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- CloseHandle(snapshot);
- }
- return error;
- }
-
- static LPCTSTR
- Setup_getProductName()
- {
- if (!Setup_productName)
- {
- LPCTSTR fileName = Setup_getFileName();
-
- if (fileName)
- {
- int fileNameLength = _tcslen(fileName);
-
- if ((fileNameLength > 4)
- && (_tcsnicmp(fileName + fileNameLength - 4, _T(".exe"), 4)
- == 0))
- {
- LPTSTR productName;
-
- fileNameLength -= 4;
- productName
- = (LPTSTR) malloc((fileNameLength + 1) * sizeof(TCHAR));
- if (productName)
- {
- _tcsncpy(productName, fileName, fileNameLength);
- *(productName + fileNameLength) = 0;
- Setup_productName = productName;
- }
- }
- if (!Setup_productName)
- Setup_productName = (LPTSTR) fileName;
- }
- }
- return Setup_productName;
- }
-
- static DWORD
- Setup_getWinMainCmdLine(LPTSTR *winMainCmdLine)
- {
- LPWSTR cmdLineW = GetCommandLineW();
- DWORD error;
-
- if (cmdLineW && wcslen(cmdLineW))
- {
- int argc;
- LPWSTR *argvW = CommandLineToArgvW(cmdLineW, &argc);
-
- if (argvW)
- {
- if (argc)
- {
- LPWSTR argvW0 = argvW[0];
- LPWSTR argvW0InCmdLineW = wcsstr(cmdLineW, argvW0);
-
- if (argvW0InCmdLineW)
- {
- wchar_t c;
-
- cmdLineW = argvW0InCmdLineW + wcslen(argvW0);
- /*
- * CommandLineToArgvW may not report quotes as part of
- * argvW0. As a workaround, skip non-whitespace characters.
- */
- while ((c = *cmdLineW) && !iswspace(c))
- cmdLineW++;
- }
- #ifdef _UNICODE
- *winMainCmdLine = cmdLineW;
- error = ERROR_SUCCESS;
- #else /* #ifdef _UNICODE */
- *winMainCmdLine = NLS_wstr2str(cmdLineW);
- if (*winMainCmdLine)
- error = ERROR_SUCCESS;
- else
- {
- error = ERROR_GEN_FAILURE;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- #endif /* #ifdef _UNICODE */
- }
- else
- {
- *winMainCmdLine = NULL;
- error = ERROR_SUCCESS;
- }
- LocalFree(argvW);
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- else
- {
- *winMainCmdLine = NULL;
- error = ERROR_SUCCESS;
- }
- return error;
- }
-
- static int
- Setup_isWow64Acceptable()
- {
- int answer = IDYES;
- HMODULE kernel32;
-
- /*
- * If this is an (automatic) update, do not ask because (1) the user has
- * already answered during the initial install and (2) it is plain annoying.
- */
- if (Setup_commandLine
- && wcsstr(
- Setup_commandLine,
- SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR_PROPERTY_BEGIN))
- return answer;
-
- kernel32 = GetModuleHandle(_T("kernel32"));
- if (kernel32)
- {
- typedef BOOL (WINAPI *LPISWOW64PROCESS)(HANDLE, PBOOL);
-
- LPISWOW64PROCESS isWow64Process
- = (LPISWOW64PROCESS) GetProcAddress(kernel32, "IsWow64Process");
- BOOL wow64Process = FALSE;
-
- if (isWow64Process
- && isWow64Process(GetCurrentProcess(), &wow64Process)
- && wow64Process)
- {
- TCHAR fileName[MAX_PATH + 1];
-
- if (GetModuleFileName(NULL, fileName, sizeof(fileName) / sizeof(TCHAR)))
- {
- UINT questionId;
- UINT buttonType;
- DWORD questionLength;
- TCHAR question[1024];
-
- #ifdef X64_SETUP_URL
- HHOOK hook
- = SetWindowsHookEx(
- WH_CALLWNDPROCRET,
- (HOOKPROC) Setup_isWow64AcceptableMessageBoxCallWndRetProc,
- NULL,
- GetCurrentThreadId());
-
- if (hook)
- {
- questionId = IDS_ISWOW64ACCEPTABLE3;
- buttonType = MB_YESNOCANCEL | MB_DEFBUTTON3;
- }
- else
- #endif /* #ifdef X64_SETUP_URL */
- {
- questionId = IDS_ISWOW64ACCEPTABLE2;
- buttonType = MB_YESNO;
- }
-
- questionLength
- = LoadString(
- GetModuleHandle(NULL),
- questionId,
- question,
- sizeof(question) / sizeof(TCHAR));
- if (questionLength)
- {
- answer
- = MessageBox(
- NULL,
- question,
- fileName,
- MB_ICONQUESTION | buttonType);
- LocalFree(question);
- }
-
- #ifdef X64_SETUP_URL
- if (hook)
- {
- UnhookWindowsHookEx(hook);
-
- switch (answer)
- {
- case IDNO: // Continue
- answer = IDYES;
- break;
- case IDYES: // Download
- answer = IDNO;
- ShellExecute(
- NULL,
- _T("open"),
- _T(X64_SETUP_URL),
- NULL,
- NULL,
- SW_SHOWNORMAL);
- break;
- }
- }
- #endif /* #ifdef X64_SETUP_URL */
- }
- }
- }
- return answer;
- }
-
- LRESULT CALLBACK
- Setup_isWow64AcceptableMessageBoxCallWndRetProc(
- int code,
- WPARAM wParam,
- LPARAM lParam)
- {
- CWPRETSTRUCT *cwprs = (CWPRETSTRUCT *) lParam;
-
- if (cwprs && (WM_INITDIALOG == cwprs->message))
- {
- HWND yes, no;
-
- yes = GetDlgItem(cwprs->hwnd, IDYES);
- if (yes)
- SendMessage(yes, WM_SETTEXT, 0, (LPARAM) _T("&Download"));
-
- no = GetDlgItem(cwprs->hwnd, IDNO);
- if (no)
- SendMessage(no, WM_SETTEXT, 0, (LPARAM) _T("&Continue"));
- }
- return CallNextHookEx(NULL, code, wParam, lParam);
- }
-
- static DWORD
- Setup_msiexec()
- {
- LPWSTR msi;
- DWORD error;
-
- Setup_commandLine = Setup_getArgW(Setup_commandLine, &msi);
- if (msi)
- error = Setup_executeMsiW(msi);
- else
- {
- error = ERROR_BAD_ARGUMENTS;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- return error;
- }
-
- static DWORD
- Setup_parseCommandLine(LPTSTR cmdLine)
- {
- LPTSTR commandLine;
- DWORD error = ERROR_SUCCESS;
-
- //#ifdef _UNICODE
- // if (cmdLine)
- // {
- // commandLine = NLS_str2wstr(cmdLine);
- // if (!commandLine)
- // {
- // error = ERROR_OUTOFMEMORY;
- // LastError_setLastError(error, _T(__FILE__), __LINE__);
- // }
- // }
- // else
- // commandLine = NULL;
- //#else
- commandLine = cmdLine;
- //#endif /* #ifdef _UNICODE */
-
- if (commandLine)
- {
- LPTSTR noWaitParentCommandLine
- = Setup_getBoolArg(
- _T("--wait-parent"),
- commandLine,
- &Setup_waitForParentProcess_);
- /*
- * The command line argument --allow-elevation is up2date legacy which
- * has to be taken into account by removing it in order to prevent it
- * from breaking msiexec.
- */
- BOOL up2date;
- LPTSTR noAllowElevationCommandLine
- = Setup_getBoolArg(
- _T("--allow-elevation"),
- noWaitParentCommandLine,
- &up2date);
- size_t noAllowElevationCommandLineLength
- = _tcslen(noAllowElevationCommandLine);
- TCHAR envVarValue[1 /* " */ + MAX_PATH + 1 /* " */ + 1];
-
- /*
- * If there are no arguments on the command line to reveal that up2date
- * is involved, try detecting it by the fact that it sets the
- * SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR environment variable. If the
- * environment variable in question is not set, it is sure that this
- * setup is to execute its post-up2date logic.
- */
- if (!up2date && !noAllowElevationCommandLineLength)
- {
- DWORD envVarValueSize
- = (sizeof(envVarValue) / sizeof(TCHAR)) - 2 /* "" */;
- DWORD envVarValueLength
- = GetEnvironmentVariable(
- _T("SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR"),
- &(envVarValue[1]),
- envVarValueSize);
-
- if (envVarValueLength)
- {
- if (envVarValueLength > envVarValueSize)
- {
- error = ERROR_NOT_ENOUGH_MEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- else
- {
- if ((envVarValueLength >= 2)
- && ('\"' == envVarValue[1])
- && ('\"' == envVarValue[1 + envVarValueLength - 1]))
- {
- noAllowElevationCommandLine = &(envVarValue[1]);
- }
- else
- {
- envVarValue[0] = '\"';
- envVarValue[1 + envVarValueLength] = '\"';
- envVarValue[1 + envVarValueLength + 1] = 0;
- envVarValueLength += 2;
- noAllowElevationCommandLine = envVarValue;
- }
- noAllowElevationCommandLineLength = envVarValueLength;
- up2date = TRUE;
- }
- }
- else
- {
- DWORD envVarError = GetLastError();
-
- if (ERROR_ENVVAR_NOT_FOUND != envVarError)
- {
- error = envVarError;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- }
- /*
- * If the up2date logic is in effect, then there are no post-up2date
- * command line arguments to parse and any command line just tells the
- * value of SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR. The latter can
- * easily be translated to the post-up2date logic at this point by
- * converting it to an msiexec property.
- */
- if (up2date && noAllowElevationCommandLineLength)
- {
- LPWSTR commandLineW;
-
- #ifdef _UNICODE
- commandLineW = noAllowElevationCommandLine;
- #else
- commandLineW = NLS_str2wstr(noAllowElevationCommandLine);
- if (!commandLineW)
- {
- error = ERROR_OUTOFMEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- #endif /* #ifdef _UNICODE */
-
- if (commandLineW)
- {
- int argc;
- LPWSTR *argv = CommandLineToArgvW(commandLineW, &argc);
-
- if (argv)
- {
- if ((1 == argc) || (2 == argc))
- {
- LPWSTR argv1 = *(argv + (argc - 1));
- size_t argv1Length = wcslen(argv1);
-
- if ((argv1Length >= 2)
- && (L'\"' == argv1[0])
- && (L'\"' == argv1[argv1Length - 1]))
- {
- argv1++;
- argv1Length -= 2;
- }
- if (argv1Length)
- {
- LPCWSTR propertyBegin
- = SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR_PROPERTY_BEGIN;
- size_t propertyBeginLength = wcslen(propertyBegin);
- LPCWSTR propertyEnd = L"\"";
- size_t propertyEndLength = wcslen(propertyEnd);
-
- Setup_commandLine
- = (LPWSTR)
- malloc(
- sizeof(wchar_t)
- * (propertyBeginLength
- + argv1Length
- + propertyEndLength
- + 1));
- if (Setup_commandLine)
- {
- LPWSTR str = Setup_commandLine;
-
- wcsncpy(
- str,
- propertyBegin,
- propertyBeginLength);
- str += propertyBeginLength;
- wcsncpy(str, argv1, argv1Length);
- str += argv1Length;
- wcsncpy(str, propertyEnd, propertyEndLength);
- *(str + propertyEndLength) = 0;
- }
- else
- {
- error = ERROR_OUTOFMEMORY;
- LastError_setLastError(
- error,
- _T(__FILE__), __LINE__);
- }
- }
- }
- LocalFree(argv);
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
-
- if (((LPVOID) commandLineW)
- != ((LPVOID) noAllowElevationCommandLine))
- free(commandLineW);
- }
- }
- /*
- * If up2date.exe is running while the MSI is being installed, the MSI
- * will display a dialog notifying of the fact and asking the user to
- * either let it close the application in question (and it will not be
- * able to if the user actually chooses the option) or reboot.
- */
- if (up2date)
- Setup_terminateUp2DateExe();
-
- /*
- * If this is the post-up2date logic, then there may be post-up2date
- * command line arguments to parse.
- */
- if (!up2date && noAllowElevationCommandLineLength)
- {
- #ifdef _UNICODE
- Setup_commandLine = _wcsdup(noAllowElevationCommandLine);
- #else
- Setup_commandLine = NLS_str2wstr(noAllowElevationCommandLine);
- #endif /* #ifdef _UNICODE */
- if (Setup_commandLine)
- {
- /*
- * It is just easier to parse the command line arguments if they
- * are ordered.
- */
-
- Setup_commandLine
- = Setup_getBoolArgW(
- L"--quiet",
- Setup_commandLine,
- &Setup_quiet);
- #ifdef PACKAGECODE
- Setup_commandLine
- = Setup_getBoolArgW(
- L"--msiexec",
- Setup_commandLine,
- &Setup_msiexec_);
- #endif /* #ifdef PACKAGECODE */
- if (!Setup_msiexec_)
- {
- Setup_commandLine
- = Setup_getBoolArgW(
- L"--xzdec",
- Setup_commandLine,
- &Setup_xzdec_);
- }
-
- /*
- * Unfortunately, the Java ProcessBuilder will break the format
- * PROPERTY="VALUE" by quoting the whole command line argument.
- * Solve the problem in general regardless of the formats of the
- * command line arguments.
- */
- Setup_fixCommandLineQuotes();
- }
- else
- {
- error = ERROR_OUTOFMEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
-
- if ((void *) commandLine != (void *) cmdLine)
- free(commandLine);
- }
- return error;
- }
-
- #define DEFINE_SETUP_SKIPWHITESPACE(f, tc, ts, space) \
- static LP ## ts \
- Setup_skipWhitespace ## f (LP ## ts str) \
- { \
- tc c; \
- \
- while ((c = *str) && space(c)) \
- ++str; \
- return str; \
- }
- #ifdef _UNICODE
- #undef _UNICODE
- DEFINE_SETUP_SKIPWHITESPACE(A, char, STR, isspace)
- #define _UNICODE
- DEFINE_SETUP_SKIPWHITESPACE(W, wchar_t, WSTR, iswspace)
- #else /* #ifdef _UNICODE */
- DEFINE_SETUP_SKIPWHITESPACE(A, char, STR, isspace)
- #define _UNICODE
- DEFINE_SETUP_SKIPWHITESPACE(W, wchar_t, WSTR, iswspace)
- #undef _UNICODE
- #endif /* #ifdef _UNICODE */
-
- static DWORD
- Setup_terminateUp2DateExe()
- {
- DWORD error;
- DWORD ppid = 0;
- LPTSTR ppFileName = NULL;
-
- error = Setup_getParentProcess(&ppid, &ppFileName);
- if ((ERROR_SUCCESS == error) && ppFileName)
- {
- size_t ppFileNameLength = _tcslen(ppFileName);
- LPCTSTR up2DateExe = _T("up2date.exe");
- size_t up2DateExeLength = _tcslen(up2DateExe);
-
- if ((ppFileNameLength >= up2DateExeLength)
- && (_tcsncmp(
- ppFileName + (ppFileNameLength - up2DateExeLength),
- up2DateExe,
- up2DateExeLength)
- == 0))
- {
- HANDLE parentProcess
- = OpenProcess(PROCESS_TERMINATE, FALSE, ppid);
-
- if (parentProcess)
- {
- if (!TerminateProcess(parentProcess, 0))
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- CloseHandle(parentProcess);
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- }
- return error;
- }
-
- static DWORD
- Setup_waitForParentProcess()
- {
- DWORD error;
- DWORD ppid = 0;
-
- error = Setup_getParentProcess(&ppid, NULL);
- if (ERROR_SUCCESS == error)
- {
- HANDLE parentProcess = OpenProcess(SYNCHRONIZE, FALSE, ppid);
-
- if (parentProcess)
- {
- DWORD event;
-
- error = ERROR_SUCCESS;
- do
- {
- event = WaitForSingleObject(parentProcess, INFINITE);
- if (WAIT_FAILED == event)
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
- }
- while (WAIT_TIMEOUT == event);
- CloseHandle(parentProcess);
- }
- else
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- }
- return error;
- }
-
- static DWORD
- Setup_xzdec(LPVOID ptr, DWORD size, HANDLE file)
- {
- lzma_stream strm = LZMA_STREAM_INIT;
- lzma_stream *_strm = &strm;
- DWORD error;
-
- switch (lzma_stream_decoder(_strm, UINT64_MAX, 0))
- {
- case LZMA_OK:
- error = ERROR_SUCCESS;
- {
- uint8_t *input = (uint8_t *) ptr;
- const size_t maxInputLengthPerCode = 8 * 1024;
- uint8_t output[maxInputLengthPerCode];
- const size_t outputCapacity = sizeof(output);
-
- while (size)
- {
- size_t inputLength;
- lzma_action action;
- DWORD outputLength;
-
- strm.next_in = input;
- strm.avail_in
- = inputLength
- = (maxInputLengthPerCode < size)
- ? maxInputLengthPerCode
- : size;
-
- size -= inputLength;
- action = size ? LZMA_RUN : LZMA_FINISH;
-
- do
- {
- DWORD numberOfBytesWritten;
-
- strm.next_out = output;
- strm.avail_out = outputCapacity;
-
- switch (lzma_code(_strm, action))
- {
- case LZMA_OK:
- case LZMA_STREAM_END:
- outputLength = outputCapacity - strm.avail_out;
- if (outputLength
- && !WriteFile(
- file,
- output, outputLength,
- &numberOfBytesWritten,
- NULL))
- {
- error = GetLastError();
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- }
- break;
- default:
- error = ERROR_WRITE_FAULT;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
-
- if (ERROR_SUCCESS != error)
- {
- action = LZMA_FINISH; /* Break out of the input loop. */
- break; /* Break out of the output loop. */
- }
- }
- while (outputLength);
-
- if (LZMA_FINISH == action)
- break;
- else
- input += inputLength;
- }
- }
- break;
- case LZMA_MEM_ERROR:
- error = ERROR_NOT_ENOUGH_MEMORY;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- case LZMA_OPTIONS_ERROR:
- error = ERROR_INVALID_PARAMETER;
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- case LZMA_PROG_ERROR:
- default:
- error = ERROR_OPEN_FAILED; /* For the lack of a better idea. */
- LastError_setLastError(error, _T(__FILE__), __LINE__);
- break;
- }
- lzma_end(_strm);
- return error;
- }
-
- int CALLBACK
- WinMain(
- HINSTANCE instance, HINSTANCE prevInstance,
- LPSTR cmdLine,
- int cmdShow)
- {
- /*
- * The value of WinMain's cmdLine argument may be incorrect, for example, in
- * the case of a character with an accent in the path of the executable. As
- * a workaround, try to reconstruct the correct value using GetCommandLineW
- * and CommandLineToArgvW.
- */
- LPTSTR winMainCmdLine = NULL;
- DWORD error = Setup_getWinMainCmdLine(&winMainCmdLine);
-
- if (ERROR_SUCCESS == error)
- {
- Setup_parseCommandLine(winMainCmdLine);
-
- /*
- * If the --xzdec command line argument has been specified, the caller
- * obviously knows what they are doing so do not ask whether Wow64 is
- * acceptable.
- */
- if (Setup_quiet || Setup_xzdec_ || (IDYES == Setup_isWow64Acceptable()))
- {
- if (Setup_msiexec_)
- error = Setup_msiexec();
- else
- {
- Setup_enumResNameProc(
- NULL,
- RT_RCDATA,
- MAKEINTRESOURCE(IDRCDATA_PAYLOAD),
- (LONG_PTR) &error);
- }
- }
- }
-
- /*
- * If anything has gone wrong, report it to the user. In accord with the
- * --quiet command line argument, report the error via either an error
- * message dialog or the application exit code.
- */
- if ((ERROR_SUCCESS != error) && !Setup_quiet)
- {
- LPTSTR message;
- DWORD messageLength
- = FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- error,
- LANG_USER_DEFAULT,
- (LPTSTR) &message,
- 0,
- NULL);
-
- if (messageLength)
- {
- /*
- * If there is debug information about the particular piece of
- * source code which has caused the error, display it to the user as
- * well so that we/the developers may get a more accurate report and
- * have a greater chance of understanding and fixing the problem.
- */
- LPCTSTR lastErrorFile = LastError_file();
- LPCTSTR productName = Setup_getProductName();
-
- if (lastErrorFile)
- {
- TCHAR lastErrorFormat[1024];
- int lastErrorFormatLength
- = LoadString(
- GetModuleHandle(NULL),
- IDS_LASTERRORFORMAT,
- lastErrorFormat,
- sizeof(lastErrorFormat) / sizeof(TCHAR));
-
- if (lastErrorFormatLength)
- {
- LPTSTR lastErrorMessage;
- DWORD_PTR lastErrorArguments[]
- = {
- (DWORD_PTR) productName,
- (DWORD_PTR) error,
- (DWORD_PTR) lastErrorFile,
- (DWORD_PTR) LastError_line(),
- (DWORD_PTR) message
- };
- DWORD lastErrorMessageLength
- = FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER
- | FORMAT_MESSAGE_ARGUMENT_ARRAY
- | FORMAT_MESSAGE_FROM_STRING,
- lastErrorFormat,
- 0,
- LANG_USER_DEFAULT,
- (LPTSTR) &lastErrorMessage,
- 0,
- (va_list *) lastErrorArguments);
-
- if (lastErrorMessageLength)
- {
- LocalFree(message);
- message = lastErrorMessage;
- }
- }
- }
-
- MessageBox(NULL, message, productName, MB_ICONERROR | MB_OK);
- LocalFree(message);
-
- /*
- * The error has just been reported to the user as an error message
- * dialog so assume it is enough and do not report it as the
- * application exit code.
- */
- error = ERROR_SUCCESS;
- }
- }
-
- /*
- * Clean up. (It is not really necessary because this application is about
- * to exit.)
- */
- if (Setup_productName && (Setup_productName != Setup_fileName))
- free(Setup_productName);
- if (Setup_fileName)
- free(Setup_fileName);
-
- return error;
- }