PageRenderTime 10ms CodeModel.GetById 11ms app.highlight 83ms RepoModel.GetById 1ms app.codeStats 0ms

/src/native/windows/setup/setup.c

https://bitbucket.org/LANJr4D/jitsi
C | 2046 lines | 1804 code | 104 blank | 138 comment | 157 complexity | ad350b093c1d592ed4d8708bac909621 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
   3 *
   4 * Distributable under LGPL license.
   5 * See terms of license at gnu.org.
   6 */
   7
   8#include "lasterror.h"
   9#include "nls.h"
  10#include "registry.h"
  11#include "setup.h"
  12
  13#include <ctype.h> /* isspace */
  14#include <stdint.h> /* intptr_t */
  15#include <stdlib.h>
  16#include <string.h>
  17#include <tchar.h>
  18
  19#include <objbase.h>
  20#ifndef ERROR_RESOURCE_ENUM_USER_STOP
  21#define ERROR_RESOURCE_ENUM_USER_STOP 0x3B02
  22#endif /* #ifndef ERROR_RESOURCE_ENUM_USER_STOP */
  23#include <shellapi.h>
  24#ifndef SEE_MASK_NOASYNC
  25#define SEE_MASK_NOASYNC 0x00000100
  26#endif /* #ifndef SEE_MASK_NOASYNC */
  27#include <tlhelp32.h> /* CreateToolhelp32Snapshot */
  28
  29#include <bspatch.h>
  30#include <lzma.h>
  31
  32#define SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR_PROPERTY_BEGIN \
  33    L"SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR=\""
  34
  35static LPWSTR Setup_commandLine = NULL;
  36static LPTSTR Setup_fileName = NULL;
  37
  38/**
  39 * The indicator which determines whether this setup is to execute as msiexec
  40 * only and is to just execute an MSI specified on the command line.
  41 */
  42static BOOL Setup_msiexec_ = FALSE;
  43static LPTSTR Setup_productName = NULL;
  44
  45/**
  46 * The indicator which determines whether this setup is to display no user
  47 * interface such as error message dialogs and the error status of the
  48 * application is to be reported as its exit code.
  49 */
  50static BOOL Setup_quiet = FALSE;
  51static BOOL Setup_waitForParentProcess_ = FALSE;
  52
  53/**
  54 * The indicator which determines whether this setup is to execute as xzdec only
  55 * and is to just extract its payload in the current directory.
  56 */
  57static BOOL Setup_xzdec_ = FALSE;
  58
  59BOOL CALLBACK Setup_enumResNameProc(HMODULE module, LPCTSTR type, LPTSTR name, LONG_PTR param);
  60static DWORD Setup_executeBspatch(LPCTSTR path);
  61static DWORD Setup_executeMsiA(LPCSTR path);
  62static DWORD Setup_executeMsiW(LPCWSTR path);
  63static DWORD Setup_extractAndExecutePayload(LPVOID ptr, DWORD size);
  64#ifdef PACKAGECODE
  65static LONG Setup_findLocalPackageByProductId(LPCTSTR productId, LPTSTR *localPackage);
  66static LONG Setup_findProductIdByPackageCode(LPCTSTR packageCode, LPTSTR *productId);
  67#endif /* #ifdef PACKAGECODE */
  68static void Setup_fixCommandLineQuotes();
  69static LPWSTR Setup_getArgW(LPWSTR commandLine, LPWSTR *value);
  70static LPSTR Setup_getBoolArgA(LPCSTR argName, LPSTR commandLine, BOOL *boolValue);
  71static LPWSTR Setup_getBoolArgW(LPCWSTR argName, LPWSTR commandLine, BOOL *boolValue);
  72static LPCTSTR Setup_getFileName();
  73static DWORD Setup_getParentProcess(DWORD *ppid, LPTSTR *fileName);
  74static LPCTSTR Setup_getProductName();
  75static DWORD Setup_getWinMainCmdLine(LPTSTR *winMainCmdLine);
  76static int Setup_isWow64Acceptable();
  77LRESULT CALLBACK Setup_isWow64AcceptableMessageBoxCallWndRetProc(int code, WPARAM wParam, LPARAM lParam);
  78static DWORD Setup_msiexec();
  79static DWORD Setup_parseCommandLine(LPTSTR cmdLine);
  80static LPSTR Setup_skipWhitespaceA(LPSTR str);
  81static LPWSTR Setup_skipWhitespaceW(LPWSTR str);
  82static DWORD Setup_terminateUp2DateExe();
  83static DWORD Setup_waitForParentProcess();
  84static DWORD Setup_xzdec(LPVOID ptr, DWORD size, HANDLE file);
  85
  86#ifdef _UNICODE
  87#define Setup_executeMsi(path) \
  88    Setup_executeMsiW(path)
  89#define Setup_getBoolArg(argName, commandLine, boolValue) \
  90    Setup_getBoolArgW(argName, commandLine, boolValue)
  91#define Setup_skipWhitespace(str) \
  92    Setup_skipWhitespaceW(str)
  93#else /* #ifdef _UNICODE */
  94#define Setup_executeMsi(path) \
  95    Setup_executeMsiA(path)
  96#define Setup_getBoolArg(argName, commandLine, boolValue) \
  97    Setup_getBoolArgA(argName, commandLine, boolValue)
  98#define Setup_skipWhitespace(str) \
  99    Setup_skipWhitespaceA(str)
 100#endif /* #ifdef _UNICODE */
 101
 102BOOL CALLBACK
 103Setup_enumResNameProc(
 104        HMODULE module,
 105        LPCTSTR type, LPTSTR name,
 106        LONG_PTR param)
 107{
 108    HRSRC rsrc = FindResource(module, name, type);
 109    BOOL proceed = TRUE;
 110    DWORD error = ERROR_SUCCESS;
 111
 112    if (rsrc)
 113    {
 114        DWORD size = SizeofResource(module, rsrc);
 115
 116        if (size)
 117        {
 118            HGLOBAL global = LoadResource(module, rsrc);
 119
 120            if (global)
 121            {
 122                LPVOID ptr = LockResource(global);
 123
 124                if (ptr)
 125                {
 126                    proceed = FALSE;
 127                    error = Setup_extractAndExecutePayload(ptr, size);
 128                }
 129                else
 130                {
 131                    error = GetLastError();
 132                    LastError_setLastError(error, _T(__FILE__), __LINE__);
 133                }
 134            }
 135            else
 136            {
 137                error = GetLastError();
 138                LastError_setLastError(error, _T(__FILE__), __LINE__);
 139            }
 140        }
 141        else
 142        {
 143            error = GetLastError();
 144            LastError_setLastError(error, _T(__FILE__), __LINE__);
 145        }
 146    }
 147    else
 148    {
 149        error = GetLastError();
 150        LastError_setLastError(error, _T(__FILE__), __LINE__);
 151    }
 152    if (param)
 153        *((DWORD *) param) = error;
 154    return proceed;
 155}
 156
 157static DWORD
 158Setup_executeBspatch(LPCTSTR path)
 159{
 160    DWORD error;
 161
 162#ifdef PACKAGECODE
 163    LPTSTR packageCode = _tcsdup(PACKAGECODE);
 164
 165    if (packageCode)
 166    {
 167        /*
 168         * Strip the display characters from the GUID, only its bytes are
 169         * important.
 170         */
 171        size_t i;
 172        size_t j;
 173        size_t packageCodeLength = _tcslen(packageCode);
 174
 175        for (i = 0, j = 0; i < packageCodeLength; i++)
 176        {
 177            TCHAR c = packageCode[i];
 178
 179            if ((_T('{') != c) && (_T('}') != c) && (_T('-') != c))
 180                packageCode[j++] = c;
 181        }
 182        packageCode[j] = 0;
 183        packageCodeLength = j;
 184
 185        if (32 == packageCodeLength)
 186        {
 187            TCHAR swap;
 188            LPTSTR pc = packageCode;
 189            LPTSTR productId;
 190
 191            /* 8 */
 192            swap = pc[7]; pc[7] = pc[0]; pc[0] = swap;
 193            swap = pc[6]; pc[6] = pc[1]; pc[1] = swap;
 194            swap = pc[5]; pc[5] = pc[2]; pc[2] = swap;
 195            swap = pc[4]; pc[4] = pc[3]; pc[3] = swap;
 196            /* 4 */
 197            swap = pc[11]; pc[11] = pc[8]; pc[8] = swap;
 198            swap = pc[10]; pc[10] = pc[9]; pc[9] = swap;
 199            /* 4 */
 200            swap = pc[15]; pc[15] = pc[12]; pc[12] = swap;
 201            swap = pc[14]; pc[14] = pc[13]; pc[13] = swap;
 202            /* 4 */
 203            swap = pc[17]; pc[17] = pc[16]; pc[16] = swap;
 204            swap = pc[19]; pc[19] = pc[18]; pc[18] = swap;
 205            /* 12 */
 206            swap = pc[21]; pc[21] = pc[20]; pc[20] = swap;
 207            swap = pc[23]; pc[23] = pc[22]; pc[22] = swap;
 208            swap = pc[25]; pc[25] = pc[24]; pc[24] = swap;
 209            swap = pc[27]; pc[27] = pc[26]; pc[26] = swap;
 210            swap = pc[29]; pc[29] = pc[28]; pc[28] = swap;
 211            swap = pc[31]; pc[31] = pc[30]; pc[30] = swap;
 212
 213            error = Setup_findProductIdByPackageCode(packageCode, &productId);
 214            if (ERROR_SUCCESS == error)
 215            {
 216                LPTSTR localPackage;
 217
 218                error
 219                    = Setup_findLocalPackageByProductId(
 220                            productId,
 221                            &localPackage);
 222#ifdef PACKAGESIZE
 223                /*
 224                 * Windows Installer on Windows XP caches the MSI database only
 225                 * so the localPackage cannot really be used with bspatch as the
 226                 * old file to produce the new file. Unfortunately, bspatch will
 227                 * report that it has successfully produced the new file from
 228                 * the old file in this scenario but the resulting MSI will be
 229                 * malformed. As a workaround to detect this error, make sure
 230                 * that the localPackage is with the expected size in bytes.
 231                 */
 232                if (ERROR_SUCCESS == error)
 233                {
 234                    HANDLE hLocalPackage
 235                        = CreateFile(
 236                                localPackage,
 237                                GENERIC_READ,
 238                                FILE_SHARE_READ,
 239                                NULL,
 240                                OPEN_EXISTING,
 241                                0,
 242                                NULL);
 243
 244                    if (INVALID_HANDLE_VALUE == hLocalPackage)
 245                    {
 246                        error = GetLastError();
 247                        LastError_setLastError(error, _T(__FILE__), __LINE__);
 248                    }
 249                    else
 250                    {
 251                        LARGE_INTEGER packageSize;
 252
 253                        if (GetFileSizeEx(hLocalPackage, &packageSize))
 254                        {
 255                            if (PACKAGESIZE != packageSize.QuadPart)
 256                            {
 257                                error = ERROR_FILE_NOT_FOUND;
 258                                LastError_setLastError(
 259                                        error,
 260                                        _T(__FILE__), __LINE__);
 261                            }
 262                        }
 263                        else
 264                        {
 265                            error = GetLastError();
 266                            LastError_setLastError(error, _T(__FILE__), __LINE__);
 267                        }
 268                        CloseHandle(hLocalPackage);
 269                    }
 270                }
 271#endif /* #ifdef PACKAGESIZE */
 272                if (ERROR_SUCCESS == error)
 273                {
 274                    /*
 275                     * The path to the new file to be produced by bspatch.exe is
 276                     * optional. If it is not specified on the command line,
 277                     * default to a path derived from the path to the .bspatch
 278                     * file.
 279                     */
 280                    LPWSTR wNewPath;
 281                    LPTSTR newPath;
 282
 283                    Setup_commandLine
 284                        = Setup_getArgW(Setup_commandLine, &wNewPath);
 285                    if (wNewPath)
 286                    {
 287#ifdef _UNICODE
 288                        newPath = wNewPath;
 289#else /* #ifdef _UNICODE */
 290                        newPath = NLS_wstr2str(wNewPath);
 291#endif /* #ifdef _UNICODE */
 292                    }
 293                    else
 294                    {
 295                        size_t pathLength = _tcslen(path);
 296                        LPCTSTR extension = _T(".msi");
 297                        size_t extensionLength = _tcslen(extension);
 298
 299                        newPath
 300                            = malloc(
 301                                    sizeof(TCHAR)
 302                                        * (pathLength + extensionLength + 1));
 303                        if (newPath)
 304                        {
 305                            LPTSTR str;
 306
 307                            str = newPath;
 308                            _tcsncpy(str, path, pathLength);
 309                            str += pathLength;
 310                            _tcsncpy(str, extension, extensionLength);
 311                            str += extensionLength;
 312                            *str = 0;
 313                        }
 314                    }
 315                    /*
 316                     * Execute bspatch.exe (or rather the function it has been
 317                     * compiled into).
 318                     */
 319                    if (newPath)
 320                    {
 321                        LPCTSTR argv[]
 322                            = {
 323                                _T("bspatch.exe"),
 324                                localPackage, newPath, path,
 325                                NULL
 326                            };
 327
 328                        if (bspatch_main(
 329                                (sizeof(argv) / sizeof(LPCTSTR)) - 1,
 330                                argv))
 331                        {
 332                            error = ERROR_GEN_FAILURE;
 333                            LastError_setLastError(error, _T(__FILE__), __LINE__);
 334                        }
 335                        if (((LPVOID) newPath) != ((LPVOID) wNewPath))
 336                            free(newPath);
 337                    }
 338                    else
 339                    {
 340                        error = ERROR_NOT_ENOUGH_MEMORY;
 341                        LastError_setLastError(error, _T(__FILE__), __LINE__);
 342                    }
 343                    free(localPackage);
 344                }
 345                free(productId);
 346            }
 347        }
 348        else
 349        {
 350            error = ERROR_INVALID_PARAMETER;
 351            LastError_setLastError(error, _T(__FILE__), __LINE__);
 352        }
 353        free(packageCode);
 354    }
 355    else
 356    {
 357        error = ERROR_NOT_ENOUGH_MEMORY;
 358        LastError_setLastError(error, _T(__FILE__), __LINE__);
 359    }
 360#else /* #ifdef PACKAGECODE */
 361    error = ERROR_CALL_NOT_IMPLEMENTED;
 362    LastError_setLastError(error, _T(__FILE__), __LINE__);
 363#endif /* #ifdef PACKAGECODE */
 364    return error;
 365}
 366
 367static DWORD
 368Setup_executeMsiA(LPCSTR path)
 369{
 370    LPWSTR wpath = NLS_str2wstr(path);
 371    DWORD error;
 372
 373    if (wpath)
 374    {
 375        error = Setup_executeMsiW(wpath);
 376        free(wpath);
 377    }
 378    else
 379    {
 380        error = ERROR_OUTOFMEMORY;
 381        LastError_setLastError(error, _T(__FILE__), __LINE__);
 382    }
 383    return error;
 384}
 385
 386static DWORD
 387Setup_executeMsiW(LPCWSTR path)
 388{
 389    DWORD error = ERROR_SUCCESS;
 390    LPCWSTR p0, p1, p2, p3;
 391    size_t p0Length, p1Length, p2Length, p3Length;
 392    LPWSTR parameters;
 393
 394    p0 = L"/i \"";
 395    p0Length = wcslen(p0);
 396    p1 = path;
 397    if (p1)
 398        p1Length = wcslen(p1);
 399    else
 400    {
 401        error = ERROR_INVALID_PARAMETER;
 402        LastError_setLastError(error, _T(__FILE__), __LINE__);
 403        return error;
 404    }
 405    p2 = L"\" REINSTALLMODE=amus ";
 406    p2Length = wcslen(p2);
 407    p3 = Setup_commandLine;
 408    p3Length = p3 ? wcslen(p3) : 0;
 409
 410    parameters
 411        = (LPWSTR)
 412            malloc(
 413                    sizeof(wchar_t)
 414                        * (p0Length + p1Length + p2Length + p3Length + 1));
 415    if (parameters)
 416    {
 417        LPWSTR str = parameters;
 418        SHELLEXECUTEINFOW sei;
 419
 420        wcsncpy(str, p0, p0Length);
 421        str += p0Length;
 422        wcsncpy(str, p1, p1Length);
 423        str += p1Length;
 424        wcsncpy(str, p2, p2Length);
 425        str += p2Length;
 426        if (p3Length)
 427        {
 428            wcsncpy(str, p3, p3Length);
 429            str += p3Length;
 430        }
 431        *str = 0;
 432
 433        ZeroMemory(&sei, sizeof(sei));
 434        sei.cbSize = sizeof(sei);
 435        sei.fMask
 436            = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI;
 437        sei.lpVerb = L"open";
 438        sei.lpFile = L"msiexec.exe";
 439        sei.lpParameters = parameters;
 440        sei.nShow = SW_SHOWNORMAL;
 441
 442        /*
 443         * MSDN says it is good practice to always initialize COM before using
 444         * ShellExecuteEx.
 445         */
 446        CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
 447
 448        if (ShellExecuteExW(&sei) && (((intptr_t) (sei.hInstApp)) > 32))
 449        {
 450            if (sei.hProcess)
 451            {
 452                DWORD event;
 453
 454                do
 455                {
 456                    event = WaitForSingleObject(sei.hProcess, INFINITE);
 457                    if (WAIT_FAILED == event)
 458                    {
 459                        error = GetLastError();
 460                        LastError_setLastError(error, _T(__FILE__), __LINE__);
 461                        break;
 462                    }
 463                }
 464                while (WAIT_TIMEOUT == event);
 465                CloseHandle(sei.hProcess);
 466            }
 467        }
 468        else
 469        {
 470            error = GetLastError();
 471            LastError_setLastError(error, _T(__FILE__), __LINE__);
 472        }
 473
 474        free(parameters);
 475    }
 476    else
 477    {
 478        error = ERROR_OUTOFMEMORY;
 479        LastError_setLastError(error, _T(__FILE__), __LINE__);
 480    }
 481    return error;
 482}
 483
 484static DWORD
 485Setup_extractAndExecutePayload(LPVOID ptr, DWORD size)
 486{
 487    TCHAR path[MAX_PATH + 1];
 488    DWORD pathSize = sizeof(path) / sizeof(TCHAR);
 489    DWORD tempPathLength;
 490    DWORD error = ERROR_SUCCESS;
 491
 492    /*
 493     * When this application is to execute in the fashion of xzdec only, it does
 494     * not sound like a nice idea to extract its payload in the TEMP directory
 495     * and the current directory sounds like an acceptable compromise (given
 496     * that it is far more complex to accept the path to extract to as a command
 497     * line argument).
 498     */
 499    if (Setup_xzdec_)
 500    {
 501        path[0] = _T('.');
 502        path[1] = _T('\\');
 503        /*
 504         * It is not necessary to null-terminate path because it will
 505         * automatically be done later in accord with the value of
 506         * tempPathLength.
 507         */
 508        tempPathLength = 2;
 509    }
 510    else
 511        tempPathLength = GetTempPath(pathSize, path);
 512    if (tempPathLength)
 513    {
 514        if (tempPathLength > pathSize)
 515        {
 516            error = ERROR_NOT_ENOUGH_MEMORY;
 517            LastError_setLastError(error, _T(__FILE__), __LINE__);
 518        }
 519        else
 520        {
 521            LPCTSTR fileName = Setup_getFileName();
 522            HANDLE file = INVALID_HANDLE_VALUE;
 523
 524            if (fileName)
 525            {
 526                size_t fileNameLength = _tcslen(fileName);
 527                size_t freePathSize;
 528#ifdef PACKAGECODE
 529                LPCTSTR fileType = _T("bspatch");
 530                BOOL xzdec = FALSE;
 531#else /* #ifdef PACKAGECODE */
 532                LPCTSTR fileType = _T("msi");
 533                BOOL xzdec = TRUE;
 534#endif /* #ifdef PACKAGECODE */
 535
 536                if ((fileNameLength > 4 /* .exe */)
 537                        && ((freePathSize
 538                                    = (pathSize
 539                                        - (tempPathLength
 540                                            + fileNameLength
 541                                            + 1)))
 542                                >= 0))
 543                {
 544                    LPTSTR str = path + tempPathLength;
 545                    size_t fileTypeLength = _tcslen(fileType);
 546
 547                    _tcsncpy(str, fileName, fileNameLength - 4);
 548                    str += (fileNameLength - 4);
 549                    *str = _T('.');
 550                    str++;
 551                    _tcsncpy(str, fileType, 3);
 552                    str += 3;
 553
 554                    /*
 555                     * If possible, use the whole fileType for the extension and
 556                     * not just its first 3 characters.
 557                     */
 558                    fileTypeLength -= 3;
 559                    if ((fileTypeLength > 0)
 560                            && (fileTypeLength <= freePathSize))
 561                    {
 562                        _tcsncpy(str, fileType + 3, fileTypeLength);
 563                        str += fileTypeLength;
 564                    }
 565
 566                    *str = 0;
 567
 568                    file
 569                        = CreateFile(
 570                                path,
 571                                GENERIC_WRITE,
 572                                0,
 573                                NULL,
 574                                CREATE_NEW,
 575                                FILE_ATTRIBUTE_TEMPORARY,
 576                                NULL);
 577                }
 578
 579                if (INVALID_HANDLE_VALUE == file)
 580                {
 581                    LPTSTR tempPath;
 582
 583                    path[tempPathLength] = 0;
 584                    tempPath = _tcsdup(path);
 585
 586                    if (tempPath)
 587                    {
 588                        if (0
 589                                == GetTempFileName(
 590                                        tempPath,
 591                                        fileType,
 592                                        0,
 593                                        path))
 594                        {
 595                            error = GetLastError();
 596                            LastError_setLastError(error, _T(__FILE__), __LINE__);
 597                        }
 598                        else
 599                        {
 600                            file
 601                                = CreateFile(
 602                                        path,
 603                                        GENERIC_WRITE,
 604                                        0,
 605                                        NULL,
 606                                        CREATE_ALWAYS,
 607                                        FILE_ATTRIBUTE_TEMPORARY,
 608                                        NULL);
 609                            if (INVALID_HANDLE_VALUE == file)
 610                            {
 611                                error = GetLastError();
 612                                LastError_setLastError(
 613                                        error,
 614                                        _T(__FILE__), __LINE__);
 615                            }
 616                        }
 617                        free(tempPath);
 618                    }
 619                    else
 620                    {
 621                        error = ERROR_OUTOFMEMORY;
 622                        LastError_setLastError(error, _T(__FILE__), __LINE__);
 623                    }
 624                }
 625
 626                if (INVALID_HANDLE_VALUE != file)
 627                {
 628                    if (xzdec)
 629                        error = Setup_xzdec(ptr, size, file);
 630                    else
 631                    {
 632                        DWORD numberOfBytesWritten;
 633
 634                        if (!WriteFile(
 635                                file,
 636                                ptr, size,
 637                                &numberOfBytesWritten,
 638                                NULL))
 639                        {
 640                            error = GetLastError();
 641                            LastError_setLastError(error, _T(__FILE__), __LINE__);
 642                        }
 643                    }
 644
 645                    /* When executing as xzdec, do not execute the MSI. */
 646                    if ((ERROR_SUCCESS == error) && !Setup_xzdec_)
 647                    {
 648                        if (Setup_waitForParentProcess_)
 649                            Setup_waitForParentProcess();
 650
 651                        CloseHandle(file);
 652                        if (_tcsnicmp(_T("bspatch"), fileType, 3) == 0)
 653                            error = Setup_executeBspatch(path);
 654                        else if (_tcsnicmp(_T("msi"), fileType, 3) == 0)
 655                            error = Setup_executeMsi(path);
 656                        else
 657                        {
 658                            error = ERROR_CALL_NOT_IMPLEMENTED;
 659                            LastError_setLastError(error, _T(__FILE__), __LINE__);
 660                        }
 661                    }
 662                    else
 663                        CloseHandle(file);
 664                    /*
 665                     * Delete the MSI if executing as setup or if executing as
 666                     * xzdec and the extraction has failed (in the fashion of
 667                     * other popular decompressors).
 668                     */
 669                    if (!Setup_xzdec_ || (ERROR_SUCCESS != error))
 670                        DeleteFile(path);
 671                }
 672            }
 673        }
 674    }
 675    else
 676    {
 677        error = GetLastError();
 678        LastError_setLastError(error, _T(__FILE__), __LINE__);
 679    }
 680    return error;
 681}
 682
 683#ifdef PACKAGECODE
 684static LONG
 685Setup_findLocalPackageByProductId(LPCTSTR productId, LPTSTR *localPackage)
 686{
 687    HKEY userDataKey;
 688    LONG error
 689        = RegOpenKeyEx(
 690                HKEY_LOCAL_MACHINE,
 691                _T("Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData"),
 692                0,
 693                KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY,
 694                &userDataKey);
 695
 696    if (ERROR_SUCCESS == error)
 697    {
 698        TCHAR userDataSubKeyName[1024];
 699        const DWORD userDataSubKeyNameCapacity
 700            = sizeof(userDataSubKeyName) / sizeof(TCHAR);
 701        DWORD index = 0;
 702        LPCTSTR products = _T("\\Products\\");
 703        const DWORD productsLength = 10;
 704        const DWORD productIdLength = 32;
 705        LPCTSTR installProperties = _T("\\InstallProperties");
 706        const DWORD installPropertiesLength = 18;
 707        TCHAR installPropertiesKeyName[
 708                userDataSubKeyNameCapacity
 709                    + productsLength
 710                    + productIdLength
 711                    + installPropertiesLength];
 712
 713        *localPackage = NULL;
 714        do
 715        {
 716            DWORD userDataSubKeyNameLength = userDataSubKeyNameCapacity;
 717            LPTSTR str;
 718            HKEY installPropertiesKey;
 719
 720            error
 721                = RegEnumKeyEx(
 722                        userDataKey,
 723                        index,
 724                        userDataSubKeyName, &userDataSubKeyNameLength,
 725                        NULL,
 726                        NULL, NULL,
 727                        NULL);
 728            index++;
 729            if (ERROR_MORE_DATA == error)
 730                continue;
 731            if (ERROR_SUCCESS != error)
 732            {
 733                LastError_setLastError(error, _T(__FILE__), __LINE__);
 734                break;
 735            }
 736
 737            str = installPropertiesKeyName;
 738            _tcsncpy(str, userDataSubKeyName, userDataSubKeyNameLength);
 739            str += userDataSubKeyNameLength;
 740            _tcsncpy(str, products, productsLength);
 741            str += productsLength;
 742            _tcsncpy(str, productId, productIdLength);
 743            str += productIdLength;
 744            _tcsncpy(str, installProperties, installPropertiesLength);
 745            str += installPropertiesLength;
 746            *str = 0;
 747
 748            error
 749                = RegOpenKeyEx(
 750                        userDataKey,
 751                        installPropertiesKeyName,
 752                        0,
 753                        KEY_QUERY_VALUE | KEY_WOW64_64KEY,
 754                        &installPropertiesKey);
 755            if (ERROR_SUCCESS == error)
 756            {
 757                error
 758                    = Run_getRegSzValue(
 759                            installPropertiesKey,
 760                            _T("LocalPackage"),
 761                            localPackage);
 762                /*
 763                 * Reset the value stored at localPackage to NULL in case
 764                 * Run_getRegSzValue has failed but has assigned an invalid
 765                 * value prior to the failure.
 766                 */
 767                if (ERROR_SUCCESS != error)
 768                    *localPackage = NULL;
 769                RegCloseKey(installPropertiesKey);
 770            }
 771        }
 772        while (!(*localPackage));
 773        RegCloseKey(userDataKey);
 774        if ((ERROR_SUCCESS == error) && !(*localPackage))
 775        {
 776            error = ERROR_FILE_NOT_FOUND;
 777            LastError_setLastError(error, _T(__FILE__), __LINE__);
 778        }
 779    }
 780    else
 781        LastError_setLastError(error, _T(__FILE__), __LINE__);
 782    return error;
 783}
 784#endif /* #ifdef PACKAGECODE */
 785
 786#ifdef PACKAGECODE
 787static LONG
 788Setup_findProductIdByPackageCode(LPCTSTR packageCode, LPTSTR *productId)
 789{
 790    HKEY key;
 791    LONG error
 792        = RegOpenKeyEx(
 793                HKEY_LOCAL_MACHINE,
 794                _T("Software\\Classes\\Installer\\Products"),
 795                0,
 796                KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY,
 797                &key);
 798
 799    if (ERROR_SUCCESS == error)
 800    {
 801        TCHAR subKeyName[33];
 802        const DWORD subKeyNameCapacity = sizeof(subKeyName) / sizeof(TCHAR);
 803        DWORD index = 0;
 804
 805        *productId = NULL;
 806        do
 807        {
 808            DWORD subKeyNameLength = subKeyNameCapacity;
 809            HKEY subKey;
 810            LPTSTR packageCodeOfProductId;
 811
 812            error
 813                = RegEnumKeyEx(
 814                        key,
 815                        index,
 816                        subKeyName, &subKeyNameLength,
 817                        NULL,
 818                        NULL, NULL,
 819                        NULL);
 820            index++;
 821            if (ERROR_MORE_DATA == error)
 822                continue;
 823            if (ERROR_SUCCESS != error)
 824            {
 825                LastError_setLastError(error, _T(__FILE__), __LINE__);
 826                break;
 827            }
 828            if (32 != subKeyNameLength)
 829                continue;
 830            error
 831                = RegOpenKeyEx(
 832                        key,
 833                        subKeyName,
 834                        0,
 835                        KEY_QUERY_VALUE | KEY_WOW64_64KEY,
 836                        &subKey);
 837            if (ERROR_SUCCESS != error)
 838            {
 839                LastError_setLastError(error, _T(__FILE__), __LINE__);
 840                break;
 841            }
 842            error
 843                = Run_getRegSzValue(
 844                        subKey,
 845                        _T("PackageCode"),
 846                        &packageCodeOfProductId);
 847            if (ERROR_SUCCESS == error)
 848            {
 849                if (_tcsnicmp(
 850                            packageCodeOfProductId, packageCode,
 851                            subKeyNameLength)
 852                        == 0)
 853                {
 854                    *productId = _tcsdup(subKeyName);
 855                    if (!(*productId))
 856                    {
 857                        error = ERROR_NOT_ENOUGH_MEMORY;
 858                        LastError_setLastError(error, _T(__FILE__), __LINE__);
 859                    }
 860                }
 861                free(packageCodeOfProductId);
 862            }
 863            else
 864                LastError_setLastError(error, _T(__FILE__), __LINE__);
 865            RegCloseKey(subKey);
 866            if (ERROR_SUCCESS != error)
 867                break;
 868        }
 869        while (!(*productId));
 870        RegCloseKey(key);
 871        if ((ERROR_SUCCESS == error) && !(*productId))
 872        {
 873            error = ERROR_FILE_NOT_FOUND;
 874            LastError_setLastError(error, _T(__FILE__), __LINE__);
 875        }
 876    }
 877    else
 878        LastError_setLastError(error, _T(__FILE__), __LINE__);
 879    return error;
 880}
 881#endif /* #ifdef PACKAGECODE */
 882
 883static void
 884Setup_fixCommandLineQuotes()
 885{
 886    LPWSTR readCmdLine = Setup_commandLine;
 887    LPWSTR writeCmdLine = Setup_commandLine;
 888
 889    do
 890    {
 891        LPWSTR arg;
 892
 893        readCmdLine = Setup_getArgW(readCmdLine, &arg);
 894        if (arg)
 895        {
 896            /*
 897             * If the argument has unquoted whitespace, quote the whole
 898             * argument.
 899             */
 900            wchar_t c;
 901            LPWSTR a = arg;
 902            BOOL quoted = FALSE;
 903            BOOL whitespace = FALSE;
 904            size_t argLength;
 905
 906            while ((c = *a))
 907            {
 908                if (iswspace(c))
 909                {
 910                    if (!quoted)
 911                    {
 912                        whitespace = TRUE;
 913                        break;
 914                    }
 915                }
 916                else if (L'\"' == c)
 917                    quoted = quoted ? FALSE : TRUE;
 918                a++;
 919            }
 920
 921            /*
 922             * If the argument is not the first one, separate it from the
 923             * previous one with a space.
 924             */
 925            if (writeCmdLine != Setup_commandLine)
 926            {
 927                *writeCmdLine = L' ';
 928                writeCmdLine++;
 929            }
 930            /* Append the argument to the command line. */
 931            argLength = wcslen(arg);
 932            if (whitespace
 933                    && ((writeCmdLine + (argLength + 1)) < readCmdLine))
 934            {
 935                *writeCmdLine = L'\"';
 936                writeCmdLine++;
 937                wcsncpy(writeCmdLine, arg, argLength);
 938                writeCmdLine += argLength;
 939                *writeCmdLine = L'\"';
 940                writeCmdLine++;
 941            }
 942            else
 943            {
 944                wcsncpy(writeCmdLine, arg, argLength);
 945                writeCmdLine += argLength;
 946            }
 947        }
 948        else
 949            break;
 950    }
 951    while (1);
 952    /* At long last, terminate the command line. */
 953    *writeCmdLine = 0;
 954}
 955
 956static LPWSTR
 957Setup_getArgW(LPWSTR commandLine, LPWSTR *value)
 958{
 959    if (commandLine)
 960    {
 961        LPWSTR v;
 962        size_t quoted;
 963        wchar_t prevC;
 964        wchar_t c;
 965
 966        /* Obviously, any leading whitespace is not a part of an argument. */
 967        commandLine = Setup_skipWhitespaceW(commandLine);
 968        v = commandLine;
 969
 970        quoted = 0;
 971        prevC = 0;
 972        while ((c = *commandLine))
 973        {
 974            if (iswspace(c))
 975            {
 976                if (!quoted)
 977                    break;
 978            }
 979            else if (L'\"' == c)
 980            {
 981                if (quoted)
 982                {
 983                    /*
 984                     * Quotes cannot simply be nested but the Java
 985                     * ProcessBuilder does nest them (in cases in which nesting
 986                     * is not even necessary) so try to deal with them. Clearly,
 987                     * the implementation will be heuristic in nature.
 988                     */
 989                    wchar_t nextC;
 990
 991                    if ((1 == quoted)
 992                            && ((nextC = *(commandLine + 1)))
 993                            && !iswspace(nextC)
 994                            && ((L'=' == prevC)
 995                                    || ((L'\"' == prevC)
 996                                            && (v + 1 == commandLine))))
 997                        quoted++;
 998                    else
 999                        quoted--;
1000                }
1001                else
1002                    quoted = 1;
1003            }
1004            prevC = c;
1005            commandLine++;
1006        }
1007        /*
1008         * If there are more arguments, get rid of any whitespace before them.
1009         */
1010        if (c)
1011        {
1012            LPWSTR vEnd = commandLine;
1013
1014            commandLine = Setup_skipWhitespaceW(commandLine);
1015            *vEnd = 0;
1016        }
1017        /*
1018         * If the argument is quoted, drop the quotes. Since the Java
1019         * ProcessBuilder will quote even the quoted command line arguments,
1020         * drop as many quotes as possible.
1021         */
1022        while (L'\"' == *v)
1023        {
1024            size_t vLength = wcslen(v);
1025
1026            if (vLength > 1)
1027            {
1028                LPWSTR vEnd = v + (vLength - 1);
1029
1030                if (L'\"' == *vEnd)
1031                {
1032                    /*
1033                     * Convert the opening quote to a whitespace character (just
1034                     * in case) and the closing quote to the null character (in
1035                     * order to terminate the argument).
1036                     */
1037                    *v = L' ';
1038                    v++;
1039                    *vEnd = 0;
1040                }
1041            }
1042        }
1043
1044        if (value)
1045            *value = *v ? v : NULL;
1046    }
1047    else
1048    {
1049        if (value)
1050            *value = NULL;
1051    }
1052    return commandLine;
1053}
1054
1055#define DEFINE_SETUP_GETBOOLARG(f, t, len, nicmp) \
1056    static LP ## t \
1057    Setup_getBoolArg ## f (LPC ## t argName, LP ## t commandLine, BOOL *boolValue) \
1058    { \
1059        size_t argNameLength; \
1060        BOOL argValue; \
1061     \
1062        argNameLength = len(argName); \
1063        commandLine = Setup_skipWhitespace ## f (commandLine); \
1064        if (0 == nicmp(commandLine, argName, argNameLength)) \
1065        { \
1066            argValue = TRUE; \
1067            commandLine = Setup_skipWhitespace ## f (commandLine + argNameLength); \
1068        } \
1069        else \
1070            argValue = FALSE; \
1071        if (boolValue) \
1072            *boolValue = argValue; \
1073        return commandLine; \
1074    }
1075#ifdef _UNICODE
1076#undef _UNICODE
1077DEFINE_SETUP_GETBOOLARG(A, STR, strlen, _strnicmp)
1078#define _UNICODE
1079DEFINE_SETUP_GETBOOLARG(W, WSTR, wcslen, _wcsnicmp)
1080#else /* #ifdef _UNICODE */
1081DEFINE_SETUP_GETBOOLARG(A, STR, strlen, _strnicmp)
1082#define _UNICODE
1083DEFINE_SETUP_GETBOOLARG(W, WSTR, wcslen, _wcsnicmp)
1084#undef _UNICODE
1085#endif /* #ifdef _UNICODE */
1086
1087static LPCTSTR
1088Setup_getFileName()
1089{
1090    if (!Setup_fileName)
1091    {
1092        TCHAR moduleFileName[MAX_PATH + 1];
1093        DWORD moduleFileNameSize = sizeof(moduleFileName) / sizeof(TCHAR);
1094        DWORD moduleFileNameLength
1095            = GetModuleFileName(NULL, moduleFileName, moduleFileNameSize);
1096
1097        if (moduleFileNameLength)
1098        {
1099            TCHAR *fileNameEnd = moduleFileName + moduleFileNameLength - 1;
1100            TCHAR *fileNameBegin = fileNameEnd;
1101            size_t fileNameLength;
1102            LPTSTR fileName;
1103
1104            for (; fileNameBegin >= moduleFileName; fileNameBegin--)
1105            {
1106                TCHAR c = *fileNameBegin;
1107
1108                if ((_T('\\') == c) || (_T('/') == c))
1109                    break;
1110            }
1111            fileNameBegin
1112                = (fileNameBegin == fileNameEnd)
1113                    ? moduleFileName
1114                    : (fileNameBegin + 1);
1115
1116            fileNameLength = (fileNameEnd - fileNameBegin) + 1;
1117            fileName = (LPTSTR) malloc((fileNameLength + 1) * sizeof(TCHAR));
1118            if (fileName)
1119            {
1120                _tcsncpy(fileName, fileNameBegin, fileNameLength);
1121                *(fileName + fileNameLength) = 0;
1122                Setup_fileName = fileName;
1123            }
1124        }
1125    }
1126    return Setup_fileName;
1127}
1128
1129static DWORD
1130Setup_getParentProcess(DWORD *ppid, LPTSTR *fileName)
1131{
1132    HANDLE snapshot;
1133    DWORD error;
1134
1135    snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1136    if (snapshot == INVALID_HANDLE_VALUE)
1137    {
1138        error = GetLastError();
1139        LastError_setLastError(error, _T(__FILE__), __LINE__);
1140    }
1141    else
1142    {
1143        PROCESSENTRY32 entry;
1144
1145        entry.dwSize = sizeof(PROCESSENTRY32);
1146        if (Process32First(snapshot, &entry))
1147        {
1148            DWORD pid;
1149
1150            error = ERROR_SUCCESS;
1151            pid = GetCurrentProcessId();
1152            if (ppid)
1153                *ppid = 0;
1154
1155            do
1156            {
1157                if (entry.th32ProcessID == pid)
1158                {
1159                    if (ppid)
1160                        *ppid = entry.th32ParentProcessID;
1161                    break;
1162                }
1163                if (!Process32Next(snapshot, &entry))
1164                {
1165                    error = GetLastError();
1166                    LastError_setLastError(error, _T(__FILE__), __LINE__);
1167                    break;
1168                }
1169            }
1170            while (1);
1171        }
1172        else
1173        {
1174            error = GetLastError();
1175            LastError_setLastError(error, _T(__FILE__), __LINE__);
1176        }
1177        if ((ERROR_SUCCESS == error) && fileName && ppid && *ppid)
1178        {
1179            if (Process32First(snapshot, &entry))
1180            {
1181                do
1182                {
1183                    if (entry.th32ProcessID == *ppid)
1184                    {
1185                        *fileName = _tcsdup(entry.szExeFile);
1186                        if (NULL == *fileName)
1187                        {
1188                            error = ERROR_OUTOFMEMORY;
1189                            LastError_setLastError(error, _T(__FILE__), __LINE__);
1190                        }
1191                        break;
1192                    }
1193                    if (!Process32Next(snapshot, &entry))
1194                    {
1195                        error = GetLastError();
1196                        LastError_setLastError(error, _T(__FILE__), __LINE__);
1197                        break;
1198                    }
1199                }
1200                while (1);
1201            }
1202            else
1203            {
1204                error = GetLastError();
1205                LastError_setLastError(error, _T(__FILE__), __LINE__);
1206            }
1207        }
1208        CloseHandle(snapshot);
1209    }
1210    return error;
1211}
1212
1213static LPCTSTR
1214Setup_getProductName()
1215{
1216    if (!Setup_productName)
1217    {
1218        LPCTSTR fileName = Setup_getFileName();
1219
1220        if (fileName)
1221        {
1222            int fileNameLength = _tcslen(fileName);
1223
1224            if ((fileNameLength > 4)
1225                    && (_tcsnicmp(fileName + fileNameLength - 4, _T(".exe"), 4)
1226                            == 0))
1227            {
1228                LPTSTR productName;
1229
1230                fileNameLength -= 4;
1231                productName
1232                    = (LPTSTR) malloc((fileNameLength + 1) * sizeof(TCHAR));
1233                if (productName)
1234                {
1235                    _tcsncpy(productName, fileName, fileNameLength);
1236                    *(productName + fileNameLength) = 0;
1237                    Setup_productName = productName;
1238                }
1239            }
1240            if (!Setup_productName)
1241                Setup_productName = (LPTSTR) fileName;
1242        }
1243    }
1244    return Setup_productName;
1245}
1246
1247static DWORD
1248Setup_getWinMainCmdLine(LPTSTR *winMainCmdLine)
1249{
1250    LPWSTR cmdLineW = GetCommandLineW();
1251    DWORD error;
1252
1253    if (cmdLineW && wcslen(cmdLineW))
1254    {
1255        int argc;
1256        LPWSTR *argvW = CommandLineToArgvW(cmdLineW, &argc);
1257
1258        if (argvW)
1259        {
1260            if (argc)
1261            {
1262                LPWSTR argvW0 = argvW[0];
1263                LPWSTR argvW0InCmdLineW = wcsstr(cmdLineW, argvW0);
1264
1265                if (argvW0InCmdLineW)
1266                {
1267                    wchar_t c;
1268
1269                    cmdLineW = argvW0InCmdLineW + wcslen(argvW0);
1270                    /*
1271                     * CommandLineToArgvW may not report quotes as part of
1272                     * argvW0. As a workaround, skip non-whitespace characters.
1273                     */
1274                    while ((c = *cmdLineW) && !iswspace(c))
1275                        cmdLineW++;
1276                }
1277#ifdef _UNICODE
1278                *winMainCmdLine = cmdLineW;
1279                error = ERROR_SUCCESS;
1280#else /* #ifdef _UNICODE */
1281                *winMainCmdLine = NLS_wstr2str(cmdLineW);
1282                if (*winMainCmdLine)
1283                    error = ERROR_SUCCESS;
1284                else
1285                {
1286                    error = ERROR_GEN_FAILURE;
1287                    LastError_setLastError(error, _T(__FILE__), __LINE__);
1288                }
1289#endif /* #ifdef _UNICODE */
1290            }
1291            else
1292            {
1293                *winMainCmdLine = NULL;
1294                error = ERROR_SUCCESS;
1295            }
1296            LocalFree(argvW);
1297        }
1298        else
1299        {
1300            error = GetLastError();
1301            LastError_setLastError(error, _T(__FILE__), __LINE__);
1302        }
1303    }
1304    else
1305    {
1306        *winMainCmdLine = NULL;
1307        error = ERROR_SUCCESS;
1308    }
1309    return error;
1310}
1311
1312static int
1313Setup_isWow64Acceptable()
1314{
1315    int answer = IDYES;
1316    HMODULE kernel32;
1317
1318    /*
1319     * If this is an (automatic) update, do not ask because (1) the user has
1320     * already answered during the initial install and (2) it is plain annoying.
1321     */
1322    if (Setup_commandLine
1323            && wcsstr(
1324                    Setup_commandLine,
1325                    SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR_PROPERTY_BEGIN))
1326        return answer;
1327
1328    kernel32 = GetModuleHandle(_T("kernel32"));
1329    if (kernel32)
1330    {
1331        typedef BOOL (WINAPI *LPISWOW64PROCESS)(HANDLE, PBOOL);
1332
1333        LPISWOW64PROCESS isWow64Process
1334            = (LPISWOW64PROCESS) GetProcAddress(kernel32, "IsWow64Process");
1335        BOOL wow64Process = FALSE;
1336
1337        if (isWow64Process
1338                && isWow64Process(GetCurrentProcess(), &wow64Process)
1339                && wow64Process)
1340        {
1341            TCHAR fileName[MAX_PATH + 1];
1342
1343            if (GetModuleFileName(NULL, fileName, sizeof(fileName) / sizeof(TCHAR)))
1344            {
1345                UINT questionId;
1346                UINT buttonType;
1347                DWORD questionLength;
1348                TCHAR question[1024];
1349
1350#ifdef X64_SETUP_URL
1351                HHOOK hook
1352                    = SetWindowsHookEx(
1353                            WH_CALLWNDPROCRET,
1354                            (HOOKPROC) Setup_isWow64AcceptableMessageBoxCallWndRetProc,
1355                            NULL,
1356                            GetCurrentThreadId());
1357
1358                if (hook)
1359                {
1360                    questionId = IDS_ISWOW64ACCEPTABLE3;
1361                    buttonType = MB_YESNOCANCEL | MB_DEFBUTTON3;
1362                }
1363                else
1364#endif /* #ifdef X64_SETUP_URL */
1365                {
1366                    questionId = IDS_ISWOW64ACCEPTABLE2;
1367                    buttonType = MB_YESNO;
1368                }
1369
1370                questionLength
1371                    = LoadString(
1372                            GetModuleHandle(NULL),
1373                            questionId,
1374                            question,
1375                            sizeof(question) / sizeof(TCHAR));
1376                if (questionLength)
1377                {
1378                    answer
1379                        = MessageBox(
1380                                NULL,
1381                                question,
1382                                fileName,
1383                                MB_ICONQUESTION | buttonType);
1384                    LocalFree(question);
1385                }
1386
1387#ifdef X64_SETUP_URL
1388                if (hook)
1389                {
1390                    UnhookWindowsHookEx(hook);
1391
1392                    switch (answer)
1393                    {
1394                    case IDNO: // Continue
1395                        answer = IDYES;
1396                        break;
1397                    case IDYES: // Download
1398                        answer = IDNO;
1399                        ShellExecute(
1400                                NULL,
1401                                _T("open"),
1402                                _T(X64_SETUP_URL),
1403                                NULL,
1404                                NULL,
1405                                SW_SHOWNORMAL);
1406                        break;
1407                    }
1408                }
1409#endif /* #ifdef X64_SETUP_URL */
1410            }
1411        }
1412    }
1413    return answer;
1414}
1415
1416LRESULT CALLBACK
1417Setup_isWow64AcceptableMessageBoxCallWndRetProc(
1418        int code,
1419        WPARAM wParam,
1420        LPARAM lParam)
1421{
1422    CWPRETSTRUCT *cwprs = (CWPRETSTRUCT *) lParam;
1423
1424    if (cwprs && (WM_INITDIALOG == cwprs->message))
1425    {
1426        HWND yes, no;
1427
1428        yes = GetDlgItem(cwprs->hwnd, IDYES);
1429        if (yes)
1430            SendMessage(yes, WM_SETTEXT, 0, (LPARAM) _T("&Download"));
1431
1432        no = GetDlgItem(cwprs->hwnd, IDNO);
1433        if (no)
1434            SendMessage(no, WM_SETTEXT, 0, (LPARAM) _T("&Continue"));
1435    }
1436    return CallNextHookEx(NULL, code, wParam, lParam);
1437}
1438
1439static DWORD
1440Setup_msiexec()
1441{
1442    LPWSTR msi;
1443    DWORD error;
1444
1445    Setup_commandLine = Setup_getArgW(Setup_commandLine, &msi);
1446    if (msi)
1447        error = Setup_executeMsiW(msi);
1448    else
1449    {
1450        error = ERROR_BAD_ARGUMENTS;
1451        LastError_setLastError(error, _T(__FILE__), __LINE__);
1452    }
1453    return error;
1454}
1455
1456static DWORD
1457Setup_parseCommandLine(LPTSTR cmdLine)
1458{
1459    LPTSTR commandLine;
1460    DWORD error = ERROR_SUCCESS;
1461
1462//#ifdef _UNICODE
1463//    if (cmdLine)
1464//    {
1465//        commandLine = NLS_str2wstr(cmdLine);
1466//        if (!commandLine)
1467//        {
1468//            error = ERROR_OUTOFMEMORY;
1469//            LastError_setLastError(error, _T(__FILE__), __LINE__);
1470//        }
1471//    }
1472//    else
1473//        commandLine = NULL;
1474//#else
1475    commandLine = cmdLine;
1476//#endif /* #ifdef _UNICODE */
1477
1478    if (commandLine)
1479    {
1480        LPTSTR noWaitParentCommandLine
1481            = Setup_getBoolArg(
1482                    _T("--wait-parent"),
1483                    commandLine,
1484                    &Setup_waitForParentProcess_);
1485        /*
1486         * The command line argument --allow-elevation is up2date legacy which
1487         * has to be taken into account by removing it in order to prevent it
1488         * from breaking msiexec.
1489         */
1490        BOOL up2date;
1491        LPTSTR noAllowElevationCommandLine
1492            = Setup_getBoolArg(
1493                    _T("--allow-elevation"),
1494                    noWaitParentCommandLine,
1495                    &up2date);
1496        size_t noAllowElevationCommandLineLength
1497            = _tcslen(noAllowElevationCommandLine);
1498        TCHAR envVarValue[1 /* " */ + MAX_PATH + 1 /* " */ + 1];
1499
1500        /*
1501         * If there are no arguments on the command line to reveal that up2date
1502         * is involved, try detecting it by the fact that it sets the
1503         * SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR environment variable. If the
1504         * environment variable in question is not set, it is sure that this
1505         * setup is to execute its post-up2date logic.
1506         */
1507        if (!up2date && !noAllowElevationCommandLineLength)
1508        {
1509            DWORD envVarValueSize
1510                = (sizeof(envVarValue) / sizeof(TCHAR)) - 2 /* "" */;
1511            DWORD envVarValueLength
1512                = GetEnvironmentVariable(
1513                        _T("SIP_COMMUNICATOR_AUTOUPDATE_INSTALLDIR"),
1514                        &(envVarValue[1]),
1515                        envVarValueSize);
1516
1517            if (envVarValueLength)
1518            {
1519                if (envVarValueLength > envVarValueSize)
1520                {
1521                    error = ERROR_NOT_ENOUGH_MEMORY;
1522                    LastError_

Large files files are truncated, but you can click here to view the full file