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.

1737 lines
44 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. dynupdt.c
  5. Abstract:
  6. Routines to handle dynamic update support during GUI setup phase
  7. Author:
  8. Ovidiu Temereanca (ovidiut) 15-Aug-2000
  9. Revision History:
  10. --*/
  11. #include "setupp.h"
  12. #include "hwdb.h"
  13. #include "newdev.h"
  14. #pragma hdrstop
  15. #define STR_UPDATES_INF TEXT("updates.inf")
  16. #define STR_DEFAULTINSTALL TEXT("DefaultInstall")
  17. #define STR_DRIVERCACHEINF TEXT("drvindex.inf")
  18. #define STR_VERSION TEXT("Version")
  19. #define STR_CABFILES TEXT("CabFiles")
  20. #define STR_CABS TEXT("Cabs")
  21. #define S_HWCOMP_DAT TEXT("hwcomp.dat")
  22. static TCHAR g_DuShare[MAX_PATH];
  23. BOOL
  24. BuildPath (
  25. OUT PTSTR PathBuffer,
  26. IN DWORD PathBufferSize,
  27. IN PCTSTR Path1,
  28. IN PCTSTR Path2
  29. )
  30. /*++
  31. Routine Description:
  32. This function builds a path given the 2 components, assumed not to contain
  33. trailing or heading wacks
  34. Arguments:
  35. PathBuffer - Receives the full path
  36. PathBuferSize - The size in chars of PathBuffer
  37. Path1 - Specifies the head path
  38. Path2 - Specifies the tail path
  39. Return Value:
  40. TRUE to indicate success; FALSE in case of failure; it means the supplied buffer
  41. was too small to fit the whole new path
  42. --*/
  43. {
  44. if (!Path1 || !Path2) {
  45. MYASSERT (FALSE);
  46. return FALSE;
  47. }
  48. return _sntprintf (PathBuffer, PathBufferSize, TEXT("%s\\%s"), Path1, Path2) > 0;
  49. }
  50. BOOL
  51. pDoesFileExist (
  52. IN PCTSTR FilePath
  53. )
  54. {
  55. WIN32_FIND_DATA fd;
  56. return FileExists (FilePath, &fd) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  57. }
  58. BOOL
  59. pDoesDirExist (
  60. IN PCTSTR FilePath
  61. )
  62. {
  63. WIN32_FIND_DATA fd;
  64. return FileExists (FilePath, &fd) && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  65. }
  66. DWORD
  67. CreateMultiLevelDirectory (
  68. IN LPCTSTR Directory
  69. )
  70. /*++
  71. Routine Description:
  72. This routine ensures that a multi-level path exists by creating individual
  73. levels one at a time. It can handle either paths of form x:... or \\?\Volume{...
  74. Arguments:
  75. Directory - supplies fully-qualified Win32 pathspec of directory to create
  76. Return Value:
  77. Win32 error code indicating outcome.
  78. --*/
  79. {
  80. TCHAR Buffer[MAX_PATH];
  81. PTSTR p,q;
  82. TCHAR c;
  83. BOOL Done;
  84. DWORD d = ERROR_SUCCESS;
  85. lstrcpyn(Buffer,Directory,MAX_PATH);
  86. //
  87. // If it already exists do nothing. (We do this before syntax checking
  88. // to allow for remote paths that already exist. This is needed for
  89. // remote boot machines.)
  90. //
  91. d = GetFileAttributes(Buffer);
  92. if(d != (DWORD)(-1)) {
  93. return((d & FILE_ATTRIBUTE_DIRECTORY) ? NO_ERROR : ERROR_DIRECTORY);
  94. }
  95. //
  96. // Check path format
  97. //
  98. c = (TCHAR)CharUpper((LPTSTR)Buffer[0]);
  99. if (c < TEXT('A') || c > TEXT('Z') || Buffer[1] != TEXT(':')) {
  100. return ERROR_INVALID_PARAMETER;
  101. }
  102. if(Buffer[2] != TEXT('\\')) {
  103. return(Buffer[2] ? ERROR_INVALID_PARAMETER : ERROR_SUCCESS);
  104. }
  105. q = Buffer + 3;
  106. if(*q == 0) {
  107. return(ERROR_SUCCESS);
  108. }
  109. Done = FALSE;
  110. do {
  111. //
  112. // Locate the next path sep char. If there is none then
  113. // this is the deepest level of the path.
  114. //
  115. if(p = _tcschr(q,TEXT('\\'))) {
  116. *p = 0;
  117. } else {
  118. Done = TRUE;
  119. }
  120. //
  121. // Create this portion of the path.
  122. //
  123. if(CreateDirectory(Buffer,NULL)) {
  124. d = ERROR_SUCCESS;
  125. } else {
  126. d = GetLastError();
  127. if(d == ERROR_ALREADY_EXISTS) {
  128. d = ERROR_SUCCESS;
  129. }
  130. }
  131. if(d == ERROR_SUCCESS) {
  132. //
  133. // Put back the path sep and move to the next component.
  134. //
  135. if(!Done) {
  136. *p = TEXT('\\');
  137. q = p+1;
  138. }
  139. } else {
  140. Done = TRUE;
  141. }
  142. } while(!Done);
  143. return(d);
  144. }
  145. DWORD
  146. GetDriverCacheSourcePath (
  147. OUT PTSTR Buffer,
  148. IN DWORD BufChars
  149. )
  150. /*++
  151. Routine Description:
  152. This routine returns the source path to the local driver cache.
  153. This value is retrieved from the following registry location:
  154. \HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
  155. DriverCachePath : REG_EXPAND_SZ :
  156. Arguments:
  157. Buffer - Receives the path.
  158. BufChars - Specifies the size of Buffer, in chars
  159. Return Value:
  160. If the function succeeds, the return value is TRUE
  161. If the function fails, the return value is FALSE.
  162. --*/
  163. {
  164. HKEY hKey;
  165. DWORD rc, DataType, DataSize;
  166. TCHAR Value[MAX_PATH];
  167. rc = RegOpenKeyEx(
  168. HKEY_LOCAL_MACHINE,
  169. REGSTR_PATH_SETUP TEXT("\\Setup"),
  170. 0,
  171. KEY_READ,
  172. &hKey
  173. );
  174. if(rc == ERROR_SUCCESS) {
  175. //
  176. // Attempt to read the "DriverCachePath" value.
  177. //
  178. DataSize = sizeof (Value);
  179. rc = RegQueryValueEx (hKey, REGSTR_VAL_DRIVERCACHEPATH, NULL, &DataType, (PBYTE)Value, &DataSize);
  180. RegCloseKey(hKey);
  181. if(rc == ERROR_SUCCESS) {
  182. ExpandEnvironmentStrings (Value, Buffer, BufChars - 6);
  183. if (Buffer[0]) {
  184. _tcscat (
  185. Buffer,
  186. #if defined(_AMD64_)
  187. TEXT("\\amd64")
  188. #elif defined(_X86_)
  189. IsNEC_98 ? TEXT("\\nec98") : TEXT("\\i386")
  190. #elif defined(_IA64_)
  191. TEXT("\\ia64")
  192. #else
  193. #error "No Target Architecture"
  194. #endif
  195. );
  196. return ERROR_SUCCESS;
  197. } else {
  198. rc = ERROR_INVALID_DATA;
  199. }
  200. }
  201. }
  202. return rc;
  203. }
  204. PCTSTR
  205. FindSubString (
  206. IN PCTSTR String,
  207. IN TCHAR Separator,
  208. IN PCTSTR SubStr,
  209. IN BOOL CaseSensitive
  210. )
  211. /*++
  212. Routine Description:
  213. This function looks for a substring of a given string, only if found
  214. between the specified separator chars
  215. Arguments:
  216. String - Specifies the full string
  217. Separator - Specifies the separator
  218. SubStr - Specifies the sub string to look for
  219. CaseSensitive - Specifies if the comparison should be case sensitive or not
  220. Return Value:
  221. NULL if the substring was not found; a pointer to the SubString inside String
  222. if it was found
  223. --*/
  224. {
  225. SIZE_T len1, len2;
  226. PCTSTR end;
  227. MYASSERT (Separator);
  228. MYASSERT (SubStr);
  229. MYASSERT (!_tcschr (SubStr, Separator));
  230. len1 = lstrlen (SubStr);
  231. MYASSERT (SubStr[len1] == 0);
  232. while (String) {
  233. end = _tcschr (String, Separator);
  234. if (end) {
  235. len2 = end - String;
  236. } else {
  237. len2 = lstrlen (String);
  238. }
  239. if ((len1 == len2) &&
  240. (CaseSensitive ?
  241. !_tcsncmp (String, SubStr, len1) :
  242. !_tcsnicmp (String, SubStr, len1)
  243. )) {
  244. break;
  245. }
  246. if (end) {
  247. String = end + 1;
  248. } else {
  249. String = NULL;
  250. }
  251. }
  252. return String;
  253. }
  254. BOOL
  255. UpdateDrvIndex (
  256. IN PCTSTR InfPath,
  257. IN PCTSTR CabFilename,
  258. IN PCTSTR SourceSifPath
  259. )
  260. /*++
  261. Routine Description:
  262. This function fixes drvindex.inf such that SetupApi
  263. will pick up the file from the right cabinet
  264. Arguments:
  265. InfPath - Specifies the full path to drvindex.inf
  266. CabFilename - Specifies the filename of the
  267. updates cabinet (basically it's "updates.cab")
  268. SourceSifPath - Specifies the full path to the associated
  269. updates.sif containing the list of files in updates.cab
  270. Return Value:
  271. TRUE to indicate success; FALSE in case of failure; use GetLastError()
  272. to find the reason of failure
  273. --*/
  274. {
  275. HANDLE sectFile = INVALID_HANDLE_VALUE;
  276. HANDLE concatFile = INVALID_HANDLE_VALUE;
  277. HANDLE hMap = NULL;
  278. PTSTR section = NULL;
  279. PBYTE base = NULL;
  280. TCHAR tempPath[MAX_PATH];
  281. TCHAR tempFile[MAX_PATH];
  282. TCHAR temp[MAX_PATH];
  283. PTSTR p;
  284. DWORD sectSize;
  285. DWORD concatSize;
  286. DWORD rc;
  287. DWORD bytes;
  288. BOOL b = FALSE;
  289. //
  290. // create a temp file to put the new section in it
  291. //
  292. if (!GetTempPath (MAX_PATH, tempPath) ||
  293. !GetTempFileName (tempPath, TEXT("STP"), 0, tempFile)
  294. ) {
  295. return FALSE;
  296. }
  297. __try {
  298. if (!CopyFile (InfPath, tempFile, FALSE)) {
  299. __leave;
  300. }
  301. SetFileAttributes (tempFile, FILE_ATTRIBUTE_NORMAL);
  302. section = pSetupDuplicateString (CabFilename);
  303. if (!section) {
  304. __leave;
  305. }
  306. p = _tcsrchr (section, TEXT('.'));
  307. if (p) {
  308. *p = 0;
  309. }
  310. if (GetPrivateProfileString (
  311. STR_CABS,
  312. section,
  313. TEXT(""),
  314. temp,
  315. MAX_PATH,
  316. tempFile
  317. )) {
  318. if (lstrcmpi (temp, CabFilename) == 0) {
  319. if (GetPrivateProfileString (
  320. STR_VERSION,
  321. STR_CABFILES,
  322. TEXT(""),
  323. tempPath,
  324. MAX_PATH,
  325. tempFile
  326. )) {
  327. if (FindSubString (tempPath, TEXT(','), section, FALSE)) {
  328. //
  329. // setup restarted, but drvindex.inf is already patched; nothing to do
  330. //
  331. b = TRUE;
  332. __leave;
  333. }
  334. }
  335. }
  336. }
  337. if (!WritePrivateProfileString (
  338. STR_CABS,
  339. section,
  340. CabFilename,
  341. tempFile
  342. )) {
  343. __leave;
  344. }
  345. if (!GetPrivateProfileString (
  346. STR_VERSION,
  347. STR_CABFILES,
  348. TEXT(""),
  349. tempPath,
  350. MAX_PATH,
  351. tempFile
  352. )) {
  353. __leave;
  354. }
  355. if (!FindSubString (tempPath, TEXT(','), section, FALSE)) {
  356. wsprintf (temp, TEXT("%s,%s"), section, tempPath);
  357. if (!WritePrivateProfileString (
  358. STR_VERSION,
  359. STR_CABFILES,
  360. temp,
  361. tempFile
  362. )) {
  363. __leave;
  364. }
  365. }
  366. sectFile = CreateFile (
  367. SourceSifPath,
  368. GENERIC_READ,
  369. 0,
  370. NULL,
  371. OPEN_EXISTING,
  372. FILE_ATTRIBUTE_NORMAL,
  373. NULL
  374. );
  375. if (sectFile == INVALID_HANDLE_VALUE) {
  376. __leave;
  377. }
  378. sectSize = GetFileSize (sectFile, NULL);
  379. if (sectSize == INVALID_FILE_SIZE) {
  380. __leave;
  381. }
  382. concatFile = CreateFile (
  383. tempFile,
  384. GENERIC_READ | GENERIC_WRITE,
  385. 0,
  386. NULL,
  387. OPEN_EXISTING,
  388. FILE_ATTRIBUTE_NORMAL,
  389. NULL
  390. );
  391. if (concatFile == INVALID_HANDLE_VALUE) {
  392. __leave;
  393. }
  394. concatSize = GetFileSize (concatFile, NULL);
  395. if (concatSize == INVALID_FILE_SIZE) {
  396. __leave;
  397. }
  398. hMap = CreateFileMapping (concatFile, NULL, PAGE_READWRITE, 0, concatSize + sectSize, NULL);
  399. if (!hMap) {
  400. __leave;
  401. }
  402. base = MapViewOfFile (
  403. hMap,
  404. FILE_MAP_ALL_ACCESS,
  405. 0,
  406. 0,
  407. 0
  408. );
  409. if (!base) {
  410. __leave;
  411. }
  412. //
  413. // make sure concatFile file didn't end in end-of-file
  414. //
  415. if (base[concatSize - 1] == 0x1A) {
  416. base[concatSize - 1] = ' ';
  417. }
  418. //
  419. // now append the other file
  420. //
  421. if (!ReadFile (sectFile, (LPVOID)(base + concatSize), sectSize, &bytes, NULL) || bytes != sectSize) {
  422. __leave;
  423. }
  424. //
  425. // now try to commit changes
  426. //
  427. if (!UnmapViewOfFile (base)) {
  428. __leave;
  429. }
  430. base = NULL;
  431. if (!CloseHandle (hMap)) {
  432. __leave;
  433. }
  434. hMap = NULL;
  435. //
  436. // close the handle to the temporary file and overwrite the real one
  437. //
  438. if (!CloseHandle (concatFile)) {
  439. __leave;
  440. }
  441. concatFile = INVALID_HANDLE_VALUE;
  442. SetFileAttributes (InfPath, FILE_ATTRIBUTE_NORMAL);
  443. b = MoveFileEx (tempFile, InfPath, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
  444. }
  445. __finally {
  446. rc = b ? ERROR_SUCCESS : GetLastError ();
  447. DeleteFile (tempFile);
  448. if (base) {
  449. UnmapViewOfFile (base);
  450. }
  451. if (hMap) {
  452. CloseHandle (hMap);
  453. }
  454. if (concatFile != INVALID_HANDLE_VALUE) {
  455. CloseHandle (concatFile);
  456. }
  457. if (sectFile != INVALID_HANDLE_VALUE) {
  458. CloseHandle (sectFile);
  459. }
  460. if (section) {
  461. MyFree (section);
  462. }
  463. SetLastError (rc);
  464. }
  465. return b;
  466. }
  467. UINT
  468. pExpandUpdatesCab (
  469. IN PVOID Context,
  470. IN UINT Code,
  471. IN UINT_PTR Param1,
  472. IN UINT_PTR Param2
  473. )
  474. {
  475. switch (Code) {
  476. case SPFILENOTIFY_FILEINCABINET:
  477. {
  478. PFILE_IN_CABINET_INFO FileInCabInfo = (PFILE_IN_CABINET_INFO)Param1;
  479. //
  480. // extract the file name
  481. //
  482. PCTSTR p = _tcsrchr (FileInCabInfo->NameInCabinet, TEXT('\\'));
  483. if (p) {
  484. p++;
  485. } else {
  486. p = FileInCabInfo->NameInCabinet;
  487. }
  488. lstrcpy (FileInCabInfo->FullTargetName, (PCTSTR)Context);
  489. pSetupConcatenatePaths (
  490. FileInCabInfo->FullTargetName,
  491. p,
  492. SIZECHARS (FileInCabInfo->FullTargetName),
  493. NULL
  494. );
  495. return FILEOP_DOIT;
  496. }
  497. case SPFILENOTIFY_NEEDNEWCABINET:
  498. {
  499. PCABINET_INFO CabInfo = (PCABINET_INFO)Param1;
  500. SetuplogError(
  501. LogSevError,
  502. SETUPLOG_USE_MESSAGEID,
  503. MSG_LOG_SYSSETUP_CAB_MISSING,
  504. CabInfo->CabinetPath,
  505. CabInfo->CabinetFile,
  506. CabInfo->DiskName,
  507. CabInfo->SetId,
  508. CabInfo->CabinetNumber,
  509. NULL,
  510. NULL
  511. );
  512. return ERROR_FILE_NOT_FOUND;
  513. }
  514. }
  515. return NO_ERROR;
  516. }
  517. VOID
  518. pInstallUpdatesInf (
  519. VOID
  520. )
  521. /*++
  522. Routine Description:
  523. This function installs the STR_DEFAULTINSTALL section of STR_UPDATES_INF
  524. if this file is found inside updates.cab
  525. Arguments:
  526. none
  527. Return Value:
  528. none
  529. --*/
  530. {
  531. TCHAR infPath[MAX_PATH];
  532. TCHAR commandLine[MAX_PATH + 30];
  533. STARTUPINFO si;
  534. PROCESS_INFORMATION pi;
  535. MYASSERT (!MiniSetup && !OobeSetup);
  536. MYASSERT (g_DuShare[0]);
  537. BuildPath (infPath, MAX_PATH, g_DuShare, STR_UPDATES_INF);
  538. if (pDoesFileExist (infPath)) {
  539. //
  540. // install this INF as if the user chose "Install" on the right-click popup menu
  541. //
  542. wsprintf (
  543. commandLine,
  544. TEXT("RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection %s %u %s"),
  545. STR_DEFAULTINSTALL,
  546. 128, // don't reboot
  547. infPath
  548. );
  549. ZeroMemory (&si, sizeof (si));
  550. si.cb = sizeof (si);
  551. if (CreateProcess (
  552. NULL,
  553. commandLine,
  554. NULL,
  555. NULL,
  556. FALSE,
  557. CREATE_NO_WINDOW | ABOVE_NORMAL_PRIORITY_CLASS,
  558. NULL,
  559. NULL,
  560. &si,
  561. &pi
  562. )) {
  563. CloseHandle (pi.hProcess);
  564. CloseHandle (pi.hThread);
  565. }
  566. } else {
  567. SetuplogError (
  568. LogSevInformation,
  569. TEXT("DUInfo: No %1 to install"),
  570. 0,
  571. STR_UPDATES_INF,
  572. NULL,
  573. NULL
  574. );
  575. }
  576. }
  577. BOOL
  578. DuInitialize (
  579. VOID
  580. )
  581. /*++
  582. Routine Description:
  583. This function initializes DU in GUI setup
  584. Arguments:
  585. none
  586. Return Value:
  587. TRUE to indicate success; FALSE in case of failure; use GetLastError()
  588. to find the reason of failure
  589. --*/
  590. {
  591. PTSTR cabFilename;
  592. TCHAR sourceCabPath[MAX_PATH];
  593. TCHAR workingDir[MAX_PATH];
  594. DWORD rc;
  595. MYASSERT (!MiniSetup && !OobeSetup);
  596. MYASSERT (AnswerFile[0]);
  597. if (!GetPrivateProfileString (
  598. WINNT_SETUPPARAMS,
  599. WINNT_SP_UPDATEDSOURCES,
  600. TEXT(""),
  601. sourceCabPath,
  602. MAX_PATH,
  603. AnswerFile
  604. )) {
  605. return TRUE;
  606. }
  607. if (!GetPrivateProfileString (
  608. WINNT_SETUPPARAMS,
  609. WINNT_SP_DYNUPDTWORKINGDIR,
  610. TEXT(""),
  611. workingDir,
  612. MAX_PATH,
  613. AnswerFile
  614. )) {
  615. MYASSERT (FALSE);
  616. if (!GetWindowsDirectory (workingDir, MAX_PATH)) {
  617. return FALSE;
  618. }
  619. pSetupConcatenatePaths (workingDir, TEXT("setupupd"), MAX_PATH, NULL);
  620. WritePrivateProfileString (
  621. WINNT_SETUPPARAMS,
  622. WINNT_SP_DYNUPDTWORKINGDIR,
  623. workingDir,
  624. AnswerFile
  625. );
  626. }
  627. MYASSERT (workingDir[0]);
  628. pSetupConcatenatePaths (workingDir, TEXT("updates"), MAX_PATH, NULL);
  629. pSetupConcatenatePaths (
  630. workingDir,
  631. #if defined(_AMD64_)
  632. TEXT("amd64"),
  633. #elif defined(_X86_)
  634. TEXT("i386"),
  635. #elif defined(_IA64_)
  636. TEXT("ia64"),
  637. #else
  638. #error "No Target Architecture"
  639. #endif
  640. MAX_PATH,
  641. NULL
  642. );
  643. if (CreateMultiLevelDirectory (workingDir) != ERROR_SUCCESS) {
  644. rc = GetLastError ();
  645. SetuplogError (
  646. LogSevError,
  647. TEXT("DUError: DuInitialize: failed to create %1 (%2!u!)\r\n"),
  648. 0,
  649. workingDir,
  650. rc,
  651. NULL,
  652. NULL
  653. );
  654. return FALSE;
  655. }
  656. //
  657. // expand updates.cab in this folder
  658. //
  659. if (!SetupIterateCabinet (sourceCabPath, 0, pExpandUpdatesCab, (PVOID)workingDir)) {
  660. rc = GetLastError ();
  661. SetuplogError (
  662. LogSevError,
  663. TEXT("DUError: DuInitialize: failed to expand %1 to %2 (%3!u!)\r\n"),
  664. 0,
  665. sourceCabPath,
  666. workingDir,
  667. rc,
  668. NULL,
  669. NULL
  670. );
  671. return FALSE;
  672. }
  673. //
  674. // OK, everything is set up; go ahead and set the global variable
  675. //
  676. lstrcpy (g_DuShare, workingDir);
  677. return TRUE;
  678. }
  679. DWORD
  680. DuInstallCatalogs (
  681. OUT SetupapiVerifyProblem* Problem,
  682. OUT PTSTR ProblemFile,
  683. IN PCTSTR DescriptionForError OPTIONAL
  684. )
  685. /*++
  686. Routine Description:
  687. This function installs any catalogs found inside updates.cab
  688. Arguments:
  689. same as InstallProductCatalogs
  690. Return Value:
  691. If successful, the return value is ERROR_SUCCESS, otherwise it is a Win32 error
  692. code indicating the cause of the failure.
  693. --*/
  694. {
  695. TCHAR catPath[MAX_PATH];
  696. WIN32_FIND_DATA fd;
  697. HANDLE h;
  698. UINT ErrorMessageId;
  699. DWORD rc = ERROR_SUCCESS;
  700. MYASSERT (!MiniSetup && !OobeSetup);
  701. if (!g_DuShare[0]) {
  702. return ERROR_SUCCESS;
  703. }
  704. BuildPath (catPath, MAX_PATH, g_DuShare, TEXT("*.cat"));
  705. h = FindFirstFile (catPath, &fd);
  706. if (h != INVALID_HANDLE_VALUE) {
  707. do {
  708. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  709. BuildPath (catPath, MAX_PATH, g_DuShare, fd.cFileName);
  710. rc = pSetupVerifyCatalogFile (catPath);
  711. if (rc == NO_ERROR) {
  712. rc = pSetupInstallCatalog(catPath, fd.cFileName, NULL);
  713. if(rc != NO_ERROR) {
  714. ErrorMessageId = MSG_LOG_SYSSETUP_CATINSTALL_FAILED;
  715. }
  716. } else {
  717. ErrorMessageId = MSG_LOG_SYSSETUP_VERIFY_FAILED;
  718. }
  719. if(rc != NO_ERROR) {
  720. SetuplogError (
  721. LogSevError,
  722. SETUPLOG_USE_MESSAGEID,
  723. ErrorMessageId,
  724. catPath,
  725. rc,
  726. NULL,
  727. NULL
  728. );
  729. //
  730. // Also, add an entry about this failure to setupapi's PSS
  731. // exception logfile.
  732. //
  733. pSetupHandleFailedVerification (
  734. MainWindowHandle,
  735. SetupapiVerifyCatalogProblem,
  736. catPath,
  737. DescriptionForError,
  738. pSetupGetCurrentDriverSigningPolicy(FALSE),
  739. TRUE, // no UI!
  740. rc,
  741. NULL, // log context
  742. NULL, // optional flags
  743. NULL
  744. );
  745. break;
  746. }
  747. }
  748. } while (FindNextFile (h, &fd));
  749. FindClose (h);
  750. } else {
  751. SetuplogError (
  752. LogSevWarning,
  753. TEXT("DUWarning: no catalogs found in %1\r\n"),
  754. 0,
  755. g_DuShare,
  756. NULL,
  757. NULL
  758. );
  759. }
  760. return rc;
  761. }
  762. DWORD
  763. DuInstallUpdates (
  764. VOID
  765. )
  766. /*++
  767. Routine Description:
  768. This routine updates drvindex.inf to point setupapi to the new binaries.
  769. Arguments:
  770. none
  771. Return Value:
  772. If successful, the return value is ERROR_SUCCESS, otherwise it is a Win32 error
  773. code indicating the cause of the failure.
  774. --*/
  775. {
  776. PTSTR cabFilename;
  777. TCHAR sourceCabPath[MAX_PATH];
  778. TCHAR sourceSifPath[MAX_PATH];
  779. TCHAR cabPath[MAX_PATH];
  780. TCHAR infPath[MAX_PATH];
  781. TCHAR tmpPath[MAX_PATH];
  782. DWORD rc;
  783. MYASSERT (!MiniSetup && !OobeSetup);
  784. if (!g_DuShare[0]) {
  785. return ERROR_SUCCESS;
  786. }
  787. //
  788. // make sure updates.sif is available
  789. //
  790. if (!GetPrivateProfileString (
  791. WINNT_SETUPPARAMS,
  792. WINNT_SP_UPDATEDSOURCES,
  793. TEXT(""),
  794. sourceCabPath,
  795. MAX_PATH,
  796. AnswerFile
  797. )) {
  798. return GetLastError ();
  799. }
  800. lstrcpy (sourceSifPath, sourceCabPath);
  801. cabFilename = _tcsrchr (sourceSifPath, TEXT('.'));
  802. if (!cabFilename || _tcschr (cabFilename, TEXT('\\'))) {
  803. SetuplogError (
  804. LogSevError,
  805. SETUPLOG_USE_MESSAGEID,
  806. MSG_LOG_INVALID_UPDATESCAB_NAME,
  807. sourceCabPath,
  808. NULL,
  809. NULL
  810. );
  811. return ERROR_INVALID_DATA;
  812. }
  813. lstrcpy (cabFilename + 1, TEXT("sif"));
  814. if (!pDoesFileExist (sourceSifPath)) {
  815. rc = GetLastError ();
  816. SetuplogError (
  817. LogSevError,
  818. SETUPLOG_USE_MESSAGEID,
  819. MSG_LOG_UPDATESSIF_NOT_FOUND,
  820. sourceSifPath,
  821. sourceCabPath,
  822. rc,
  823. NULL,
  824. NULL
  825. );
  826. return rc;
  827. }
  828. //
  829. // copy this where source cabs reside
  830. //
  831. rc = GetDriverCacheSourcePath (cabPath, MAX_PATH);
  832. if (rc != ERROR_SUCCESS) {
  833. SetuplogError (
  834. LogSevError,
  835. SETUPLOG_USE_MESSAGEID,
  836. MSG_LOG_DRIVER_CACHE_NOT_FOUND,
  837. rc,
  838. NULL,
  839. NULL
  840. );
  841. return rc;
  842. }
  843. cabFilename = _tcsrchr (sourceCabPath, TEXT('\\'));
  844. if (cabFilename) {
  845. cabFilename++;
  846. } else {
  847. cabFilename = cabPath;
  848. }
  849. pSetupConcatenatePaths (cabPath, cabFilename, MAX_PATH, NULL);
  850. //
  851. // GUI setup should be restartable; copy file, don't move it
  852. //
  853. SetFileAttributes (cabPath, FILE_ATTRIBUTE_NORMAL);
  854. if (!CopyFile (sourceCabPath, cabPath, FALSE)) {
  855. rc = GetLastError ();
  856. SetuplogError (
  857. LogSevError,
  858. SETUPLOG_USE_MESSAGEID,
  859. MSG_LOG_FAILED_TO_COPY_UPDATES,
  860. rc,
  861. NULL,
  862. NULL
  863. );
  864. return rc;
  865. }
  866. //
  867. // now make sure the file attributes are set to RHS to protect it
  868. //
  869. SetFileAttributes (cabPath, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
  870. //
  871. // temp folder for expanded files
  872. //
  873. if (!GetTempPath (MAX_PATH, tmpPath)) {
  874. rc = GetLastError ();
  875. return rc;
  876. }
  877. //
  878. // full path to drvindex.inf, assuming the file is in %windir%\inf
  879. //
  880. if (!GetWindowsDirectory (infPath, MAX_PATH)) {
  881. rc = GetLastError ();
  882. return rc;
  883. }
  884. _tcscat (infPath, TEXT("\\inf\\"));
  885. _tcscat (infPath, STR_DRIVERCACHEINF);
  886. if (GetFileAttributes (infPath) == (DWORD)-1) {
  887. rc = GetLastError ();
  888. SetuplogError (
  889. LogSevError,
  890. TEXT("DUError: %1 not found (rc=%2!u!)\r\n"),
  891. 0,
  892. infPath,
  893. rc,
  894. NULL,
  895. NULL
  896. );
  897. return rc;
  898. }
  899. //
  900. // now patch drvindex.inf
  901. //
  902. if (!UpdateDrvIndex (infPath, cabFilename, sourceSifPath)) {
  903. rc = GetLastError ();
  904. SetuplogError (
  905. LogSevError,
  906. SETUPLOG_USE_MESSAGEID,
  907. MSG_LOG_FAILED_TO_UPDATE_DRVINDEX,
  908. rc,
  909. NULL,
  910. NULL
  911. );
  912. SetFileAttributes (cabPath, FILE_ATTRIBUTE_NORMAL);
  913. DeleteFile (cabPath);
  914. return rc;
  915. }
  916. //
  917. // finally run updates.inf
  918. //
  919. pInstallUpdatesInf ();
  920. return rc;
  921. }
  922. BOOL
  923. DuInstallEndGuiSetupDrivers (
  924. VOID
  925. )
  926. /*++
  927. Routine Description:
  928. This routine installs any WU drivers not approved for the beginning of GUI setup.
  929. Arguments:
  930. none
  931. Return Value:
  932. If successful, the return value is TRUE
  933. --*/
  934. {
  935. DWORD chars;
  936. TCHAR datPath[MAX_PATH];
  937. TCHAR infPath[MAX_PATH];
  938. TCHAR buf[MAX_PATH * 16];
  939. PTSTR source, p, next;
  940. BOOL bRebootRequired;
  941. HWDBINF_ENUM e;
  942. PCTSTR pnpId;
  943. HMODULE hNewDev;
  944. HINF hGuiDrvsInf;
  945. INFCONTEXT ic;
  946. UINT line;
  947. BOOL (WINAPI* pfnUpdateDriver) (
  948. HWND hwndParent,
  949. LPCWSTR HardwareId,
  950. LPCWSTR FullInfPath,
  951. DWORD InstallFlags,
  952. PBOOL bRebootRequired OPTIONAL
  953. );
  954. //
  955. // try to append any additional POST GUI setup drivers
  956. // in the DevicePath
  957. //
  958. if (!SpSetupLoadParameter (
  959. WINNT_SP_DYNUPDTADDITIONALPOSTGUIDRIVERS,
  960. buf,
  961. MAX_PATH * 16
  962. )) {
  963. return TRUE;
  964. }
  965. chars = lstrlen (buf);
  966. if (!chars) {
  967. return TRUE;
  968. }
  969. //
  970. // load the support library newdev.dll
  971. //
  972. hNewDev = LoadLibrary (TEXT("newdev.dll"));
  973. if (!hNewDev) {
  974. return FALSE;
  975. }
  976. (FARPROC)pfnUpdateDriver = GetProcAddress (hNewDev, "UpdateDriverForPlugAndPlayDevicesW");
  977. if (!pfnUpdateDriver) {
  978. FreeLibrary (hNewDev);
  979. return FALSE;
  980. }
  981. if (!HwdbInitializeW (NULL)) {
  982. SetuplogError (
  983. LogSevWarning,
  984. TEXT("DUWarning: HwdbInitialize failed (rc=%1!u!); no DU drivers will be installed\r\n"),
  985. 0,
  986. GetLastError (),
  987. NULL,
  988. NULL
  989. );
  990. FreeLibrary (hNewDev);
  991. return FALSE;
  992. }
  993. //
  994. // look for driver-controlling inf
  995. //
  996. hGuiDrvsInf = INVALID_HANDLE_VALUE;
  997. if (SpSetupLoadParameter (
  998. WINNT_SP_DYNUPDTDRIVERINFOFILE,
  999. infPath,
  1000. MAX_PATH
  1001. )) {
  1002. if (pDoesFileExist (infPath)) {
  1003. hGuiDrvsInf = SetupOpenInfFile (infPath, NULL, INF_STYLE_WIN4, &line);
  1004. if (hGuiDrvsInf == INVALID_HANDLE_VALUE) {
  1005. SetuplogError (
  1006. LogSevWarning,
  1007. TEXT("DUWarning: SetupOpenInfFile(%1) failed (rc=%2!u!); all DU drivers will be installed\r\n"),
  1008. 0,
  1009. infPath,
  1010. GetLastError (),
  1011. NULL,
  1012. NULL
  1013. );
  1014. }
  1015. } else {
  1016. SetuplogError (
  1017. LogSevWarning,
  1018. TEXT("DUWarning: File %1 missing; all DU drivers will be installed\r\n"),
  1019. 0,
  1020. infPath,
  1021. NULL,
  1022. NULL
  1023. );
  1024. }
  1025. } else {
  1026. SetuplogError (
  1027. LogSevInformation,
  1028. TEXT("DUInfo: File %1 missing; all DU drivers will be installed\r\n"),
  1029. 0,
  1030. infPath,
  1031. NULL,
  1032. NULL
  1033. );
  1034. }
  1035. source = buf;
  1036. while (source) {
  1037. next = _tcschr (source, TEXT(','));
  1038. if (next) {
  1039. *next = 0;
  1040. }
  1041. p = source;
  1042. if (*p == TEXT('\"')) {
  1043. p = ++source;
  1044. }
  1045. while (*p && *p != TEXT('\"')) {
  1046. p++;
  1047. }
  1048. *p = 0;
  1049. if (pDoesDirExist (source)) {
  1050. BuildPath (datPath, MAX_PATH, source, S_HWCOMP_DAT);
  1051. if (pDoesFileExist (datPath)) {
  1052. //
  1053. // OK, we have the file with hardware info
  1054. //
  1055. if (HwdbEnumFirstInf (&e, datPath)) {
  1056. do {
  1057. BuildPath (infPath, MAX_PATH, source, e.InfFile);
  1058. if (!pDoesFileExist (infPath)) {
  1059. continue;
  1060. }
  1061. //
  1062. // iterate through all PNPIDs in this INF
  1063. //
  1064. for (pnpId = e.PnpIds; *pnpId; pnpId = _tcschr (pnpId, 0) + 1) {
  1065. //
  1066. // excluded PNPID are NOT in hwcomp.dat
  1067. // guidrvs.inf was already processed during winnt32
  1068. //
  1069. if (!pfnUpdateDriver (
  1070. NULL,
  1071. pnpId,
  1072. infPath,
  1073. 0, // BUGBUG - if we specify INSTALLFLAG_NONINTERACTIVE and there is a driver signing problem, the API will fail!
  1074. &bRebootRequired
  1075. )) {
  1076. if (GetLastError() != ERROR_SUCCESS) {
  1077. //
  1078. // well, if the device we wanted to update the driver for
  1079. // doesn't actually exist on this machine, don't log anything
  1080. //
  1081. if (GetLastError() != ERROR_NO_SUCH_DEVINST) {
  1082. SetuplogError (
  1083. LogSevWarning,
  1084. TEXT("DUWarning: UpdateDriverForPlugAndPlayDevices failed (rc=%3!u!) for PNPID=%1 (INF=%2)\r\n"),
  1085. 0,
  1086. pnpId,
  1087. infPath,
  1088. GetLastError (),
  1089. NULL,
  1090. NULL
  1091. );
  1092. }
  1093. } else {
  1094. SetuplogError (
  1095. LogSevInformation,
  1096. TEXT("DUInfo: UpdateDriverForPlugAndPlayDevices did not update the driver for PNPID=%1\r\n"),
  1097. 0,
  1098. pnpId,
  1099. NULL,
  1100. NULL
  1101. );
  1102. }
  1103. continue;
  1104. }
  1105. //
  1106. // SUCCESS! - log this information
  1107. //
  1108. SetuplogError (
  1109. LogSevInformation,
  1110. TEXT("DUInfo: UpdateDriverForPlugAndPlayDevices succeeded for PNPID=%1\r\n"),
  1111. 0,
  1112. pnpId,
  1113. NULL,
  1114. NULL
  1115. );
  1116. //
  1117. // also update the PNF with the info that this is an INTERNET driver
  1118. //
  1119. if (!SetupCopyOEMInf (
  1120. infPath,
  1121. NULL,
  1122. SPOST_URL,
  1123. SP_COPY_REPLACEONLY,
  1124. NULL,
  1125. 0,
  1126. NULL,
  1127. NULL
  1128. )) {
  1129. SetuplogError (
  1130. LogSevInformation,
  1131. TEXT("DUInfo: SetupCopyOEMInf failed to update OEMSourceMediaType for INF=%1\r\n"),
  1132. 0,
  1133. infPath,
  1134. NULL,
  1135. NULL
  1136. );
  1137. }
  1138. }
  1139. } while (HwdbEnumNextInf (&e));
  1140. }
  1141. }
  1142. }
  1143. if (next) {
  1144. source = next + 1;
  1145. } else {
  1146. source = NULL;
  1147. }
  1148. }
  1149. HwdbTerminate ();
  1150. FreeLibrary (hNewDev);
  1151. return TRUE;
  1152. }
  1153. VOID
  1154. DuCleanup (
  1155. VOID
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. This routine performs DU cleanup
  1160. Arguments:
  1161. none
  1162. Return Value:
  1163. none
  1164. --*/
  1165. {
  1166. TCHAR buf[MAX_PATH * 16];
  1167. DWORD chars;
  1168. HKEY key;
  1169. PTSTR devicePath;
  1170. PTSTR p;
  1171. DWORD rc;
  1172. DWORD size;
  1173. DWORD type;
  1174. //
  1175. // cleanup the file system
  1176. //
  1177. MYASSERT (AnswerFile[0]);
  1178. if (GetPrivateProfileString (
  1179. WINNT_SETUPPARAMS,
  1180. WINNT_SP_DYNUPDTWORKINGDIR,
  1181. TEXT(""),
  1182. buf,
  1183. MAX_PATH,
  1184. AnswerFile
  1185. )) {
  1186. Delnode (buf);
  1187. }
  1188. //
  1189. // cleanup the registry
  1190. //
  1191. chars = GetPrivateProfileString (
  1192. WINNT_SETUPPARAMS,
  1193. WINNT_SP_DYNUPDTADDITIONALGUIDRIVERS,
  1194. TEXT(""),
  1195. buf,
  1196. MAX_PATH * 16,
  1197. AnswerFile
  1198. );
  1199. if (chars > 0) {
  1200. //
  1201. // got it; now remove it from DevicePath
  1202. //
  1203. rc = RegOpenKey (HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, &key);
  1204. if (rc == ERROR_SUCCESS) {
  1205. rc = RegQueryValueEx (key, REGSTR_VAL_DEVICEPATH, NULL, NULL, NULL, &size);
  1206. if (rc == ERROR_SUCCESS) {
  1207. devicePath = (PTSTR) MyMalloc (size);
  1208. if (devicePath) {
  1209. rc = RegQueryValueEx (key, REGSTR_VAL_DEVICEPATH, NULL, &type, (LPBYTE)devicePath, &size);
  1210. if (rc == ERROR_SUCCESS && size / sizeof (TCHAR) >= chars + 1) {
  1211. p = _tcsstr (devicePath, buf);
  1212. if (p &&
  1213. (p == devicePath || *(p - 1) == TEXT(';')) &&
  1214. (!p[chars] || p[chars] == TEXT(';'))
  1215. ) {
  1216. if (p == devicePath) {
  1217. _tcscpy (p, p[chars] == TEXT(';') ? p + chars + 1 : p + chars);
  1218. } else {
  1219. _tcscpy (p - 1, p + chars);
  1220. }
  1221. size = (_tcslen (devicePath) + 1) * sizeof (TCHAR);
  1222. rc = RegSetValueEx (key, REGSTR_VAL_DEVICEPATH, 0, type, (PBYTE)devicePath, size);
  1223. }
  1224. }
  1225. MyFree (devicePath);
  1226. }
  1227. }
  1228. RegCloseKey (key);
  1229. }
  1230. }
  1231. g_DuShare[0] = 0;
  1232. }
  1233. BOOL
  1234. DuInstallDuAsms (
  1235. VOID
  1236. )
  1237. /*++
  1238. Routine Description:
  1239. This routine installs additional DU assemblies
  1240. Arguments:
  1241. none
  1242. Return Value:
  1243. TRUE if successful, FALSE otherwise
  1244. --*/
  1245. {
  1246. TCHAR duasmsRoot[MAX_PATH];
  1247. TCHAR duasmsSource[MAX_PATH];
  1248. DWORD chars;
  1249. SIDE_BY_SIDE SideBySide = {0};
  1250. BOOL b1;
  1251. BOOL b2;
  1252. PTSTR p;
  1253. PCTSTR source;
  1254. BOOL fSuccess = TRUE;
  1255. //
  1256. // look for any assemblies root specified in the answer file
  1257. //
  1258. MYASSERT (AnswerFile[0]);
  1259. if (GetPrivateProfileString (
  1260. WINNT_SETUPPARAMS,
  1261. WINNT_SP_UPDATEDDUASMS,
  1262. TEXT(""),
  1263. duasmsRoot,
  1264. MAX_PATH,
  1265. AnswerFile
  1266. )) {
  1267. //
  1268. // make sure this directory exists; remove any existing quotes first
  1269. //
  1270. p = duasmsRoot;
  1271. if (*p == TEXT('\"')) {
  1272. p++;
  1273. }
  1274. source = p;
  1275. while (*p && *p != TEXT('\"')) {
  1276. p++;
  1277. }
  1278. *p = 0;
  1279. if (pDoesDirExist (source)) {
  1280. //
  1281. // root directory found
  1282. // first copy them in a protected location, then install assemblies from there
  1283. //
  1284. DWORD rc;
  1285. rc = GetDriverCacheSourcePath (duasmsSource, MAX_PATH);
  1286. if (rc != ERROR_SUCCESS) {
  1287. SetuplogError (
  1288. LogSevError,
  1289. SETUPLOG_USE_MESSAGEID,
  1290. MSG_LOG_DRIVER_CACHE_NOT_FOUND,
  1291. rc,
  1292. NULL,
  1293. NULL
  1294. );
  1295. return FALSE;
  1296. }
  1297. pSetupConcatenatePaths (duasmsSource, TEXT("duasms"), MAX_PATH, NULL);
  1298. //
  1299. // first remove any already existing duasms "backup source" previously downloaded
  1300. //
  1301. Delnode (duasmsSource);
  1302. //
  1303. // now tree copy from the temp location to this "backup source"
  1304. //
  1305. rc = TreeCopy (source, duasmsSource);
  1306. if (rc != ERROR_SUCCESS) {
  1307. SetuplogError(
  1308. LogSevError,
  1309. TEXT("Setup failed to TreeCopy %2 to %3 (TreeCopy failed %1!u!)\r\n"),
  1310. 0,
  1311. rc,
  1312. source,
  1313. duasmsSource,
  1314. NULL,
  1315. NULL
  1316. );
  1317. return FALSE;
  1318. }
  1319. //
  1320. // install duasms from there
  1321. //
  1322. b1 = SideBySidePopulateCopyQueue (&SideBySide, NULL, duasmsSource);
  1323. b2 = SideBySideFinish (&SideBySide, b1);
  1324. if (!b1 || !b2) {
  1325. fSuccess = FALSE;
  1326. SetuplogError (
  1327. LogSevError,
  1328. TEXT("DUError: DuInstallDuAsms failed (rc=%1!u!)\r\n"),
  1329. 0,
  1330. GetLastError (),
  1331. NULL,
  1332. NULL
  1333. );
  1334. }
  1335. } else {
  1336. fSuccess = FALSE;
  1337. SetuplogError (
  1338. LogSevError,
  1339. TEXT("DUError: Invalid directory %1; DuInstallDuAsms failed\r\n"),
  1340. 0,
  1341. source,
  1342. NULL,
  1343. NULL
  1344. );
  1345. }
  1346. }
  1347. return fSuccess;
  1348. }
  1349. BOOL
  1350. BuildPathToInstallationFileEx (
  1351. IN PCTSTR Filename,
  1352. OUT PTSTR PathBuffer,
  1353. IN DWORD PathBufferSize,
  1354. IN BOOL UseDuShare
  1355. )
  1356. /*++
  1357. Routine Description:
  1358. This routine returns the path to the updated DU file, if one exists
  1359. and the caller wanted this. Otherwise it will simply return the path
  1360. to the CD file.
  1361. Arguments:
  1362. Filename - Specifies the filename to look for
  1363. PathBuffer - Receives the full path to the file
  1364. PathBufferSize - Specifies the size in chars of the above buffer
  1365. UseDuShare - Specifies TRUE if the function should check the DU
  1366. location first
  1367. Return Value:
  1368. TRUE if building the path was successful. This does not guarantee the file exist.
  1369. --*/
  1370. {
  1371. if (g_DuShare[0] && UseDuShare) {
  1372. if (BuildPath (PathBuffer, PathBufferSize, g_DuShare, Filename) &&
  1373. pDoesFileExist (PathBuffer)
  1374. ) {
  1375. return TRUE;
  1376. }
  1377. }
  1378. return BuildPath (PathBuffer, PathBufferSize, LegacySourcePath, Filename);
  1379. }
  1380. PCTSTR
  1381. DuGetUpdatesPath (
  1382. VOID
  1383. )
  1384. {
  1385. return g_DuShare[0] ? g_DuShare : NULL;
  1386. }
  1387. BOOL
  1388. DuDoesUpdatedFileExistEx (
  1389. IN PCTSTR Filename,
  1390. OUT PTSTR PathBuffer, OPTIONAL
  1391. IN DWORD PathBufferSize
  1392. )
  1393. /*++
  1394. Routine Description:
  1395. This routine checks if there exists an updated file with the given name.
  1396. Arguments:
  1397. Filename - Specifies the filename to look for
  1398. PathBuffer - Receives the full path to the file; optional
  1399. PathBufferSize - Specifies the size in chars of the above buffer
  1400. Return Value:
  1401. TRUE if a DU file with this name exists, FALSE otherwise
  1402. --*/
  1403. {
  1404. TCHAR path[MAX_PATH];
  1405. if (g_DuShare[0] &&
  1406. BuildPath (path, MAX_PATH, g_DuShare, Filename) &&
  1407. pDoesFileExist (path)
  1408. ) {
  1409. if (PathBuffer) {
  1410. lstrcpyn (PathBuffer, path, PathBufferSize);
  1411. }
  1412. return TRUE;
  1413. }
  1414. return FALSE;
  1415. }
  1416. UINT
  1417. DuSetupPromptForDisk (
  1418. HWND hwndParent, // parent window of the dialog box
  1419. PCTSTR DialogTitle, // optional, title of the dialog box
  1420. PCTSTR DiskName, // optional, name of disk to insert
  1421. PCTSTR PathToSource, // optional, expected source path
  1422. PCTSTR FileSought, // name of file needed
  1423. PCTSTR TagFile, // optional, source media tag file
  1424. DWORD DiskPromptStyle, // specifies dialog box behavior
  1425. PTSTR PathBuffer, // receives the source location
  1426. DWORD PathBufferSize, // size of the supplied buffer
  1427. PDWORD PathRequiredSize // optional, buffer size needed
  1428. )
  1429. {
  1430. TCHAR buffer[MAX_PATH];
  1431. if ((DiskPromptStyle & IDF_CHECKFIRST) &&
  1432. PathBuffer &&
  1433. PathBufferSize &&
  1434. FileSought &&
  1435. g_DuShare[0]
  1436. ) {
  1437. if (BuildPath (PathBuffer, PathBufferSize, g_DuShare, FileSought) &&
  1438. pDoesFileExist (PathBuffer)
  1439. ) {
  1440. lstrcpyn (PathBuffer, g_DuShare, PathBufferSize);
  1441. return DPROMPT_SUCCESS;
  1442. }
  1443. }
  1444. return SetupPromptForDisk (
  1445. hwndParent,
  1446. DialogTitle,
  1447. DiskName,
  1448. PathToSource,
  1449. FileSought,
  1450. TagFile,
  1451. DiskPromptStyle,
  1452. PathBuffer,
  1453. PathBufferSize,
  1454. PathRequiredSize
  1455. );
  1456. }