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.

3004 lines
86 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. infopenv.c
  5. Abstract:
  6. Externally exposed INF routines for INF opening, closing,
  7. and versioning.
  8. Author:
  9. Ted Miller (tedm) 20-Jan-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. BOOL
  15. pSetupVersionNodeFromInfInformation(
  16. IN PSP_INF_INFORMATION InfInformation,
  17. IN UINT InfIndex,
  18. OUT PINF_VERSION_NODE VersionNode,
  19. OUT PTSTR OriginalFilename OPTIONAL
  20. );
  21. #ifdef UNICODE
  22. //
  23. // ANSI version
  24. //
  25. BOOL
  26. SetupGetInfInformationA(
  27. IN LPCVOID InfSpec,
  28. IN DWORD SearchControl,
  29. OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
  30. IN DWORD ReturnBufferSize,
  31. OUT PDWORD RequiredSize OPTIONAL
  32. )
  33. {
  34. PCWSTR infspec;
  35. BOOL b;
  36. DWORD rc;
  37. //
  38. // For this API, the return buffer does not have to be translated
  39. // from Unicode to ANSI. This makes things much easier since the
  40. // required size is the same for the ANSI and Unicode versions.
  41. //
  42. if((SearchControl == INFINFO_INF_NAME_IS_ABSOLUTE)
  43. || (SearchControl == INFINFO_DEFAULT_SEARCH)
  44. || (SearchControl == INFINFO_REVERSE_DEFAULT_SEARCH)
  45. || (SearchControl == INFINFO_INF_PATH_LIST_SEARCH)) {
  46. rc = pSetupCaptureAndConvertAnsiArg(InfSpec,&infspec);
  47. if(rc != NO_ERROR) {
  48. SetLastError(rc);
  49. return(FALSE);
  50. }
  51. } else {
  52. //
  53. // Not a pointer to a string, just pass it on.
  54. //
  55. infspec = InfSpec;
  56. }
  57. //
  58. // Note that the data returned from this API is in an
  59. // internal format, and thus we don't need any less space
  60. // for the ANSI API, and can just use the buffer and sizes
  61. // passed in by the caller.
  62. //
  63. b = SetupGetInfInformationW(
  64. infspec,
  65. SearchControl,
  66. ReturnBuffer,
  67. ReturnBufferSize,
  68. RequiredSize
  69. );
  70. rc = GetLastError();
  71. if(infspec != InfSpec) {
  72. MyFree(infspec);
  73. }
  74. SetLastError(rc);
  75. return(b);
  76. }
  77. #else
  78. //
  79. // Unicode stub
  80. //
  81. BOOL
  82. SetupGetInfInformationW(
  83. IN LPCVOID InfSpec,
  84. IN DWORD SearchControl,
  85. OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
  86. IN DWORD ReturnBufferSize,
  87. OUT PDWORD RequiredSize OPTIONAL
  88. )
  89. {
  90. UNREFERENCED_PARAMETER(InfSpec);
  91. UNREFERENCED_PARAMETER(SearchControl);
  92. UNREFERENCED_PARAMETER(ReturnBuffer);
  93. UNREFERENCED_PARAMETER(ReturnBufferSize);
  94. UNREFERENCED_PARAMETER(RequiredSize);
  95. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  96. return(FALSE);
  97. }
  98. #endif
  99. BOOL
  100. SetupGetInfInformation(
  101. IN LPCVOID InfSpec,
  102. IN DWORD SearchControl,
  103. OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
  104. IN DWORD ReturnBufferSize,
  105. OUT PDWORD RequiredSize OPTIONAL
  106. )
  107. /*++
  108. Routine Description:
  109. Arguments:
  110. Return Value:
  111. --*/
  112. {
  113. BOOL UnloadInf;
  114. PLOADED_INF Inf, CurInf;
  115. UINT InfCount;
  116. PUCHAR Out;
  117. DWORD TotalSpaceRequired;
  118. DWORD d;
  119. DWORD ErrorLineNumber;
  120. TCHAR Path[MAX_PATH];
  121. PINF_VERSION_NODE VersionNode;
  122. INF_VERSION_BLOCK UNALIGNED *Prev;
  123. BOOL TryPnf;
  124. WIN32_FIND_DATA FindData;
  125. PTSTR DontCare;
  126. UINT OriginalFilenameSize;
  127. //
  128. // Set up some state based on the SearchSpec parameter.
  129. //
  130. Inf = NULL;
  131. switch(SearchControl) {
  132. case INFINFO_INF_SPEC_IS_HINF:
  133. Inf = (PLOADED_INF)InfSpec;
  134. d = NO_ERROR;
  135. try {
  136. if (!LockInf(Inf)) {
  137. d = ERROR_INVALID_HANDLE;
  138. }
  139. } except(EXCEPTION_EXECUTE_HANDLER) {
  140. d = ERROR_INVALID_HANDLE;
  141. }
  142. if (d != NO_ERROR) {
  143. SetLastError(d);
  144. return FALSE;
  145. }
  146. break;
  147. case INFINFO_INF_NAME_IS_ABSOLUTE:
  148. //
  149. // Make sure we have a fully-qualified path.
  150. //
  151. d = GetFullPathName((PCTSTR)InfSpec,
  152. SIZECHARS(Path),
  153. Path,
  154. &DontCare
  155. );
  156. if(!d) {
  157. //
  158. // LastError has already been set
  159. // (unless InfSpec was NULL or "")
  160. //
  161. if (GetLastError()==NO_ERROR) {
  162. SetLastError(ERROR_FILE_NOT_FOUND);
  163. }
  164. return FALSE;
  165. } else if(d >= SIZECHARS(Path)) {
  166. MYASSERT(0);
  167. SetLastError(ERROR_BUFFER_OVERFLOW);
  168. return FALSE;
  169. }
  170. if(FileExists(Path, &FindData)) {
  171. InfSourcePathFromFileName(Path, NULL, &TryPnf);
  172. break;
  173. } else {
  174. //
  175. // LastError has already been set.
  176. //
  177. return FALSE;
  178. }
  179. case INFINFO_DEFAULT_SEARCH:
  180. case INFINFO_REVERSE_DEFAULT_SEARCH:
  181. case INFINFO_INF_PATH_LIST_SEARCH:
  182. try {
  183. d = SearchForInfFile((PCTSTR)InfSpec,
  184. &FindData,
  185. SearchControl,
  186. Path,
  187. SIZECHARS(Path),
  188. NULL
  189. );
  190. } except(EXCEPTION_EXECUTE_HANDLER) {
  191. d = ERROR_INVALID_PARAMETER;
  192. }
  193. if(d == NO_ERROR) {
  194. TryPnf = TRUE;
  195. break;
  196. } else {
  197. SetLastError(d);
  198. return FALSE;
  199. }
  200. default:
  201. SetLastError(ERROR_INVALID_PARAMETER);
  202. return(FALSE);
  203. }
  204. //
  205. // Load the inf if necessary.
  206. //
  207. if(Inf) {
  208. UnloadInf = FALSE;
  209. } else {
  210. d = LoadInfFile(Path,
  211. &FindData,
  212. INF_STYLE_ALL,
  213. TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0,
  214. NULL,
  215. NULL,
  216. NULL,
  217. NULL,
  218. NULL, // LogContext
  219. &Inf,
  220. &ErrorLineNumber,
  221. NULL
  222. );
  223. if(d != NO_ERROR) {
  224. SetLastError(d);
  225. return(FALSE);
  226. }
  227. UnloadInf = TRUE;
  228. }
  229. //
  230. // Determine the number of infs associated with this handle,
  231. // and calculate the amount of space that will be needed to
  232. // store version information about them.
  233. //
  234. // For each inf we will need space for the version block,
  235. // as well as an offset in the SP_INF_INFORMATION structure
  236. // to indicate where that inf's version block is located
  237. // in the output buffer.
  238. //
  239. TotalSpaceRequired = offsetof(SP_INF_INFORMATION, VersionData);
  240. for(InfCount = 0, CurInf = Inf;
  241. CurInf;
  242. InfCount++, CurInf = CurInf->Next)
  243. {
  244. OriginalFilenameSize = CurInf->OriginalInfName
  245. ? (lstrlen(CurInf->OriginalInfName) + 1) * sizeof(TCHAR)
  246. : 0;
  247. TotalSpaceRequired += (offsetof(INF_VERSION_BLOCK, Filename) +
  248. CurInf->VersionBlock.FilenameSize +
  249. CurInf->VersionBlock.DataSize +
  250. OriginalFilenameSize
  251. );
  252. }
  253. if(RequiredSize) {
  254. *RequiredSize = TotalSpaceRequired;
  255. }
  256. //
  257. // See if we have a large enough output buffer.
  258. // If we have a large enough buffer then set up some
  259. // initial values in it.
  260. //
  261. if(ReturnBufferSize < TotalSpaceRequired) {
  262. if(UnloadInf) {
  263. FreeInfFile(Inf);
  264. } else {
  265. UnlockInf(Inf);
  266. }
  267. if(ReturnBuffer) {
  268. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  269. return FALSE;
  270. } else {
  271. return TRUE;
  272. }
  273. }
  274. d = NO_ERROR;
  275. try {
  276. ReturnBuffer->InfStyle = Inf->Style;
  277. ReturnBuffer->InfCount = InfCount;
  278. } except(EXCEPTION_EXECUTE_HANDLER) {
  279. if(UnloadInf) {
  280. FreeInfFile(Inf);
  281. } else {
  282. UnlockInf(Inf);
  283. }
  284. SetLastError(d = ERROR_INVALID_PARAMETER);
  285. }
  286. if(d != NO_ERROR) {
  287. return FALSE;
  288. }
  289. Out = (PUCHAR)ReturnBuffer + offsetof(SP_INF_INFORMATION, VersionData);
  290. //
  291. // Traverse all infs associated with this inf handle and copy
  292. // version data into the caller's buffer. Guard with SEH to ensure
  293. // that the caller passed a valid buffer.
  294. //
  295. try {
  296. Prev = NULL;
  297. for(CurInf = Inf; CurInf; CurInf = CurInf->Next) {
  298. //
  299. // Store offset into
  300. //
  301. if(Prev) {
  302. Prev->NextOffset = (UINT)((UINT_PTR)Out - (UINT_PTR)ReturnBuffer);
  303. }
  304. Prev = (PVOID)Out;
  305. OriginalFilenameSize = CurInf->OriginalInfName
  306. ? (lstrlen(CurInf->OriginalInfName) + 1) * sizeof(TCHAR)
  307. : 0;
  308. Prev->LastWriteTime = CurInf->VersionBlock.LastWriteTime;
  309. Prev->DatumCount = CurInf->VersionBlock.DatumCount;
  310. Prev->OffsetToData = CurInf->VersionBlock.FilenameSize + OriginalFilenameSize;
  311. Prev->DataSize = CurInf->VersionBlock.DataSize;
  312. Prev->TotalSize = offsetof(INF_VERSION_BLOCK, Filename) +
  313. CurInf->VersionBlock.FilenameSize +
  314. OriginalFilenameSize +
  315. CurInf->VersionBlock.DataSize;
  316. Out += offsetof(INF_VERSION_BLOCK, Filename);
  317. //
  318. // Now copy the filename, (optionally) original filename, and
  319. // version data into the output buffer.
  320. //
  321. CopyMemory(Out, CurInf->VersionBlock.Filename, CurInf->VersionBlock.FilenameSize);
  322. Out += CurInf->VersionBlock.FilenameSize;
  323. if(CurInf->OriginalInfName) {
  324. CopyMemory(Out, CurInf->OriginalInfName, OriginalFilenameSize);
  325. Out += OriginalFilenameSize;
  326. }
  327. CopyMemory(Out, CurInf->VersionBlock.DataBlock, CurInf->VersionBlock.DataSize);
  328. Out += CurInf->VersionBlock.DataSize;
  329. }
  330. } except(EXCEPTION_EXECUTE_HANDLER) {
  331. if(UnloadInf) {
  332. FreeInfFile(Inf);
  333. } else {
  334. UnlockInf(Inf);
  335. }
  336. SetLastError(d = ERROR_INVALID_PARAMETER);
  337. }
  338. if(d != NO_ERROR) {
  339. return FALSE;
  340. }
  341. Prev->NextOffset = 0;
  342. //
  343. // Unload the inf if necessary
  344. //
  345. if(UnloadInf) {
  346. FreeInfFile(Inf);
  347. } else {
  348. UnlockInf(Inf);
  349. }
  350. return TRUE;
  351. }
  352. #ifdef UNICODE
  353. //
  354. // ANSI version
  355. //
  356. BOOL
  357. SetupQueryInfFileInformationA(
  358. IN PSP_INF_INFORMATION InfInformation,
  359. IN UINT InfIndex,
  360. OUT PSTR ReturnBuffer, OPTIONAL
  361. IN DWORD ReturnBufferSize,
  362. OUT PDWORD RequiredSize OPTIONAL
  363. )
  364. {
  365. WCHAR returnbuffer[MAX_PATH];
  366. DWORD requiredsize;
  367. DWORD rc;
  368. PSTR ansi;
  369. BOOL b;
  370. b = SetupQueryInfFileInformationW(
  371. InfInformation,
  372. InfIndex,
  373. returnbuffer,
  374. MAX_PATH,
  375. &requiredsize
  376. );
  377. rc = GetLastError();
  378. if(b) {
  379. if(ansi = pSetupUnicodeToAnsi(returnbuffer)) {
  380. rc = NO_ERROR;
  381. requiredsize = lstrlenA(ansi);
  382. if(RequiredSize) {
  383. try {
  384. *RequiredSize = requiredsize;
  385. } except(EXCEPTION_EXECUTE_HANDLER) {
  386. rc = ERROR_INVALID_PARAMETER;
  387. b = FALSE;
  388. }
  389. }
  390. if(b) {
  391. if(ReturnBuffer) {
  392. if(ReturnBufferSize >= requiredsize) {
  393. //
  394. // lstrcpy returns NULL if it faults
  395. //
  396. if(!lstrcpyA(ReturnBuffer,ansi)) {
  397. rc = ERROR_INVALID_PARAMETER;
  398. b = FALSE;
  399. }
  400. } else {
  401. b = FALSE;
  402. rc = ERROR_INSUFFICIENT_BUFFER;
  403. }
  404. }
  405. }
  406. MyFree(ansi);
  407. } else {
  408. rc = ERROR_NOT_ENOUGH_MEMORY;
  409. b = FALSE;
  410. }
  411. }
  412. SetLastError(rc);
  413. return(b);
  414. }
  415. #else
  416. //
  417. // Unicode stub
  418. //
  419. BOOL
  420. SetupQueryInfFileInformationW(
  421. IN PSP_INF_INFORMATION InfInformation,
  422. IN UINT InfIndex,
  423. OUT PWSTR ReturnBuffer, OPTIONAL
  424. IN DWORD ReturnBufferSize,
  425. OUT PDWORD RequiredSize OPTIONAL
  426. )
  427. {
  428. UNREFERENCED_PARAMETER(InfInformation);
  429. UNREFERENCED_PARAMETER(InfIndex);
  430. UNREFERENCED_PARAMETER(ReturnBuffer);
  431. UNREFERENCED_PARAMETER(ReturnBufferSize);
  432. UNREFERENCED_PARAMETER(RequiredSize);
  433. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  434. return(FALSE);
  435. }
  436. #endif
  437. BOOL
  438. SetupQueryInfFileInformation(
  439. IN PSP_INF_INFORMATION InfInformation,
  440. IN UINT InfIndex,
  441. OUT PTSTR ReturnBuffer, OPTIONAL
  442. IN DWORD ReturnBufferSize,
  443. OUT PDWORD RequiredSize OPTIONAL
  444. )
  445. /*++
  446. Routine Description:
  447. Arguments:
  448. Return Value:
  449. --*/
  450. {
  451. UINT FilenameLength;
  452. INF_VERSION_NODE VersionNode;
  453. DWORD rc;
  454. //
  455. // See whether the index is in range and
  456. // retrieve the version descriptor for this inf.
  457. //
  458. rc = NO_ERROR;
  459. try {
  460. if(!pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode,NULL)) {
  461. rc = ERROR_INVALID_PARAMETER;
  462. }
  463. } except(EXCEPTION_EXECUTE_HANDLER) {
  464. rc = ERROR_INVALID_PARAMETER;
  465. }
  466. if(rc != NO_ERROR) {
  467. SetLastError(rc);
  468. return(FALSE);
  469. }
  470. FilenameLength = VersionNode.FilenameSize / sizeof(TCHAR);
  471. if(RequiredSize) {
  472. try {
  473. *RequiredSize = FilenameLength;
  474. } except(EXCEPTION_EXECUTE_HANDLER) {
  475. rc = ERROR_INVALID_PARAMETER;
  476. }
  477. if(rc != NO_ERROR) {
  478. SetLastError(rc);
  479. return(FALSE);
  480. }
  481. }
  482. //
  483. // Check length of user's buffer.
  484. //
  485. if(FilenameLength > ReturnBufferSize) {
  486. if(ReturnBuffer) {
  487. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  488. return FALSE;
  489. } else {
  490. return TRUE;
  491. }
  492. }
  493. //
  494. // Copy the data into user's buffer.
  495. //
  496. try {
  497. CopyMemory(ReturnBuffer,VersionNode.Filename,VersionNode.FilenameSize);
  498. } except(EXCEPTION_EXECUTE_HANDLER) {
  499. rc = ERROR_INVALID_PARAMETER;
  500. }
  501. if(rc != NO_ERROR) {
  502. SetLastError(rc);
  503. return(FALSE);
  504. }
  505. return TRUE;
  506. }
  507. #ifdef UNICODE
  508. //
  509. // ANSI version
  510. //
  511. BOOL
  512. WINAPI
  513. SetupQueryInfOriginalFileInformationA(
  514. IN PSP_INF_INFORMATION InfInformation,
  515. IN UINT InfIndex,
  516. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  517. OUT PSP_ORIGINAL_FILE_INFO_A OriginalFileInfo
  518. )
  519. {
  520. SP_ORIGINAL_FILE_INFO_W UnicodeOriginalFileInfo;
  521. DWORD rc;
  522. int i;
  523. BOOL b;
  524. rc = NO_ERROR;
  525. //
  526. // Do an initial check on user-supplied output buffer to see if it seems
  527. // to be valid.
  528. //
  529. try {
  530. if(OriginalFileInfo->cbSize != sizeof(SP_ORIGINAL_FILE_INFO_A)) {
  531. rc = ERROR_INVALID_USER_BUFFER;
  532. }
  533. } except(EXCEPTION_EXECUTE_HANDLER) {
  534. rc = ERROR_INVALID_PARAMETER;
  535. }
  536. if(rc != NO_ERROR) {
  537. SetLastError(rc);
  538. return FALSE;
  539. }
  540. UnicodeOriginalFileInfo.cbSize = sizeof(SP_ORIGINAL_FILE_INFO_W);
  541. b = SetupQueryInfOriginalFileInformationW(
  542. InfInformation,
  543. InfIndex,
  544. AlternatePlatformInfo,
  545. &UnicodeOriginalFileInfo
  546. );
  547. rc = GetLastError();
  548. if(b) {
  549. //
  550. // Convert the Unicode fields of the original file info structure into
  551. // ANSI, and store the information in the caller-supplied ANSI
  552. // structure.
  553. //
  554. try {
  555. //
  556. // First, translate/store the original INF name...
  557. //
  558. i = WideCharToMultiByte(
  559. CP_ACP,
  560. 0,
  561. UnicodeOriginalFileInfo.OriginalInfName,
  562. -1,
  563. OriginalFileInfo->OriginalInfName,
  564. sizeof(OriginalFileInfo->OriginalInfName),
  565. NULL,
  566. NULL
  567. );
  568. //
  569. // ...and if that succeeded, then translate/store the original
  570. // catalog filename.
  571. //
  572. if(i) {
  573. //
  574. // Note that the original catalog filename may be the empty
  575. // string (i.e., the INF didn't specify an associated catalog
  576. // file). We don't need to special-case this, since
  577. // WideCharToMultiByte can handle empty strings just fine.
  578. //
  579. i = WideCharToMultiByte(
  580. CP_ACP,
  581. 0,
  582. UnicodeOriginalFileInfo.OriginalCatalogName,
  583. -1,
  584. OriginalFileInfo->OriginalCatalogName,
  585. sizeof(OriginalFileInfo->OriginalCatalogName),
  586. NULL,
  587. NULL
  588. );
  589. }
  590. if(!i) {
  591. b = FALSE;
  592. rc = GetLastError();
  593. //
  594. // If we start seeing cases where our Unicode->ANSI expansion
  595. // blows our buffersize, we need to know about it...
  596. //
  597. MYASSERT((rc != NO_ERROR) && (rc != ERROR_INSUFFICIENT_BUFFER));
  598. }
  599. } except(EXCEPTION_EXECUTE_HANDLER) {
  600. rc = ERROR_INVALID_PARAMETER;
  601. b = FALSE;
  602. }
  603. }
  604. SetLastError(rc);
  605. return b;
  606. }
  607. #else
  608. //
  609. // Unicode stub
  610. //
  611. BOOL
  612. WINAPI
  613. SetupQueryInfOriginalFileInformationW(
  614. IN PSP_INF_INFORMATION InfInformation,
  615. IN UINT InfIndex,
  616. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  617. OUT PSP_ORIGINAL_FILE_INFO_W OriginalFileInfo
  618. )
  619. {
  620. UNREFERENCED_PARAMETER(InfInformation);
  621. UNREFERENCED_PARAMETER(InfIndex);
  622. UNREFERENCED_PARAMETER(AlternatePlatformInfo);
  623. UNREFERENCED_PARAMETER(OriginalFileInfo);
  624. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  625. return(FALSE);
  626. }
  627. #endif
  628. BOOL
  629. WINAPI
  630. SetupQueryInfOriginalFileInformation(
  631. IN PSP_INF_INFORMATION InfInformation,
  632. IN UINT InfIndex,
  633. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  634. OUT PSP_ORIGINAL_FILE_INFO OriginalFileInfo
  635. )
  636. /*++
  637. Routine Description:
  638. This routine returns an INF's original name (which will be different from
  639. its current name if the INF was installed into %windir%\Inf, for example).
  640. If the INF's original name is the same as its current name, the current
  641. name is returned.
  642. It also returns the original filename of the catalog file specified by the
  643. INF via a (potentially decorated) CatalogFile= entry in the INF's [version]
  644. section. The OS/architecture-specific decoration may be overridden from
  645. the default (i.e., current platform) by passing in an optional alternate
  646. platform information structure. If the INF doesn't specify any catalog
  647. file, then this field in the output OriginalFileInfo structure will be set
  648. to an empty string.
  649. Both filenames returned in the OriginalFileInfo are simple filenames, i.e.,
  650. there is no path information included.
  651. Arguments:
  652. InfInformation - supplies context from which we retrieve information about
  653. the INF whose index is specified by InfIndex.
  654. InfIndex - supplies the zero-based index of the INF within the
  655. InfInformation context buffer that we're retrieving original file
  656. information for.
  657. AlternatePlatformInfo - optionally, supplies alternate platform information
  658. used when searching for the appropriately decorated CatalogFile= entry
  659. within the INF's [version] section.
  660. (NOTE: caller may actually pass in a V1 struct instead--we detect this
  661. case and convert the V1 struct into a V2 one.)
  662. OriginalFileInfo - supplies the address of an original file information
  663. buffer that upon success receives information about the original
  664. (simple) filenames of files associated with this INF. This structure
  665. must have its cbSize field set to sizeof(SP_ORIGINAL_FILE_INFO) upon
  666. entry to this routine or the call will fail with GetLastError()
  667. returning ERROR_INVALID_USER_BUFFER.
  668. The fields of this structure are set upon successful return as follows:
  669. OriginalInfName - receives the INF's original filename, which may be
  670. different than its current filename in the case where the INF was
  671. an OEM in that was installed into the %windir%\Inf directory (e.g.,
  672. via SetupCopyOEMInf).
  673. OriginalCatalogName - receives the platform-appropriate CatalogFile=
  674. entry in the INF's [version] section (where the platform is the
  675. default native one unless AlternatePlatformInfo is supplied). If
  676. there is no applicable CatalogFile= entry, this field will be set
  677. to the empty string.
  678. Return Value:
  679. If successful, the return value is non-zero.
  680. If unsuccessful, the return value is FALSE, and GetLastError() may be
  681. called to determine the cause of failure.
  682. --*/
  683. {
  684. INF_VERSION_NODE VersionNode;
  685. DWORD rc;
  686. SP_ALTPLATFORM_INFO_V2 AltPlatformInfoV2;
  687. rc = NO_ERROR;
  688. //
  689. // See whether the index is in range and retrieve the version descriptor
  690. // and original filename for this inf.
  691. //
  692. try {
  693. //
  694. // Do an initial check on user-supplied output buffer to see if it
  695. // seems to be valid.
  696. //
  697. if(OriginalFileInfo->cbSize != sizeof(SP_ORIGINAL_FILE_INFO)) {
  698. rc = ERROR_INVALID_USER_BUFFER;
  699. goto clean0;
  700. }
  701. //
  702. // Now validate the AlternatePlatformInfo parameter.
  703. //
  704. if(AlternatePlatformInfo) {
  705. if(AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO_V2)) {
  706. //
  707. // The caller may have passed us in a Version 1 struct, or they
  708. // may have passed us in bad data...
  709. //
  710. if(AlternatePlatformInfo->cbSize == sizeof(SP_ALTPLATFORM_INFO_V1)) {
  711. //
  712. // Flags/Reserved field is reserved in V1
  713. //
  714. if(AlternatePlatformInfo->Reserved) {
  715. rc = ERROR_INVALID_PARAMETER;
  716. goto clean0;
  717. }
  718. //
  719. // Convert the caller-supplied data into Version 2 format.
  720. //
  721. ZeroMemory(&AltPlatformInfoV2, sizeof(AltPlatformInfoV2));
  722. AltPlatformInfoV2.cbSize = sizeof(SP_ALTPLATFORM_INFO_V2);
  723. AltPlatformInfoV2.Platform = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->Platform;
  724. AltPlatformInfoV2.MajorVersion = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->MajorVersion;
  725. AltPlatformInfoV2.MinorVersion = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->MinorVersion;
  726. AltPlatformInfoV2.ProcessorArchitecture = ((PSP_ALTPLATFORM_INFO_V1)AlternatePlatformInfo)->ProcessorArchitecture;
  727. AltPlatformInfoV2.Flags = 0;
  728. AlternatePlatformInfo = &AltPlatformInfoV2;
  729. } else {
  730. rc = ERROR_INVALID_USER_BUFFER;
  731. goto clean0;
  732. }
  733. }
  734. //
  735. // Gotta be either Windows or Windows NT
  736. //
  737. if((AlternatePlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS) &&
  738. (AlternatePlatformInfo->Platform != VER_PLATFORM_WIN32_NT)) {
  739. rc = ERROR_INVALID_PARAMETER;
  740. goto clean0;
  741. }
  742. //
  743. // Processor had better be either i386, alpha, ia64, or amd64
  744. //
  745. if((AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) &&
  746. (AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_ALPHA) &&
  747. (AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64) &&
  748. (AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_ALPHA64) &&
  749. (AlternatePlatformInfo->ProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64)) {
  750. rc = ERROR_INVALID_PARAMETER;
  751. goto clean0;
  752. }
  753. //
  754. // MajorVersion field must be non-zero (MinorVersion field can be
  755. // anything)
  756. //
  757. if(!AlternatePlatformInfo->MajorVersion) {
  758. rc = ERROR_INVALID_PARAMETER;
  759. goto clean0;
  760. }
  761. //
  762. // Validate structure parameter flags (bits indicating what
  763. // parts of the structure are valid).
  764. //
  765. if((AlternatePlatformInfo->Flags & ~ (SP_ALTPLATFORM_FLAGS_VERSION_RANGE)) != 0) {
  766. rc = ERROR_INVALID_PARAMETER;
  767. goto clean0;
  768. }
  769. //
  770. // fill in version validation range if none supplied by caller
  771. //
  772. if((AlternatePlatformInfo->Flags & SP_ALTPLATFORM_FLAGS_VERSION_RANGE) == 0) {
  773. //
  774. // If caller does not know about FirstValidate*Version,
  775. // version upper and lower bounds are equal.
  776. //
  777. AlternatePlatformInfo->FirstValidatedMajorVersion = AlternatePlatformInfo->MajorVersion;
  778. AlternatePlatformInfo->FirstValidatedMinorVersion = AlternatePlatformInfo->MinorVersion;
  779. AlternatePlatformInfo->Flags |= SP_ALTPLATFORM_FLAGS_VERSION_RANGE;
  780. }
  781. }
  782. //
  783. // OK, now retrieve the INF's original filename...
  784. //
  785. if(!pSetupVersionNodeFromInfInformation(InfInformation,
  786. InfIndex,
  787. &VersionNode,
  788. OriginalFileInfo->OriginalInfName)) {
  789. rc = ERROR_INVALID_PARAMETER;
  790. goto clean0;
  791. }
  792. //
  793. // ...and retrieve the (platform-appropriate) catalog file associated
  794. // with this INF (if there is one).
  795. //
  796. if(!pSetupGetCatalogFileValue(&VersionNode,
  797. OriginalFileInfo->OriginalCatalogName,
  798. SIZECHARS(OriginalFileInfo->OriginalCatalogName),
  799. AlternatePlatformInfo)) {
  800. //
  801. // No applicable CatalogFile= entry found--set field to empty
  802. // string.
  803. //
  804. *(OriginalFileInfo->OriginalCatalogName) = TEXT('\0');
  805. }
  806. clean0: ; // nothing to do
  807. } except(EXCEPTION_EXECUTE_HANDLER) {
  808. rc = ERROR_INVALID_PARAMETER;
  809. }
  810. SetLastError(rc);
  811. return (rc == NO_ERROR);
  812. }
  813. #ifdef UNICODE
  814. //
  815. // ANSI version
  816. //
  817. BOOL
  818. SetupQueryInfVersionInformationA(
  819. IN PSP_INF_INFORMATION InfInformation,
  820. IN UINT InfIndex,
  821. IN PCSTR Key, OPTIONAL
  822. OUT PSTR ReturnBuffer, OPTIONAL
  823. IN DWORD ReturnBufferSize,
  824. OUT PDWORD RequiredSize OPTIONAL
  825. )
  826. {
  827. INF_VERSION_NODE VersionNode;
  828. PCWSTR Data;
  829. DWORD rc;
  830. PSTR ansidata;
  831. UINT ansilength;
  832. PCWSTR key;
  833. //
  834. // See whether the index is in range and
  835. // get pointer to version descriptor for this inf.
  836. //
  837. try {
  838. if(pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode,NULL)) {
  839. //
  840. // See whether we want a specific value.
  841. //
  842. if(Key) {
  843. rc = pSetupCaptureAndConvertAnsiArg(Key,&key);
  844. if(rc == NO_ERROR) {
  845. if(Data = pSetupGetVersionDatum(&VersionNode,key)) {
  846. if(ansidata = pSetupUnicodeToAnsi(Data)) {
  847. ansilength = lstrlenA(ansidata) + 1;
  848. if(RequiredSize) {
  849. *RequiredSize = ansilength;
  850. }
  851. if(ReturnBuffer) {
  852. if(ReturnBufferSize >= ansilength) {
  853. CopyMemory(ReturnBuffer,ansidata,ansilength);
  854. rc = NO_ERROR;
  855. } else {
  856. rc = ERROR_INSUFFICIENT_BUFFER;
  857. }
  858. } else {
  859. rc = NO_ERROR;
  860. }
  861. MyFree(ansidata);
  862. } else {
  863. rc = ERROR_NOT_ENOUGH_MEMORY;
  864. }
  865. } else {
  866. rc = ERROR_INVALID_DATA;
  867. }
  868. MyFree(key);
  869. }
  870. } else {
  871. //
  872. // Caller wants all values. Copy whole data block to caller's buffer,
  873. // plus a terminating NUL character.
  874. //
  875. // Maximum size the data could be in ansi is the exact same
  876. // size it is in unicode, if every char is a double-byte char.
  877. //
  878. if(ansidata = MyMalloc(VersionNode.DataSize)) {
  879. ansilength = WideCharToMultiByte(
  880. CP_ACP,
  881. 0,
  882. (PWSTR)VersionNode.DataBlock,
  883. VersionNode.DataSize / sizeof(WCHAR),
  884. ansidata,
  885. VersionNode.DataSize,
  886. NULL,
  887. NULL
  888. );
  889. if(RequiredSize) {
  890. //
  891. // account for terminating nul
  892. //
  893. *RequiredSize = ansilength+1;
  894. }
  895. if(ReturnBuffer) {
  896. if(ReturnBufferSize >= *RequiredSize) {
  897. CopyMemory(ReturnBuffer,ansidata,ansilength);
  898. ReturnBuffer[ansilength] = 0;
  899. rc = NO_ERROR;
  900. } else {
  901. rc = ERROR_INSUFFICIENT_BUFFER;
  902. }
  903. } else {
  904. rc = NO_ERROR;
  905. }
  906. MyFree(ansidata);
  907. } else {
  908. rc = ERROR_NOT_ENOUGH_MEMORY;
  909. }
  910. }
  911. } else {
  912. rc = ERROR_INVALID_PARAMETER;
  913. }
  914. } except(EXCEPTION_EXECUTE_HANDLER) {
  915. rc = ERROR_INVALID_PARAMETER;
  916. }
  917. SetLastError(rc);
  918. return(rc == NO_ERROR);
  919. }
  920. #else
  921. //
  922. // Unicode stub
  923. //
  924. BOOL
  925. SetupQueryInfVersionInformationW(
  926. IN PSP_INF_INFORMATION InfInformation,
  927. IN UINT InfIndex,
  928. IN PCWSTR Key, OPTIONAL
  929. OUT PWSTR ReturnBuffer, OPTIONAL
  930. IN DWORD ReturnBufferSize,
  931. OUT PDWORD RequiredSize OPTIONAL
  932. )
  933. {
  934. UNREFERENCED_PARAMETER(InfInformation);
  935. UNREFERENCED_PARAMETER(InfIndex);
  936. UNREFERENCED_PARAMETER(Key);
  937. UNREFERENCED_PARAMETER(ReturnBuffer);
  938. UNREFERENCED_PARAMETER(ReturnBufferSize);
  939. UNREFERENCED_PARAMETER(RequiredSize);
  940. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  941. return(FALSE);
  942. }
  943. #endif
  944. BOOL
  945. SetupQueryInfVersionInformation(
  946. IN PSP_INF_INFORMATION InfInformation,
  947. IN UINT InfIndex,
  948. IN PCTSTR Key, OPTIONAL
  949. OUT PTSTR ReturnBuffer, OPTIONAL
  950. IN DWORD ReturnBufferSize,
  951. OUT PDWORD RequiredSize OPTIONAL
  952. )
  953. /*++
  954. Routine Description:
  955. Arguments:
  956. Return Value:
  957. --*/
  958. {
  959. INF_VERSION_NODE VersionNode;
  960. PCTSTR Data;
  961. UINT DataLength;
  962. DWORD rc;
  963. //
  964. // See whether the index is in range and
  965. // get pointer to version descriptor for this inf.
  966. //
  967. try {
  968. if(pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode,NULL)) {
  969. //
  970. // See whether we want a specific value.
  971. //
  972. if(Key) {
  973. if(Data = pSetupGetVersionDatum(&VersionNode,Key)) {
  974. DataLength = lstrlen(Data) + 1;
  975. if(RequiredSize) {
  976. *RequiredSize = DataLength;
  977. }
  978. if(ReturnBuffer) {
  979. if(ReturnBufferSize >= DataLength) {
  980. CopyMemory(ReturnBuffer,Data,DataLength * sizeof(TCHAR));
  981. rc = NO_ERROR;
  982. } else {
  983. rc = ERROR_INSUFFICIENT_BUFFER;
  984. }
  985. } else {
  986. rc = NO_ERROR;
  987. }
  988. } else {
  989. rc = ERROR_INVALID_DATA;
  990. }
  991. } else {
  992. //
  993. // Caller wants all values. Copy whole data block to caller's buffer,
  994. // plus a terminating NUL character.
  995. //
  996. DataLength = (VersionNode.DataSize / sizeof(TCHAR)) + 1;
  997. if(RequiredSize) {
  998. *RequiredSize = DataLength;
  999. }
  1000. if(ReturnBuffer) {
  1001. if(ReturnBufferSize >= DataLength) {
  1002. CopyMemory(ReturnBuffer,VersionNode.DataBlock,VersionNode.DataSize);
  1003. ReturnBuffer[VersionNode.DataSize/sizeof(TCHAR)] = 0;
  1004. rc = NO_ERROR;
  1005. } else {
  1006. rc = ERROR_INSUFFICIENT_BUFFER;
  1007. }
  1008. } else {
  1009. rc = NO_ERROR;
  1010. }
  1011. }
  1012. } else {
  1013. rc = ERROR_INVALID_PARAMETER;
  1014. }
  1015. } except(EXCEPTION_EXECUTE_HANDLER) {
  1016. rc = ERROR_INVALID_PARAMETER;
  1017. }
  1018. SetLastError(rc);
  1019. return(rc == NO_ERROR);
  1020. }
  1021. BOOL
  1022. _SetupGetInfFileList(
  1023. IN PCTSTR DirectoryPath, OPTIONAL
  1024. IN DWORD InfStyle,
  1025. OUT PVOID ReturnBuffer, OPTIONAL
  1026. IN DWORD ReturnBufferSize,
  1027. OUT PDWORD RequiredSize OPTIONAL
  1028. #ifdef UNICODE
  1029. IN ,BOOL ConvertToAnsi
  1030. #endif
  1031. )
  1032. {
  1033. TCHAR SearchSpec[MAX_PATH];
  1034. PTCHAR FilenameStart;
  1035. WIN32_FIND_DATA FindData;
  1036. HANDLE FindHandle;
  1037. DWORD Style;
  1038. UINT FileNameLength;
  1039. DWORD RemainingSpaceInBuffer;
  1040. DWORD CurrentOffsetInBuffer;
  1041. DWORD TotalSpaceNeededInBuffer;
  1042. BOOL InsufficientBuffer;
  1043. DWORD d;
  1044. PTSTR DontCare;
  1045. #ifdef UNICODE
  1046. CHAR ansi[MAX_PATH];
  1047. #endif
  1048. //
  1049. // Set up the search directory
  1050. //
  1051. if(DirectoryPath) {
  1052. //
  1053. // Make sure this directory path is fully-qualified.
  1054. //
  1055. d = GetFullPathName(DirectoryPath,
  1056. SIZECHARS(SearchSpec),
  1057. SearchSpec,
  1058. &DontCare
  1059. );
  1060. if(!d) {
  1061. //
  1062. // LastError has already been set.
  1063. //
  1064. return FALSE;
  1065. } else if(d >= SIZECHARS(SearchSpec)) {
  1066. MYASSERT(0);
  1067. SetLastError(ERROR_BUFFER_OVERFLOW);
  1068. return FALSE;
  1069. }
  1070. } else {
  1071. lstrcpyn(SearchSpec, InfDirectory,SIZECHARS(SearchSpec));
  1072. }
  1073. pSetupConcatenatePaths(SearchSpec, pszInfWildcard, SIZECHARS(SearchSpec), NULL);
  1074. FilenameStart = (PTSTR)pSetupGetFileTitle(SearchSpec);
  1075. FindHandle = FindFirstFile(SearchSpec,&FindData);
  1076. if(FindHandle == INVALID_HANDLE_VALUE) {
  1077. d = GetLastError();
  1078. if((d == ERROR_NO_MORE_FILES) || (d == ERROR_FILE_NOT_FOUND) || (d == ERROR_PATH_NOT_FOUND)) {
  1079. if(RequiredSize) {
  1080. d = NO_ERROR;
  1081. try {
  1082. *RequiredSize = 1;
  1083. } except(EXCEPTION_EXECUTE_HANDLER) {
  1084. d = ERROR_INVALID_PARAMETER;
  1085. }
  1086. if(d != NO_ERROR) {
  1087. SetLastError(d);
  1088. return(FALSE);
  1089. }
  1090. }
  1091. if(ReturnBuffer) {
  1092. if(ReturnBufferSize) {
  1093. d = NO_ERROR;
  1094. try {
  1095. #ifdef UNICODE
  1096. if(ConvertToAnsi) {
  1097. *(PCHAR)ReturnBuffer = 0;
  1098. } else
  1099. #endif
  1100. *(PTCHAR)ReturnBuffer = 0;
  1101. } except(EXCEPTION_EXECUTE_HANDLER) {
  1102. d = ERROR_INVALID_PARAMETER;
  1103. }
  1104. SetLastError(d);
  1105. return(d == NO_ERROR);
  1106. } else {
  1107. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1108. return FALSE;
  1109. }
  1110. } else {
  1111. return TRUE;
  1112. }
  1113. }
  1114. SetLastError(d);
  1115. return(FALSE);
  1116. }
  1117. //
  1118. // Leave space for the extra terminating nul char.
  1119. //
  1120. RemainingSpaceInBuffer = ReturnBufferSize;
  1121. if(RemainingSpaceInBuffer) {
  1122. RemainingSpaceInBuffer--;
  1123. }
  1124. TotalSpaceNeededInBuffer = 1;
  1125. CurrentOffsetInBuffer = 0;
  1126. InsufficientBuffer = FALSE;
  1127. d = NO_ERROR;
  1128. do {
  1129. //
  1130. // Skip directories
  1131. //
  1132. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1133. continue;
  1134. }
  1135. //
  1136. // Form full pathname of file in SearchSpec.
  1137. //
  1138. lstrcpy(FilenameStart,FindData.cFileName);
  1139. //
  1140. // Determine the inf type and see whether the caller
  1141. // wants to know about infs of this type.
  1142. //
  1143. Style = DetermineInfStyle(SearchSpec, &FindData);
  1144. if((Style == INF_STYLE_NONE) || !(Style & InfStyle)) {
  1145. continue;
  1146. }
  1147. //
  1148. // Got a legit inf file.
  1149. //
  1150. #ifdef UNICODE
  1151. if(ConvertToAnsi) {
  1152. //
  1153. // The nul is included because it's converted
  1154. // so no need to add 1
  1155. //
  1156. FileNameLength = WideCharToMultiByte(
  1157. CP_ACP,
  1158. 0,
  1159. FindData.cFileName,
  1160. -1,
  1161. ansi,
  1162. MAX_PATH,
  1163. NULL,
  1164. NULL
  1165. );
  1166. } else
  1167. #endif
  1168. FileNameLength = lstrlen(FindData.cFileName) + 1;
  1169. TotalSpaceNeededInBuffer += FileNameLength;
  1170. if(ReturnBuffer) {
  1171. if(RemainingSpaceInBuffer >= FileNameLength ) {
  1172. RemainingSpaceInBuffer -= FileNameLength;
  1173. //
  1174. // lstrcpy will return NULL if it faults
  1175. //
  1176. #ifdef UNICODE
  1177. if(ConvertToAnsi) {
  1178. DontCare = (PVOID)lstrcpyA((PCHAR)ReturnBuffer+CurrentOffsetInBuffer,ansi);
  1179. } else
  1180. #endif
  1181. DontCare = lstrcpy((PTCHAR)ReturnBuffer+CurrentOffsetInBuffer,FindData.cFileName);
  1182. if(!DontCare) {
  1183. d = ERROR_INVALID_PARAMETER;
  1184. } else {
  1185. CurrentOffsetInBuffer += FileNameLength;
  1186. try {
  1187. #ifdef UNICODE
  1188. if(ConvertToAnsi) {
  1189. ((PCHAR)ReturnBuffer)[CurrentOffsetInBuffer] = 0;
  1190. } else
  1191. #endif
  1192. ((PTCHAR)ReturnBuffer)[CurrentOffsetInBuffer] = 0;
  1193. } except(EXCEPTION_EXECUTE_HANDLER) {
  1194. d = ERROR_INVALID_PARAMETER;
  1195. }
  1196. }
  1197. } else {
  1198. InsufficientBuffer = TRUE;
  1199. }
  1200. }
  1201. } while((d == NO_ERROR) && FindNextFile(FindHandle,&FindData));
  1202. FindClose(FindHandle);
  1203. if(d != NO_ERROR) {
  1204. SetLastError(d);
  1205. }
  1206. if(GetLastError() == ERROR_NO_MORE_FILES) {
  1207. d = NO_ERROR;
  1208. try {
  1209. if(RequiredSize) {
  1210. *RequiredSize = TotalSpaceNeededInBuffer;
  1211. }
  1212. } except(EXCEPTION_EXECUTE_HANDLER) {
  1213. d = ERROR_INVALID_PARAMETER;
  1214. }
  1215. if(d == NO_ERROR) {
  1216. if(InsufficientBuffer) {
  1217. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1218. return FALSE;
  1219. }
  1220. return(TRUE);
  1221. } else {
  1222. SetLastError(d);
  1223. }
  1224. }
  1225. //
  1226. // Last error already set
  1227. //
  1228. return(FALSE);
  1229. }
  1230. #ifdef UNICODE
  1231. //
  1232. // ANSI version
  1233. //
  1234. BOOL
  1235. SetupGetInfFileListA(
  1236. IN PCSTR DirectoryPath, OPTIONAL
  1237. IN DWORD InfStyle,
  1238. OUT PSTR ReturnBuffer, OPTIONAL
  1239. IN DWORD ReturnBufferSize,
  1240. OUT PDWORD RequiredSize OPTIONAL
  1241. )
  1242. {
  1243. PWSTR dirpath;
  1244. DWORD rc;
  1245. BOOL b;
  1246. if(DirectoryPath) {
  1247. rc = pSetupCaptureAndConvertAnsiArg(DirectoryPath,&dirpath);
  1248. if(rc != NO_ERROR) {
  1249. SetLastError(rc);
  1250. return(FALSE);
  1251. }
  1252. } else {
  1253. dirpath = NULL;
  1254. }
  1255. b = _SetupGetInfFileList(dirpath,InfStyle,ReturnBuffer,ReturnBufferSize,RequiredSize,TRUE);
  1256. rc = GetLastError();
  1257. if(dirpath) {
  1258. MyFree(dirpath);
  1259. }
  1260. SetLastError(rc);
  1261. return(b);
  1262. }
  1263. #else
  1264. //
  1265. // Unicode stub
  1266. //
  1267. BOOL
  1268. SetupGetInfFileListW(
  1269. IN PCWSTR DirectoryPath, OPTIONAL
  1270. IN DWORD InfStyle,
  1271. OUT PWSTR ReturnBuffer, OPTIONAL
  1272. IN DWORD ReturnBufferSize,
  1273. OUT PDWORD RequiredSize OPTIONAL
  1274. )
  1275. {
  1276. UNREFERENCED_PARAMETER(DirectoryPath);
  1277. UNREFERENCED_PARAMETER(InfStyle);
  1278. UNREFERENCED_PARAMETER(ReturnBuffer);
  1279. UNREFERENCED_PARAMETER(ReturnBufferSize);
  1280. UNREFERENCED_PARAMETER(RequiredSize);
  1281. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1282. return(FALSE);
  1283. }
  1284. #endif
  1285. BOOL
  1286. SetupGetInfFileList(
  1287. IN PCTSTR DirectoryPath, OPTIONAL
  1288. IN DWORD InfStyle,
  1289. OUT PTSTR ReturnBuffer, OPTIONAL
  1290. IN DWORD ReturnBufferSize,
  1291. OUT PDWORD RequiredSize OPTIONAL
  1292. )
  1293. /*++
  1294. Routine Description:
  1295. Arguments:
  1296. Return Value:
  1297. --*/
  1298. {
  1299. PTSTR dirpath;
  1300. DWORD rc;
  1301. BOOL b;
  1302. if(DirectoryPath) {
  1303. rc = CaptureStringArg(DirectoryPath,&dirpath);
  1304. if(rc != NO_ERROR) {
  1305. SetLastError(rc);
  1306. return(FALSE);
  1307. }
  1308. } else {
  1309. dirpath = NULL;
  1310. }
  1311. b = _SetupGetInfFileList(
  1312. dirpath,
  1313. InfStyle,
  1314. ReturnBuffer,
  1315. ReturnBufferSize,
  1316. RequiredSize
  1317. #ifdef UNICODE
  1318. ,FALSE
  1319. #endif
  1320. );
  1321. rc = GetLastError();
  1322. if(dirpath) {
  1323. MyFree(dirpath);
  1324. }
  1325. SetLastError(rc);
  1326. return(b);
  1327. }
  1328. #ifdef UNICODE
  1329. //
  1330. // ANSI version
  1331. //
  1332. HINF
  1333. SetupOpenInfFileA(
  1334. IN PCSTR FileName,
  1335. IN PCSTR InfType, OPTIONAL
  1336. IN DWORD InfStyle,
  1337. OUT PUINT ErrorLine OPTIONAL
  1338. )
  1339. {
  1340. PCTSTR fileName,infType;
  1341. DWORD err;
  1342. HINF h;
  1343. err = NO_ERROR;
  1344. fileName = NULL;
  1345. infType = NULL;
  1346. //
  1347. // Set error line to 0 since ansi arg conversion could fail
  1348. // and we need to indicate that there's no error in the inf itself.
  1349. //
  1350. if(ErrorLine) {
  1351. try {
  1352. *ErrorLine = 0;
  1353. } except(EXCEPTION_EXECUTE_HANDLER) {
  1354. err = ERROR_INVALID_PARAMETER;
  1355. }
  1356. }
  1357. if(err == NO_ERROR) {
  1358. err = pSetupCaptureAndConvertAnsiArg(FileName,&fileName);
  1359. if((err == NO_ERROR) && InfType) {
  1360. err = pSetupCaptureAndConvertAnsiArg(InfType,&infType);
  1361. }
  1362. }
  1363. if(err == NO_ERROR) {
  1364. h = SetupOpenInfFileW(fileName,infType,InfStyle,ErrorLine);
  1365. err = GetLastError();
  1366. } else {
  1367. h = INVALID_HANDLE_VALUE;
  1368. }
  1369. if(fileName) {
  1370. MyFree(fileName);
  1371. }
  1372. if(infType) {
  1373. MyFree(infType);
  1374. }
  1375. SetLastError(err);
  1376. return(h);
  1377. }
  1378. #else
  1379. //
  1380. // Unicode stub
  1381. //
  1382. HINF
  1383. SetupOpenInfFileW(
  1384. IN PCWSTR FileName,
  1385. IN PCWSTR InfType, OPTIONAL
  1386. IN DWORD InfStyle,
  1387. OUT PUINT ErrorLine OPTIONAL
  1388. )
  1389. {
  1390. UNREFERENCED_PARAMETER(FileName);
  1391. UNREFERENCED_PARAMETER(InfType);
  1392. UNREFERENCED_PARAMETER(InfStyle);
  1393. UNREFERENCED_PARAMETER(ErrorLine);
  1394. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1395. return(INVALID_HANDLE_VALUE);
  1396. }
  1397. #endif
  1398. HINF
  1399. SetupOpenInfFile(
  1400. IN PCTSTR FileName,
  1401. IN PCTSTR InfClass, OPTIONAL
  1402. IN DWORD InfStyle,
  1403. OUT PUINT ErrorLine OPTIONAL
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. This routine opens an INF file and returns a handle to it.
  1408. Arguments:
  1409. FileName - Supplies the address of a NULL-terminated string containing
  1410. the name (and optionally, the path) of the INF file to be opened. If
  1411. the filename contains no path separator characters, it is searched for
  1412. first in the %windir%\inf directory, and then in the %windir%\system32
  1413. directory. Otherwise, the name is assumed to be a full path
  1414. specification, and no is opened as-is.
  1415. InfClass - Optionally, supplies the address of a NULL-terminated string
  1416. containing the class of the INF file desired. For old-style (i.e.,
  1417. Windows NT 3.x script-base) INF files, this string must match the type
  1418. specified in the OptionType value of the [Identification] section of the
  1419. INF (e.g., OptionType=NetAdapter). For Windows 95-compatibile INF
  1420. files, this string must match the class of the specified INF. If the
  1421. INF has a Class value in its [version] section, then this value is used
  1422. for the comparison. If no Class value is present, but a ClassGUID value
  1423. is present in the [version] section, then the corresponding class name
  1424. for that GUID is retrieved, and comparison is done based on that name.
  1425. InfStyle - Specifies the style of the INF to open. May be a combination of
  1426. the following flags:
  1427. INF_STYLE_OLDNT - Windows NT 3.x script-based INF files.
  1428. INF_STYLE_WIN4 - Windows 95-compatible INF files.
  1429. INF_STYLE_CACHE_ENABLE - always cache INF, even outside of
  1430. %windir%\Inf.
  1431. INF_STYLE_CACHE_DISABLE - delete INF from cache, if outside of
  1432. %windir%\Inf.
  1433. ErrorLine - If an error occurs loading the file, this parameter receives the
  1434. (1-based) line number where the error occurred. This value is generally
  1435. reliable only if GetLastError does not return ERROR_NOT_ENOUGH_MEMORY.
  1436. If out-of-memory does occur, the ErrorLine may be 0.
  1437. Return Value:
  1438. If the function succeeds, the return value is a handle to the opened INF
  1439. file.
  1440. If the function fails, the return value is INVALID_HANDLE_VALUE. To get
  1441. extended error information, call GetLastError.
  1442. Remarks:
  1443. If the load fails because the INF class does not match InfClass, the
  1444. function returns FALSE, and GetLastError returns ERROR_CLASS_MISMATCH.
  1445. The SetupCloseInfFile function is used to close a handle returned by
  1446. SetupOpenInfFile.
  1447. If multiple INF styles are specified, the style of the INF file opened may
  1448. be ascertained by calling SetupGetInfInformation.
  1449. Since there may be multiple class GUIDs all having the same class name,
  1450. callers interested in only INFs of a particular class (i.e., a particular
  1451. class GUID) should retrieve the ClassGuid value from the INF to verify that
  1452. the class matches exactly.
  1453. If both the INF_STYLE_CACHE_ENABLE and INF_STYLE_CACHE_DISABLE InfStyle
  1454. flags are specified, then the existing cached information that is maintained
  1455. about the INF (e.g., original source location) is discarded, and the INF is
  1456. re-added to the cache without this old information.
  1457. (Internal: Presently, the INF_STYLE_CACHE_ENABLE and
  1458. INF_STYLE_CACHE_DISABLE flags cause us to create or delete PNFs outside of
  1459. %windir%\Inf. Their rather vague-sounding names were chosen to reflect the
  1460. possibility of modifying the caching/indexing scheme in the future.)
  1461. --*/
  1462. {
  1463. UINT errorLine;
  1464. DWORD d;
  1465. PLOADED_INF Inf;
  1466. PCTSTR Class;
  1467. TCHAR TempString[MAX_PATH];
  1468. GUID ClassGuid;
  1469. HRESULT hr;
  1470. BOOL TryPnf;
  1471. WIN32_FIND_DATA FindData;
  1472. PTSTR DontCare;
  1473. PTSTR TempCharPtr = NULL;
  1474. //
  1475. // Determine whether just the filename (no path) was specified. If so,
  1476. // look for it in the DevicePath directory search path. Otherwise,
  1477. // use the path as-is.
  1478. //
  1479. try {
  1480. if(FileName == pSetupGetFileTitle(FileName)) {
  1481. //
  1482. // The specified INF name is a simple filename. Search for it in
  1483. // the INF directories using the default search order.
  1484. //
  1485. d = SearchForInfFile(
  1486. FileName,
  1487. &FindData,
  1488. INFINFO_DEFAULT_SEARCH,
  1489. TempString,
  1490. SIZECHARS(TempString),
  1491. NULL
  1492. );
  1493. if(d == NO_ERROR) {
  1494. TryPnf = TRUE;
  1495. }
  1496. } else {
  1497. //
  1498. // The specified INF filename contains more than just a filename.
  1499. // Assume it's an absolute path. (We need to make sure it's
  1500. // fully-qualified, because that's what LoadInfFile expects.)
  1501. //
  1502. d = GetFullPathName(FileName,
  1503. SIZECHARS(TempString),
  1504. TempString,
  1505. &DontCare
  1506. );
  1507. if(!d) {
  1508. d = GetLastError();
  1509. } else if(d >= SIZECHARS(TempString)) {
  1510. MYASSERT(0);
  1511. d = ERROR_BUFFER_OVERFLOW;
  1512. } else {
  1513. //
  1514. // We successfully retrieved the full pathname, now see if the
  1515. // file exists.
  1516. //
  1517. if(FileExists(TempString, &FindData)) {
  1518. //
  1519. // We have everything we need to load this INF.
  1520. //
  1521. InfSourcePathFromFileName(TempString, &TempCharPtr, &TryPnf);
  1522. d = NO_ERROR;
  1523. } else {
  1524. d = GetLastError();
  1525. }
  1526. }
  1527. }
  1528. } except(EXCEPTION_EXECUTE_HANDLER) {
  1529. //
  1530. // Assume FileName was invalid and thus pSetupGetFileTitle fell over.
  1531. //
  1532. d = ERROR_INVALID_PARAMETER;
  1533. TempCharPtr = TempCharPtr;
  1534. }
  1535. if(d != NO_ERROR) {
  1536. goto PrepareForReturn;
  1537. }
  1538. if(InfStyle & INF_STYLE_CACHE_DISABLE) {
  1539. //
  1540. // Delete the existing PNF for this INF (if any).
  1541. //
  1542. TCHAR PnfFullPath[MAX_PATH];
  1543. PTSTR PnfFileName, PnfFileExt;
  1544. lstrcpy(PnfFullPath, TempString);
  1545. //
  1546. // Find the start of the filename component of the path, and then find
  1547. // the last period (if one exists) in that filename.
  1548. //
  1549. PnfFileName = (PTSTR)pSetupGetFileTitle(PnfFullPath);
  1550. if(!(PnfFileExt = _tcsrchr(PnfFileName, TEXT('.')))) {
  1551. PnfFileExt = PnfFullPath + lstrlen(PnfFullPath);
  1552. }
  1553. //
  1554. // Now create a corresponding filename with the extension '.PNF'
  1555. //
  1556. lstrcpyn(PnfFileExt, pszPnfSuffix, SIZECHARS(PnfFullPath) - (int)(PnfFileExt - PnfFullPath));
  1557. SetFileAttributes(PnfFullPath, FILE_ATTRIBUTE_NORMAL);
  1558. DeleteFile(PnfFullPath);
  1559. }
  1560. if(InfStyle & INF_STYLE_CACHE_ENABLE) {
  1561. //
  1562. // The caller has requested that this INF be cached (even though it may
  1563. // be outside of our INF search path).
  1564. //
  1565. TryPnf = TRUE;
  1566. }
  1567. try {
  1568. d = LoadInfFile(
  1569. TempString,
  1570. &FindData,
  1571. InfStyle,
  1572. TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0,
  1573. NULL,
  1574. TempCharPtr,
  1575. NULL,
  1576. NULL,
  1577. NULL, // LogContext
  1578. &Inf,
  1579. &errorLine,
  1580. NULL
  1581. );
  1582. } except(EXCEPTION_EXECUTE_HANDLER) {
  1583. d = ERROR_INVALID_PARAMETER;
  1584. }
  1585. if(d == NO_ERROR) {
  1586. if(InfClass) {
  1587. d = ERROR_CLASS_MISMATCH; // assume mismatch
  1588. //
  1589. // Match based on class of inf. The following check works for
  1590. // both new and old style infs, because old-style infs use
  1591. // [Identification].OptionType as the class (see oldinf.c
  1592. // function ProcessOldInfVersionBlock()).
  1593. //
  1594. if(Class = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClass)) {
  1595. try {
  1596. if(!lstrcmpi(Class,InfClass)) {
  1597. d = NO_ERROR;
  1598. }
  1599. } except(EXCEPTION_EXECUTE_HANDLER) {
  1600. d = ERROR_INVALID_PARAMETER;
  1601. }
  1602. } else {
  1603. //
  1604. // No Class entry--check for ClassGUID entry.
  1605. //
  1606. if(Class = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClassGuid)) {
  1607. //
  1608. // Get the class name associated with this GUID, and see if it
  1609. // matches the caller-supplied class name.
  1610. //
  1611. // (We have to cast away the CONST-ness of the Class string, because
  1612. // the prototype for CLSIDFromString doesn't specify this parameter
  1613. // as constant.)
  1614. //
  1615. if((hr = pSetupGuidFromString((PTSTR)Class, &ClassGuid)) == S_OK) {
  1616. if(SetupDiClassNameFromGuid(&ClassGuid,
  1617. TempString,
  1618. SIZECHARS(TempString),
  1619. NULL)) {
  1620. try {
  1621. if(!lstrcmpi(TempString,InfClass)) {
  1622. d = NO_ERROR;
  1623. }
  1624. } except(EXCEPTION_EXECUTE_HANDLER) {
  1625. d = ERROR_INVALID_PARAMETER;
  1626. }
  1627. }
  1628. } else {
  1629. if(hr == E_OUTOFMEMORY) {
  1630. d = ERROR_NOT_ENOUGH_MEMORY;
  1631. }
  1632. }
  1633. }
  1634. }
  1635. if(d != NO_ERROR) {
  1636. FreeInfFile(Inf);
  1637. }
  1638. }
  1639. } else {
  1640. if(ErrorLine) {
  1641. try {
  1642. *ErrorLine = errorLine;
  1643. } except(EXCEPTION_EXECUTE_HANDLER) {
  1644. d = ERROR_INVALID_PARAMETER;
  1645. }
  1646. }
  1647. }
  1648. PrepareForReturn:
  1649. if(TempCharPtr) {
  1650. MyFree(TempCharPtr);
  1651. }
  1652. SetLastError(d);
  1653. return((d == NO_ERROR) ? (HINF)Inf : (HINF)INVALID_HANDLE_VALUE);
  1654. }
  1655. HINF
  1656. SetupOpenMasterInf(
  1657. VOID
  1658. )
  1659. /*++
  1660. Routine Description:
  1661. Arguments:
  1662. Return Value:
  1663. --*/
  1664. {
  1665. TCHAR FileName[MAX_PATH];
  1666. lstrcpyn(FileName,InfDirectory,SIZECHARS(FileName)-11);
  1667. lstrcat(FileName,TEXT("\\LAYOUT.INF"));
  1668. return(SetupOpenInfFile(FileName,NULL,INF_STYLE_WIN4,NULL));
  1669. }
  1670. #ifdef UNICODE
  1671. //
  1672. // ANSI version
  1673. //
  1674. BOOL
  1675. SetupOpenAppendInfFileA(
  1676. IN PCSTR FileName, OPTIONAL
  1677. IN HINF InfHandle,
  1678. OUT PUINT ErrorLine OPTIONAL
  1679. )
  1680. {
  1681. PCWSTR fileName = NULL;
  1682. DWORD d;
  1683. BOOL b;
  1684. //
  1685. // Set error line to 0 since ansi arg conversion could fail
  1686. // and we need to indicate that there's no error in the inf itself.
  1687. //
  1688. d = NO_ERROR;
  1689. if(ErrorLine) {
  1690. try {
  1691. *ErrorLine = 0;
  1692. } except(EXCEPTION_EXECUTE_HANDLER) {
  1693. d = ERROR_INVALID_PARAMETER;
  1694. }
  1695. }
  1696. if(d == NO_ERROR) {
  1697. if(FileName) {
  1698. d = pSetupCaptureAndConvertAnsiArg(FileName,&fileName);
  1699. } else {
  1700. fileName = NULL;
  1701. }
  1702. }
  1703. if(d == NO_ERROR) {
  1704. b = SetupOpenAppendInfFileW(fileName,InfHandle,ErrorLine);
  1705. d = GetLastError();
  1706. } else {
  1707. b = FALSE;
  1708. }
  1709. if(fileName) {
  1710. MyFree(fileName);
  1711. }
  1712. SetLastError(d);
  1713. return(b);
  1714. }
  1715. #else
  1716. //
  1717. // Unicode stub
  1718. //
  1719. BOOL
  1720. SetupOpenAppendInfFileW(
  1721. IN PCWSTR FileName, OPTIONAL
  1722. IN HINF InfHandle,
  1723. OUT PUINT ErrorLine OPTIONAL
  1724. )
  1725. {
  1726. UNREFERENCED_PARAMETER(FileName);
  1727. UNREFERENCED_PARAMETER(InfHandle);
  1728. UNREFERENCED_PARAMETER(ErrorLine);
  1729. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1730. return(FALSE);
  1731. }
  1732. #endif
  1733. BOOL
  1734. SetupOpenAppendInfFile(
  1735. IN PCTSTR FileName, OPTIONAL
  1736. IN HINF InfHandle,
  1737. OUT PUINT ErrorLine OPTIONAL
  1738. )
  1739. /*++
  1740. Routine Description:
  1741. Arguments:
  1742. Return Value:
  1743. --*/
  1744. {
  1745. PLOADED_INF ExistingInf = NULL, CurInf = NULL;
  1746. DWORD d = NO_ERROR;
  1747. TCHAR Filename[2][MAX_PATH];
  1748. UINT FilenameCount, i, Field;
  1749. UINT errorLine = 0;
  1750. BOOL LookInInfDirAlso;
  1751. BOOL TryPnf;
  1752. WIN32_FIND_DATA FindData;
  1753. PTSTR TempCharPtr = NULL;
  1754. PTSTR DontCare;
  1755. PINF_SECTION InfSection;
  1756. UINT LineNumber;
  1757. PINF_LINE InfLine = NULL;
  1758. try {
  1759. if(LockInf((PLOADED_INF)InfHandle)) {
  1760. ExistingInf = (PLOADED_INF)InfHandle;
  1761. } else {
  1762. d = ERROR_INVALID_HANDLE;
  1763. goto clean0;
  1764. }
  1765. //
  1766. // Check INF Signature field as a further validation on the InfHandle.
  1767. //
  1768. if(ExistingInf->Signature != LOADED_INF_SIG) {
  1769. d = ERROR_INVALID_HANDLE;
  1770. goto clean0;
  1771. }
  1772. //
  1773. // Only allow this for win95-style infs.
  1774. //
  1775. if(ExistingInf->Style != INF_STYLE_WIN4) {
  1776. d = ERROR_INVALID_PARAMETER;
  1777. goto clean0;
  1778. }
  1779. //
  1780. // If there is no filename, search through the list of existing INFs, looking
  1781. // for a layout entry in their version blocks. We begin at the end of the list,
  1782. // and search backward, using the first layout file we encounter. This allows
  1783. // for the possibility of append-loading several INFs together (e.g., as done by the
  1784. // optional components dialog), and calling SetupOpenAppendInfFile with no filename
  1785. // for each. Each INF could specify its own layout file, and everything works great.
  1786. // (NOTE: In the above example, if all the INFs specified the same layout file, it
  1787. // would only get loaded once, as expected.)
  1788. //
  1789. // We also can now handle 'LayoutFile' entries that specify multiple layout files. E.g.,
  1790. //
  1791. // LayoutFile = pluslay.inf, layout.inf
  1792. //
  1793. // In the above example, we would append-load 'pluslay.inf', followed by 'layout.inf'.
  1794. // Because of the way we store INFs, any duplicate entries in both INFs would resolve in
  1795. // favor of pluslay.inf, since it was loaded first (unless, of course, layout.inf was
  1796. // already in our list of loaded INFs).
  1797. //
  1798. if(!FileName) {
  1799. //
  1800. // First, find the end of the list.
  1801. //
  1802. for(CurInf = ExistingInf; CurInf->Next; CurInf = CurInf->Next);
  1803. //
  1804. // Now, search the list, back-to-front, looking for a layout file in each INF's
  1805. // [version] section.
  1806. //
  1807. for(; CurInf; CurInf = CurInf->Prev) {
  1808. //
  1809. // Locate the [Version] section.
  1810. //
  1811. if(InfSection = InfLocateSection(CurInf, pszVersion, NULL)) {
  1812. //
  1813. // Now look for a LayoutFile line.
  1814. //
  1815. LineNumber = 0;
  1816. if(InfLocateLine(CurInf, InfSection, pszLayoutFile, &LineNumber, &InfLine)) {
  1817. //
  1818. // We've found the line containing the INFs to be append-
  1819. // loaded. Get the first field on the line to start off
  1820. // our loop below.
  1821. //
  1822. FileName = InfGetField(CurInf, InfLine, 1, NULL);
  1823. break;
  1824. } else {
  1825. //
  1826. // Make sure InfLine is still NULL, so we won't try to use it.
  1827. //
  1828. InfLine = NULL;
  1829. }
  1830. }
  1831. }
  1832. if(!FileName) {
  1833. //
  1834. // Then we didn't find any INFs that specify a layout file.
  1835. //
  1836. d = ERROR_INVALID_DATA;
  1837. goto clean0;
  1838. }
  1839. }
  1840. //
  1841. // Now append-load the INF (or the possibly multiple INFs, if we're
  1842. // using a LayoutFile line).
  1843. //
  1844. for(Field = 1;
  1845. FileName;
  1846. FileName = InfLine ? InfGetField(CurInf, InfLine, ++Field, NULL) : NULL) {
  1847. FilenameCount = 0;
  1848. LookInInfDirAlso = TRUE;
  1849. TryPnf = FALSE;
  1850. //
  1851. // Determine whether just the filename (no path) was specified.
  1852. //
  1853. if(FileName == pSetupGetFileTitle(FileName)) {
  1854. //
  1855. // If we retrieved this filename from an INF's [version] section,
  1856. // then we first attempt to open up the layout file from the
  1857. // directory where we found the INF. If we don't find it in that
  1858. // directory, and that directory wasn't the Inf directory, then
  1859. // we try to open it up in %windir%\Inf as well.
  1860. //
  1861. if(CurInf) {
  1862. //
  1863. // Copy the path without the ending backslash character,
  1864. // because that's how the 'InfDirectory' string is formatted.
  1865. //
  1866. lstrcpyn(Filename[0],
  1867. CurInf->VersionBlock.Filename,
  1868. (int)(pSetupGetFileTitle(CurInf->VersionBlock.Filename) - CurInf->VersionBlock.Filename)
  1869. );
  1870. //
  1871. // Compare this path against the InfDirectory path, to see
  1872. // if they're the same.
  1873. //
  1874. if(!lstrcmpi(Filename[0], InfDirectory)) {
  1875. TryPnf = TRUE;
  1876. LookInInfDirAlso = FALSE;
  1877. }
  1878. //
  1879. // Now concatenate the layout filename onto the path.
  1880. //
  1881. pSetupConcatenatePaths(Filename[0], FileName, MAX_PATH, NULL);
  1882. FilenameCount = 1;
  1883. //
  1884. // If 'TryPnf' is still FALSE, then that means that the INF
  1885. // wasn't in the INF directory. Now find out if it's in a
  1886. // location that requires a non-NULL SourcePath (i.e.,
  1887. // something other than the default).
  1888. //
  1889. if(!TryPnf) {
  1890. InfSourcePathFromFileName(Filename[0], &TempCharPtr, &TryPnf);
  1891. }
  1892. }
  1893. if(LookInInfDirAlso) {
  1894. lstrcpy(Filename[FilenameCount], InfDirectory);
  1895. pSetupConcatenatePaths(Filename[FilenameCount], FileName, MAX_PATH, NULL);
  1896. if(!FilenameCount) {
  1897. TryPnf = TRUE;
  1898. }
  1899. FilenameCount++;
  1900. }
  1901. } else {
  1902. //
  1903. // The INF filename contains more than just a filename. Assume
  1904. // it's an absolute path. (We need to make sure it's fully-
  1905. // qualified, because that's what LoadInfFile expects.)
  1906. //
  1907. d = GetFullPathName(FileName,
  1908. SIZECHARS(Filename[0]),
  1909. Filename[0],
  1910. &DontCare
  1911. );
  1912. if(!d) {
  1913. d = GetLastError();
  1914. goto clean0;
  1915. } else if(d >= SIZECHARS(Filename[0])) {
  1916. MYASSERT(0);
  1917. d = ERROR_BUFFER_OVERFLOW;
  1918. goto clean0;
  1919. }
  1920. InfSourcePathFromFileName(Filename[0], &TempCharPtr, &TryPnf);
  1921. FilenameCount = 1;
  1922. //
  1923. // (Since we're setting FilenameCount to 1, we know we'll go
  1924. // through the loop below at least once, thus d will get set to
  1925. // the proper error, so we don't have to re-initialize it to
  1926. // NO_ERROR here.)
  1927. //
  1928. }
  1929. for(i = 0; i < FilenameCount; i++) {
  1930. //
  1931. // Load the inf
  1932. //
  1933. if(FileExists(Filename[i], &FindData)) {
  1934. if((d = LoadInfFile(Filename[i],
  1935. &FindData,
  1936. INF_STYLE_WIN4,
  1937. (i | TryPnf) ? LDINF_FLAG_ALWAYS_TRY_PNF : 0,
  1938. NULL,
  1939. (i | TryPnf) ? NULL : TempCharPtr,
  1940. NULL,
  1941. ExistingInf,
  1942. ExistingInf->LogContext,
  1943. &ExistingInf,
  1944. &errorLine,
  1945. NULL)) == NO_ERROR) {
  1946. break;
  1947. }
  1948. } else {
  1949. d = GetLastError();
  1950. }
  1951. }
  1952. //
  1953. // We no longer need the INF source path--free it if necessary.
  1954. //
  1955. if(TempCharPtr) {
  1956. MyFree(TempCharPtr);
  1957. TempCharPtr = NULL;
  1958. }
  1959. if(d != NO_ERROR) {
  1960. break;
  1961. }
  1962. }
  1963. clean0:
  1964. //
  1965. // If the caller requested it, give them the line number at which any error occurred.
  1966. // (This may be zero on non-parse errors.)
  1967. //
  1968. if(ErrorLine) {
  1969. *ErrorLine = errorLine;
  1970. }
  1971. } except(EXCEPTION_EXECUTE_HANDLER) {
  1972. //
  1973. // If we hit an AV, then use invalid parameter error, otherwise, assume an inpage error when dealing
  1974. // with a mapped-in file.
  1975. //
  1976. d = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  1977. if(TempCharPtr) {
  1978. MyFree(TempCharPtr);
  1979. }
  1980. //
  1981. // Access the 'ExistingInf' variable, so that the compiler will respect our statement
  1982. // ordering w.r.t. this variable. Otherwise, we may not always know whether or not
  1983. // we should be unlocking this INF.
  1984. //
  1985. ExistingInf = ExistingInf;
  1986. }
  1987. if(ExistingInf) {
  1988. UnlockInf(ExistingInf);
  1989. }
  1990. SetLastError(d);
  1991. return(d == NO_ERROR);
  1992. }
  1993. VOID
  1994. SetupCloseInfFile(
  1995. IN HINF InfHandle
  1996. )
  1997. /*++
  1998. Routine Description:
  1999. Arguments:
  2000. Return Value:
  2001. --*/
  2002. {
  2003. PLOADED_INF CurInf, NextInf;
  2004. try {
  2005. //
  2006. // Make sure we can lock the head of the INF list before
  2007. // we start deleting!
  2008. //
  2009. if(LockInf((PLOADED_INF)InfHandle)) {
  2010. //
  2011. // Also check INF Signature field as a further validation.
  2012. //
  2013. if(((PLOADED_INF)InfHandle)->Signature == LOADED_INF_SIG) {
  2014. CurInf = ((PLOADED_INF)InfHandle)->Next;
  2015. DestroySynchronizedAccess(&(((PLOADED_INF)InfHandle)->Lock));
  2016. FreeLoadedInfDescriptor((PLOADED_INF)InfHandle);
  2017. for(; CurInf; CurInf = NextInf) {
  2018. NextInf = CurInf->Next;
  2019. FreeInfFile(CurInf);
  2020. }
  2021. } else {
  2022. UnlockInf((PLOADED_INF)InfHandle);
  2023. }
  2024. }
  2025. } except(EXCEPTION_EXECUTE_HANDLER) {
  2026. ;
  2027. }
  2028. }
  2029. #ifdef UNICODE
  2030. //
  2031. // ANSI version
  2032. //
  2033. BOOL
  2034. WINAPI
  2035. SetupVerifyInfFileA(
  2036. IN PCSTR InfName,
  2037. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  2038. OUT PSP_INF_SIGNER_INFO_A InfSignerInfo
  2039. )
  2040. {
  2041. DWORD Err = NO_ERROR;
  2042. SP_INF_SIGNER_INFO_W InfSignerInfoW;
  2043. int i;
  2044. PWSTR InfNameUnicode = NULL;
  2045. try {
  2046. if (!InfName) {
  2047. SetLastError(ERROR_INVALID_PARAMETER);
  2048. leave;
  2049. }
  2050. if (!InfSignerInfo || (InfSignerInfo->cbSize != sizeof(SP_INF_SIGNER_INFO_A))) {
  2051. SetLastError(ERROR_INVALID_PARAMETER);
  2052. leave; // exit try block
  2053. }
  2054. Err = pSetupCaptureAndConvertAnsiArg(InfName, &InfNameUnicode);
  2055. if (Err != NO_ERROR) {
  2056. leave; // exit try block
  2057. }
  2058. InfSignerInfoW.cbSize = sizeof(InfSignerInfoW);
  2059. Err = SetupVerifyInfFile(InfNameUnicode,
  2060. AltPlatformInfo,
  2061. &InfSignerInfoW
  2062. );
  2063. if (Err == NO_ERROR) {
  2064. i = WideCharToMultiByte(
  2065. CP_ACP,
  2066. 0,
  2067. InfSignerInfoW.CatalogFile,
  2068. -1,
  2069. InfSignerInfo->CatalogFile,
  2070. sizeof(InfSignerInfo->CatalogFile),
  2071. NULL,
  2072. NULL
  2073. );
  2074. if (i==0) {
  2075. //
  2076. // error occurred (LastError set to error)
  2077. //
  2078. Err = GetLastError();
  2079. leave; // exit try block
  2080. }
  2081. i = WideCharToMultiByte(
  2082. CP_ACP,
  2083. 0,
  2084. InfSignerInfoW.DigitalSigner,
  2085. -1,
  2086. InfSignerInfo->DigitalSigner,
  2087. sizeof(InfSignerInfo->DigitalSigner),
  2088. NULL,
  2089. NULL
  2090. );
  2091. if (i==0) {
  2092. //
  2093. // error occurred (LastError set to error)
  2094. //
  2095. Err = GetLastError();
  2096. leave; // exit try block
  2097. }
  2098. i = WideCharToMultiByte(
  2099. CP_ACP,
  2100. 0,
  2101. InfSignerInfoW.DigitalSignerVersion,
  2102. -1,
  2103. InfSignerInfo->DigitalSignerVersion,
  2104. sizeof(InfSignerInfo->DigitalSignerVersion),
  2105. NULL,
  2106. NULL
  2107. );
  2108. if (i==0) {
  2109. //
  2110. // error occurred (LastError set to error)
  2111. //
  2112. Err = GetLastError();
  2113. leave; // exit try block
  2114. }
  2115. }
  2116. } except(EXCEPTION_EXECUTE_HANDLER) {
  2117. Err = ERROR_INVALID_PARAMETER;
  2118. }
  2119. if (InfNameUnicode) {
  2120. MyFree(InfNameUnicode);
  2121. }
  2122. SetLastError(Err);
  2123. return (Err == NO_ERROR);
  2124. }
  2125. #else
  2126. //
  2127. // Unicode stub
  2128. //
  2129. BOOL
  2130. WINAPI
  2131. SetupVerifyInfFileW(
  2132. IN PCWSTR InfName,
  2133. IN PSP_ALTPLATFORM_INFO AltPlatformInfo, OPTIONAL
  2134. OUT PSP_INF_SIGNER_INFO_W InfSignerInfo
  2135. )
  2136. {
  2137. UNREFERENCED_PARAMETER(InfName);
  2138. UNREFERENCED_PARAMETER(AltPlatformInfo);
  2139. UNREFERENCED_PARAMETER(InfSignerInfo);
  2140. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  2141. return(FALSE);
  2142. }
  2143. #endif
  2144. BOOL
  2145. WINAPI
  2146. SetupVerifyInfFile(
  2147. IN LPCTSTR InfName,
  2148. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  2149. OUT PSP_INF_SIGNER_INFO InfSignerInfo
  2150. )
  2151. /*++
  2152. Routine Description:
  2153. Arguments:
  2154. InfName - Supplies the name of the INF file for which to retrieve class information.
  2155. This name may include a path.
  2156. Return Value:
  2157. If the function succeeds, the return value is TRUE.
  2158. If the function fails, the return value is FALSE. To get extended error
  2159. information, call GetLastError.
  2160. --*/
  2161. {
  2162. DWORD Err = NO_ERROR;
  2163. TCHAR PathBuffer[MAX_PATH];
  2164. PLOADED_INF Inf = NULL;
  2165. BOOL PnfWasUsed;
  2166. UINT ErrorLineNumber;
  2167. BOOL TryPnf;
  2168. WIN32_FIND_DATA FindData;
  2169. DWORD TempRequiredSize;
  2170. PTSTR DontCare;
  2171. try {
  2172. if (!InfName) {
  2173. Err = ERROR_INVALID_PARAMETER;
  2174. leave;
  2175. }
  2176. if (!InfSignerInfo || (InfSignerInfo->cbSize != sizeof(SP_INF_SIGNER_INFO))) {
  2177. Err = ERROR_INVALID_PARAMETER;
  2178. leave;
  2179. }
  2180. if(InfName == pSetupGetFileTitle(InfName)) {
  2181. //
  2182. // The specified INF name is a simple filename. Search for it in
  2183. // the DevicePath search path list.
  2184. //
  2185. Err = SearchForInfFile(InfName,
  2186. &FindData,
  2187. INFINFO_INF_PATH_LIST_SEARCH,
  2188. PathBuffer,
  2189. SIZECHARS(PathBuffer),
  2190. NULL
  2191. );
  2192. if(Err == NO_ERROR) {
  2193. TryPnf = TRUE;
  2194. } else {
  2195. leave;
  2196. }
  2197. } else {
  2198. //
  2199. // The specified INF filename contains more than just a filename.
  2200. // Assume it's an absolute path. (We need to make sure it's
  2201. // fully-qualified, because that's what LoadInfFile expects.)
  2202. //
  2203. TempRequiredSize = GetFullPathName(InfName,
  2204. SIZECHARS(PathBuffer),
  2205. PathBuffer,
  2206. &DontCare
  2207. );
  2208. if(!TempRequiredSize) {
  2209. Err = GetLastError();
  2210. leave;
  2211. } else if(TempRequiredSize >= SIZECHARS(PathBuffer)) {
  2212. MYASSERT(0);
  2213. Err = ERROR_BUFFER_OVERFLOW;
  2214. leave;
  2215. }
  2216. if(FileExists(PathBuffer, &FindData)) {
  2217. //
  2218. // We have a valid file path, and we're ready to load this INF.
  2219. //
  2220. InfSourcePathFromFileName(PathBuffer, NULL, &TryPnf);
  2221. } else {
  2222. Err = GetLastError();
  2223. leave;
  2224. }
  2225. }
  2226. //
  2227. // Load the INF.
  2228. //
  2229. Err = LoadInfFile(PathBuffer,
  2230. &FindData,
  2231. INF_STYLE_WIN4,
  2232. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS | (TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0),
  2233. NULL,
  2234. NULL,
  2235. NULL,
  2236. NULL,
  2237. NULL, // LogContext
  2238. &Inf,
  2239. &ErrorLineNumber,
  2240. NULL
  2241. );
  2242. if(Err != NO_ERROR) {
  2243. leave;
  2244. }
  2245. InfSignerInfo->CatalogFile[0] = TEXT('\0');
  2246. InfSignerInfo->DigitalSigner[0] = TEXT('\0');
  2247. InfSignerInfo->DigitalSignerVersion[0] = TEXT('\0');
  2248. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  2249. //
  2250. // We can't call the VerifyDeviceInfFile internal routine, because
  2251. // it doesn't expect to be asked for the signer info (it doesn't
  2252. // make any sense to talk about the signer info, because we have
  2253. // no idea who signed the INF, or even if it was signed).
  2254. //
  2255. Err = NO_ERROR;
  2256. } else {
  2257. if (VerifyDeviceInfFile(NULL,
  2258. NULL,
  2259. PathBuffer,
  2260. Inf,
  2261. AltPlatformInfo,
  2262. InfSignerInfo->CatalogFile,
  2263. InfSignerInfo->DigitalSigner,
  2264. InfSignerInfo->DigitalSignerVersion
  2265. )) {
  2266. Err = NO_ERROR;
  2267. } else {
  2268. Err = GetLastError();
  2269. }
  2270. }
  2271. } except(EXCEPTION_EXECUTE_HANDLER) {
  2272. Err = ERROR_INVALID_DATA;
  2273. }
  2274. if (Inf) {
  2275. FreeInfFile(Inf);
  2276. Inf = NULL;
  2277. }
  2278. SetLastError(Err);
  2279. return (Err == NO_ERROR);
  2280. }
  2281. /////////////////////////////////////////////////////////////////
  2282. //
  2283. // Internal routines
  2284. //
  2285. /////////////////////////////////////////////////////////////////
  2286. BOOL
  2287. pSetupVersionNodeFromInfInformation(
  2288. IN PSP_INF_INFORMATION InfInformation,
  2289. IN UINT InfIndex,
  2290. OUT PINF_VERSION_NODE VersionNode,
  2291. OUT PTSTR OriginalFilename OPTIONAL
  2292. )
  2293. /*++
  2294. Routine Description:
  2295. Fills in a caller-supplied INF_VERSION_NODE buffer for an INF file
  2296. from the SP_INF_INFORMATION structure.
  2297. Arguments:
  2298. InfInformation - supplies the inf information descriptor
  2299. InfIndex - supplies the 0-based index of the inf whose version block
  2300. is requested. If this value is not inrange an error is returned.
  2301. VersionNode - supplies the address of a buffer that receives the version
  2302. node structure.
  2303. OriginalFilename - optionally, supplies the address of a character buffer
  2304. (that must be at least MAX_PATH characters large) that receives the
  2305. INF's original filename (which may be the same as its current filename
  2306. if the INF isn't an OEM INF.
  2307. Return Value:
  2308. If successful, the return value is TRUE, otherwise, it is FALSE.
  2309. --*/
  2310. {
  2311. PINF_VERSION_BLOCK First;
  2312. INF_VERSION_BLOCK UNALIGNED *Ver;
  2313. PUCHAR Base;
  2314. UINT ord;
  2315. INF_VERSION_BLOCK TempVersionBlock;
  2316. UINT FilenameSize;
  2317. //
  2318. // Get pointer to first version block.
  2319. //
  2320. Base = (PUCHAR)InfInformation;
  2321. First = (PINF_VERSION_BLOCK)(Base+offsetof(SP_INF_INFORMATION,VersionData));
  2322. //
  2323. // Find relevant version block
  2324. //
  2325. ord = 0;
  2326. for(Ver=First; Ver; Ver=(INF_VERSION_BLOCK UNALIGNED *)(Base+Ver->NextOffset)) {
  2327. if(ord++ == InfIndex) {
  2328. break;
  2329. }
  2330. }
  2331. if(!Ver) {
  2332. return FALSE;
  2333. }
  2334. //
  2335. // Now fill in the version node based on the information contained in the version block.
  2336. //
  2337. VersionNode->LastWriteTime = Ver->LastWriteTime;
  2338. VersionNode->DataBlock = (CONST TCHAR *)((PBYTE)(Ver->Filename) + Ver->OffsetToData);
  2339. VersionNode->DataSize = Ver->DataSize;
  2340. VersionNode->DatumCount = Ver->DatumCount;
  2341. //
  2342. // The 'filename' character buffer may actually contain two strings--the
  2343. // first being the INF's current filename (with path), and the second being
  2344. // the INF's original filename (this won't be present if the INF's name
  2345. // hasn't changed from its original name).
  2346. //
  2347. // Copy the first MAX_PATH characters of this buffer (or the entire buffer,
  2348. // whichever is smaller) into the VersionNode's Filename buffer, then after
  2349. // we've computed the string length of that string, we can ascertain whether
  2350. // or not there's another string following it containing the INF's original
  2351. // name.
  2352. //
  2353. FilenameSize = (Ver->OffsetToData < SIZECHARS(VersionNode->Filename))
  2354. ? Ver->OffsetToData : SIZECHARS(VersionNode->Filename);
  2355. CopyMemory(VersionNode->Filename, Ver->Filename, FilenameSize);
  2356. VersionNode->FilenameSize = (lstrlen(VersionNode->Filename) + 1) * sizeof(TCHAR);
  2357. MYASSERT(Ver->OffsetToData >= VersionNode->FilenameSize);
  2358. if(OriginalFilename) {
  2359. if(Ver->OffsetToData > VersionNode->FilenameSize) {
  2360. //
  2361. // Then there's more data in the Filename buffer, namely the INF's
  2362. // original name--fill this filename into the caller-supplied buffer.
  2363. //
  2364. FilenameSize = Ver->OffsetToData - VersionNode->FilenameSize;
  2365. MYASSERT(((UINT)(FilenameSize / sizeof(TCHAR)) * sizeof(TCHAR)) == FilenameSize);
  2366. MYASSERT(FilenameSize > sizeof(TCHAR));
  2367. CopyMemory(OriginalFilename,
  2368. (PBYTE)Ver->Filename + VersionNode->FilenameSize,
  2369. FilenameSize
  2370. );
  2371. MYASSERT(((lstrlen(OriginalFilename) + 1) * sizeof(TCHAR)) == FilenameSize);
  2372. } else {
  2373. //
  2374. // No original name info stored--must be same as current name.
  2375. //
  2376. lstrcpy(OriginalFilename, pSetupGetFileTitle(VersionNode->Filename));
  2377. }
  2378. }
  2379. return TRUE;
  2380. }
  2381. PCTSTR
  2382. pSetupGetVersionDatum(
  2383. IN PINF_VERSION_NODE VersionNode,
  2384. IN PCTSTR DatumName
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. Look up a piece of version data in an version data node.
  2389. Arguments:
  2390. VersionNode - supplies a pointer to the version node to
  2391. be searched for the datum.
  2392. DatumName - supplies the name of the datum to be retreived.
  2393. Return Value:
  2394. NULL if the datum does not exist in the data block.
  2395. Otherwise a pointer to the datum value is returned. The caller
  2396. must not free or write into this memory.
  2397. --*/
  2398. {
  2399. WORD Datum;
  2400. UINT StringLength;
  2401. PCTSTR Data = VersionNode->DataBlock;
  2402. for(Datum=0; Datum < VersionNode->DatumCount; Datum++) {
  2403. StringLength = lstrlen(Data) + 1;
  2404. //
  2405. // Go through the version block looking for a matching datum name.
  2406. //
  2407. if(lstrcmpi(Data, DatumName)) {
  2408. //
  2409. // Point to the next one.
  2410. //
  2411. Data += StringLength;
  2412. Data += lstrlen(Data) + 1;
  2413. } else {
  2414. //
  2415. // Found it. Return datum value to caller.
  2416. //
  2417. return (Data + StringLength);
  2418. }
  2419. }
  2420. return(NULL);
  2421. }
  2422. BOOL
  2423. pSetupGetCatalogFileValue(
  2424. IN PINF_VERSION_NODE InfVersionNode,
  2425. OUT LPTSTR Buffer,
  2426. IN DWORD BufferSize,
  2427. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo OPTIONAL
  2428. )
  2429. /*++
  2430. Routine Description:
  2431. This routine fetches the (potentially decorated) CatalogFile= value from the
  2432. specified inf version section.
  2433. Arguments:
  2434. InfVersionNode - points to the INF version node from which we're attempting
  2435. to retrieve the associated catalog file.
  2436. Buffer - if the routine returns TRUE, receives the value for CatalogFile=
  2437. in the [Version] section of the inf.
  2438. BufferSize - supplies the size in bytes (ansi) or chars (unicode) of
  2439. the buffer pointed to by Buffer.
  2440. AltPlatformInfo - optionally, supplies the address of a structure describing
  2441. the platform parameters that should be used in formulating the decorated
  2442. CatalogFile= entry to be used when searching for the INF's associated
  2443. catalog file.
  2444. Return Value:
  2445. Boolean value indicating whether a value was found and copied to the
  2446. caller-supplied Buffer.
  2447. --*/
  2448. {
  2449. TCHAR CatFileWithExt[64];
  2450. LPCTSTR p, NtPlatformSuffixToUse;
  2451. DWORD PlatformId;
  2452. MYASSERT(BufferSize >= MAX_PATH);
  2453. p = NULL;
  2454. CopyMemory(CatFileWithExt, pszCatalogFile, sizeof(pszCatalogFile) - sizeof(TCHAR));
  2455. //
  2456. // Set up some variables based on the native platform or upon the non-native
  2457. // platform specified in the AltPlatformInfo parameter.
  2458. //
  2459. if(AltPlatformInfo) {
  2460. PlatformId = AltPlatformInfo->Platform;
  2461. switch(AltPlatformInfo->ProcessorArchitecture) {
  2462. case PROCESSOR_ARCHITECTURE_INTEL:
  2463. NtPlatformSuffixToUse = pszNtX86Suffix;
  2464. break;
  2465. case PROCESSOR_ARCHITECTURE_ALPHA:
  2466. NtPlatformSuffixToUse = pszNtAlphaSuffix;
  2467. break;
  2468. case PROCESSOR_ARCHITECTURE_IA64:
  2469. NtPlatformSuffixToUse = pszNtIA64Suffix;
  2470. break;
  2471. case PROCESSOR_ARCHITECTURE_ALPHA64:
  2472. NtPlatformSuffixToUse = pszNtAXP64Suffix;
  2473. break;
  2474. case PROCESSOR_ARCHITECTURE_AMD64:
  2475. NtPlatformSuffixToUse = pszNtAMD64Suffix;
  2476. break;
  2477. default:
  2478. return FALSE;
  2479. }
  2480. } else {
  2481. PlatformId = OSVersionInfo.dwPlatformId;
  2482. NtPlatformSuffixToUse = pszNtPlatformSuffix;
  2483. }
  2484. if(PlatformId == VER_PLATFORM_WIN32_NT) {
  2485. //
  2486. // We're running on NT, so first try the NT architecture-specific
  2487. // extension, then the generic NT extension.
  2488. //
  2489. lstrcpyn((PTSTR)((PBYTE)CatFileWithExt + (sizeof(pszCatalogFile) - sizeof(TCHAR))),
  2490. NtPlatformSuffixToUse,
  2491. SIZECHARS(CatFileWithExt) - (sizeof(pszCatalogFile) - sizeof(TCHAR))
  2492. );
  2493. p = pSetupGetVersionDatum(InfVersionNode, CatFileWithExt);
  2494. if(!p) {
  2495. //
  2496. // We didn't find an NT architecture-specific CatalogFile= entry, so
  2497. // fall back to looking for just an NT-specific one.
  2498. //
  2499. CopyMemory((PBYTE)CatFileWithExt + (sizeof(pszCatalogFile) - sizeof(TCHAR)),
  2500. pszNtSuffix,
  2501. sizeof(pszNtSuffix)
  2502. );
  2503. p = pSetupGetVersionDatum(InfVersionNode, CatFileWithExt);
  2504. }
  2505. } else {
  2506. //
  2507. // We're running on Windows 95, so try the Windows-specific extension
  2508. //
  2509. CopyMemory((PBYTE)CatFileWithExt + (sizeof(pszCatalogFile) - sizeof(TCHAR)),
  2510. pszWinSuffix,
  2511. sizeof(pszWinSuffix)
  2512. );
  2513. p = pSetupGetVersionDatum(InfVersionNode, CatFileWithExt);
  2514. }
  2515. //
  2516. // If we didn't find an OS/architecture-specific CatalogFile= entry above,
  2517. // then look for an undecorated entry.
  2518. //
  2519. if(!p) {
  2520. p = pSetupGetVersionDatum(InfVersionNode, pszCatalogFile);
  2521. }
  2522. //
  2523. // If we got back an empty string, then treat this as if there was no
  2524. // CatalogFile= entry (this might be used, for example, so that a system-
  2525. // supplied INF that supports both NT and Win98 could specify an undecorated
  2526. // CatalogFile= entry for Win98, yet supply an NT-specific CatalogFile=
  2527. // entry that's an empty string, so that we'd do global verification on NT).
  2528. //
  2529. if(p && lstrlen(p)) {
  2530. lstrcpyn(Buffer, p, BufferSize);
  2531. return TRUE;
  2532. } else {
  2533. return FALSE;
  2534. }
  2535. }
  2536. VOID
  2537. pSetupGetPhysicalInfFilepath(
  2538. IN PINFCONTEXT LineContext,
  2539. OUT LPTSTR Buffer,
  2540. IN DWORD BufferSize
  2541. )
  2542. {
  2543. lstrcpyn(
  2544. Buffer,
  2545. ((PLOADED_INF)LineContext->CurrentInf)->VersionBlock.Filename,
  2546. BufferSize
  2547. );
  2548. }