Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2658 lines
64 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. Dufns.cpp
  5. Abstract:
  6. Functions used throughout the app.
  7. Notes:
  8. Unicode only.
  9. History:
  10. 03/02/2001 rparsons Created
  11. --*/
  12. #include "precomp.h"
  13. extern SETUP_INFO g_si;
  14. /*++
  15. Routine Description:
  16. Parses the command line and fills in our
  17. structure that contains app-related data
  18. Arguments:
  19. None
  20. Return Value:
  21. TRUE on success, FALSE otherwise
  22. --*/
  23. BOOL
  24. ParseCommandLine()
  25. {
  26. int nArgc = 0;
  27. int nCount = 0;
  28. LPWSTR *lpwCommandLine = NULL;
  29. //
  30. // Initialize structure members to defaults
  31. //
  32. g_si.fQuiet = FALSE;
  33. g_si.fInstall = TRUE;
  34. g_si.fForceInstall = FALSE;
  35. g_si.nErrorLevel = ERROR;
  36. g_si.fNoReboot = FALSE;
  37. g_si.fNoUninstall = FALSE;
  38. g_si.fNeedToAdjustACL = FALSE;
  39. g_si.fOnWin2K = FALSE;
  40. g_si.fUpdateDllCache = TRUE;
  41. g_si.fCanUninstall = TRUE;
  42. g_si.nErrorLevel = ERROR;
  43. //
  44. // Get the command line
  45. //
  46. lpwCommandLine = CommandLineToArgvW(GetCommandLine(), &nArgc);
  47. if (NULL == lpwCommandLine) {
  48. return FALSE;
  49. }
  50. for (nCount = 1; nCount < nArgc; nCount++) {
  51. if ((lpwCommandLine[nCount][0] == L'-') ||
  52. (lpwCommandLine[nCount][0] == L'/')) {
  53. switch (lpwCommandLine[nCount][1]) {
  54. case 'q':
  55. case 'Q':
  56. g_si.fQuiet = TRUE;
  57. break;
  58. case 'i':
  59. case 'I':
  60. g_si.fInstall = TRUE;
  61. break;
  62. case 'u':
  63. case 'U':
  64. g_si.fInstall = FALSE;
  65. break;
  66. case 'f':
  67. case 'F':
  68. g_si.fForceInstall = TRUE;
  69. break;
  70. case 'd':
  71. case 'D':
  72. g_si.nErrorLevel = TRACE;
  73. break;
  74. case 'z':
  75. case 'Z':
  76. g_si.fNoReboot = TRUE;
  77. break;
  78. case 'n':
  79. case 'N':
  80. g_si.fNoUninstall = TRUE;
  81. break;
  82. }
  83. }
  84. }
  85. GlobalFree(lpwCommandLine);
  86. return TRUE;
  87. }
  88. /*++
  89. Routine Description:
  90. Determines if another instance of the
  91. application is running
  92. Arguments:
  93. lpwInstanceName - Name of the instance to look for
  94. Return Value:
  95. TRUE if another instance is present, FALSE otherwise
  96. --*/
  97. BOOL
  98. IsAnotherInstanceRunning(
  99. IN LPCWSTR lpwInstanceName
  100. )
  101. {
  102. HANDLE hMutex = NULL;
  103. DWORD dwLastError = 0;
  104. //
  105. // Attempt to create a mutex with the given name
  106. //
  107. hMutex = CreateMutex(NULL, FALSE, lpwInstanceName);
  108. if (NULL != hMutex) {
  109. //
  110. // See if it was created by another instance
  111. //
  112. dwLastError = GetLastError();
  113. if (ERROR_ALREADY_EXISTS == dwLastError) {
  114. CloseHandle(hMutex);
  115. return TRUE;
  116. } else {
  117. CloseHandle(hMutex);
  118. return FALSE;
  119. }
  120. }
  121. return FALSE;
  122. }
  123. /*++
  124. Routine Description:
  125. Obtains the path that the EXE is currently
  126. running from. This memory is allocated
  127. with the MALLOC macro and should be released
  128. with the FREE macro
  129. Arguments:
  130. None
  131. Return Value:
  132. On success, a pointer to our current directory
  133. On failure, NULL
  134. The directory path will not contain a trailing
  135. backslash
  136. --*/
  137. LPWSTR
  138. GetCurWorkingDirectory()
  139. {
  140. WCHAR wszFullPath[MAX_PATH];
  141. LPWSTR lpwEnd = NULL, lpwReturn = NULL;
  142. DWORD dwLen = 0;
  143. //
  144. // Retrieve the full path where we're running from
  145. //
  146. dwLen = GetModuleFileName(NULL, wszFullPath, MAX_PATH);
  147. if (dwLen <= 0) {
  148. return NULL;
  149. }
  150. //
  151. // Allocate memory and store the path
  152. //
  153. lpwReturn = (LPWSTR) MALLOC((wcslen(wszFullPath)+1)*sizeof(WCHAR));
  154. if (NULL == lpwReturn) {
  155. return NULL;
  156. }
  157. wcscpy(lpwReturn, wszFullPath);
  158. //
  159. // Find the last backslash
  160. //
  161. lpwEnd = wcsrchr(lpwReturn, '\\');
  162. if (NULL == lpwEnd) {
  163. return NULL;
  164. }
  165. //
  166. // Trim off the EXE name
  167. //
  168. if (lpwEnd){
  169. *lpwEnd = '\0';
  170. }
  171. return (lpwReturn);
  172. }
  173. /*++
  174. Routine Description:
  175. Obtains a non-string value from the given
  176. INF file
  177. Arguments:
  178. hInf - Handle to the INF
  179. lpSectionName - Name of the section
  180. lpKeyName - Name of the key
  181. pdwValue - Receives the value
  182. Return Value:
  183. TRUE on success, FALSE otherwise
  184. --*/
  185. BOOL
  186. GetInfValue(
  187. IN HINF hInf,
  188. IN LPCSTR lpSectionName,
  189. IN LPCSTR lpKeyName,
  190. OUT PDWORD pdwValue
  191. )
  192. {
  193. BOOL fReturn = FALSE;
  194. char szBuffer[MAX_PATH] = "";
  195. fReturn = SetupGetLineTextA(NULL,
  196. hInf,
  197. lpSectionName,
  198. lpKeyName,
  199. szBuffer,
  200. sizeof(szBuffer),
  201. NULL);
  202. *pdwValue = strtoul(szBuffer, NULL, 0);
  203. return (fReturn);
  204. }
  205. /*++
  206. Routine Description:
  207. Determines if the user is an administrator
  208. Arguments:
  209. None
  210. Return Value:
  211. -1 on failure
  212. 1 if the user is an admin
  213. 0 if they are not
  214. --*/
  215. int
  216. IsUserAnAdministrator()
  217. {
  218. HANDLE hToken;
  219. DWORD dwStatus = 0, dwAccessMask = 0;
  220. DWORD dwAccessDesired = 0, dwACLSize = 0;
  221. DWORD dwStructureSize = sizeof(PRIVILEGE_SET);
  222. PACL pACL = NULL;
  223. PSID psidAdmin = NULL;
  224. BOOL fReturn = FALSE;
  225. int nReturn = -1;
  226. PRIVILEGE_SET ps;
  227. GENERIC_MAPPING GenericMapping;
  228. PSECURITY_DESCRIPTOR psdAdmin = NULL;
  229. SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
  230. __try {
  231. // AccessCheck() requires an impersonation token
  232. if (!ImpersonateSelf(SecurityImpersonation)) {
  233. __leave;
  234. }
  235. // Attempt to access the token for the current thread
  236. if (!OpenThreadToken(GetCurrentThread(),
  237. TOKEN_QUERY,
  238. FALSE,
  239. &hToken)) {
  240. if (GetLastError() != ERROR_NO_TOKEN) {
  241. __leave;
  242. }
  243. // If the thread does not have an access token, we'll
  244. // examine the access token associated with the process.
  245. if (!OpenProcessToken(GetCurrentProcess(),
  246. TOKEN_QUERY,
  247. &hToken)) __leave;
  248. }
  249. // Build a SID for administrators group
  250. if (!AllocateAndInitializeSid(&SystemSidAuthority,
  251. 2,
  252. SECURITY_BUILTIN_DOMAIN_RID,
  253. DOMAIN_ALIAS_RID_ADMINS,
  254. 0, 0, 0, 0, 0, 0,
  255. &psidAdmin)) __leave;
  256. // Allocate memory for the security descriptor
  257. psdAdmin = MALLOC(SECURITY_DESCRIPTOR_MIN_LENGTH);
  258. if (psdAdmin == NULL) {
  259. __leave;
  260. }
  261. // Initialize the new security descriptor
  262. if (!InitializeSecurityDescriptor(psdAdmin,
  263. SECURITY_DESCRIPTOR_REVISION)) {
  264. __leave;
  265. }
  266. // Compute size needed for the ACL
  267. dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) +
  268. GetLengthSid(psidAdmin) - sizeof(DWORD);
  269. // Allocate memory for ACL
  270. pACL = (PACL) MALLOC(dwACLSize);
  271. if (pACL == NULL) {
  272. __leave;
  273. }
  274. // Initialize the new ACL
  275. if (!InitializeAcl(pACL,
  276. dwACLSize,
  277. ACL_REVISION2)) {
  278. __leave;
  279. }
  280. dwAccessMask = ACCESS_READ | ACCESS_WRITE;
  281. // Add the access-allowed ACE to the DACL
  282. if (!AddAccessAllowedAce(pACL,
  283. ACL_REVISION2,
  284. dwAccessMask,
  285. psidAdmin)) {
  286. __leave;
  287. }
  288. // Set our DACL to the security descriptor
  289. if (!SetSecurityDescriptorDacl(psdAdmin,
  290. TRUE,
  291. pACL,
  292. FALSE)) {
  293. __leave;
  294. }
  295. // AccessCheck is sensitive about the format of the
  296. // security descriptor; set the group & owner
  297. SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE);
  298. SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE);
  299. // Ensure that the SD is valid
  300. if (!IsValidSecurityDescriptor(psdAdmin)) {
  301. __leave;
  302. }
  303. dwAccessDesired = ACCESS_READ;
  304. // Initialize GenericMapping structure even though we
  305. // won't be using generic rights.
  306. GenericMapping.GenericRead = ACCESS_READ;
  307. GenericMapping.GenericWrite = ACCESS_WRITE;
  308. GenericMapping.GenericExecute = 0;
  309. GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE;
  310. // After all that work, it boils down to this call
  311. if (!AccessCheck(psdAdmin,
  312. hToken,
  313. dwAccessDesired,
  314. &GenericMapping,
  315. &ps,
  316. &dwStructureSize,
  317. &dwStatus,
  318. &fReturn)) {
  319. __leave;
  320. }
  321. RevertToSelf();
  322. // Everything was a success
  323. nReturn = (int) fReturn;
  324. } // try
  325. __finally {
  326. if (pACL) {
  327. FREE(pACL);
  328. }
  329. if (psdAdmin){
  330. FREE(psdAdmin);
  331. }
  332. if (psidAdmin){
  333. FreeSid(psidAdmin);
  334. }
  335. } // finally
  336. return (nReturn);
  337. }
  338. /*++
  339. Routine Description:
  340. Gets the amount of available disk space
  341. on the drive that contains the Windows
  342. system files (boot partition)
  343. Arguments:
  344. None
  345. Return Value:
  346. A 64-bit value containing the free space
  347. available on success, 0 on failure
  348. --*/
  349. DWORDLONG
  350. GetDiskSpaceFreeOnNTDrive()
  351. {
  352. UINT nLen = 0;
  353. BOOL fUseHeap = FALSE, fReturn = FALSE;
  354. WCHAR wszSysDir[MAX_PATH] = L"";
  355. WCHAR wszDiskName[4] = {'x',':','\\','\0'};
  356. LPWSTR lpwSysDir = NULL;
  357. DWORDLONG dwlReturn = 0;
  358. unsigned __int64 i64FreeBytesToCaller = 0,
  359. i64TotalBytes = 0,
  360. i64TotalFreeBytes = 0;
  361. nLen = GetSystemDirectory(wszSysDir, MAX_PATH);
  362. if (0 == nLen) {
  363. return 0;
  364. }
  365. if (nLen > MAX_PATH) {
  366. //
  367. // Allocate a buffer that will hold the return
  368. //
  369. lpwSysDir = (LPWSTR) MALLOC(nLen*sizeof(WCHAR));
  370. if (NULL == lpwSysDir) {
  371. return 0;
  372. }
  373. GetSystemDirectory(lpwSysDir, nLen*sizeof(WCHAR));
  374. fUseHeap = TRUE;
  375. }
  376. if (!fUseHeap) {
  377. wszDiskName[0] = wszSysDir[0];
  378. } else {
  379. wszDiskName[0] = lpwSysDir[0];
  380. }
  381. fReturn = GetDiskFreeSpaceEx(wszDiskName,
  382. (PULARGE_INTEGER) &i64FreeBytesToCaller,
  383. (PULARGE_INTEGER) &i64TotalBytes,
  384. (PULARGE_INTEGER) &i64TotalFreeBytes);
  385. if (FALSE == fReturn) {
  386. return 0;
  387. }
  388. //
  389. // Calculate free MBs on drive
  390. //
  391. dwlReturn = i64FreeBytesToCaller / 0x100000;
  392. if (lpwSysDir) {
  393. FREE(lpwSysDir);
  394. }
  395. return (dwlReturn);
  396. }
  397. /*++
  398. Routine Description:
  399. Displays a formated error to the screen
  400. Arguments:
  401. hWnd - Handle to the parent window
  402. dwMessageId - Message identifier
  403. lpwMessageArray - An array of insertion strings
  404. Return Value:
  405. TRUE on success, FALSE otherwise
  406. --*/
  407. BOOL
  408. DisplayErrMsg(
  409. IN HWND hWnd,
  410. IN DWORD dwMessageId,
  411. IN LPWSTR lpwMessageArray
  412. )
  413. {
  414. LPVOID lpMsgBuf = NULL;
  415. DWORD dwReturn = 0;
  416. int nReturn = 0;
  417. WCHAR wszError[MAX_PATH] = L"";
  418. dwReturn = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
  419. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  420. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  421. g_si.hInstance,
  422. dwMessageId,
  423. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  424. (LPWSTR) &lpMsgBuf,
  425. 0,
  426. (va_list*) lpwMessageArray);
  427. if (0 == dwReturn) {
  428. //
  429. // We can't let it go without displaying an error message
  430. // to the user
  431. //
  432. nReturn = LoadString(g_si.hInstance,
  433. IDS_FORMAT_MESSAGE_FAILED,
  434. wszError,
  435. MAX_PATH);
  436. if (0 == nReturn) {
  437. //
  438. // Major problems - can't pull a string from the EXE
  439. //
  440. MessageBox(hWnd,
  441. LOAD_STRING_FAILED,
  442. g_si.lpwMessageBoxTitle,
  443. MB_OK | MB_ICONERROR);
  444. return FALSE;
  445. }
  446. MessageBox(hWnd,
  447. wszError,
  448. g_si.lpwMessageBoxTitle,
  449. MB_OK | MB_ICONERROR);
  450. return FALSE;
  451. }
  452. //
  453. // Display the intended message to the user
  454. //
  455. MessageBox(hWnd,
  456. (LPCWSTR) lpMsgBuf,
  457. g_si.lpwMessageBoxTitle,
  458. MB_OK | MB_ICONERROR);
  459. LocalFree(lpMsgBuf);
  460. return TRUE;
  461. }
  462. /*++
  463. Routine Description:
  464. Given a version string, convert it to a long DWORD. This string will
  465. be in the form of aa,bb,cc,dd
  466. Arguments:
  467. lpwVersionString - The string to convert
  468. lpVersionNumber - Receives the converted version
  469. Return Value:
  470. TRUE on success, FALSE otherwise
  471. --*/
  472. BOOL
  473. VersionStringToNumber(
  474. IN LPCWSTR lpwVersionString,
  475. IN OUT DWORDLONG *lpVersionNumber
  476. )
  477. {
  478. DWORDLONG dwVersion = 0;
  479. DWORD dwSubVersion;
  480. int nIndex;
  481. for (nIndex = 0; nIndex < 4; nIndex++) {
  482. if (*lpwVersionString == '\0') {
  483. return FALSE;
  484. }
  485. dwSubVersion = 0;
  486. while ((*lpwVersionString >= '0') && (*lpwVersionString <= '9')) {
  487. dwSubVersion *= 10;
  488. dwSubVersion += ( *lpwVersionString - '0' );
  489. if (dwSubVersion > 0x0000FFFF) {
  490. return FALSE;
  491. }
  492. lpwVersionString++;
  493. }
  494. if (*lpwVersionString == ',') {
  495. lpwVersionString++;
  496. } else if (*lpwVersionString != '\0') {
  497. return FALSE;
  498. }
  499. dwVersion <<= 16;
  500. dwVersion += dwSubVersion;
  501. }
  502. if (lpVersionNumber != NULL) {
  503. *lpVersionNumber = dwVersion;
  504. }
  505. return TRUE;
  506. }
  507. /*++
  508. Routine Description:
  509. Converts a UNICODE string to an ANSI one
  510. Arguments:
  511. lpwUnicodeString - The UNICODE string
  512. lpAnsiString - Receives the ANSI string
  513. nLen - The size of the ANSI buffer
  514. Return Value:
  515. None
  516. --*/
  517. void
  518. pUnicodeToAnsi(
  519. IN LPCWSTR lpwUnicodeString,
  520. IN OUT LPSTR lpAnsiString,
  521. IN int nLen
  522. )
  523. {
  524. WideCharToMultiByte(CP_ACP,
  525. 0,
  526. lpwUnicodeString,
  527. -1,
  528. lpAnsiString,
  529. nLen,
  530. NULL,
  531. NULL);
  532. return;
  533. }
  534. /*++
  535. Routine Description:
  536. Converts an ANSI string to a UNICODE one
  537. Arguments:
  538. lpAnsiString - The ANSI string
  539. lpwUnicodeString - Receives the UNICODE string
  540. nLen - The size of the UNICODE buffer
  541. Return Value:
  542. None
  543. --*/
  544. void
  545. pAnsiToUnicode(
  546. IN LPCSTR lpAnsiString,
  547. IN OUT LPWSTR lpwUnicodeString,
  548. IN int nLen
  549. )
  550. {
  551. MultiByteToWideChar(CP_ACP,
  552. 0,
  553. lpAnsiString,
  554. -1,
  555. lpwUnicodeString,
  556. nLen);
  557. return;
  558. }
  559. /*++
  560. Routine Description:
  561. Initializes frequently used strings,
  562. paths, etc.
  563. Arguments:
  564. None
  565. Return Value:
  566. TRUE on success, FALSE otherwise
  567. --*/
  568. BOOL
  569. WUInitialize()
  570. {
  571. BOOL fReturn = FALSE;
  572. int nReturn = 0;
  573. LPWSTR lpwCurrentDirectory = NULL;
  574. char szTemp[MAX_PATH] = "";
  575. WCHAR wszTemp[MAX_PATH] = L"";
  576. WCHAR wszInstInfFileName[MAX_PATH] = L"";
  577. char szInstInfFileName[MAX_PATH] = "";
  578. WCHAR wszUninstInfFileName[MAX_PATH] = L"";
  579. char szUninstInfFileName[MAX_PATH] = "";
  580. char szMessageBoxTitle[MAX_PATH] = "";
  581. WCHAR wszMessageBoxTitle[MAX_PATH] = L"";
  582. char szComponentName[MAX_PATH] = "";
  583. WCHAR wszComponentName[MAX_PATH] = L"";
  584. char szEventLogSourceName[MAX_PATH] = "";
  585. WCHAR wszEventLogSourceName[MAX_PATH] = L"";
  586. char szDestDir[MAX_PATH] = "";
  587. WCHAR wszDestDir[MAX_PATH] = L"";
  588. char szUninstallDir[MAX_PATH] = "";
  589. WCHAR wszUninstallDir[MAX_PATH] = L"";
  590. WCHAR wszSysDir[MAX_PATH] = L"";
  591. WCHAR wszWinDir[MAX_PATH] = L"";
  592. UINT uDirLen = 0;
  593. DWORD dwNoReboot = 0, dwNoUninstall = 0, dwQuiet = 0;
  594. DWORD dwAdjustACL = 0, dwUpdateDllCache = 0;
  595. DWORDLONG dwlFreeSpace = 0;
  596. OSVERSIONINFOEX osviex;
  597. //
  598. // Perform a version check - Windows 2000 or greater
  599. //
  600. ZeroMemory(&osviex, sizeof(OSVERSIONINFOEX));
  601. osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  602. GetVersionEx((OSVERSIONINFO *) &osviex);
  603. if ((osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
  604. (osviex.dwMajorVersion == 5) &&
  605. (osviex.dwMinorVersion == 0)) {
  606. g_si.fOnWin2K = TRUE;
  607. } else if ((osviex.dwPlatformId != VER_PLATFORM_WIN32_NT) &&
  608. (osviex.dwMajorVersion < 5)) {
  609. return FALSE;
  610. }
  611. //
  612. // Determine where we're running from and save it
  613. //
  614. lpwCurrentDirectory = GetCurWorkingDirectory();
  615. if (NULL == lpwCurrentDirectory) {
  616. return FALSE;
  617. }
  618. g_si.lpwExtractPath = (LPWSTR) MALLOC((wcslen(lpwCurrentDirectory)+1)*sizeof(WCHAR));
  619. if (NULL == g_si.lpwExtractPath) {
  620. return FALSE;
  621. }
  622. wcscpy(g_si.lpwExtractPath, lpwCurrentDirectory);
  623. //
  624. // Set up the path to the install INF, make it ANSI, and save it
  625. //
  626. wsprintf(wszInstInfFileName, L"%s\\%s", lpwCurrentDirectory, INF_FILE_NAMEW);
  627. pUnicodeToAnsi(wszInstInfFileName, szInstInfFileName, MAX_PATH);
  628. g_si.lpwInstallINFPath = (LPWSTR) MALLOC((wcslen(wszInstInfFileName)+1)*sizeof(WCHAR));
  629. if (NULL == g_si.lpwInstallINFPath) {
  630. return FALSE;
  631. }
  632. wcscpy(g_si.lpwInstallINFPath, wszInstInfFileName);
  633. //
  634. // Set up the path to the uninstall INF, make it ANSI, and save it
  635. //
  636. wsprintf(wszUninstInfFileName, L"%s\\%s", lpwCurrentDirectory, UNINST_INF_FILE_NAMEW);
  637. pUnicodeToAnsi(wszUninstInfFileName, szUninstInfFileName, MAX_PATH);
  638. FREE(lpwCurrentDirectory);
  639. g_si.lpwUninstallINFPath = (LPWSTR) MALLOC((wcslen(wszUninstInfFileName)+1)*sizeof(WCHAR));
  640. if (NULL == g_si.lpwUninstallINFPath) {
  641. return FALSE;
  642. }
  643. wcscpy(g_si.lpwUninstallINFPath, wszUninstInfFileName);
  644. //
  645. // We need to grab some strings from the INF
  646. //
  647. g_si.hInf = SetupOpenInfFileA(g_si.fInstall ? szInstInfFileName : szUninstInfFileName,
  648. NULL,
  649. INF_STYLE_WIN4,
  650. NULL);
  651. if ((NULL == g_si.hInf) || (INVALID_HANDLE_VALUE == g_si.hInf)) {
  652. Print(ERROR, L"[WUInitialize] Failed to open INF\n");
  653. return FALSE;
  654. }
  655. fReturn = SetupGetLineTextA(NULL,
  656. g_si.hInf,
  657. "Strings",
  658. "MessageBoxTitle",
  659. szMessageBoxTitle,
  660. sizeof(szMessageBoxTitle),
  661. NULL);
  662. if (!fReturn) {
  663. return FALSE;
  664. }
  665. fReturn = SetupGetLineTextA(NULL,
  666. g_si.hInf,
  667. "Strings",
  668. "ComponentName",
  669. szComponentName,
  670. sizeof(szComponentName),
  671. NULL);
  672. if (!fReturn) {
  673. return FALSE;
  674. }
  675. fReturn = SetupGetLineTextA(NULL,
  676. g_si.hInf,
  677. "Strings",
  678. "EventLogSourceName",
  679. szEventLogSourceName,
  680. sizeof(szEventLogSourceName),
  681. NULL);
  682. if (!fReturn) {
  683. return FALSE;
  684. }
  685. fReturn = SetupGetLineTextA(NULL,
  686. g_si.hInf,
  687. "Strings",
  688. "DestDir",
  689. szTemp,
  690. sizeof(szTemp),
  691. NULL);
  692. if (!fReturn) {
  693. return FALSE;
  694. }
  695. fReturn = SetupGetLineTextA(NULL,
  696. g_si.hInf,
  697. "Strings",
  698. "UninstallDirName",
  699. szUninstallDir,
  700. sizeof(szUninstallDir),
  701. NULL);
  702. if (!fReturn) {
  703. return FALSE;
  704. }
  705. if (g_si.fInstall) {
  706. fReturn = GetInfValue(g_si.hInf,
  707. "Version",
  708. "RequiredFreeSpaceNoUninstall",
  709. &g_si.dwRequiredFreeSpaceNoUninstall);
  710. if (!fReturn) {
  711. return FALSE;
  712. }
  713. fReturn = GetInfValue(g_si.hInf,
  714. "Version",
  715. "RequiredFreeSpaceWithUninstall",
  716. &g_si.dwRequiredFreeSpaceWithUninstall);
  717. if (!fReturn) {
  718. return FALSE;
  719. }
  720. GetInfValue(g_si.hInf, "Version", "NoReboot", &dwNoReboot);
  721. GetInfValue(g_si.hInf, "Version", "NoUninstall", &dwNoUninstall);
  722. GetInfValue(g_si.hInf, "Version", "AdjustACLOnTargetDir", &dwAdjustACL);
  723. GetInfValue(g_si.hInf, "Version", "UpdateDllCache", &dwUpdateDllCache);
  724. }
  725. GetInfValue(g_si.hInf, "Version", "RunQuietly", &dwQuiet);
  726. if (dwNoReboot) {
  727. g_si.fNoReboot = TRUE;
  728. }
  729. if (dwNoUninstall) {
  730. g_si.fNoUninstall = TRUE;
  731. }
  732. if (dwQuiet) {
  733. g_si.fQuiet = TRUE;
  734. }
  735. if (dwAdjustACL) {
  736. g_si.fNeedToAdjustACL = TRUE;
  737. }
  738. if (!dwUpdateDllCache) {
  739. g_si.fUpdateDllCache = FALSE;
  740. }
  741. //
  742. // Expand the directory string
  743. //
  744. pAnsiToUnicode(szTemp, wszTemp, MAX_PATH);
  745. ExpandEnvironmentStrings(wszTemp, wszDestDir, MAX_PATH);
  746. //
  747. // Save the strings for later use
  748. //
  749. pAnsiToUnicode(szMessageBoxTitle, wszMessageBoxTitle, MAX_PATH);
  750. pAnsiToUnicode(szComponentName, wszComponentName, MAX_PATH);
  751. pAnsiToUnicode(szEventLogSourceName, wszEventLogSourceName, MAX_PATH);
  752. pAnsiToUnicode(szUninstallDir, wszUninstallDir, MAX_PATH);
  753. uDirLen = GetSystemDirectory(wszSysDir, MAX_PATH);
  754. if (0 == uDirLen) {
  755. return FALSE;
  756. }
  757. uDirLen = GetWindowsDirectory(wszWinDir, MAX_PATH);
  758. if (0 == uDirLen) {
  759. return FALSE;
  760. }
  761. g_si.lpwMessageBoxTitle = (LPWSTR) MALLOC((wcslen(wszMessageBoxTitle)+1)*sizeof(WCHAR));
  762. g_si.lpwPrettyAppName = (LPWSTR) MALLOC((wcslen(wszComponentName)+1)*sizeof(WCHAR));
  763. g_si.lpwEventLogSourceName = (LPWSTR) MALLOC((wcslen(wszEventLogSourceName)+1)*sizeof(WCHAR));
  764. g_si.lpwInstallDirectory = (LPWSTR) MALLOC((wcslen(wszDestDir)+1)*sizeof(WCHAR));
  765. g_si.lpwUninstallDirectory = (LPWSTR) MALLOC((wcslen(wszUninstallDir)+1)*sizeof(WCHAR));
  766. g_si.lpwSystem32Directory = (LPWSTR) MALLOC((wcslen(wszSysDir)+1)*sizeof(WCHAR));
  767. g_si.lpwWindowsDirectory = (LPWSTR) MALLOC((wcslen(wszWinDir)+1)*sizeof(WCHAR));
  768. if ((NULL == g_si.lpwMessageBoxTitle) || (NULL == g_si.lpwPrettyAppName) ||
  769. (NULL == g_si.lpwEventLogSourceName) || (NULL == g_si.lpwInstallDirectory) ||
  770. (NULL == g_si.lpwUninstallDirectory) || (NULL == g_si.lpwSystem32Directory) ||
  771. (NULL == g_si.lpwWindowsDirectory)) {
  772. return FALSE;
  773. }
  774. wcscpy(g_si.lpwMessageBoxTitle, wszMessageBoxTitle);
  775. wcscpy(g_si.lpwPrettyAppName, wszComponentName);
  776. wcscpy(g_si.lpwEventLogSourceName, wszEventLogSourceName);
  777. wcscpy(g_si.lpwInstallDirectory, wszDestDir);
  778. wcscpy(g_si.lpwUninstallDirectory, wszUninstallDir);
  779. wcscpy(g_si.lpwSystem32Directory, wszSysDir);
  780. wcscpy(g_si.lpwWindowsDirectory, wszWinDir);
  781. //
  782. // Ensure that the user has administrator rights
  783. //
  784. nReturn = IsUserAnAdministrator();
  785. if (0 == nReturn) {
  786. //
  787. // The user is not an admin
  788. //
  789. LogEventDisplayError(EVENTLOG_ERROR_TYPE,
  790. ID_NOT_ADMIN,
  791. TRUE,
  792. FALSE);
  793. return FALSE;
  794. } else if (-1 == nReturn) {
  795. //
  796. // The access check failed. Assume that problems occured
  797. // during the check and continue. The worst thing that will
  798. // happen is the user will see an error later on
  799. //
  800. LogEventDisplayError(EVENTLOG_WARNING_TYPE,
  801. ID_ADMIN_CHECK_FAILED,
  802. FALSE,
  803. FALSE);
  804. return FALSE;
  805. }
  806. //
  807. // Verify that we have enough disk space for the install
  808. //
  809. if (g_si.fInstall) {
  810. dwlFreeSpace = GetDiskSpaceFreeOnNTDrive();
  811. if (dwlFreeSpace < g_si.dwRequiredFreeSpaceNoUninstall) {
  812. //
  813. // Not enough space available to complete
  814. //
  815. LogEventDisplayError(EVENTLOG_WARNING_TYPE,
  816. ID_NOT_ENOUGH_DISK_SPACE,
  817. TRUE,
  818. FALSE);
  819. return FALSE;
  820. }
  821. }
  822. return TRUE;
  823. }
  824. /*++
  825. Routine Description:
  826. Releases any memory used throughout the app
  827. Arguments:
  828. None
  829. Return Value:
  830. None
  831. --*/
  832. void
  833. WUCleanup()
  834. {
  835. if (NULL != g_si.lpwEventLogSourceName) {
  836. FREE(g_si.lpwEventLogSourceName);
  837. }
  838. if (NULL != g_si.lpwExtractPath) {
  839. FREE(g_si.lpwExtractPath);
  840. }
  841. if (NULL != g_si.lpwInstallDirectory) {
  842. FREE(g_si.lpwInstallDirectory);
  843. }
  844. if (NULL != g_si.lpwInstallINFPath) {
  845. FREE(g_si.lpwInstallINFPath);
  846. }
  847. if (NULL != g_si.lpwUninstallINFPath) {
  848. FREE(g_si.lpwUninstallINFPath);
  849. }
  850. if (NULL != g_si.lpwMessageBoxTitle) {
  851. FREE(g_si.lpwMessageBoxTitle);
  852. }
  853. if (NULL != g_si.lpwPrettyAppName) {
  854. FREE(g_si.lpwPrettyAppName);
  855. }
  856. if (NULL != g_si.lpwSystem32Directory) {
  857. FREE(g_si.lpwSystem32Directory);
  858. }
  859. if (NULL != g_si.lpwUninstallDirectory) {
  860. FREE(g_si.lpwUninstallDirectory);
  861. }
  862. if (NULL != g_si.lpwWindowsDirectory) {
  863. FREE(g_si.lpwWindowsDirectory);
  864. }
  865. if (NULL != g_si.hInf) {
  866. SetupCloseInfFile(g_si.hInf);
  867. }
  868. return;
  869. }
  870. /*++
  871. Routine Description:
  872. Takes the DACL from a given directory and
  873. applies it to another directory
  874. Arguments:
  875. lpwSourceDir - The directory to get the DACL from
  876. lpwDestDir - The directory to apply the DACL to
  877. Return Value:
  878. TRUE on success, FALSE otherwise
  879. --*/
  880. BOOL
  881. MirrorDirectoryPerms(
  882. IN LPWSTR lpwSourceDir,
  883. IN LPWSTR lpwDestDir
  884. )
  885. {
  886. DWORD dwResult = 0;
  887. BOOL fResult = FALSE;
  888. PACL pDACL = NULL;
  889. PSECURITY_DESCRIPTOR pSD = NULL;
  890. PSID pOwnerSid;
  891. __try {
  892. //
  893. // Get the DACL from the source directory
  894. //
  895. dwResult = GetNamedSecurityInfo(lpwSourceDir,
  896. SE_FILE_OBJECT,
  897. DACL_SECURITY_INFORMATION |
  898. OWNER_SECURITY_INFORMATION,
  899. &pOwnerSid,
  900. NULL,
  901. &pDACL,
  902. NULL,
  903. &pSD);
  904. if (ERROR_SUCCESS != dwResult) {
  905. __leave;
  906. }
  907. //
  908. // Attach the DACL to the destination directory
  909. //
  910. dwResult = SetNamedSecurityInfo(lpwDestDir,
  911. SE_FILE_OBJECT,
  912. DACL_SECURITY_INFORMATION |
  913. OWNER_SECURITY_INFORMATION,
  914. pOwnerSid,
  915. NULL,
  916. pDACL,
  917. NULL);
  918. if (ERROR_SUCCESS != dwResult) {
  919. __leave;
  920. }
  921. fResult = TRUE;
  922. } //try
  923. __finally {
  924. if (NULL != pSD) {
  925. LocalFree((HLOCAL) pSD);
  926. }
  927. } //finally
  928. return (fResult);
  929. }
  930. /*++
  931. Routine Description:
  932. Adjusts permissions on the given directory
  933. Arguments:
  934. lpwDirPath - Directory to modify
  935. Return Value:
  936. TRUE on success, FALSE otherwise
  937. --*/
  938. BOOL
  939. AdjustDirectoryPerms(
  940. IN LPWSTR lpwDirPath
  941. )
  942. {
  943. DWORD dwResult = 0;
  944. PSID pSid = NULL;
  945. BOOL fReturn = FALSE, fResult = FALSE;
  946. PACL pOldDACL = NULL, pNewDACL = NULL;
  947. EXPLICIT_ACCESS ea;
  948. PSECURITY_DESCRIPTOR pSD = NULL;
  949. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  950. __try {
  951. //
  952. // Get the DACL for the directory
  953. //
  954. dwResult = GetNamedSecurityInfo(lpwDirPath,
  955. SE_FILE_OBJECT,
  956. DACL_SECURITY_INFORMATION,
  957. NULL,
  958. NULL,
  959. &pOldDACL,
  960. NULL,
  961. &pSD);
  962. if (ERROR_SUCCESS != dwResult) {
  963. __leave;
  964. }
  965. //
  966. // Build a SID to the local Users group
  967. //
  968. fReturn = AllocateAndInitializeSid(&sia, 2,
  969. SECURITY_BUILTIN_DOMAIN_RID,
  970. DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0,
  971. &pSid);
  972. if (!fReturn) {
  973. __leave;
  974. }
  975. //
  976. // Ensure that the SID is valid
  977. //
  978. fReturn = IsValidSid(pSid);
  979. if (!fReturn) {
  980. __leave;
  981. }
  982. //
  983. // Initialize an EXPLICIT_ACCESS structure for the new ACE
  984. //
  985. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
  986. ea.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
  987. ea.grfAccessMode = GRANT_ACCESS;
  988. ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  989. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  990. ea.Trustee.ptstrName = (LPTSTR) pSid;
  991. //
  992. // Create a new ACL that merges the new ACE
  993. // into the existing DACL
  994. //
  995. dwResult = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
  996. if (ERROR_SUCCESS != dwResult) {
  997. __leave;
  998. }
  999. //
  1000. // Attach the new ACL as the object's DACL
  1001. //
  1002. dwResult = SetNamedSecurityInfo(lpwDirPath,
  1003. SE_FILE_OBJECT,
  1004. DACL_SECURITY_INFORMATION,
  1005. NULL,
  1006. NULL,
  1007. pNewDACL,
  1008. NULL);
  1009. if (ERROR_SUCCESS != dwResult) {
  1010. __leave;
  1011. }
  1012. // Everything was a success
  1013. fResult = TRUE;
  1014. } // try
  1015. __finally {
  1016. if (NULL != pSD) {
  1017. LocalFree((HLOCAL) pSD);
  1018. }
  1019. if (NULL != pNewDACL) {
  1020. LocalFree((HLOCAL) pNewDACL);
  1021. }
  1022. if (NULL != pSid) {
  1023. FreeSid(pSid);
  1024. }
  1025. } //finally
  1026. return (fResult);
  1027. }
  1028. /*++
  1029. Routine Description:
  1030. Retrieves version information from a catalog file
  1031. Arguments:
  1032. lpwCatName - The catalog file to check
  1033. Return Value:
  1034. A DWORD which contains a version number for the catalog
  1035. --*/
  1036. DWORD
  1037. GetCatVersion(
  1038. IN LPWSTR lpwCatName
  1039. )
  1040. {
  1041. char szVersionString[MAX_PATH] = "";
  1042. HANDLE hCat = NULL;
  1043. DWORD dwVer = 0;
  1044. CRYPTCATATTRIBUTE *pSpCatAttr = NULL;
  1045. NTSTATUS Status;
  1046. __try {
  1047. hCat = CryptCATOpen(lpwCatName, 0, 0, 0, 0);
  1048. if (NULL == hCat) {
  1049. __leave;
  1050. }
  1051. pSpCatAttr = CryptCATGetCatAttrInfo(hCat, L"SPAttr");
  1052. if ((pSpCatAttr == NULL) || (pSpCatAttr->pbValue == NULL)) {
  1053. __leave;
  1054. }
  1055. pUnicodeToAnsi((LPWSTR)pSpCatAttr->pbValue, szVersionString, MAX_PATH);
  1056. Status = RtlCharToInteger(szVersionString, 10, (PULONG)&dwVer);
  1057. if (!NT_SUCCESS(Status)) {
  1058. __leave;
  1059. }
  1060. } // try
  1061. __finally {
  1062. if (hCat) {
  1063. CryptCATClose(hCat);
  1064. }
  1065. } // finally
  1066. return (dwVer);
  1067. }
  1068. /*++
  1069. Routine Description:
  1070. Wraps CreateProcess and WaitForSingleObject
  1071. Arguments:
  1072. lpwCommandLine - Command line to execute
  1073. pdwReturnCode - Receives a return code from the process
  1074. Return Value:
  1075. TRUE on success, FALSE otherwise
  1076. --*/
  1077. BOOL
  1078. LaunchProcessAndWait(
  1079. IN LPCWSTR lpwCommandLine,
  1080. OUT PDWORD pdwReturnCode
  1081. )
  1082. {
  1083. PROCESS_INFORMATION pi;
  1084. STARTUPINFO si;
  1085. BOOL fReturn = FALSE;
  1086. LPWSTR lpwCmdLine = NULL;
  1087. //
  1088. // CreateProcess requires a non-const command line
  1089. //
  1090. lpwCmdLine = (LPWSTR) MALLOC((wcslen(lpwCommandLine)+1)*sizeof(WCHAR));
  1091. if (NULL == lpwCmdLine) {
  1092. return FALSE;
  1093. }
  1094. wcscpy(lpwCmdLine, lpwCommandLine);
  1095. ZeroMemory(&si, sizeof(si));
  1096. si.cb = sizeof(si);
  1097. si.dwFlags = STARTF_USESHOWWINDOW;
  1098. si.wShowWindow = SW_HIDE;
  1099. fReturn = CreateProcess(NULL,
  1100. lpwCmdLine,
  1101. NULL,
  1102. NULL,
  1103. FALSE,
  1104. 0,
  1105. NULL,
  1106. NULL,
  1107. &si,
  1108. &pi);
  1109. if (!fReturn) {
  1110. return FALSE;
  1111. }
  1112. WaitForSingleObject(pi.hProcess, INFINITE);
  1113. if (NULL != pdwReturnCode) {
  1114. GetExitCodeProcess(pi.hProcess, pdwReturnCode);
  1115. }
  1116. if (NULL != lpwCmdLine) {
  1117. FREE(lpwCmdLine);
  1118. }
  1119. CloseHandle(pi.hProcess);
  1120. CloseHandle(pi.hThread);
  1121. return TRUE;
  1122. }
  1123. /*++
  1124. Routine Description:
  1125. Callback function for our directory enumeration routine
  1126. Arguments:
  1127. lpwPath - Path of the directory or filename
  1128. pFindFileData - Pointer to WIN32_FIND_DATA struct
  1129. containing information about lpwPath
  1130. pEnumerateParameter - A 32-bit enumeration parameter
  1131. Return Value:
  1132. TRUE on success, FALSE otherwise
  1133. --*/
  1134. BOOL
  1135. DeleteOneFile(
  1136. IN LPCWSTR lpwPath,
  1137. IN PWIN32_FIND_DATA pFindFileData,
  1138. IN PVOID pEnumerateParameter
  1139. )
  1140. {
  1141. WCHAR wszTempPath[MAX_PATH] = L"";
  1142. char szFileName[MAX_PATH] = "";
  1143. WCHAR wszFileName[MAX_PATH] = L"";
  1144. char szEntry[MAX_QUEUE_SIZE] = "";
  1145. WCHAR wszEntry[MAX_QUEUE_SIZE] = L"";
  1146. WCHAR wszTestPath[MAX_PATH] = L"";
  1147. BOOL fCheckQueue = FALSE, fReturn = FALSE, fDelete = TRUE;
  1148. LPWSTR lpwDestDir = NULL;
  1149. int nLen = 0;
  1150. LONG cLines = 0;
  1151. INFCONTEXT InfContext;
  1152. if (pFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1153. return TRUE;
  1154. }
  1155. //
  1156. // Note: This may seem a little complex, but because there could
  1157. // multiple entries in a section, we have to run through them
  1158. // each time this function gets called.
  1159. //
  1160. //
  1161. // See if there's anything in the exclusion queue
  1162. //
  1163. fCheckQueue = (BOOL) pEnumerateParameter;
  1164. if (fCheckQueue) {
  1165. nLen = g_si.ExclusionQueue.GetSize();
  1166. while (nLen != 0) {
  1167. //
  1168. // Walk through the queue and make sure
  1169. // we don't delete files we shouldn't
  1170. //
  1171. g_si.ExclusionQueue.Dequeue(wszEntry, MAX_QUEUE_SIZE - 1, TRUE);
  1172. pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
  1173. //
  1174. // Get the destination directory
  1175. //
  1176. GetNextToken(wszEntry, L".");
  1177. lpwDestDir = GetNextToken(NULL, L".");
  1178. if (NULL == lpwDestDir) {
  1179. return FALSE;
  1180. }
  1181. //
  1182. // Get the number of files in the section
  1183. //
  1184. cLines = SetupGetLineCountA(g_si.hInf, szEntry);
  1185. //
  1186. // Loop through all the lines in the exclusion section(s),
  1187. // and do a comparison
  1188. //
  1189. fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL,
  1190. &InfContext) &&
  1191. SetupGetLineTextA(&InfContext,
  1192. NULL, NULL, NULL,
  1193. szFileName, MAX_PATH, NULL);
  1194. while (fReturn) {
  1195. while (cLines != 0) {
  1196. pAnsiToUnicode(szFileName, wszFileName, MAX_PATH);
  1197. //
  1198. // Put the path together
  1199. //
  1200. wsprintf(wszTestPath, L"%s\\%s", lpwDestDir, wszFileName);
  1201. wcscpy(wszTempPath, lpwPath);
  1202. CharLower(wszTestPath);
  1203. CharLower(wszTempPath);
  1204. //
  1205. // See if the paths match
  1206. //
  1207. if (wcsstr(wszTempPath, wszTestPath)) {
  1208. fDelete = FALSE;
  1209. break; // paths match, move to the next file
  1210. }
  1211. SetupFindNextLine(&InfContext, &InfContext);
  1212. SetupGetLineTextA(&InfContext,
  1213. NULL, NULL, NULL,
  1214. szFileName, MAX_PATH, NULL);
  1215. --cLines;
  1216. }
  1217. if (fDelete) {
  1218. ForceDelete(lpwPath);
  1219. fDelete = TRUE; // reset the flag
  1220. }
  1221. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  1222. SetupGetLineTextA(&InfContext,
  1223. NULL, NULL, NULL,
  1224. szFileName, MAX_PATH, NULL);
  1225. }
  1226. nLen--;
  1227. }
  1228. } else {
  1229. //
  1230. // Don't worry about the queue, delete the file
  1231. //
  1232. ForceDelete(lpwPath);
  1233. }
  1234. return TRUE;
  1235. }
  1236. /*++
  1237. Routine Description:
  1238. Retrieves a token, given a separator.
  1239. Basically a wrapper for strtok
  1240. Arguments:
  1241. lpwSourceString - The source string to parse
  1242. lpwSeparator - The separator string that specifies
  1243. the delimiter
  1244. Return Value:
  1245. A pointer to the return string
  1246. --*/
  1247. LPWSTR
  1248. GetNextToken(
  1249. IN LPWSTR lpwSourceString,
  1250. IN LPCWSTR lpwSeparator
  1251. )
  1252. {
  1253. LPWSTR lpwReturn = NULL;
  1254. lpwReturn = wcstok(lpwSourceString, lpwSeparator);
  1255. return (lpwReturn);
  1256. }
  1257. /*++
  1258. Routine Description:
  1259. Attempts to move a file.
  1260. If it's in use, replace it on reboot
  1261. Arguments:
  1262. lpwSourceFileName - The source file name
  1263. lpwDestFileName - The destination file name
  1264. Return Value:
  1265. TRUE on success, FALSE otherwise
  1266. --*/
  1267. BOOL
  1268. ForceMove(
  1269. IN LPCWSTR lpwSourceFileName,
  1270. IN LPCWSTR lpwDestFileName
  1271. )
  1272. {
  1273. WCHAR wszTempPath[MAX_PATH] = L"";
  1274. WCHAR wszDelFileName[MAX_PATH] = L"";
  1275. if (!lpwSourceFileName || !lpwDestFileName) {
  1276. return FALSE;
  1277. }
  1278. if (!MoveFileEx(lpwSourceFileName,
  1279. lpwDestFileName,
  1280. MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) {
  1281. Print(TRACE,
  1282. L"[ForceMove] First call to MoveFileEx failed. GLE = %d\n",
  1283. GetLastError());
  1284. if (!GetTempPath(MAX_PATH, wszTempPath)) {
  1285. return FALSE;
  1286. }
  1287. if (!GetTempFileName(wszTempPath, L"DEL", 0, wszDelFileName)) {
  1288. return FALSE;
  1289. }
  1290. if (!MoveFileEx(lpwDestFileName,
  1291. wszDelFileName,
  1292. MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) {
  1293. Print(ERROR,
  1294. L"[ForceMove] Second call to MoveFileEx failed. GLE = %d\n",
  1295. GetLastError());
  1296. return FALSE;
  1297. }
  1298. if (!MoveFileEx(wszDelFileName,
  1299. NULL,
  1300. MOVEFILE_DELAY_UNTIL_REBOOT)) {
  1301. Print(ERROR,
  1302. L"[ForceMove] Third call to MoveFileEx failed. GLE = %d\n",
  1303. GetLastError());
  1304. return FALSE;
  1305. }
  1306. if (!MoveFileEx(lpwSourceFileName,
  1307. lpwDestFileName,
  1308. MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) {
  1309. Print(ERROR,
  1310. L"[ForceMove] Second call to MoveFileEx failed. GLE = %d\n",
  1311. GetLastError());
  1312. return FALSE;
  1313. }
  1314. }
  1315. return TRUE;
  1316. }
  1317. /*++
  1318. Routine Description:
  1319. Attempts to delete a file.
  1320. If it's in use, delete it on reboot
  1321. Arguments:
  1322. lpwFileName - The file name to delete
  1323. Return Value:
  1324. TRUE on success, FALSE otherwise
  1325. --*/
  1326. BOOL
  1327. ForceDelete(
  1328. IN LPCWSTR lpwFileName
  1329. )
  1330. {
  1331. WCHAR *pTempFile = NULL;
  1332. WCHAR *pExt = NULL;
  1333. //
  1334. // Attempt to delete the specified file
  1335. //
  1336. SetFileAttributes(lpwFileName, FILE_ATTRIBUTE_NORMAL);
  1337. if (!DeleteFile(lpwFileName)) {
  1338. //
  1339. // The file is most likely in use
  1340. // Attempt to rename it
  1341. //
  1342. pTempFile = _wcsdup(lpwFileName);
  1343. pExt = PathFindExtension(pTempFile);
  1344. if (pExt) {
  1345. wcscpy(pExt, L"._wu");
  1346. }
  1347. if (MoveFile(lpwFileName, pTempFile)) {
  1348. //
  1349. // We renamed the target - delete it on reboot
  1350. //
  1351. MoveFileEx(pTempFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1352. } else {
  1353. //
  1354. // Couldn't rename it - mark it for deletion on reboot
  1355. //
  1356. MoveFileEx(lpwFileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1357. }
  1358. free(pTempFile);
  1359. }
  1360. return TRUE;
  1361. }
  1362. /*++
  1363. Routine Description:
  1364. Attempts to copy a file
  1365. If it's in use, move it and replace on reboot
  1366. Arguments:
  1367. lpwSourceFileName - The source file name
  1368. lpwDestFileName - The destination file name
  1369. Return Value:
  1370. TRUE on success, FALSE otherwise
  1371. --*/
  1372. BOOL
  1373. ForceCopy(
  1374. IN LPCWSTR lpwSourceFileName,
  1375. IN LPCWSTR lpwDestFileName
  1376. )
  1377. {
  1378. WCHAR wszTempPath[MAX_PATH] = L"";
  1379. WCHAR wszDelFileName[MAX_PATH] = L"";
  1380. if (!lpwSourceFileName || !lpwDestFileName) {
  1381. return FALSE;
  1382. }
  1383. if (!CopyFile(lpwSourceFileName, lpwDestFileName, FALSE)) {
  1384. if (!GetTempPath(MAX_PATH, wszTempPath)) {
  1385. return FALSE;
  1386. }
  1387. if (!GetTempFileName(wszTempPath, L"DEL", 0, wszDelFileName)) {
  1388. return FALSE;
  1389. }
  1390. if (!MoveFileEx(lpwDestFileName,
  1391. wszDelFileName,
  1392. MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) {
  1393. return FALSE;
  1394. }
  1395. if (!MoveFileEx(wszDelFileName,
  1396. NULL,
  1397. MOVEFILE_COPY_ALLOWED | MOVEFILE_DELAY_UNTIL_REBOOT)) {
  1398. return FALSE;
  1399. }
  1400. if (!CopyFile(lpwSourceFileName, lpwDestFileName, FALSE)) {
  1401. return FALSE;
  1402. }
  1403. }
  1404. return TRUE;
  1405. }
  1406. /*++
  1407. Routine Description:
  1408. Determines if a file is protected by WFP
  1409. Arguments:
  1410. lpwFileName - Name of the file
  1411. Return Value:
  1412. TRUE if the file is protected, FALSE otherwise
  1413. --*/
  1414. BOOL
  1415. IsFileProtected(
  1416. IN LPCWSTR lpwFileName
  1417. )
  1418. {
  1419. BOOL fReturn = FALSE;
  1420. if (lpwFileName == NULL) {
  1421. return FALSE;
  1422. }
  1423. return (SfcIsFileProtected(NULL, lpwFileName));
  1424. }
  1425. /*++
  1426. Routine Description:
  1427. Retrieve file version and language info from a file
  1428. The version is specified in the dwFileVersionMS and dwFileVersionLS fields
  1429. of a VS_FIXEDFILEINFO, as filled in by the win32 version APIs. For the
  1430. language we look at the translation table in the version resources and assume
  1431. that the first langid/codepage pair specifies the language
  1432. If the file is not a coff image or does not have version resources,
  1433. the function fails. The function does not fail if we are able to retrieve
  1434. the version but not the language
  1435. Arguments:
  1436. lpwFileName - Supplies the full path of the file
  1437. whose version data is desired
  1438. pdwVersion - Receives the version stamp of the file.
  1439. If the file is not a coff image or does not contain
  1440. the appropriate version resource data, the function fails
  1441. Return Value:
  1442. TRUE on success, FALSE otherwise
  1443. --*/
  1444. BOOL
  1445. GetVersionInfoFromImage(
  1446. IN LPCWSTR lpwFileName,
  1447. OUT PDWORDLONG pdwVersion
  1448. )
  1449. {
  1450. DWORD nSize = 0L, dwIgnored = 0L;
  1451. UINT nDataLength = 0;
  1452. BOOL fResult = FALSE;
  1453. PVOID pVersionBlock = NULL;
  1454. VS_FIXEDFILEINFO *FixedVersionInfo;
  1455. //
  1456. // Get the size of version info block
  1457. //
  1458. nSize = GetFileVersionInfoSize((LPWSTR)lpwFileName, &dwIgnored);
  1459. if (nSize) {
  1460. //
  1461. // Allocate memory block of sufficient size to hold version info block
  1462. //
  1463. pVersionBlock = MALLOC(nSize*sizeof(WCHAR));
  1464. if (pVersionBlock) {
  1465. //
  1466. // Get the version block from the file.
  1467. //
  1468. if (GetFileVersionInfo((LPWSTR)lpwFileName,
  1469. 0,
  1470. nSize*sizeof(WCHAR),
  1471. pVersionBlock)) {
  1472. //
  1473. // Get fixed version info
  1474. //
  1475. if (VerQueryValue(pVersionBlock,
  1476. L"\\",
  1477. (LPVOID*) &FixedVersionInfo,
  1478. &nDataLength)) {
  1479. //
  1480. // Return version to caller
  1481. //
  1482. *pdwVersion = (((DWORDLONG)FixedVersionInfo->dwFileVersionMS) << 32)
  1483. + FixedVersionInfo->dwFileVersionLS;
  1484. fResult = TRUE;
  1485. }
  1486. }
  1487. FREE(pVersionBlock);
  1488. }
  1489. }
  1490. return (fResult);
  1491. }
  1492. /*++
  1493. Routine Description:
  1494. Copies the specified file giving it a temporary name
  1495. Arguments:
  1496. lpwFileName - The full path & name of the file
  1497. Return Value:
  1498. A pointer to the full path & name of the file
  1499. The caller is responsible for freeing the memory
  1500. --*/
  1501. LPWSTR
  1502. CopyTempFile(
  1503. IN LPCWSTR lpwSrcFileName,
  1504. IN LPCWSTR lpwDestDir
  1505. )
  1506. {
  1507. LPWSTR lpwTempFileName = NULL;
  1508. lpwTempFileName = (LPWSTR) MALLOC(MAX_PATH * sizeof(WCHAR));
  1509. if (NULL == lpwTempFileName) {
  1510. return NULL;
  1511. }
  1512. if (!GetTempFileName(lpwDestDir, L"_wu", 0, lpwTempFileName)) {
  1513. FREE(lpwTempFileName);
  1514. return NULL;
  1515. } else {
  1516. //
  1517. // Copy the source file down to the destination directory
  1518. // using the name we just got
  1519. //
  1520. if (!CopyFile(lpwSrcFileName, lpwTempFileName, FALSE)) {
  1521. FREE(lpwTempFileName);
  1522. return NULL;
  1523. }
  1524. }
  1525. return (lpwTempFileName);
  1526. }
  1527. /*++
  1528. Routine Description:
  1529. Prints formatted debug strings
  1530. Arguments:
  1531. uLevel - A flag to indicate if the message should be displayed
  1532. lpwFmt - A string to be displayed
  1533. ... - A variable length argument list of insertion strings
  1534. Return Value:
  1535. TRUE on success, FALSE otherwise
  1536. --*/
  1537. #if DBG
  1538. void Print(
  1539. IN UINT uLevel,
  1540. IN LPWSTR lpwFmt,
  1541. IN ...
  1542. )
  1543. {
  1544. va_list arglist;
  1545. if (g_si.nErrorLevel < uLevel) {
  1546. return;
  1547. }
  1548. va_start(arglist, lpwFmt);
  1549. _vsnwprintf(g_si.wszDebugOut, 2047, lpwFmt, arglist);
  1550. g_si.wszDebugOut[2047] = 0;
  1551. va_end(arglist);
  1552. OutputDebugString(g_si.wszDebugOut);
  1553. return;
  1554. }
  1555. #endif
  1556. /*++
  1557. Routine Description:
  1558. Reboots the system
  1559. Arguments:
  1560. fForceClose - A flag to indicate if apps should be forced
  1561. to close
  1562. fReboot - A flag to indicate if we should reboot
  1563. after shutdown
  1564. Return Value:
  1565. TRUE on success, FALSE otherwise
  1566. --*/
  1567. BOOL
  1568. ShutdownSystem(
  1569. IN BOOL fForceClose,
  1570. IN BOOL fReboot
  1571. )
  1572. {
  1573. BOOL fResult = FALSE;
  1574. if (!ModifyTokenPrivilege(L"SeShutdownPrivilege", TRUE)) {
  1575. return FALSE;
  1576. }
  1577. fResult = InitiateSystemShutdown(NULL, // machinename
  1578. NULL, // shutdown message
  1579. 0, // delay
  1580. fForceClose, // force apps close
  1581. fReboot // reboot after shutdown
  1582. );
  1583. ModifyTokenPrivilege(L"SeShutdownPrivilege", FALSE);
  1584. return (fResult);
  1585. }
  1586. /*++
  1587. Routine Description:
  1588. Enables or disables a specified privilege
  1589. Arguments:
  1590. lpwPrivilege - The name of the privilege
  1591. fEnable - A flag to indicate if the
  1592. privilege should be enabled
  1593. Return Value:
  1594. TRUE on success, FALSE otherwise
  1595. --*/
  1596. BOOL
  1597. ModifyTokenPrivilege(
  1598. IN LPCWSTR lpwPrivilege,
  1599. IN BOOL fEnable
  1600. )
  1601. {
  1602. HANDLE hToken = NULL;
  1603. LUID luid;
  1604. BOOL fResult = FALSE;
  1605. TOKEN_PRIVILEGES tp;
  1606. if (NULL == lpwPrivilege) {
  1607. return FALSE;
  1608. }
  1609. __try {
  1610. //
  1611. // Get a handle to the access token associated with the current process
  1612. //
  1613. OpenProcessToken(GetCurrentProcess(),
  1614. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1615. &hToken);
  1616. if (NULL == hToken) {
  1617. __leave;
  1618. }
  1619. //
  1620. // Obtain a LUID for the specified privilege
  1621. //
  1622. if (!LookupPrivilegeValue(NULL, lpwPrivilege, &luid)) {
  1623. __leave;
  1624. }
  1625. tp.PrivilegeCount = 1;
  1626. tp.Privileges[0].Luid = luid;
  1627. tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
  1628. //
  1629. // Modify the access token
  1630. //
  1631. if (!AdjustTokenPrivileges(hToken,
  1632. FALSE,
  1633. &tp,
  1634. sizeof(TOKEN_PRIVILEGES),
  1635. NULL,
  1636. NULL)) {
  1637. __leave;
  1638. }
  1639. fResult = TRUE;
  1640. } // try
  1641. __finally {
  1642. if (hToken) {
  1643. CloseHandle(hToken);
  1644. }
  1645. } // finally
  1646. return (fResult);
  1647. }
  1648. /*++
  1649. Routine Description:
  1650. Saves the specified information to the file
  1651. that will be used by the uninstaller
  1652. Arguments:
  1653. lpwSectionName - The name of the section where our entry
  1654. will be saved
  1655. lpwKeyName - A 1-based number in a string. It should
  1656. be unique for each entry in the section
  1657. lpwEntryName - The value or entry to save
  1658. lpwFileName - The file to save our changes to
  1659. Return Value:
  1660. TRUE on success, FALSE otherwise
  1661. --*/
  1662. BOOL SaveEntryToINF(
  1663. IN LPCWSTR lpwSectionName,
  1664. IN LPCWSTR lpwKeyName,
  1665. IN LPCWSTR lpwEntryName,
  1666. IN LPCWSTR lpwFileName
  1667. )
  1668. {
  1669. BOOL fReturn = FALSE;
  1670. //
  1671. // Write the entry to the INF
  1672. //
  1673. fReturn = WritePrivateProfileString(lpwSectionName,
  1674. lpwKeyName,
  1675. lpwEntryName,
  1676. lpwFileName);
  1677. if (!fReturn) {
  1678. Print(ERROR,
  1679. L"[SaveEntryToINF] Failed to save entry: Section: %\nKey Name: %s\n Entry: %s\n File: %s\n");
  1680. }
  1681. return (fReturn ? TRUE : FALSE);
  1682. }
  1683. /*++
  1684. Routine Description:
  1685. Deletes the specified registry
  1686. keys during install
  1687. Arguments:
  1688. None
  1689. Return Value:
  1690. TRUE on success, FALSE otherwise
  1691. --*/
  1692. BOOL
  1693. CommonDeleteRegistryKeys()
  1694. {
  1695. BOOL fReturn = FALSE, fResult = FALSE;
  1696. HKEY hKeyRoot = NULL;
  1697. char szEntry[MAX_PATH] = "";
  1698. WCHAR wszEntry[MAX_PATH] = L"";
  1699. char szKeyPath[MAX_PATH*3] = "";
  1700. WCHAR wszKeyPath[MAX_PATH*3] = L"";
  1701. LPWSTR lpwKeyRoot = NULL, lpwSubKey = NULL;
  1702. UINT uCount = 0;
  1703. CRegistry creg;
  1704. INFCONTEXT InfContext;
  1705. //
  1706. // Step through each entry in the queue
  1707. //
  1708. while (g_si.DeleteRegistryQueue.GetSize()) {
  1709. g_si.DeleteRegistryQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
  1710. pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
  1711. //
  1712. // Loop through all the lines in the delete registry section(s),
  1713. // and perform the deletion
  1714. //
  1715. fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL,
  1716. &InfContext) &&
  1717. SetupGetLineTextA(&InfContext,
  1718. NULL, NULL, NULL,
  1719. szKeyPath, MAX_PATH, NULL);
  1720. while (fReturn) {
  1721. pAnsiToUnicode(szKeyPath, wszKeyPath, MAX_PATH*3);
  1722. //
  1723. // Split the key path into two separate parts
  1724. //
  1725. lpwKeyRoot = GetNextToken(wszKeyPath, L",");
  1726. if (NULL == lpwKeyRoot) {
  1727. break;
  1728. }
  1729. Print(TRACE, L"[CommonDeleteRegistryKeys] Key root: %s\n", lpwKeyRoot);
  1730. if (!_wcsicmp(lpwKeyRoot, L"HKLM")) {
  1731. hKeyRoot = HKEY_LOCAL_MACHINE;
  1732. } else if (!_wcsicmp(lpwKeyRoot, L"HKCR")) {
  1733. hKeyRoot = HKEY_CLASSES_ROOT;
  1734. } else if (!_wcsicmp(lpwKeyRoot, L"HKCU")) {
  1735. hKeyRoot = HKEY_CURRENT_USER;
  1736. } else if (!_wcsicmp(lpwKeyRoot, L"HKU")) {
  1737. hKeyRoot = HKEY_USERS;
  1738. } else {
  1739. break;
  1740. }
  1741. lpwSubKey = GetNextToken(NULL, L",");
  1742. if (NULL == lpwSubKey) {
  1743. break;
  1744. }
  1745. Print(TRACE, L"[CommonDeleteRegistryKeys] Subkey path %s\n", lpwSubKey);
  1746. //
  1747. // Verify that the specified key exists
  1748. //
  1749. fResult = creg.IsRegistryKeyPresent(hKeyRoot, lpwSubKey);
  1750. if (fResult) {
  1751. //
  1752. // Do a recursive delete on the key
  1753. //
  1754. SHDeleteKey(hKeyRoot, lpwSubKey);
  1755. }
  1756. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  1757. SetupGetLineTextA(&InfContext,
  1758. NULL, NULL, NULL,
  1759. szKeyPath, MAX_PATH, NULL);
  1760. }
  1761. }
  1762. return TRUE;
  1763. }
  1764. /*++
  1765. Routine Description:
  1766. Based on the flag, performs a server
  1767. registration or performs a server
  1768. removal (unregistration)
  1769. Arguments:
  1770. fRegister - A flag to indicate if we should
  1771. perform a register server
  1772. Return Value:
  1773. TRUE on success, FALSE otherwise
  1774. --*/
  1775. BOOL
  1776. CommonRegisterServers(
  1777. IN BOOL fRegister
  1778. )
  1779. {
  1780. int nLen = 0;
  1781. char szFileName[MAX_PATH] = "";
  1782. WCHAR wszFileToRun[MAX_PATH] = L"";
  1783. WCHAR wszFileName[MAX_PATH] = L"";
  1784. char szEntry[MAX_PATH] = "";
  1785. WCHAR wszEntry[MAX_PATH] = L"";
  1786. WCHAR wszEntryToSave[MAX_PATH*2] = L"";
  1787. WCHAR wszKey[10] = L"";
  1788. WCHAR wszSectionName[MAX_PATH] = L"";
  1789. BOOL fReturn = FALSE;
  1790. UINT uCount = 0;
  1791. LPWSTR lpwDestDir = NULL;
  1792. INFCONTEXT InfContext;
  1793. //
  1794. // Step through each entry in the queue
  1795. //
  1796. while (g_si.RegistrationQueue.GetSize()) {
  1797. g_si.RegistrationQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
  1798. pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
  1799. //
  1800. // Get the destination directory
  1801. //
  1802. GetNextToken(wszEntry, L".");
  1803. lpwDestDir = GetNextToken(NULL, L".");
  1804. if (NULL == lpwDestDir) {
  1805. return FALSE;
  1806. }
  1807. //
  1808. // Loop through all the lines in the approriate section,
  1809. // spawning off each one
  1810. //
  1811. fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL,
  1812. &InfContext) &&
  1813. SetupGetLineTextA(&InfContext,
  1814. NULL, NULL, NULL,
  1815. szFileName, MAX_PATH, NULL);
  1816. while (fReturn) {
  1817. pAnsiToUnicode(szFileName, wszFileName, MAX_PATH);
  1818. //
  1819. // Set up the path to the file to (un)register and run it
  1820. //
  1821. if (fRegister) {
  1822. wsprintf(wszFileToRun,
  1823. L"regsvr32.exe /s \"%s\\%s\\%s\"",
  1824. g_si.lpwWindowsDirectory,
  1825. lpwDestDir,
  1826. wszFileName);
  1827. } else {
  1828. wsprintf(wszFileToRun,
  1829. L"regsvr32.exe /s /u \"%s\"",
  1830. wszFileName);
  1831. }
  1832. Print(TRACE, L"[CommonRegisterServers] Preparing to launch %s\n",
  1833. wszFileToRun);
  1834. LaunchProcessAndWait(wszFileToRun, NULL);
  1835. if (fRegister) {
  1836. //
  1837. // Now save an entry to the queue
  1838. //
  1839. wsprintf(wszEntryToSave,
  1840. L"%s\\%s\\%s",
  1841. g_si.lpwWindowsDirectory,
  1842. lpwDestDir,
  1843. wszFileName);
  1844. wsprintf(wszKey, L"%u", ++uCount);
  1845. wsprintf(wszSectionName,
  1846. L"%s.%s",
  1847. INF_UNREGISTRATIONSW,
  1848. lpwDestDir);
  1849. SaveEntryToINF(wszSectionName,
  1850. wszKey,
  1851. wszEntryToSave,
  1852. g_si.lpwUninstallINFPath);
  1853. }
  1854. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  1855. SetupGetLineTextA(&InfContext,
  1856. NULL, NULL, NULL,
  1857. szFileName, MAX_PATH, NULL);
  1858. }
  1859. }
  1860. return TRUE;
  1861. }
  1862. /*++
  1863. Routine Description:
  1864. Removes all files from the specified directory,
  1865. then removes the directory
  1866. Arguments:
  1867. lpwDirectoryPath - Full path to the directory
  1868. pEnumerateParameter - A parameter for misc storage
  1869. fRemoveDirectory - A flag to indicate if we should
  1870. remove the directory
  1871. fRemoveSubDirs - A flag to indicate if we should
  1872. remove subdirectories
  1873. Return Value:
  1874. TRUE on success, FALSE otherwise
  1875. --*/
  1876. BOOL
  1877. CommonRemoveDirectoryAndFiles(
  1878. IN LPCWSTR lpwDirectoryPath,
  1879. IN PVOID pEnumerateParameter,
  1880. IN BOOL fRemoveDirectory,
  1881. IN BOOL fRemoveSubDirs
  1882. )
  1883. {
  1884. CEnumDir ced;
  1885. //
  1886. // Remove any files from the directory
  1887. //
  1888. ced.EnumerateDirectoryTree(lpwDirectoryPath,
  1889. DeleteOneFile,
  1890. fRemoveSubDirs,
  1891. pEnumerateParameter);
  1892. //
  1893. // Now try to remove the directory itself
  1894. //
  1895. if (fRemoveDirectory) {
  1896. SetFileAttributes(lpwDirectoryPath, FILE_ATTRIBUTE_NORMAL);
  1897. if (!RemoveDirectory(lpwDirectoryPath)) {
  1898. Print(ERROR,
  1899. L"[CommonRemoveDirectoryAndFiles] Failed to remove directory %s\n",
  1900. lpwDirectoryPath);
  1901. return FALSE;
  1902. }
  1903. }
  1904. return TRUE;
  1905. }
  1906. /*++
  1907. Routine Description:
  1908. Enables protected renames in the registry
  1909. Arguments:
  1910. None
  1911. Return Value:
  1912. TRUE on success, FALSE otherwise
  1913. --*/
  1914. BOOL
  1915. CommonEnableProtectedRenames()
  1916. {
  1917. CRegistry creg;
  1918. BOOL fReturn = FALSE;
  1919. fReturn = creg.SetDword(HKEY_LOCAL_MACHINE,
  1920. REG_SESSION_MANAGER,
  1921. REG_PROT_RENAMES,
  1922. (DWORD) 1,
  1923. TRUE);
  1924. return (fReturn);
  1925. }
  1926. /*++
  1927. Routine Description:
  1928. Installs a catalog file
  1929. Arguments:
  1930. lpwCatalogFullPath - Full path to the catalog file
  1931. lpwNewBaseName - Name catalog should get when
  1932. it's installed in the store
  1933. Return Value:
  1934. NO_ERROR on success
  1935. --*/
  1936. #ifdef WIN2KSE
  1937. DWORD
  1938. pInstallCatalogFile(
  1939. IN LPCWSTR lpwCatalogFullPath,
  1940. IN LPCWSTR lpwNewBaseName
  1941. )
  1942. {
  1943. DWORD dwError = 0;
  1944. dwError = VerifyCatalogFile(lpwCatalogFullPath);
  1945. if (dwError == NO_ERROR) {
  1946. dwError = InstallCatalog(lpwCatalogFullPath, lpwNewBaseName, NULL);
  1947. }
  1948. return (dwError);
  1949. }
  1950. #else
  1951. DWORD
  1952. pInstallCatalogFile(
  1953. IN LPCWSTR lpwCatalogFullPath,
  1954. IN LPCWSTR lpwNewBaseName
  1955. )
  1956. {
  1957. DWORD dwError = 0;
  1958. dwError = pSetupVerifyCatalogFile(lpwCatalogFullPath);
  1959. if (dwError == NO_ERROR) {
  1960. dwError = pSetupInstallCatalog(lpwCatalogFullPath, lpwNewBaseName, NULL);
  1961. }
  1962. return (dwError);
  1963. }
  1964. #endif