Leaked source code of windows server 2003
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.

2328 lines
58 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. dll.c
  5. Abstract:
  6. Initialization/de-initialization of setupapi.dll
  7. Author:
  8. Lonny McMichael (lonnym) 10-May-1995
  9. Revision History:
  10. Jamie Hunter (JamieHun) Apr-25-2002
  11. Security code review
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. HANDLE MyDllModuleHandle;
  16. OSVERSIONINFOEX OSVersionInfo;
  17. //
  18. // TLS Data
  19. //
  20. DWORD TlsIndex = (DWORD)(-1); // no data
  21. PSETUP_TLS pLastTlsAlloc = NULL; // for cleanup
  22. //
  23. // Static strings we retreive once. Listed in order they are retrieved
  24. //
  25. PCTSTR OsLoaderRelativePath = NULL; // (can be NULL)
  26. PCTSTR OsSystemPartitionRoot = NULL; // eg: \\?\GLOBALROOT\Device\HarddiskVolume1
  27. PCTSTR ProcessFileName = NULL; // Filename of app calling setupapi
  28. PCTSTR WindowsDirectory = NULL; // %windir%, GetSystemWindowsDirectory()
  29. PCTSTR InfDirectory = NULL; // %windir%\INF
  30. PCTSTR System16Directory = NULL; // %windir%\SYSTEM
  31. PCTSTR LastGoodDirectory = NULL; // %windir%\LastGood
  32. PCTSTR SystemDirectory = NULL; // <sys>, %windir%\SYSTEM or %windir%\System32
  33. PCTSTR WindowsBackupDirectory = NULL; // <sys>\ReinstallBackups
  34. PCTSTR ConfigDirectory = NULL; // <sys>\CONFIG
  35. PCTSTR DriversDirectory = NULL; // <sys>\DRIVERS
  36. PCTSTR SystemSourcePath = NULL; // location system installed from
  37. PCTSTR ServicePackSourcePath = NULL; // location service pack installed from (can be NULL)
  38. PCTSTR ServicePackCachePath = NULL; // location service pack files are cached
  39. PCTSTR DriverCacheSourcePath = NULL; // location of driver cache (can be NULL)
  40. BOOL GuiSetupInProgress = FALSE; // set if we determine we're in GUI setup
  41. PCTSTR InfSearchPaths = NULL; // Multi-sz list of fully-qualified directories where INFs are to be searched for.
  42. #ifndef _WIN64
  43. BOOL IsWow64 = FALSE; // set if we're running under WOW64
  44. #endif
  45. CRITICAL_SECTION InitMutex; // for one-time initializations
  46. CRITICAL_SECTION ImageHlpMutex; // for dealing with IMAGEHLP library
  47. CRITICAL_SECTION DelayedComponentMutex; // for any delayed initialization of certain components
  48. CRITICAL_SECTION PlatformPathOverrideCritSect;
  49. CRITICAL_SECTION LogUseCountCs;
  50. CRITICAL_SECTION MruCritSect;
  51. CRITICAL_SECTION NetConnectionListCritSect;
  52. BOOL InInitialization = FALSE;
  53. DWORD DoneInitialization = 0; // bitmask of items we've initialized
  54. DWORD DoneCleanup = 0; // bitmask of items we've cleaned up
  55. DWORD DoneComponentInitialize = 0; // bitmask of components we've done delayed initialization
  56. DWORD FailedComponentInitialize = 0; // bitmask of components we've failed initialization
  57. HANDLE GlobalNoDriverPromptsEventFlag = NULL; // event that acts as a flag during setup
  58. INT DoneCriticalSections = 0;
  59. DWORD Seed;
  60. CRITICAL_SECTION * CriticalSectionList[] = {
  61. &InitMutex,
  62. &ImageHlpMutex,
  63. &DelayedComponentMutex,
  64. &PlatformPathOverrideCritSect,
  65. &LogUseCountCs,
  66. &MruCritSect,
  67. &NetConnectionListCritSect,
  68. NULL
  69. };
  70. #define DONEINIT_TLS (0x0000001)
  71. #define DONEINIT_UTILS (0x0000002)
  72. #define DONEINIT_MEM (0x0000004)
  73. #define DONEINIT_CTRL (0x0000008)
  74. #define DONEINIT_FUSION (0x0000010)
  75. #define DONEINIT_STUBS (0x0000020)
  76. #define DONEINIT_COMMON (0x0000040)
  77. #define DONEINIT_DIAMOND (0x0000080)
  78. #define DONEINIT_LOGGING (0x0000100)
  79. #define DONEINIT_CFGMGR32 (0x0000200)
  80. #define DONEINIT_COMPLETE (0x8000000)
  81. //
  82. // various control flags
  83. //
  84. DWORD GlobalSetupFlags = 0;
  85. DWORD GlobalSetupFlagsOverride = PSPGF_MINIMAL_EMBEDDED | PSPGF_NO_SCE_EMBEDDED; // flags that cannot be modified
  86. //
  87. // Declare a (non-CONST) array of strings that specifies what lines to look for
  88. // in an INF's [ControlFlags] section when determining whether a particular device
  89. // ID should be excluded. These lines are of the form "ExcludeFromSelect[.<suffix>]",
  90. // where <suffix> is determined and filled in during process attach as an optimization.
  91. //
  92. // The max string length (including NULL) is 32, and there can be a maximum of 3
  93. // such strings. E.g.: ExcludeFromSelect, ExcludeFromSelect.NT, ExcludeFromSelect.NTAmd64
  94. //
  95. // WARNING!! Be very careful when mucking with the order/number of these entries. Check
  96. // the assumptions made in devdrv.c!pSetupShouldDevBeExcluded.
  97. //
  98. TCHAR pszExcludeFromSelectList[3][32] = { INFSTR_KEY_EXCLUDEFROMSELECT,
  99. INFSTR_KEY_EXCLUDEFROMSELECT,
  100. INFSTR_KEY_EXCLUDEFROMSELECT
  101. };
  102. DWORD ExcludeFromSelectListUb; // contains the number of strings in the above list (2 or 3).
  103. #ifndef _WIN64
  104. BOOL
  105. GetIsWow64 (
  106. VOID
  107. );
  108. #endif
  109. BOOL
  110. CommonProcessAttach(
  111. IN BOOL Attach
  112. );
  113. PCTSTR
  114. GetDriverCacheSourcePath(
  115. VOID
  116. );
  117. PCTSTR
  118. pSetupGetOsLoaderPath(
  119. VOID
  120. );
  121. PCTSTR
  122. pSetupGetSystemPartitionRoot(
  123. VOID
  124. );
  125. PCTSTR
  126. pSetupGetProcessPath(
  127. VOID
  128. );
  129. BOOL
  130. pGetGuiSetupInProgress(
  131. VOID
  132. );
  133. BOOL
  134. CfgmgrEntry(
  135. PVOID hModule,
  136. ULONG Reason,
  137. PCONTEXT pContext
  138. );
  139. BOOL
  140. ThreadTlsInitialize(
  141. IN BOOL Init
  142. );
  143. VOID
  144. ThreadTlsCleanup(
  145. );
  146. BOOL
  147. IsNoDriverPrompts(
  148. VOID
  149. );
  150. DWORD
  151. GetEmbeddedFlags(
  152. VOID
  153. );
  154. DWORD
  155. GetSeed(
  156. VOID
  157. );
  158. BOOL
  159. ProcessAttach(
  160. IN HANDLE DllHandle,
  161. IN DWORD Reason,
  162. IN LPVOID Reserved
  163. )
  164. /*++
  165. Routine Description:
  166. Handles DLL_PROCESS_ATTACH in a way that can be unwound
  167. Arguments:
  168. Reserved = 'Reserved' value passed into DllMain
  169. Return Value:
  170. TRUE if processed initialized
  171. FALSE if partially/not initialized
  172. --*/
  173. {
  174. BOOL b = FALSE;
  175. if(DoneCleanup) {
  176. //
  177. // if we get here, this means someone lied to us
  178. //
  179. MYASSERT(!DoneCleanup);
  180. DoneInitialization &= ~DoneCleanup;
  181. DoneCleanup = 0;
  182. }
  183. //
  184. // nothing should already be initialized
  185. //
  186. MYASSERT(!DoneInitialization);
  187. try {
  188. MyDllModuleHandle = DllHandle;
  189. //
  190. // initialize TLS before anything else - hence why we use LocalAlloc
  191. //
  192. TlsIndex = TlsAlloc();
  193. if (TlsIndex!=(DWORD)(-1)) {
  194. DoneInitialization |= DONEINIT_TLS;
  195. } else {
  196. leave;
  197. }
  198. //
  199. // always do pSetupInitializeUtils and MemoryInitializeEx first
  200. // (pSetupInitializeUtils sets up memory functions)
  201. //
  202. if(pSetupInitializeUtils()) {
  203. DoneInitialization |= DONEINIT_UTILS;
  204. } else {
  205. leave;
  206. }
  207. if(MemoryInitializeEx(TRUE)) {
  208. DoneInitialization |= DONEINIT_MEM;
  209. } else {
  210. leave;
  211. }
  212. if(spFusionInitialize()) {
  213. DoneInitialization |= DONEINIT_FUSION;
  214. }
  215. //
  216. // Dynamically load proc addresses of NT-specific APIs
  217. // must be before CommonProcessAttach etc
  218. // however memory must be initialized
  219. //
  220. InitializeStubFnPtrs();
  221. DoneInitialization |= DONEINIT_STUBS;
  222. //
  223. // most of the remaining initialization
  224. //
  225. if(CommonProcessAttach(TRUE)) {
  226. DoneInitialization |= DONEINIT_COMMON;
  227. } else {
  228. leave;
  229. }
  230. if(DiamondProcessAttach(TRUE)) {
  231. DoneInitialization |= DONEINIT_DIAMOND;
  232. } else {
  233. leave;
  234. }
  235. if(InitializeContextLogging(TRUE)) {
  236. DoneInitialization |= DONEINIT_LOGGING;
  237. } else {
  238. leave;
  239. }
  240. //
  241. // Since we've incorporated cfgmgr32 into setupapi, we need
  242. // to make sure it gets initialized just like it did when it was
  243. // its own DLL. - must do AFTER everything else
  244. //
  245. if(CfgmgrEntry(DllHandle, Reason, Reserved)) {
  246. DoneInitialization |= DONEINIT_CFGMGR32;
  247. }
  248. DoneInitialization |= DONEINIT_COMPLETE;
  249. b = TRUE;
  250. } except(EXCEPTION_EXECUTE_HANDLER) {
  251. }
  252. return b;
  253. }
  254. void
  255. DestroySetupTlsData(
  256. )
  257. /*++
  258. Routine Description:
  259. Destroy all TLS data from every thread
  260. calling any cleanup routines as required
  261. Arguments:
  262. NONE
  263. Return Value:
  264. NONE
  265. --*/
  266. {
  267. PSETUP_TLS pTLS;
  268. if(pLastTlsAlloc) {
  269. pLastTlsAlloc->Prev->Next = NULL;
  270. while(pLastTlsAlloc) {
  271. pTLS = pLastTlsAlloc;
  272. pLastTlsAlloc = pTLS->Next;
  273. TlsSetValue(TlsIndex,pTLS); // switch specific data into this thread
  274. ThreadTlsCleanup();
  275. LocalFree(pTLS);
  276. }
  277. }
  278. TlsSetValue(TlsIndex,NULL); // don't leave invalid pointer hanging around
  279. }
  280. void
  281. ProcessDetach(
  282. IN HANDLE DllHandle,
  283. IN DWORD Reason,
  284. IN LPVOID Reserved
  285. )
  286. /*++
  287. Routine Description:
  288. Handles DLL_PROCESS_DETACH
  289. Arguments:
  290. Reserved = 'Reserved' value passed into DllMain
  291. Which is actually TRUE for Process Exit, FALSE otherwise
  292. Return Value:
  293. None
  294. --*/
  295. {
  296. DWORD ToCleanup = DoneInitialization & ~ DoneCleanup;
  297. if(!ToCleanup) {
  298. //
  299. // nothing to cleanup
  300. //
  301. return;
  302. }
  303. try {
  304. if (ToCleanup & DONEINIT_COMPLETE) {
  305. DoneCleanup |= DONEINIT_COMPLETE;
  306. }
  307. if(DoneInitialization & DONEINIT_TLS) {
  308. //
  309. // cleanup all remaining Tls data
  310. //
  311. if(!Reserved) {
  312. //
  313. // only do this for FreeLibrary/ failed LoadLibrary
  314. //
  315. DestroySetupTlsData();
  316. }
  317. }
  318. if(ToCleanup & DONEINIT_TLS) {
  319. //
  320. // destroy our allocated TLS index
  321. // do this now so that we don't try allocating
  322. // TLS storage during this cleanup
  323. //
  324. TlsFree(TlsIndex);
  325. TlsIndex = (DWORD)(-1);
  326. DoneCleanup |= DONEINIT_TLS;
  327. }
  328. //
  329. // do things generally in reverse order of ProcessAttach
  330. //
  331. // Since we've incorporated cfgmgr32 into setupapi, we need
  332. // to make sure it gets uninitialized just like it did when it was
  333. // its own DLL. - must do BEFORE anything else
  334. //
  335. if(ToCleanup & DONEINIT_CFGMGR32) {
  336. CfgmgrEntry(DllHandle, Reason, Reserved);
  337. DoneCleanup |= DONEINIT_CFGMGR32;
  338. }
  339. if(ToCleanup & DONEINIT_DIAMOND) {
  340. DiamondProcessAttach(FALSE);
  341. DoneCleanup |= DONEINIT_DIAMOND;
  342. }
  343. #if 0 // see ComponentCleanup at end of file
  344. ComponentCleanup(DoneComponentInitialize);
  345. #endif
  346. if(ToCleanup & DONEINIT_FUSION) {
  347. //
  348. // Fusion cleanup
  349. // only do full if this is FreeLibrary (or failed attach)
  350. //
  351. spFusionUninitialize((Reserved == NULL) ? TRUE : FALSE);
  352. DoneCleanup |= DONEINIT_FUSION;
  353. }
  354. if(ToCleanup & DONEINIT_COMMON) {
  355. //
  356. // Most of remaining cleanup
  357. //
  358. CommonProcessAttach(FALSE);
  359. DoneCleanup |= DONEINIT_COMMON;
  360. }
  361. if(ToCleanup & DONEINIT_STUBS) {
  362. //
  363. // Clean up stub functions
  364. //
  365. CleanUpStubFns();
  366. DoneCleanup |= DONEINIT_STUBS;
  367. }
  368. if(ToCleanup & DONEINIT_LOGGING) {
  369. //
  370. // Clean up context logging
  371. //
  372. InitializeContextLogging(FALSE);
  373. DoneCleanup |= DONEINIT_LOGGING;
  374. }
  375. //
  376. // *THESE MUST ALWAYS BE* very last things, in this order
  377. //
  378. if(ToCleanup & DONEINIT_MEM) {
  379. //
  380. // Clean up context logging
  381. //
  382. MemoryInitializeEx(FALSE);
  383. DoneCleanup |= DONEINIT_MEM;
  384. }
  385. if(ToCleanup & DONEINIT_UTILS) {
  386. //
  387. // Clean up context logging
  388. //
  389. pSetupUninitializeUtils();
  390. DoneCleanup |= DONEINIT_UTILS;
  391. }
  392. } except(EXCEPTION_EXECUTE_HANDLER) {
  393. }
  394. }
  395. //
  396. // Called by CRT when _DllMainCRTStartup is the DLL entry point
  397. //
  398. BOOL
  399. WINAPI
  400. DllMain(
  401. IN HANDLE DllHandle,
  402. IN DWORD Reason,
  403. IN LPVOID Reserved
  404. )
  405. {
  406. BOOL b;
  407. InInitialization = TRUE;
  408. b = TRUE;
  409. switch(Reason) {
  410. case DLL_PROCESS_ATTACH:
  411. b = ProcessAttach(DllHandle,Reason,Reserved);
  412. if(!b) {
  413. ProcessDetach(DllHandle,DLL_THREAD_DETACH,NULL);
  414. }
  415. break;
  416. case DLL_THREAD_ATTACH:
  417. //
  418. // don't do anything here
  419. // any TLS must be done on demand
  420. // via SetupGetTlsData
  421. //
  422. break;
  423. case DLL_PROCESS_DETACH:
  424. //
  425. // any TLS cleanup must be done in ThreadTlsCleanup
  426. //
  427. ProcessDetach(DllHandle,Reason,Reserved);
  428. break;
  429. case DLL_THREAD_DETACH:
  430. ThreadTlsInitialize(FALSE);
  431. break;
  432. }
  433. InInitialization = FALSE;
  434. return(b);
  435. }
  436. PSETUP_TLS
  437. SetupGetTlsData(
  438. )
  439. /*++
  440. Routine Description:
  441. Called to obtain a pointer to TLS data
  442. Arguments:
  443. NONE
  444. Return Value:
  445. Pointer to TLS data, or NULL
  446. --*/
  447. {
  448. PSETUP_TLS pTLS;
  449. if (TlsIndex==(DWORD)(-1)) {
  450. return NULL;
  451. }
  452. pTLS = (PSETUP_TLS)TlsGetValue(TlsIndex);
  453. if (!pTLS) {
  454. ThreadTlsInitialize(TRUE);
  455. pTLS = (PSETUP_TLS)TlsGetValue(TlsIndex);
  456. }
  457. return pTLS;
  458. }
  459. VOID
  460. ThreadTlsCleanup(
  461. )
  462. /*++
  463. Routine Description:
  464. Called to uninitialize some pTLS data
  465. might be a different thread to initialize
  466. but SetupAPI TLS data will have been switched in
  467. Arguments:
  468. pTLS - data to cleanup
  469. Return Value:
  470. NONE.
  471. --*/
  472. {
  473. DiamondTlsInit(FALSE);
  474. ContextLoggingTlsInit(FALSE);
  475. }
  476. BOOL
  477. ThreadTlsUnlink(
  478. IN PSETUP_TLS pTLS
  479. )
  480. {
  481. BOOL b;
  482. try {
  483. EnterCriticalSection(&InitMutex);
  484. if(pTLS->Next == pTLS->Prev) {
  485. pLastTlsAlloc = NULL;
  486. } else {
  487. pTLS->Prev->Next = pTLS->Next;
  488. pTLS->Next->Prev = pTLS->Prev;
  489. pLastTlsAlloc = pTLS->Prev; // anything but pTLS
  490. }
  491. LeaveCriticalSection(&InitMutex);
  492. b = TRUE;
  493. } except(EXCEPTION_EXECUTE_HANDLER) {
  494. b = FALSE;
  495. }
  496. return b;
  497. }
  498. PSETUP_TLS
  499. ThreadTlsCreate(
  500. )
  501. /*++
  502. Routine Description:
  503. Called to create pTLS data for this thread
  504. Arguments:
  505. NONE
  506. Return Value:
  507. per-thread data, or NULL on failure
  508. --*/
  509. {
  510. BOOL b;
  511. PSETUP_TLS pTLS;
  512. if (TlsIndex==(DWORD)(-1)) {
  513. return NULL;
  514. }
  515. pTLS = (PSETUP_TLS)LocalAlloc(LMEM_ZEROINIT,sizeof(SETUP_TLS));
  516. if(!pTLS) {
  517. return NULL;
  518. }
  519. b = TlsSetValue(TlsIndex,pTLS);
  520. if(!b) {
  521. LocalFree(pTLS);
  522. return NULL;
  523. }
  524. try {
  525. EnterCriticalSection(&InitMutex);
  526. if(pLastTlsAlloc) {
  527. pTLS->Prev = pLastTlsAlloc;
  528. pTLS->Next = pTLS->Prev->Next;
  529. pTLS->Prev->Next = pTLS;
  530. pTLS->Next->Prev = pTLS;
  531. } else {
  532. pTLS->Next = pTLS;
  533. pTLS->Prev = pTLS;
  534. }
  535. pLastTlsAlloc = pTLS;
  536. LeaveCriticalSection(&InitMutex);
  537. b = TRUE;
  538. } except(EXCEPTION_EXECUTE_HANDLER) {
  539. b = FALSE;
  540. }
  541. if(!b) {
  542. LocalFree(pTLS);
  543. TlsSetValue(TlsIndex,NULL);
  544. return NULL;
  545. }
  546. //
  547. // TLS data initialized, now specific Init routines
  548. //
  549. b = DiamondTlsInit(TRUE);
  550. if(b) {
  551. b = ContextLoggingTlsInit(TRUE);
  552. if(b) {
  553. //
  554. // all done ok
  555. //
  556. return pTLS;
  557. }
  558. //
  559. // cleanup DiamondTlsInit
  560. //
  561. DiamondTlsInit(FALSE);
  562. }
  563. //
  564. // cleanup memory
  565. //
  566. TlsSetValue(TlsIndex,NULL);
  567. if(ThreadTlsUnlink(pTLS)) {
  568. LocalFree(pTLS);
  569. }
  570. return NULL;
  571. }
  572. BOOL
  573. ThreadTlsInitialize(
  574. IN BOOL Init
  575. )
  576. /*++
  577. Routine Description:
  578. Called with TRUE to initialize TLS, if FALSE, to uninitialize
  579. Arguments:
  580. Init - indicates if we are to initialize vs uninitialize
  581. Return Value:
  582. NONE.
  583. --*/
  584. {
  585. BOOL b = FALSE;
  586. PSETUP_TLS pTLS = NULL;
  587. if (TlsIndex!=(DWORD)(-1)) {
  588. if (Init) {
  589. pTLS = ThreadTlsCreate();
  590. b = pTLS ? TRUE : FALSE;
  591. } else {
  592. pTLS = (PSETUP_TLS)TlsGetValue(TlsIndex);
  593. if(pTLS) {
  594. ThreadTlsCleanup();
  595. TlsSetValue(TlsIndex,NULL);
  596. if(ThreadTlsUnlink(pTLS)) {
  597. LocalFree(pTLS);
  598. }
  599. }
  600. b = TRUE;
  601. }
  602. }
  603. return b;
  604. }
  605. BOOL
  606. IsInteractiveWindowStation(
  607. )
  608. /*++
  609. Routine Description:
  610. Determine if we are running on an interactive station vs non-interactive station (i.e., service)
  611. Arguments:
  612. none
  613. Return Value:
  614. True if interactive
  615. --*/
  616. {
  617. HWINSTA winsta;
  618. USEROBJECTFLAGS flags;
  619. BOOL interactive = TRUE; // true unless we determine otherwise
  620. DWORD lenNeeded;
  621. winsta = GetProcessWindowStation();
  622. if(!winsta) {
  623. return interactive;
  624. }
  625. if(GetUserObjectInformation(winsta,UOI_FLAGS,&flags,sizeof(flags),&lenNeeded)) {
  626. interactive = (flags.dwFlags & WSF_VISIBLE) ? TRUE : FALSE;
  627. }
  628. //
  629. // don't call CLoseWindowStation
  630. //
  631. return interactive;
  632. }
  633. BOOL
  634. CommonProcessAttach(
  635. IN BOOL Attach
  636. )
  637. {
  638. BOOL b;
  639. TCHAR Buffer[MAX_PATH+32];
  640. PTCHAR p;
  641. UINT u;
  642. b = !Attach;
  643. if(Attach) {
  644. try {
  645. //
  646. // (remaining) critical sections
  647. //
  648. while(CriticalSectionList[DoneCriticalSections]) {
  649. InitializeCriticalSection(CriticalSectionList[DoneCriticalSections]);
  650. //
  651. // increment only if we get here (exception can occur)
  652. //
  653. DoneCriticalSections++;
  654. }
  655. #ifndef _WIN64
  656. IsWow64 = GetIsWow64();
  657. #endif
  658. //
  659. // flag indicating we're running in context of GUI setup
  660. //
  661. GuiSetupInProgress = pGetGuiSetupInProgress();
  662. //
  663. // determine if we're interactive or not
  664. //
  665. if(!IsInteractiveWindowStation()) {
  666. GlobalSetupFlagsOverride |= PSPGF_NONINTERACTIVE; // don't allow this to be changed
  667. GlobalSetupFlags |= PSPGF_NONINTERACTIVE; // actual value
  668. }
  669. if(IsNoDriverPrompts()) {
  670. GlobalSetupFlagsOverride |= PSPGF_UNATTENDED_SETUP; // don't allow this to be changed
  671. GlobalSetupFlags |= PSPGF_UNATTENDED_SETUP; // actual value
  672. }
  673. GlobalSetupFlags |= GetEmbeddedFlags();
  674. Seed = GetSeed();
  675. pSetupInitNetConnectionList(TRUE);
  676. pSetupInitPlatformPathOverrideSupport(TRUE);
  677. OsLoaderRelativePath = pSetupGetOsLoaderPath(); // ok to fail
  678. OsSystemPartitionRoot = pSetupGetSystemPartitionRoot(); // ok to fail
  679. //
  680. // Fill in system and windows directories.
  681. //
  682. if ((ProcessFileName = pSetupGetProcessPath()) == NULL) {
  683. goto cleanAll;
  684. }
  685. //
  686. // determine %windir%
  687. //
  688. if(((u = GetSystemWindowsDirectory(Buffer,MAX_PATH)) == 0) || u>MAX_PATH) {
  689. goto cleanAll;
  690. }
  691. p = Buffer + u; // offset past directory to do all the sub-directories
  692. //
  693. // %windir% ==> WindowsDirectory
  694. //
  695. if((WindowsDirectory = DuplicateString(Buffer)) == NULL) {
  696. goto cleanAll;
  697. }
  698. //
  699. // %windir%\INF ==> InfDirectory
  700. //
  701. *p = 0;
  702. if(!pSetupConcatenatePaths(Buffer,TEXT("INF"),MAX_PATH,NULL)
  703. || ((InfDirectory = DuplicateString(Buffer)) == NULL)) {
  704. goto cleanAll;
  705. }
  706. //
  707. // %windir%\SYSTEM ==> System16Directory
  708. //
  709. *p = 0;
  710. if(!pSetupConcatenatePaths(Buffer,TEXT("SYSTEM"),MAX_PATH,NULL)
  711. || ((System16Directory = DuplicateString(Buffer))==NULL)) {
  712. goto cleanAll;
  713. }
  714. //
  715. // %windir%\LastGood ==> LastGoodDirectory
  716. //
  717. *p = 0;
  718. if(!pSetupConcatenatePaths(Buffer,SP_LASTGOOD_NAME,MAX_PATH,NULL)
  719. || ((LastGoodDirectory = DuplicateString(Buffer))==NULL)) {
  720. goto cleanAll;
  721. }
  722. //
  723. // determine system directory
  724. //
  725. if(((u = GetSystemDirectory(Buffer,MAX_PATH)) == 0) || u>MAX_PATH) {
  726. goto cleanAll;
  727. }
  728. p = Buffer + u; // offset past directory to do all the sub-directories
  729. //
  730. // <sys> ==> SystemDirectory (%windir%\System or %windir%\System32)
  731. //
  732. if((SystemDirectory = DuplicateString(Buffer)) == NULL) {
  733. goto cleanAll;
  734. }
  735. //
  736. // <sys>\ReinstallBackups ==> WindowsBackupDirectory
  737. //
  738. *p = 0;
  739. if(!pSetupConcatenatePaths(Buffer,TEXT("ReinstallBackups"),MAX_PATH,NULL)
  740. || ((WindowsBackupDirectory = DuplicateString(Buffer))==NULL)) {
  741. goto cleanAll;
  742. }
  743. //
  744. // <sys>\CONFIG ==> ConfigDirectory
  745. //
  746. *p = 0;
  747. if(!pSetupConcatenatePaths(Buffer,TEXT("CONFIG"),MAX_PATH,NULL)
  748. || ((ConfigDirectory = DuplicateString(Buffer))==NULL)) {
  749. goto cleanAll;
  750. }
  751. //
  752. // <sys>\DRIVERS ==> DriversDirectory
  753. //
  754. *p = 0;
  755. if(!pSetupConcatenatePaths(Buffer,TEXT("DRIVERS"),MAX_PATH,NULL)
  756. || ((DriversDirectory = DuplicateString(Buffer))==NULL)) {
  757. goto cleanAll;
  758. }
  759. //
  760. // location system installed from
  761. //
  762. if((SystemSourcePath = GetSystemSourcePath())==NULL) {
  763. goto cleanAll;
  764. }
  765. //
  766. // location service pack installed from (may be NULL)
  767. //
  768. ServicePackSourcePath = GetServicePackSourcePath();
  769. //
  770. // location of local disk cached files (may be NULL)
  771. // files here have precedence over everything else
  772. //
  773. ServicePackCachePath = GetServicePackCachePath();
  774. //
  775. // location of driver cache (may be NULL)
  776. //
  777. DriverCacheSourcePath = GetDriverCacheSourcePath();
  778. //
  779. // determine driver search path
  780. //
  781. if((InfSearchPaths = AllocAndReturnDriverSearchList(INFINFO_INF_PATH_LIST_SEARCH))==NULL) {
  782. goto cleanAll;
  783. }
  784. //
  785. // note that InitMiniIconList, InitDrvSearchInProgressList, and
  786. // InitDrvSignPolicyList need to be explicitly cleaned up on failure
  787. //
  788. //
  789. // initialize mini icons
  790. //
  791. if(!InitMiniIconList()) {
  792. goto cleanAll;
  793. }
  794. //
  795. // allows aborting of search
  796. //
  797. if(!InitDrvSearchInProgressList()) {
  798. DestroyMiniIconList();
  799. goto cleanAll;
  800. }
  801. //
  802. // global list of device setup classes subject to driver signing policy
  803. //
  804. if(!InitDrvSignPolicyList()) {
  805. DestroyMiniIconList();
  806. DestroyDrvSearchInProgressList();
  807. goto cleanAll;
  808. }
  809. //
  810. // common version initialization
  811. //
  812. ZeroMemory(&OSVersionInfo,sizeof(OSVersionInfo));
  813. OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
  814. if((!GetVersionEx((LPOSVERSIONINFO)&OSVersionInfo))
  815. || (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)) {
  816. //
  817. // should never get here
  818. //
  819. MYASSERT(FALSE);
  820. DestroyMiniIconList();
  821. DestroyDrvSearchInProgressList();
  822. DestroyDrvSignPolicyList();
  823. goto cleanAll;
  824. }
  825. //
  826. // Fill in our ExcludeFromSelect string list which
  827. // we pre-compute as an optimization.
  828. //
  829. if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  830. lstrcat(pszExcludeFromSelectList[1],
  831. pszNtSuffix
  832. );
  833. lstrcat(pszExcludeFromSelectList[2],
  834. pszNtPlatformSuffix
  835. );
  836. ExcludeFromSelectListUb = 3;
  837. } else {
  838. lstrcat(pszExcludeFromSelectList[1],
  839. pszWinSuffix
  840. );
  841. ExcludeFromSelectListUb = 2;
  842. }
  843. //
  844. // Now lower-case all the strings in this list, so that it
  845. // doesn't have to be done at each string table lookup.
  846. //
  847. for(u = 0; u < ExcludeFromSelectListUb; u++) {
  848. CharLower(pszExcludeFromSelectList[u]);
  849. }
  850. b = TRUE;
  851. cleanAll: ;
  852. } except (EXCEPTION_EXECUTE_HANDLER) {
  853. //
  854. // Unexpected exception occurred, drop into cleanup
  855. //
  856. }
  857. if(b) {
  858. //
  859. // succeeded
  860. //
  861. goto Done;
  862. }
  863. } else {
  864. //
  865. // Detach
  866. //
  867. DestroyMiniIconList();
  868. DestroyDrvSearchInProgressList();
  869. DestroyDrvSignPolicyList();
  870. if(GlobalNoDriverPromptsEventFlag) {
  871. CloseHandle(GlobalNoDriverPromptsEventFlag);
  872. }
  873. }
  874. while(DoneCriticalSections--) {
  875. DeleteCriticalSection(CriticalSectionList[DoneCriticalSections]);
  876. }
  877. if (InfSearchPaths) {
  878. MyFree(InfSearchPaths);
  879. InfSearchPaths = NULL;
  880. }
  881. if (DriverCacheSourcePath) {
  882. MyFree(DriverCacheSourcePath);
  883. DriverCacheSourcePath = NULL;
  884. }
  885. if (ServicePackSourcePath) {
  886. MyFree(ServicePackSourcePath);
  887. ServicePackSourcePath = NULL;
  888. }
  889. if (ServicePackCachePath) {
  890. MyFree(ServicePackCachePath);
  891. ServicePackCachePath = NULL;
  892. }
  893. if (SystemSourcePath) {
  894. MyFree(SystemSourcePath);
  895. SystemSourcePath = NULL;
  896. }
  897. if (SystemDirectory) {
  898. MyFree(SystemDirectory);
  899. SystemDirectory = NULL;
  900. if (WindowsBackupDirectory) {
  901. MyFree(WindowsBackupDirectory);
  902. WindowsBackupDirectory = NULL;
  903. }
  904. if (ConfigDirectory) {
  905. MyFree(ConfigDirectory);
  906. ConfigDirectory = NULL;
  907. }
  908. if (DriversDirectory) {
  909. MyFree(DriversDirectory);
  910. DriversDirectory = NULL;
  911. }
  912. }
  913. if (WindowsDirectory) {
  914. MyFree(WindowsDirectory);
  915. WindowsDirectory = NULL;
  916. if (InfDirectory) {
  917. MyFree(InfDirectory);
  918. InfDirectory = NULL;
  919. }
  920. if (System16Directory) {
  921. MyFree(System16Directory);
  922. System16Directory = NULL;
  923. }
  924. if (LastGoodDirectory) {
  925. MyFree(LastGoodDirectory);
  926. } LastGoodDirectory = NULL;
  927. }
  928. if (ProcessFileName) {
  929. MyFree(ProcessFileName);
  930. ProcessFileName = NULL;
  931. }
  932. if (OsLoaderRelativePath) {
  933. MyFree(OsLoaderRelativePath);
  934. OsLoaderRelativePath = NULL;
  935. }
  936. if (OsSystemPartitionRoot) {
  937. MyFree(OsSystemPartitionRoot);
  938. OsSystemPartitionRoot = NULL;
  939. }
  940. pSetupInitNetConnectionList(FALSE);
  941. pSetupInitPlatformPathOverrideSupport(FALSE);
  942. Done:
  943. return(b);
  944. }
  945. #if MEM_DBG
  946. #undef GetSystemSourcePath // defined again below
  947. #endif
  948. PCTSTR
  949. GetSystemSourcePath(
  950. TRACK_ARG_DECLARE
  951. )
  952. /*++
  953. Routine Description:
  954. This routine returns a newly-allocated buffer containing the source path from
  955. which the system was installed, or "A:\" if that value cannot be determined.
  956. This value is retrieved from the following registry location:
  957. \HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
  958. SourcePath : REG_SZ : "\\ntamd64\1300fre.wks" // for example.
  959. Arguments:
  960. None.
  961. Return Value:
  962. If the function succeeds, the return value is a pointer to the path string.
  963. This memory must be freed via MyFree().
  964. If the function fails due to out-of-memory, the return value is NULL.
  965. --*/
  966. {
  967. HKEY hKey;
  968. TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
  969. DWORD Err, DataType, DataSize;
  970. PTSTR Value;
  971. PCTSTR ReturnVal;
  972. TRACK_PUSH
  973. CopyMemory(CharBuffer,
  974. pszPathSetup,
  975. sizeof(pszPathSetup) - sizeof(TCHAR)
  976. );
  977. CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
  978. pszKeySetup,
  979. sizeof(pszKeySetup)
  980. );
  981. if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  982. CharBuffer,
  983. 0,
  984. KEY_READ,
  985. &hKey)) == ERROR_SUCCESS) {
  986. //
  987. // Attempt to read the the "SourcePath" value.
  988. //
  989. Err = QueryRegistryValue(hKey, pszSourcePath, &Value, &DataType, &DataSize);
  990. RegCloseKey(hKey);
  991. }
  992. ReturnVal = NULL;
  993. if(Err == NO_ERROR) {
  994. ReturnVal = Value;
  995. }
  996. if(!ReturnVal && Err != ERROR_NOT_ENOUGH_MEMORY) {
  997. //
  998. // We failed to retrieve the SourcePath value, and it wasn't due to an out-of-memory
  999. // condition. Fall back to our default of "A:\".
  1000. //
  1001. ReturnVal = DuplicateString(pszOemInfDefaultPath);
  1002. }
  1003. TRACK_POP
  1004. return ReturnVal;
  1005. }
  1006. #if MEM_DBG
  1007. #define GetSystemSourcePath() GetSystemSourcePath(TRACK_ARG_CALL)
  1008. #endif
  1009. #if MEM_DBG
  1010. #undef GetServicePackSourcePath // defined again below
  1011. #undef GetServicePackCachePath // defined again below
  1012. #endif
  1013. PCTSTR
  1014. GetServicePackSourcePath(
  1015. TRACK_ARG_DECLARE
  1016. )
  1017. /*++
  1018. Routine Description:
  1019. This routine returns a newly-allocated buffer containing the service pack source path
  1020. where we should look for service pack source files, or "CDM" if that value cannot be determined.
  1021. This value is retrieved from the following registry location:
  1022. \HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
  1023. ServicePackSourcePath : REG_SZ : "\\ntamd64\1300fre.wks" // for example.
  1024. Arguments:
  1025. None.
  1026. Return Value:
  1027. If the function succeeds, the return value is a pointer to the path string.
  1028. This memory must be freed via MyFree().
  1029. If the function fails due to out-of-memory, the return value is NULL.
  1030. --*/
  1031. {
  1032. HKEY hKey;
  1033. TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
  1034. DWORD Err, DataType, DataSize;
  1035. PTSTR Value;
  1036. PCTSTR ReturnStr = NULL;
  1037. TRACK_PUSH
  1038. CopyMemory(CharBuffer,
  1039. pszPathSetup,
  1040. sizeof(pszPathSetup) - sizeof(TCHAR)
  1041. );
  1042. CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
  1043. pszKeySetup,
  1044. sizeof(pszKeySetup)
  1045. );
  1046. if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1047. CharBuffer,
  1048. 0,
  1049. KEY_READ,
  1050. &hKey)) == ERROR_SUCCESS) {
  1051. //
  1052. // Attempt to read the the "ServicePackSourcePath" value.
  1053. //
  1054. Err = QueryRegistryValue(hKey, pszSvcPackPath, &Value, &DataType, &DataSize);
  1055. RegCloseKey(hKey);
  1056. }
  1057. if(Err == NO_ERROR) {
  1058. ReturnStr = Value;
  1059. }
  1060. if(!ReturnStr && Err != ERROR_NOT_ENOUGH_MEMORY) {
  1061. //
  1062. // We failed to retrieve the ServicePackSourcePath value, and it wasn't due to an out-of-memory
  1063. // condition. Fall back to the SourcePath value in the registry
  1064. //
  1065. ReturnStr = GetSystemSourcePath();
  1066. }
  1067. TRACK_POP
  1068. return ReturnStr;
  1069. }
  1070. PCTSTR
  1071. GetServicePackCachePath(
  1072. TRACK_ARG_DECLARE
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. This routine returns a newly-allocated buffer containing the service pack cache path
  1077. where we should look for files ahead of anything else
  1078. This value is retrieved from the following registry location:
  1079. \HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
  1080. ServicePackCachePath : REG_SZ : "c:\windows\foo" // for example.
  1081. Arguments:
  1082. None.
  1083. Return Value:
  1084. If the function succeeds, the return value is a pointer to the path string.
  1085. This memory must be freed via MyFree().
  1086. If the function fails due to out-of-memory, the return value is NULL.
  1087. --*/
  1088. {
  1089. HKEY hKey;
  1090. TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
  1091. DWORD Err, DataType, DataSize;
  1092. PTSTR Value;
  1093. PCTSTR ReturnStr = NULL;
  1094. TRACK_PUSH
  1095. CopyMemory(CharBuffer,
  1096. pszPathSetup,
  1097. sizeof(pszPathSetup) - sizeof(TCHAR)
  1098. );
  1099. CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
  1100. pszKeySetup,
  1101. sizeof(pszKeySetup)
  1102. );
  1103. if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1104. CharBuffer,
  1105. 0,
  1106. KEY_READ,
  1107. &hKey)) == ERROR_SUCCESS) {
  1108. //
  1109. // Attempt to read the the "ServicePackCachePath" value.
  1110. //
  1111. Err = QueryRegistryValue(hKey, pszSvcPackCachePath, &Value, &DataType, &DataSize);
  1112. RegCloseKey(hKey);
  1113. }
  1114. if(Err == NO_ERROR) {
  1115. ReturnStr = Value;
  1116. }
  1117. TRACK_POP
  1118. return ReturnStr;
  1119. }
  1120. #if MEM_DBG
  1121. #define GetServicePackSourcePath() GetServicePackSourcePath(TRACK_ARG_CALL)
  1122. #define GetServicePackCachePath() GetServicePackCachePath(TRACK_ARG_CALL)
  1123. #endif
  1124. PCTSTR
  1125. GetDriverCacheSourcePath(
  1126. VOID
  1127. )
  1128. /*++
  1129. Routine Description:
  1130. This routine returns a newly-allocated buffer containing the source path to the local driver cache
  1131. cab-file.
  1132. This value is retrieved from the following registry location:
  1133. \HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
  1134. DriverCachePath : REG_SZ : "\\ntamd64\1300fre.wks" // for example.
  1135. Arguments:
  1136. None.
  1137. Return Value:
  1138. If the function succeeds, the return value is a pointer to the path string.
  1139. This memory must be freed via MyFree().
  1140. If the function fails due to out-of-memory, the return value is NULL.
  1141. --*/
  1142. {
  1143. HKEY hKey;
  1144. TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
  1145. DWORD Err, DataType, DataSize;
  1146. PTSTR Value;
  1147. TCHAR Path[MAX_PATH];
  1148. CopyMemory(CharBuffer,
  1149. pszPathSetup,
  1150. sizeof(pszPathSetup) - sizeof(TCHAR)
  1151. );
  1152. CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
  1153. pszKeySetup,
  1154. sizeof(pszKeySetup)
  1155. );
  1156. if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1157. CharBuffer,
  1158. 0,
  1159. KEY_READ,
  1160. &hKey)) == ERROR_SUCCESS) {
  1161. //
  1162. // Attempt to read the the "DriverCachePath" value.
  1163. //
  1164. Err = QueryRegistryValue(hKey, pszDriverCachePath, &Value, &DataType, &DataSize);
  1165. RegCloseKey(hKey);
  1166. }
  1167. if(Err == NO_ERROR) {
  1168. if(Value) {
  1169. ExpandEnvironmentStrings(Value,Path,MAX_PATH);
  1170. MyFree(Value);
  1171. Value = NULL;
  1172. if (*Path) {
  1173. Value = DuplicateString( Path );
  1174. }
  1175. return (PCTSTR)Value;
  1176. }
  1177. } else if(Err == ERROR_NOT_ENOUGH_MEMORY) {
  1178. return NULL;
  1179. }
  1180. return NULL;
  1181. }
  1182. BOOL
  1183. pSetupSetSystemSourcePath(
  1184. IN PCTSTR NewSourcePath,
  1185. IN PCTSTR NewSvcPackSourcePath
  1186. )
  1187. /*++
  1188. Routine Description:
  1189. This routine is used to override the system source path used by setupapi (as
  1190. retrieved by GetSystemSourcePath during DLL initialization). This is used by
  1191. syssetup.dll to set the system source path appropriately during GUI-mode setup,
  1192. so that the device installer APIs will copy files from the correct source location.
  1193. We do the same thing for the service pack source path
  1194. NOTE: This routine IS NOT thread safe!
  1195. Arguments:
  1196. NewSourcePath - supplies the new source path to be used.
  1197. NewSvcPackSourcePath - supplies the new svcpack source path to be used.
  1198. Return Value:
  1199. If the function succeeds, the return value is TRUE.
  1200. If the function fails (due to out-of-memory), the return value is FALSE.
  1201. --*/
  1202. {
  1203. PCTSTR p,q;
  1204. p = (PCTSTR)DuplicateString(NewSourcePath);
  1205. q = (PCTSTR)DuplicateString(NewSvcPackSourcePath);
  1206. if(p) {
  1207. MyFree(SystemSourcePath);
  1208. SystemSourcePath = p;
  1209. }
  1210. if (q) {
  1211. MyFree(ServicePackSourcePath);
  1212. ServicePackSourcePath = q;
  1213. }
  1214. if (!p || !q) {
  1215. //
  1216. // failed due to out of memory!
  1217. //
  1218. return(FALSE);
  1219. }
  1220. return TRUE;
  1221. }
  1222. PCTSTR
  1223. pSetupGetOsLoaderPath(
  1224. VOID
  1225. )
  1226. /*++
  1227. Routine Description:
  1228. This routine returns a newly-allocated buffer containing the path to the OsLoader
  1229. (relative to the system partition drive). This value is retrieved from the
  1230. following registry location:
  1231. HKLM\System\Setup
  1232. OsLoaderPath : REG_SZ : <path> // e.g., "\os\winnt40"
  1233. Arguments:
  1234. None.
  1235. Return Value:
  1236. If the registry entry is found, the return value is a pointer to the string containing
  1237. the path. The caller must free this buffer via MyFree().
  1238. If the registry entry is not found, or memory cannot be allocated for the buffer, the
  1239. return value is NULL.
  1240. --*/
  1241. {
  1242. HKEY hKey;
  1243. PTSTR Value;
  1244. DWORD Err, DataType, DataSize;
  1245. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1246. TEXT("SYSTEM\\Setup"),
  1247. 0,
  1248. KEY_READ,
  1249. &hKey) == ERROR_SUCCESS) {
  1250. Err = QueryRegistryValue(hKey, TEXT("OsLoaderPath"), &Value, &DataType, &DataSize);
  1251. RegCloseKey(hKey);
  1252. return (Err == NO_ERROR) ? (PCTSTR)Value : NULL;
  1253. }
  1254. return NULL;
  1255. }
  1256. PCTSTR
  1257. pSetupGetSystemPartitionRoot(
  1258. VOID
  1259. )
  1260. /*++
  1261. Routine Description:
  1262. This routine returns a newly-allocated buffer containing the path to the OsLoader
  1263. (relative to the system partition drive). This value is retrieved from the
  1264. following registry location:
  1265. HKLM\System\Setup
  1266. SystemPartition : REG_SZ : <path> // e.g., "\Device\HarddiskVolume1"
  1267. Arguments:
  1268. None.
  1269. Return Value:
  1270. If the registry entry is found, the return value is a pointer to the string containing
  1271. the path. The caller must free this buffer via MyFree().
  1272. If the registry entry is not found, or memory cannot be allocated for the buffer, the
  1273. return value is NULL.
  1274. --*/
  1275. {
  1276. #ifdef UNICODE
  1277. HKEY hKey;
  1278. PTSTR Value;
  1279. DWORD Err, DataType, DataSize;
  1280. TCHAR Path[MAX_PATH];
  1281. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1282. TEXT("SYSTEM\\Setup"),
  1283. 0,
  1284. KEY_READ,
  1285. &hKey) == ERROR_SUCCESS) {
  1286. Err = QueryRegistryValue(hKey, TEXT("SystemPartition"), &Value, &DataType, &DataSize);
  1287. RegCloseKey(hKey);
  1288. if(Err == NO_ERROR) {
  1289. //
  1290. // prepend \\?\GLOBALROOT\
  1291. //
  1292. lstrcpy(Path,TEXT("\\\\?\\GLOBALROOT\\"));
  1293. if(pSetupConcatenatePaths(Path,Value,MAX_PATH,NULL)) {
  1294. MyFree(Value);
  1295. Value = DuplicateString(Path);
  1296. if(!Value) {
  1297. Err = ERROR_NOT_ENOUGH_MEMORY;
  1298. }
  1299. } else {
  1300. Err = GetLastError();
  1301. MyFree(Value);
  1302. }
  1303. }
  1304. return (Err == NO_ERROR) ? (PCTSTR)Value : NULL;
  1305. }
  1306. #endif
  1307. return NULL;
  1308. }
  1309. PCTSTR
  1310. pSetupGetProcessPath(
  1311. VOID
  1312. )
  1313. /*++
  1314. Routine Description:
  1315. Get the name of the EXE that we're running in.
  1316. Arguments:
  1317. NONE.
  1318. Return Value:
  1319. Pointer to a dynamically allocated string containing the name.
  1320. --*/
  1321. {
  1322. LPTSTR modname;
  1323. modname = MyMalloc(MAX_PATH * sizeof(TCHAR));
  1324. if(modname != NULL) {
  1325. if(GetModuleFileName(NULL, modname, MAX_PATH) > 0) {
  1326. LPTSTR modname2;
  1327. modname2 = MyRealloc(modname, (lstrlen(modname)+1)*sizeof(TCHAR));
  1328. if(modname2) {
  1329. modname = modname2;
  1330. }
  1331. return modname;
  1332. } else {
  1333. #ifdef PRERELEASE
  1334. OutputDebugStringA("GetModuleFileName returned 0\r\n");
  1335. DebugBreak();
  1336. #endif
  1337. MyFree(modname);
  1338. }
  1339. }
  1340. return NULL;
  1341. }
  1342. #ifdef UNICODE
  1343. BOOL
  1344. pGetGuiSetupInProgress(
  1345. VOID
  1346. )
  1347. /*++
  1348. Routine Description:
  1349. This routine determines if we're doing a gui-mode setup.
  1350. This value is retrieved from the following registry location:
  1351. \HKLM\System\Setup\
  1352. SystemSetupInProgress : REG_DWORD : 0x00 (where nonzero means we're doing a gui-setup)
  1353. Arguments:
  1354. None.
  1355. Return Value:
  1356. If the function succeeds, the return value is a pointer to the path string.
  1357. This memory must be freed via MyFree().
  1358. If the function fails due to out-of-memory, the return value is NULL.
  1359. --*/
  1360. {
  1361. HKEY hKey;
  1362. TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
  1363. DWORD Err, DataType, DataSize = sizeof(DWORD);
  1364. DWORD Value;
  1365. if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1366. TEXT("System\\Setup"),
  1367. 0,
  1368. KEY_READ,
  1369. &hKey)) == ERROR_SUCCESS) {
  1370. //
  1371. // Attempt to read the the "DriverCachePath" value.
  1372. //
  1373. Err = RegQueryValueEx(
  1374. hKey,
  1375. TEXT("SystemSetupInProgress"),
  1376. NULL,
  1377. &DataType,
  1378. (LPBYTE)&Value,
  1379. &DataSize);
  1380. RegCloseKey(hKey);
  1381. }
  1382. if(Err == NO_ERROR) {
  1383. if(Value) {
  1384. return(TRUE);
  1385. }
  1386. }
  1387. return(FALSE);
  1388. }
  1389. #else
  1390. BOOL
  1391. pGetGuiSetupInProgress(
  1392. VOID
  1393. )
  1394. {
  1395. return FALSE;
  1396. }
  1397. #endif
  1398. VOID pSetupSetGlobalFlags(
  1399. IN DWORD Value
  1400. )
  1401. /*++
  1402. exported as a private function
  1403. Routine Description:
  1404. Sets global flags to change certain setupapi features,
  1405. such as "should we call runonce after installing every device" (set if we will manually call it)
  1406. or "should we backup every file"
  1407. Used to initialize value
  1408. Arguments:
  1409. Value: combination of:
  1410. PSPGF_NO_RUNONCE - set to inhibit runonce calls (e.g., during GUI-
  1411. mode setup)
  1412. PSPGF_NO_BACKUP - set to inhibit automatic backup (e.g., during
  1413. GUI-mode setup)
  1414. PSPGF_NONINTERACTIVE - set to inhibit _all_ UI (e.g., for server-side
  1415. device installation)
  1416. PSPGF_SERVER_SIDE_RUNONCE - batch RunOnce entries for server-side
  1417. processing (for use only by umpnpmgr)
  1418. PSPGF_NO_VERIFY_INF - set to inhibit verification (digital signature) of
  1419. INF files until after the cyrpto DLLs have been registered.
  1420. PSPGF_UNATTENDED_SETUP - similar to NONINTERACTIVE - but specific to unattended setup
  1421. PSPGF_AUTOFAIL_VERIFIES - automatically fail all calls to crypto
  1422. Return Value:
  1423. none
  1424. --*/
  1425. {
  1426. pSetupModifyGlobalFlags((DWORD)(-1),Value);
  1427. }
  1428. VOID
  1429. pSetupModifyGlobalFlags(
  1430. IN DWORD Flags,
  1431. IN DWORD Value
  1432. )
  1433. /*++
  1434. exported as a private function
  1435. Routine Description:
  1436. Modifies global setup flags
  1437. such as "should we call runonce after installing every device" (set if we will manually call it)
  1438. or "should we backup every file"
  1439. only modifies specified flags to given value
  1440. Arguments:
  1441. Flags: what actual flags to modify, combination of:
  1442. PSPGF_NO_RUNONCE - set to inhibit runonce calls (e.g., during GUI-
  1443. mode setup)
  1444. PSPGF_NO_BACKUP - set to inhibit automatic backup (e.g., during
  1445. GUI-mode setup)
  1446. PSPGF_NONINTERACTIVE - set to inhibit _all_ UI (e.g., for server-side
  1447. device installation)
  1448. PSPGF_SERVER_SIDE_RUNONCE - batch RunOnce entries for server-side
  1449. processing (for use only by umpnpmgr)
  1450. PSPGF_NO_VERIFY_INF - set to inhibit verification (digital signature) of
  1451. INF files until after the cyrpto DLLs have been registered.
  1452. PSPGF_UNATTENDED_SETUP - similar to PSPGF_NONINTERACTIVE, but specific to setup
  1453. PSPGF_AUTOFAIL_VERIFIES - automatically fail all calls to crypto
  1454. Value: new value of bits specified in Flags
  1455. Return Value:
  1456. none
  1457. --*/
  1458. {
  1459. Flags &= ~GlobalSetupFlagsOverride; // exclusion
  1460. #ifdef UNICODE
  1461. if((Flags & PSPGF_NO_VERIFY_INF) && !(Value & PSPGF_NO_VERIFY_INF) && (GlobalSetupFlags & PSPGF_NO_VERIFY_INF)) {
  1462. Seed = GetSeed();
  1463. }
  1464. #endif
  1465. GlobalSetupFlags = (Value & Flags) | (GlobalSetupFlags & ~Flags);
  1466. }
  1467. DWORD pSetupGetGlobalFlags(
  1468. VOID
  1469. )
  1470. /*++
  1471. exported as a private function, also called internally
  1472. Routine Description:
  1473. Return flags previously set
  1474. Arguments:
  1475. none
  1476. Return value:
  1477. Flags (combination of values described above for pSetupSetGlobalFlags)
  1478. --*/
  1479. {
  1480. return GlobalSetupFlags;
  1481. }
  1482. BOOL
  1483. WINAPI
  1484. SetupSetNonInteractiveMode(
  1485. IN BOOL NonInteractiveFlag
  1486. )
  1487. /*++
  1488. Global access to the flag PSPGF_NONINTERACTIVE
  1489. Routine Description:
  1490. Set/Reset the NonInteractiveMode flag, and return previous flag value
  1491. (can't clear override)
  1492. Arguments:
  1493. New flag value
  1494. Return value:
  1495. Old flag value
  1496. --*/
  1497. {
  1498. BOOL f = (GlobalSetupFlags & PSPGF_NONINTERACTIVE) ? TRUE : FALSE;
  1499. if (NonInteractiveFlag) {
  1500. pSetupModifyGlobalFlags(PSPGF_NONINTERACTIVE,PSPGF_NONINTERACTIVE);
  1501. } else {
  1502. pSetupModifyGlobalFlags(PSPGF_NONINTERACTIVE,0);
  1503. }
  1504. return f;
  1505. }
  1506. BOOL
  1507. WINAPI
  1508. SetupGetNonInteractiveMode(
  1509. VOID
  1510. )
  1511. /*++
  1512. Global access to the flag PSPGF_NONINTERACTIVE
  1513. Routine Description:
  1514. Get current flag value
  1515. Arguments:
  1516. none
  1517. Return value:
  1518. Current flag value
  1519. --*/
  1520. {
  1521. return (GlobalSetupFlags & PSPGF_NONINTERACTIVE) ? TRUE : FALSE;
  1522. }
  1523. #ifndef _WIN64
  1524. BOOL
  1525. GetIsWow64 (
  1526. VOID
  1527. )
  1528. /*++
  1529. Routine Description:
  1530. Determine if we're running on WOW64 or not (not supported on ANSI builds)
  1531. Arguments:
  1532. none
  1533. Return value:
  1534. TRUE if running under WOW64 (and special Wow64 features available)
  1535. --*/
  1536. {
  1537. #ifdef UNICODE
  1538. ULONG_PTR ul = 0;
  1539. NTSTATUS st;
  1540. //
  1541. // If this call succeeds and sets ul non-zero
  1542. // it's a 32-bit process running on Win64
  1543. //
  1544. st = NtQueryInformationProcess(NtCurrentProcess(),
  1545. ProcessWow64Information,
  1546. &ul,
  1547. sizeof(ul),
  1548. NULL);
  1549. if (NT_SUCCESS(st) && (0 != ul)) {
  1550. // 32-bit code running on Win64
  1551. return TRUE;
  1552. }
  1553. #endif
  1554. return FALSE;
  1555. }
  1556. #endif // _WIN64
  1557. #if 0 // deleted code
  1558. //
  1559. // this will be useful at somepoint, but not used right now
  1560. //
  1561. BOOL
  1562. InitComponents(
  1563. DWORD Components
  1564. )
  1565. /*++
  1566. Routine Description:
  1567. Called at a point we want certain components initialized
  1568. Arguments:
  1569. bitmask of components to initialize
  1570. Return value:
  1571. TRUE if all initialized ok
  1572. --*/
  1573. {
  1574. BOOL success = FALSE;
  1575. PSETUP_TLS pPerThread = SetupGetTlsData();
  1576. BOOL locked = FALSE;
  1577. if(!pPerThread) {
  1578. MYASSERT(pPerThread);
  1579. return FALSE;
  1580. }
  1581. try {
  1582. EnterCriticalSection(&DelayedComponentMutex);
  1583. locked = TRUE;
  1584. Components &= ~ DoneComponentInitialize;
  1585. Components &= ~ pPerThread->PerThreadDoneComponent;
  1586. if (!Components) {
  1587. //
  1588. // already done
  1589. //
  1590. success = TRUE;
  1591. leave;
  1592. }
  1593. if (Components & FailedComponentInitialize) {
  1594. //
  1595. // previously failed
  1596. //
  1597. leave;
  1598. }
  1599. if (Components & pPerThread->PerThreadFailedComponent) {
  1600. //
  1601. // previously failed
  1602. //
  1603. leave;
  1604. }
  1605. MYASSERT(((DoneComponentInitialize | pPerThread->PerThreadDoneComponent) & Components) == Components);
  1606. MYASSERT(((FailedComponentInitialize | pPerThread->PerThreadFailedComponent) & Components) == 0);
  1607. success = TRUE;
  1608. } except (EXCEPTION_EXECUTE_HANDLER) {
  1609. MYASSERT(FALSE);
  1610. }
  1611. if(locked) {
  1612. LeaveCriticalSection(&DelayedComponentMutex);
  1613. }
  1614. return success;
  1615. }
  1616. VOID
  1617. ComponentCleanup(
  1618. DWORD Components
  1619. )
  1620. /*++
  1621. Routine Description:
  1622. Called to cleanup components
  1623. Arguments:
  1624. bitmask of components to uninitialize
  1625. Return value:
  1626. none
  1627. --*/
  1628. {
  1629. PSETUP_TLS pPerThread = SetupGetTlsData();
  1630. BOOL locked = FALSE;
  1631. try {
  1632. EnterCriticalSection(&DelayedComponentMutex);
  1633. locked = TRUE;
  1634. Components &= (DoneComponentInitialize | (pPerThread? pPerThread->PerThreadDoneComponent : 0));
  1635. if (!Components) {
  1636. //
  1637. // already done
  1638. //
  1639. leave;
  1640. }
  1641. } except (EXCEPTION_EXECUTE_HANDLER) {
  1642. MYASSERT(FALSE);
  1643. }
  1644. MYASSERT(((DoneComponentInitialize | (pPerThread ? pPerThread->PerThreadDoneComponent : 0)) & Components) == 0);
  1645. if(locked) {
  1646. LeaveCriticalSection(&DelayedComponentMutex);
  1647. }
  1648. }
  1649. #endif // deleted code
  1650. #ifdef UNICODE
  1651. BOOL
  1652. pSetupSetNoDriverPrompts(
  1653. BOOL Flag
  1654. )
  1655. /*++
  1656. exported as a private function
  1657. Routine Description:
  1658. Sets system into headless/non-headless mode
  1659. Arguments:
  1660. Flag - indicating mode
  1661. --*/
  1662. {
  1663. //
  1664. //
  1665. if(!GuiSetupInProgress) {
  1666. return FALSE;
  1667. }
  1668. if(GlobalNoDriverPromptsEventFlag == NULL) {
  1669. GlobalNoDriverPromptsEventFlag = CreateEvent(NULL,TRUE,Flag,SETUP_NODRIVERPROMPTS_MODE);
  1670. if(GlobalNoDriverPromptsEventFlag == NULL) {
  1671. return FALSE;
  1672. }
  1673. }
  1674. if(Flag) {
  1675. //
  1676. // force this process's setupapi to be non-interative, and any future setupapi's
  1677. //
  1678. GlobalSetupFlagsOverride |= PSPGF_UNATTENDED_SETUP; // don't allow this to be changed
  1679. GlobalSetupFlags |= PSPGF_UNATTENDED_SETUP; // actual value
  1680. SetEvent(GlobalNoDriverPromptsEventFlag);
  1681. } else {
  1682. //
  1683. // can't reset flag for this/existing processes, but can reset it for all future processes
  1684. //
  1685. ResetEvent(GlobalNoDriverPromptsEventFlag);
  1686. }
  1687. return TRUE;
  1688. }
  1689. #endif
  1690. BOOL
  1691. IsNoDriverPrompts(
  1692. VOID
  1693. )
  1694. /*++
  1695. internal
  1696. Routine Description:
  1697. Obtains headless state
  1698. Arguments:
  1699. Flag - indicating mode
  1700. --*/
  1701. {
  1702. #ifdef UNICODE
  1703. if(!GuiSetupInProgress) {
  1704. return FALSE;
  1705. }
  1706. if(GlobalNoDriverPromptsEventFlag == NULL) {
  1707. GlobalNoDriverPromptsEventFlag = OpenEvent(SYNCHRONIZE,FALSE,SETUP_NODRIVERPROMPTS_MODE);
  1708. if(GlobalNoDriverPromptsEventFlag == NULL) {
  1709. return FALSE;
  1710. }
  1711. }
  1712. //
  1713. // poll event, returning TRUE if it's signalled
  1714. //
  1715. return WaitForSingleObject(GlobalNoDriverPromptsEventFlag,0) == WAIT_OBJECT_0;
  1716. #else
  1717. return FALSE;
  1718. #endif
  1719. }
  1720. DWORD
  1721. GetEmbeddedFlags(
  1722. VOID
  1723. )
  1724. /*++
  1725. Routine Description:
  1726. This routine determines whether or not we are running on an embedded
  1727. product, and if so, whether:
  1728. * The "minimize setupapi footprint" option is enabled. This causes us to
  1729. modify our default behaviors as follows:
  1730. 1. Never call any crypto APIs, and just assume everything is signed
  1731. 2. Never generate PNFs.
  1732. * The "disable SCE" option is enabled. This causes us to avoid all use of
  1733. the Security Configuration Editor (SCE) routines (as the corresponding
  1734. DLLs won't be available on that embedded configuration).
  1735. Arguments:
  1736. none
  1737. Return value:
  1738. Combination of the following flags:
  1739. PSPGF_MINIMAL_EMBEDDED if we're running in "minimize footprint" mode
  1740. PSPGF_NO_SCE_EMBEDDED if we're running in "disable SCE" mode
  1741. --*/
  1742. {
  1743. OSVERSIONINFOEX osvix;
  1744. DWORDLONG dwlConditionMask = 0;
  1745. HKEY hKey;
  1746. TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
  1747. DWORD RegDataType, Data, DataSize;
  1748. DWORD Flags;
  1749. //
  1750. // Are we on the embedded product suite?
  1751. //
  1752. ZeroMemory(&osvix, sizeof(OSVERSIONINFOEX));
  1753. osvix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1754. osvix.wSuiteMask = VER_SUITE_EMBEDDEDNT;
  1755. VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
  1756. if(!VerifyVersionInfo(&osvix,
  1757. VER_SUITENAME,
  1758. dwlConditionMask)) {
  1759. return 0;
  1760. }
  1761. Flags = 0;
  1762. //
  1763. // OK, we running on embedded. Now we need to find out whether or not we
  1764. // should run in "minimal footprint" mode. This is stored in a REG_DWORD
  1765. // value entry called "MinimizeFootprint" under
  1766. // HKLM\Software\Microsoft\Windows\CurrentVersion\Setup.
  1767. //
  1768. CopyMemory(CharBuffer,
  1769. pszPathSetup,
  1770. sizeof(pszPathSetup) - sizeof(TCHAR)
  1771. );
  1772. CopyMemory((PBYTE)CharBuffer + (sizeof(pszPathSetup) - sizeof(TCHAR)),
  1773. pszKeySetup,
  1774. sizeof(pszKeySetup)
  1775. );
  1776. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1777. CharBuffer,
  1778. 0,
  1779. KEY_READ,
  1780. &hKey)) {
  1781. DataSize = sizeof(Data);
  1782. if((ERROR_SUCCESS == RegQueryValueEx(hKey,
  1783. pszMinimizeFootprint,
  1784. NULL,
  1785. &RegDataType,
  1786. (LPBYTE)&Data,
  1787. &DataSize))
  1788. && (RegDataType == REG_DWORD) && (DataSize == sizeof(Data))) {
  1789. Flags |= PSPGF_MINIMAL_EMBEDDED;
  1790. }
  1791. RegCloseKey(hKey);
  1792. }
  1793. //
  1794. // Now look under HKLM\Software\Microsoft\EmbeddedNT\Security for a
  1795. // DisableSCE REG_DWORD value entry, indicating we shouldn't call SCE.
  1796. //
  1797. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1798. pszEmbeddedNTSecurity,
  1799. 0,
  1800. KEY_READ,
  1801. &hKey)) {
  1802. DataSize = sizeof(Data);
  1803. if((ERROR_SUCCESS == RegQueryValueEx(hKey,
  1804. pszDisableSCE,
  1805. NULL,
  1806. &RegDataType,
  1807. (LPBYTE)&Data,
  1808. &DataSize))
  1809. && (RegDataType == REG_DWORD) && (DataSize == sizeof(Data))) {
  1810. Flags |= PSPGF_NO_SCE_EMBEDDED;
  1811. }
  1812. RegCloseKey(hKey);
  1813. }
  1814. return Flags;
  1815. }
  1816. #ifdef UNICODE
  1817. DWORD
  1818. GetSeed(
  1819. VOID
  1820. )
  1821. {
  1822. HKEY hKey;
  1823. DWORD val = 0;
  1824. DWORD valsize, valdatatype;
  1825. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  1826. return val;
  1827. }
  1828. if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1829. L"System\\WPA\\PnP",
  1830. 0,
  1831. KEY_READ,
  1832. &hKey)) {
  1833. valsize = sizeof(val);
  1834. if((ERROR_SUCCESS != RegQueryValueEx(hKey,
  1835. L"seed",
  1836. NULL,
  1837. &valdatatype,
  1838. (PBYTE)&val,
  1839. &valsize))
  1840. || (valdatatype != REG_DWORD) || (valsize != sizeof(val))) {
  1841. val = 0;
  1842. }
  1843. RegCloseKey(hKey);
  1844. }
  1845. return val;
  1846. }
  1847. #endif