PageRenderTime 72ms CodeModel.GetById 28ms 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
Possible License(s): BSD-3-Clause, LGPL-2.1

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

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