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.

9264 lines
293 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. infinst.c
  5. Abstract:
  6. High-level INF install section processing API.
  7. Author:
  8. Ted Miller (tedm) 6-Mar-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Define invalid flags for SetupInstallServicesFromInfSection(Ex)
  15. //
  16. #define SPSVCINST_ILLEGAL_FLAGS (~( SPSVCINST_TAGTOFRONT \
  17. | SPSVCINST_ASSOCSERVICE \
  18. | SPSVCINST_DELETEEVENTLOGENTRY \
  19. | SPSVCINST_NOCLOBBER_DISPLAYNAME \
  20. | SPSVCINST_NOCLOBBER_STARTTYPE \
  21. | SPSVCINST_NOCLOBBER_ERRORCONTROL \
  22. | SPSVCINST_NOCLOBBER_LOADORDERGROUP \
  23. | SPSVCINST_NOCLOBBER_DEPENDENCIES \
  24. | SPSVCINST_STOPSERVICE ))
  25. //
  26. // Flags for UpdateInis in INFs
  27. //
  28. #define FLG_MATCH_KEY_AND_VALUE 1
  29. //
  30. // Flags for UpdateIniFields in INFs
  31. //
  32. #define FLG_INIFIELDS_WILDCARDS 1
  33. #define FLG_INIFIELDS_USE_SEP2 2
  34. #define TIME_SCALAR (1000)
  35. #define REGISTER_WAIT_TIMEOUT_DEFAULT (60)
  36. #define RUNONCE_TIMEOUT (2*60*1000)
  37. #define RUNONCE_THRESHOLD (20) // * RUNONCE_TIMEOUT
  38. #define DLLINSTALL "DllInstall"
  39. #define DLLREGISTER "DllRegisterServer"
  40. #define DLLUNREGISTER "DllUnregisterServer"
  41. #define EXEREGSVR TEXT("/RegServer")
  42. #define EXEUNREGSVR TEXT("/UnRegServer")
  43. typedef struct _INIFILESECTION {
  44. PTSTR IniFileName;
  45. PTSTR SectionName;
  46. PTSTR SectionData;
  47. int BufferSize;
  48. int BufferUsed;
  49. struct _INIFILESECTION *Next;
  50. } INIFILESECTION, *PINIFILESECTION;
  51. typedef struct _INISECTIONCACHE {
  52. //
  53. // Head of section list.
  54. //
  55. PINIFILESECTION Sections;
  56. } INISECTIONCACHE, *PINISECTIONCACHE;
  57. #ifdef CHILDREGISTRATION
  58. typedef struct _WOWSURRAGATE_IPC {
  59. GUID MemoryRegionName;
  60. HANDLE hFileMap;
  61. PVOID MemoryRegion;
  62. GUID SignalReadyToRegisterName;
  63. HANDLE SignalReadyToRegister;
  64. GUID SignalRegistrationCompleteName;
  65. HANDLE SignalRegistrationComplete;
  66. HANDLE hProcess;
  67. } WOWSURRAGATE_IPC, *PWOWSURRAGATE_IPC;
  68. #endif
  69. typedef struct _REF_STATUS {
  70. DWORD RefCount;
  71. DWORD ExtendedStatus;
  72. #if PRERELEASE
  73. unsigned ThreadId;
  74. #endif
  75. } REF_STATUS, *PREF_STATUS;
  76. typedef struct _OLE_CONTROL_DATA {
  77. LPTSTR FullPath;
  78. UINT RegType;
  79. PSETUP_LOG_CONTEXT LogContext;
  80. BOOL Register; // or unregister
  81. LPCTSTR Argument;
  82. PREF_STATUS Status;
  83. #ifdef CHILDREGISTRATION
  84. PWOWSURRAGATE_IPC WowIpcData;
  85. #endif
  86. } OLE_CONTROL_DATA, *POLE_CONTROL_DATA;
  87. CONST TCHAR pszUpdateInis[] = SZ_KEY_UPDATEINIS,
  88. pszUpdateIniFields[] = SZ_KEY_UPDATEINIFIELDS,
  89. pszIni2Reg[] = SZ_KEY_INI2REG,
  90. pszAddReg[] = SZ_KEY_ADDREG,
  91. pszDelReg[] = SZ_KEY_DELREG,
  92. pszBitReg[] = SZ_KEY_BITREG,
  93. pszRegSvr[] = SZ_KEY_REGSVR,
  94. pszUnRegSvr[] = SZ_KEY_UNREGSVR,
  95. pszProfileItems[] = SZ_KEY_PROFILEITEMS;
  96. //
  97. // Separator chars in an ini field
  98. //
  99. TCHAR pszIniFieldSeparators[] = TEXT(" ,\t");
  100. //
  101. // Mapping between registry key specs in an inf file
  102. // and predefined registry handles.
  103. //
  104. STRING_TO_DATA InfRegSpecTohKey[] = {
  105. TEXT("HKEY_LOCAL_MACHINE"), ((UINT_PTR)HKEY_LOCAL_MACHINE),
  106. TEXT("HKLM") , ((UINT_PTR)HKEY_LOCAL_MACHINE),
  107. TEXT("HKEY_CLASSES_ROOT") , ((UINT_PTR)HKEY_CLASSES_ROOT),
  108. TEXT("HKCR") , ((UINT_PTR)HKEY_CLASSES_ROOT),
  109. TEXT("HKR") , ((UINT_PTR)NULL),
  110. TEXT("HKEY_CURRENT_USER") , ((UINT_PTR)HKEY_CURRENT_USER),
  111. TEXT("HKCU") , ((UINT_PTR)HKEY_CURRENT_USER),
  112. TEXT("HKEY_USERS") , ((UINT_PTR)HKEY_USERS),
  113. TEXT("HKU") , ((UINT_PTR)HKEY_USERS),
  114. NULL , ((UINT_PTR)NULL)
  115. };
  116. //
  117. // Mapping between registry value names and CM device registry property (CM_DRP) codes
  118. //
  119. // These values must be in the exact ordering of the SPDRP codes, as defined in setupapi.h.
  120. // This allows us to easily map between SPDRP and CM_DRP property codes.
  121. //
  122. STRING_TO_DATA InfRegValToDevRegProp[] = { pszDeviceDesc, CM_DRP_DEVICEDESC,
  123. pszHardwareID, CM_DRP_HARDWAREID,
  124. pszCompatibleIDs, CM_DRP_COMPATIBLEIDS,
  125. TEXT(""), CM_DRP_UNUSED0,
  126. pszService, CM_DRP_SERVICE,
  127. TEXT(""), CM_DRP_UNUSED1,
  128. TEXT(""), CM_DRP_UNUSED2,
  129. pszClass, CM_DRP_CLASS,
  130. pszClassGuid, CM_DRP_CLASSGUID,
  131. pszDriver, CM_DRP_DRIVER,
  132. pszConfigFlags, CM_DRP_CONFIGFLAGS,
  133. pszMfg, CM_DRP_MFG,
  134. pszFriendlyName, CM_DRP_FRIENDLYNAME,
  135. pszLocationInformation, CM_DRP_LOCATION_INFORMATION,
  136. TEXT(""), CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME,
  137. pszCapabilities, CM_DRP_CAPABILITIES,
  138. pszUiNumber, CM_DRP_UI_NUMBER,
  139. pszUpperFilters, CM_DRP_UPPERFILTERS,
  140. pszLowerFilters, CM_DRP_LOWERFILTERS,
  141. TEXT(""), CM_DRP_BUSTYPEGUID,
  142. TEXT(""), CM_DRP_LEGACYBUSTYPE,
  143. TEXT(""), CM_DRP_BUSNUMBER,
  144. TEXT(""), CM_DRP_ENUMERATOR_NAME,
  145. TEXT(""), CM_DRP_SECURITY,
  146. pszDevSecurity, CM_DRP_SECURITY_SDS,
  147. pszDevType, CM_DRP_DEVTYPE,
  148. pszExclusive, CM_DRP_EXCLUSIVE,
  149. pszCharacteristics, CM_DRP_CHARACTERISTICS,
  150. TEXT(""), CM_DRP_ADDRESS,
  151. pszUiNumberDescFormat, CM_DRP_UI_NUMBER_DESC_FORMAT,
  152. TEXT(""), CM_DRP_DEVICE_POWER_DATA,
  153. TEXT(""), CM_DRP_REMOVAL_POLICY,
  154. TEXT(""), CM_DRP_REMOVAL_POLICY_HW_DEFAULT,
  155. pszRemovalPolicyOverride, CM_DRP_REMOVAL_POLICY_OVERRIDE,
  156. TEXT(""), CM_DRP_INSTALL_STATE,
  157. NULL, 0
  158. };
  159. //
  160. // Mapping between registry value names and CM class registry property (CM_CRP) codes
  161. //
  162. // These values must be in the exact ordering of the SPCRP codes, as defined in setupapi.h.
  163. // This allows us to easily map between SPCRP and CM_CRP property codes.
  164. //
  165. STRING_TO_DATA InfRegValToClassRegProp[] = { TEXT(""), 0,
  166. TEXT(""), 0,
  167. TEXT(""), 0,
  168. TEXT(""), 0,
  169. TEXT(""), 0,
  170. TEXT(""), 0,
  171. TEXT(""), 0,
  172. TEXT(""), 0,
  173. TEXT(""), 0,
  174. TEXT(""), 0,
  175. TEXT(""), 0,
  176. TEXT(""), 0,
  177. TEXT(""), 0,
  178. TEXT(""), 0,
  179. TEXT(""), 0,
  180. TEXT(""), 0,
  181. TEXT(""), 0,
  182. TEXT(""), 0,
  183. TEXT(""), 0,
  184. TEXT(""), 0,
  185. TEXT(""), 0,
  186. TEXT(""), 0,
  187. TEXT(""), 0,
  188. TEXT(""), CM_CRP_SECURITY,
  189. pszDevSecurity, CM_CRP_SECURITY_SDS,
  190. pszDevType, CM_CRP_DEVTYPE,
  191. pszExclusive, CM_CRP_EXCLUSIVE,
  192. pszCharacteristics, CM_CRP_CHARACTERISTICS,
  193. TEXT(""), 0,
  194. NULL, 0
  195. };
  196. //
  197. // Linked list of RunOnce entries encountered during INF processing while
  198. // running in unattended mode. The contents of this list are accessed by the
  199. // caller via pSetupAccessRunOnceNodeList, and freed via
  200. // pSetupDestroyRunOnceNodeList.
  201. //
  202. // ** NOTE -- THIS LIST IS NOT THREAD SAFE, AND IS FOR USE SOLELY BY THE **
  203. // ** SINGLE THREAD IN UMPNPMGR THAT DOES DEVICE INSTALLATIONS. **
  204. //
  205. PPSP_RUNONCE_NODE RunOnceListHead = NULL;
  206. HKEY
  207. pSetupInfRegSpecToKeyHandle(
  208. IN PCTSTR InfRegSpec,
  209. IN HKEY UserRootKey,
  210. IN PBOOL NeedToCloseKey
  211. );
  212. DWORD
  213. pSetupValidateDevRegProp(
  214. IN ULONG CmPropertyCode,
  215. IN DWORD ValueType,
  216. IN PCVOID Data,
  217. IN DWORD DataSize,
  218. OUT PVOID *ConvertedBuffer,
  219. OUT PDWORD ConvertedBufferSize
  220. );
  221. DWORD
  222. pSetupValidateClassRegProp(
  223. IN ULONG CmPropertyCode,
  224. IN DWORD ValueType,
  225. IN PCVOID Data,
  226. IN DWORD DataSize,
  227. OUT PVOID *ConvertedBuffer,
  228. OUT PDWORD ConvertedBufferSize
  229. );
  230. //
  231. // Internal ini file routines.
  232. //
  233. PINIFILESECTION
  234. pSetupLoadIniFileSection(
  235. IN PCTSTR FileName,
  236. IN PCTSTR SectionName,
  237. IN OUT PINISECTIONCACHE SectionList
  238. );
  239. DWORD
  240. pSetupUnloadIniFileSections(
  241. IN PINISECTIONCACHE SectionList,
  242. IN BOOL WriteToFile
  243. );
  244. PTSTR
  245. pSetupFindLineInSection(
  246. IN PINIFILESECTION Section,
  247. IN PCTSTR KeyName, OPTIONAL
  248. IN PCTSTR RightHandSide OPTIONAL
  249. );
  250. BOOL
  251. pSetupReplaceOrAddLineInSection(
  252. IN PINIFILESECTION Section,
  253. IN PCTSTR KeyName, OPTIONAL
  254. IN PCTSTR RightHandSide, OPTIONAL
  255. IN BOOL MatchRHS
  256. );
  257. BOOL
  258. pSetupAppendLineToSection(
  259. IN PINIFILESECTION Section,
  260. IN PCTSTR KeyName, OPTIONAL
  261. IN PCTSTR RightHandSide OPTIONAL
  262. );
  263. BOOL
  264. pSetupDeleteLineFromSection(
  265. IN PINIFILESECTION Section,
  266. IN PCTSTR KeyName, OPTIONAL
  267. IN PCTSTR RightHandSide OPTIONAL
  268. );
  269. DWORD
  270. pSetupSetSecurityForAddRegSection(
  271. IN HINF Inf,
  272. IN PCTSTR Section,
  273. IN PVOID Context
  274. );
  275. DWORD
  276. LoadNtOnlyDll(
  277. IN PCTSTR DllName,
  278. OUT HINSTANCE *Dll_Handle
  279. );
  280. VOID
  281. pSetupFreeOleControlData(
  282. IN POLE_CONTROL_DATA OleControlData);
  283. DWORD
  284. pSetupEnumInstallationSections(
  285. IN PVOID Inf,
  286. IN PCTSTR Section,
  287. IN PCTSTR Key,
  288. IN ULONG_PTR (*EnumCallbackFunc)(PVOID,PINFCONTEXT,PVOID),
  289. IN PVOID Context
  290. )
  291. /*++
  292. Routine Description:
  293. Iterate all values on a line in a given section with a given key,
  294. treating each as the name of a section, and then pass each of the lines
  295. in the referenced sections to a callback function.
  296. Arguments:
  297. Inf - supplies a handle to an open inf file.
  298. Section - supplies the name of the section in which the line whose
  299. values are to be iterated resides.
  300. Key - supplies the key of the line whose values are to be iterated.
  301. EnumCallbackFunc - supplies a pointer to the callback function.
  302. Each line in each referenced section is passed to this function.
  303. Context - supplies a context value to be passes through to the
  304. callback function.
  305. Return Value:
  306. Win32 error code indicating outcome.
  307. --*/
  308. {
  309. BOOL b;
  310. INFCONTEXT LineContext;
  311. DWORD FieldCount;
  312. DWORD Field;
  313. DWORD d;
  314. PCTSTR SectionName;
  315. INFCONTEXT FirstLineContext;
  316. //
  317. // Find the relevent line in the given install section.
  318. // If not present then we're done -- report success.
  319. //
  320. b = SetupFindFirstLine(Inf,Section,Key,&LineContext);
  321. if(!b) {
  322. d = GetLastError();
  323. if ((d != NO_ERROR) && (d != ERROR_SECTION_NOT_FOUND) && (d != ERROR_LINE_NOT_FOUND)) {
  324. pSetupLogSectionError(Inf,NULL,NULL,NULL,Section,MSG_LOG_INSTALLSECT_ERROR,d,NULL);
  325. }
  326. return NO_ERROR; // for compatibility with older SetupAPI
  327. }
  328. do {
  329. //
  330. // Each value on the line in the given install section
  331. // is the name of another section.
  332. //
  333. FieldCount = SetupGetFieldCount(&LineContext);
  334. for(Field=1; Field<=FieldCount; Field++) {
  335. if((SectionName = pSetupGetField(&LineContext,Field))
  336. && SetupFindFirstLine(Inf,SectionName,NULL,&FirstLineContext)) {
  337. //
  338. // Call the callback routine for every line in the section.
  339. //
  340. do {
  341. d = (DWORD)EnumCallbackFunc(Inf,&FirstLineContext,Context);
  342. if(d != NO_ERROR) {
  343. pSetupLogSectionError(Inf,NULL,NULL,NULL,SectionName,MSG_LOG_SECT_ERROR,d,Key);
  344. return(d);
  345. }
  346. } while(SetupFindNextLine(&FirstLineContext,&FirstLineContext));
  347. }
  348. }
  349. } while(SetupFindNextMatchLine(&LineContext,Key,&LineContext));
  350. SetLastError(NO_ERROR);
  351. return(NO_ERROR);
  352. }
  353. #ifdef UNICODE
  354. DWORD
  355. pSetupSetSecurityForAddRegSection(
  356. IN HINF Inf,
  357. IN PCTSTR Section,
  358. IN PVOID Context
  359. )
  360. /*
  361. This function takes an Addreg section and processes its corresponding .Security section
  362. if it exists
  363. Arguments:
  364. Inf - supplies an INF handle so we can get a LogContext.
  365. Section - Name of the section to process
  366. Context - supplies the address of a registry modification context
  367. structure used in adding the registry value. The structure is
  368. defined as:
  369. typedef struct _REGMOD_CONTEXT {
  370. DWORD Flags; // indicates what fields are filled in
  371. HKEY UserRootKey; // HKR
  372. PGUID ClassGuid; // INF_PFLAG_CLASSPROP
  373. HMACHINE hMachine; // INF_PFLAG_CLASSPROP
  374. DWORD DevInst; // INF_PFLAG_DEVPROP
  375. } REGMOD_CONTEXT, *PREGMOD_CONTEXT;
  376. where UserRootKey is a handle to the open inf key to be used as
  377. the root when HKR is specified as the root for the operation, and
  378. DevInst is the optional device instance handle that is supplied when
  379. the AddReg section is for a hardware key (i.e., under the Enum branch).
  380. If this handle is supplied, then the value is checked to see whether it
  381. is the name of a Plug&Play device registry property, and if so, the
  382. registry property is set via a CM API instead of via the registry API
  383. (which doesn't refer to the same location on Windows NT).
  384. Flags indicates if DevInst should be used, or if ClassGuid/hMachine pair should be used
  385. Return Value:
  386. Win32 error code indicating outcome.
  387. */
  388. {
  389. BOOL b;
  390. DWORD ret, LoadStatus;
  391. DWORD error = NO_ERROR;
  392. INFCONTEXT LineContext;
  393. DWORD FieldCount;
  394. DWORD Field;
  395. PCTSTR SectionName;
  396. INFCONTEXT FirstLineContext;
  397. PREGMOD_CONTEXT RegModContext;
  398. PCTSTR RootKeySpec;
  399. FARPROC SceRegUpdate;
  400. HKEY RootKey;
  401. HINSTANCE Sce_Dll;
  402. DWORD slot_regop = 0;
  403. BOOL CloseKey = FALSE;
  404. PCTSTR SubKeyName, SecDesc;
  405. SecDesc = NULL;
  406. //
  407. // If we're in "Disable SCE" mode on embedded, then don't process security
  408. // stuff.
  409. //
  410. if(GlobalSetupFlags & PSPGF_NO_SCE_EMBEDDED) {
  411. return NO_ERROR;
  412. }
  413. //
  414. // Find the relevent line in the given install section.
  415. // If not present then we're done -- report success.
  416. //
  417. b = SetupFindFirstLine(Inf,Section,pszAddReg,&LineContext);
  418. if(!b) {
  419. return( NO_ERROR );
  420. }
  421. slot_regop = AllocLogInfoSlot(((PLOADED_INF) Inf)->LogContext,FALSE);
  422. do {
  423. //
  424. // Each value on the line in the given install section
  425. // is the name of another section.
  426. //
  427. FieldCount = SetupGetFieldCount(&LineContext);
  428. for(Field=1; Field<=FieldCount; Field++) {
  429. if( (SectionName = pSetupGetField(&LineContext,Field)) &&
  430. (SetupFindFirstLine(Inf,SectionName,NULL,&FirstLineContext)) ){
  431. //
  432. //If security section not present then don't bother and goto next section
  433. //
  434. if( !pSetupGetSecurityInfo( Inf, SectionName, &SecDesc )) {
  435. continue;
  436. }
  437. //
  438. // Call the callback routine for every line in the section.
  439. //
  440. do {
  441. RegModContext = (PREGMOD_CONTEXT)Context;
  442. if(RootKeySpec = pSetupGetField(&FirstLineContext,1)) {
  443. CloseKey = FALSE;
  444. RootKey = pSetupInfRegSpecToKeyHandle(RootKeySpec, RegModContext->UserRootKey,&CloseKey);
  445. if(!RootKey) {
  446. if (slot_regop) {
  447. ReleaseLogInfoSlot(((PLOADED_INF) Inf)->LogContext,slot_regop);
  448. }
  449. return( ERROR_BADKEY );
  450. }
  451. SubKeyName = pSetupGetField(&FirstLineContext,2);
  452. //
  453. // log the fact that we're setting the security...
  454. //
  455. WriteLogEntry(
  456. ((PLOADED_INF) Inf)->LogContext,
  457. slot_regop,
  458. MSG_LOG_SETTING_SECURITY_ON_SUBKEY,
  459. NULL,
  460. RootKeySpec,
  461. (SubKeyName ? TEXT("\\") : TEXT("")),
  462. (SubKeyName ? SubKeyName : TEXT("")),
  463. SecDesc);
  464. error = ERROR_INVALID_DATA;
  465. try {
  466. error = (DWORD)SceSetupUpdateSecurityKey( RootKey, (PWSTR)SubKeyName, 0, (PWSTR)SecDesc);
  467. } except(EXCEPTION_EXECUTE_HANDLER) {
  468. error = ERROR_INVALID_DATA;
  469. }
  470. if(error) {
  471. WriteLogError(
  472. ((PLOADED_INF) Inf)->LogContext,
  473. SETUP_LOG_ERROR,
  474. error);
  475. if (CloseKey) {
  476. RegCloseKey( RootKey );
  477. }
  478. return( error );
  479. }
  480. } else {
  481. if (slot_regop) {
  482. ReleaseLogInfoSlot(((PLOADED_INF) Inf)->LogContext,slot_regop);
  483. }
  484. return( ERROR_INVALID_DATA );
  485. }
  486. if (CloseKey) {
  487. RegCloseKey( RootKey );
  488. }
  489. } while(SetupFindNextLine(&FirstLineContext,&FirstLineContext));
  490. }
  491. }
  492. }while(SetupFindNextMatchLine(&LineContext,pszAddReg,&LineContext));
  493. if (slot_regop) {
  494. ReleaseLogInfoSlot(((PLOADED_INF) Inf)->LogContext,slot_regop);
  495. }
  496. return( NO_ERROR );
  497. }
  498. #endif // UNICODE
  499. DWORD_PTR
  500. pSetupProcessUpdateInisLine(
  501. IN PVOID Inf,
  502. IN PINFCONTEXT InfLineContext,
  503. IN PVOID Context
  504. )
  505. /*++
  506. Routine Description:
  507. Process a line containing update-inis directives.
  508. The line is expected to be in the following format:
  509. <filename>,<section>,<old-entry>,<new-entry>,<flags>
  510. <filename> supplies the filename of the ini file.
  511. <section> supplies the section in the ini file.
  512. <old-entry> is optional and if specified supplies an entry to
  513. be removed from the section, in the form "key=val".
  514. <new-entry> is optional and if specified supplies an entry to
  515. be added to the section, in the form "key=val".
  516. <flags> are optional flags
  517. FLG_MATCH_KEY_AND_VALUE (1)
  518. Arguments:
  519. Inf - supplies an INF handle so we can get a LogContext.
  520. InfLineContext - supplies context for current line in the section.
  521. Context - Supplies pointer to structure describing loaded ini file sections.
  522. Return Value:
  523. Win32 error code indicating outcome.
  524. --*/
  525. {
  526. PCTSTR File;
  527. PCTSTR Section;
  528. PCTSTR OldLine;
  529. PCTSTR NewLine;
  530. BOOL b;
  531. DWORD d;
  532. PTCHAR Key,Value;
  533. PTCHAR p;
  534. UINT Flags;
  535. PINIFILESECTION SectData;
  536. PTSTR LineData;
  537. PINISECTIONCACHE IniSectionCache;
  538. IniSectionCache = Context;
  539. //
  540. // Get fields from the line.
  541. //
  542. File = pSetupGetField(InfLineContext,1);
  543. Section = pSetupGetField(InfLineContext,2);
  544. OldLine = pSetupGetField(InfLineContext,3);
  545. if(OldLine && (*OldLine == 0)) {
  546. OldLine = NULL;
  547. }
  548. NewLine = pSetupGetField(InfLineContext,4);
  549. if(NewLine && (*NewLine == 0)) {
  550. NewLine = NULL;
  551. }
  552. if(!SetupGetIntField(InfLineContext,5,&Flags)) {
  553. Flags = 0;
  554. }
  555. //
  556. // File and section must be specified.
  557. //
  558. if(!File || !Section) {
  559. return(ERROR_INVALID_DATA);
  560. }
  561. //
  562. // If oldline and newline are both not specified, we're done.
  563. //
  564. if(!OldLine && !NewLine) {
  565. return(NO_ERROR);
  566. }
  567. //
  568. // Open the file and section.
  569. //
  570. SectData = pSetupLoadIniFileSection(File,Section,IniSectionCache);
  571. if(!SectData) {
  572. return(ERROR_NOT_ENOUGH_MEMORY);
  573. }
  574. //
  575. // If there's an old entry specified, delete it.
  576. //
  577. if(OldLine) {
  578. Key = DuplicateString(OldLine);
  579. if(!Key) {
  580. return(ERROR_NOT_ENOUGH_MEMORY);
  581. }
  582. p = Key;
  583. if(Value = _tcschr(Key,TEXT('='))) {
  584. //
  585. // Delete by key.
  586. //
  587. *Value = 0;
  588. Value = NULL;
  589. } else {
  590. //
  591. // Delete by value.
  592. //
  593. Value = Key;
  594. Key = NULL;
  595. }
  596. pSetupDeleteLineFromSection(SectData,Key,Value);
  597. MyFree(p);
  598. }
  599. //
  600. // If there's a new entry specified, add it.
  601. //
  602. if(NewLine) {
  603. Key = DuplicateString(NewLine);
  604. if(!Key) {
  605. return(ERROR_NOT_ENOUGH_MEMORY);
  606. }
  607. p = Key;
  608. if(Value = _tcschr(Key,TEXT('='))) {
  609. //
  610. // There is a key. Depending on flags, we want to match
  611. // key only or key and value.
  612. //
  613. *Value++ = 0;
  614. b = ((Flags & FLG_MATCH_KEY_AND_VALUE) != 0);
  615. } else {
  616. //
  617. // No key. match whole line. This is the same as matching
  618. // the RHS only, since no line with a key can match.
  619. //
  620. Value = Key;
  621. Key = NULL;
  622. b = TRUE;
  623. }
  624. if(!pSetupReplaceOrAddLineInSection(SectData,Key,Value,b)) {
  625. d = ERROR_NOT_ENOUGH_MEMORY;
  626. }
  627. MyFree(p);
  628. }
  629. return(NO_ERROR);
  630. }
  631. BOOL
  632. pSetupFieldPresentInIniFileLine(
  633. IN PTCHAR Line,
  634. IN PCTSTR Field,
  635. OUT PTCHAR *Start,
  636. OUT PTCHAR *End
  637. )
  638. {
  639. TCHAR c;
  640. PTCHAR p,q;
  641. BOOL b;
  642. //
  643. // Skip the key if there is one (there should be one since we use
  644. // GetPrivateProfileString to query the value!)
  645. //
  646. if(p = _tcschr(Line,TEXT('='))) {
  647. Line = p+1;
  648. }
  649. //
  650. // Skip ini field separators.
  651. //
  652. Line += _tcsspn(Line,pszIniFieldSeparators);
  653. while(*Line) {
  654. //
  655. // Locate the end of the field.
  656. //
  657. p = Line;
  658. while(*p && !_tcschr(pszIniFieldSeparators,*p)) {
  659. if(*p == TEXT('\"')) {
  660. //
  661. // Find terminating quote. If none, ignore the quote.
  662. //
  663. if(q = _tcschr(p,TEXT('\"'))) {
  664. p = q;
  665. }
  666. }
  667. p++;
  668. }
  669. //
  670. // p now points to first char past end of field.
  671. // Make sure the field is 0-terminated and see if we have
  672. // what we're looking for.
  673. c = *p;
  674. *p = 0;
  675. b = (lstrcmpi(Line,Field) == 0);
  676. *p = c;
  677. //
  678. // Skip separators so p points to first char in next field,
  679. // or to the terminating 0.
  680. //
  681. p += _tcsspn(p,pszIniFieldSeparators);
  682. if(b) {
  683. *Start = Line;
  684. *End = p;
  685. return(TRUE);
  686. }
  687. Line = p;
  688. }
  689. return(FALSE);
  690. }
  691. DWORD_PTR
  692. pSetupProcessUpdateIniFieldsLine(
  693. IN PVOID Inf,
  694. IN PINFCONTEXT InfLineContext,
  695. IN PVOID Context
  696. )
  697. /*++
  698. Routine Description:
  699. Process a line containing update-ini-fields directives. Such directives
  700. allow individual values in ini files to be removed, added, or replaced.
  701. The line is expected to be in the following format:
  702. <filename>,<section>,<key>,<old-field>,<new-field>,<flags>
  703. <filename> supplies the filename of the ini file.
  704. <section> supplies the section in the ini file.
  705. <key> supplies the keyname of the line in the section in the ini file.
  706. <old-field> supplies the field to be deleted, if specified.
  707. <new-field> supplies the field to be added to the line, if specified.
  708. <flags> are optional flags
  709. Arguments:
  710. InfLineContext - supplies context for current line in the section.
  711. Context - Supplies pointer to structure describing loaded ini file sections.
  712. Return Value:
  713. Win32 error code indicating outcome.
  714. --*/
  715. {
  716. PCTSTR File;
  717. PCTSTR Section;
  718. PCTSTR Key;
  719. TCHAR Value[512];
  720. #define BUF_SIZE (sizeof(Value)/sizeof(TCHAR))
  721. TCHAR CONST *Old,*New;
  722. PTCHAR Start,End;
  723. BOOL b;
  724. DWORD d;
  725. DWORD Space;
  726. PCTSTR Separator;
  727. UINT Flags;
  728. PINISECTIONCACHE IniSectionCache;
  729. PINIFILESECTION SectData;
  730. PTSTR Line;
  731. IniSectionCache = Context;
  732. //
  733. // Get fields.
  734. //
  735. File = pSetupGetField(InfLineContext,1);
  736. Section = pSetupGetField(InfLineContext,2);
  737. Key = pSetupGetField(InfLineContext,3);
  738. Old = pSetupGetField(InfLineContext,4);
  739. if(Old && (*Old == 0)) {
  740. Old = NULL;
  741. }
  742. New = pSetupGetField(InfLineContext,5);
  743. if(New && (*New == 0)) {
  744. New = NULL;
  745. }
  746. if(!SetupGetIntField(InfLineContext,6,&Flags)) {
  747. Flags = 0;
  748. }
  749. //
  750. // Filename, section name, and key name are mandatory.
  751. //
  752. if(!File || !Section || !Key) {
  753. return(ERROR_INVALID_DATA);
  754. }
  755. //
  756. // If oldline and newline are both not specified, we're done.
  757. //
  758. if(!Old && !New) {
  759. return(NO_ERROR);
  760. }
  761. //
  762. // Open the file and section.
  763. //
  764. SectData = pSetupLoadIniFileSection(File,Section,IniSectionCache);
  765. if(!SectData) {
  766. return(ERROR_NOT_ENOUGH_MEMORY);
  767. }
  768. Separator = (Flags & FLG_INIFIELDS_USE_SEP2) ? TEXT(", ") : TEXT(" ");
  769. if(Line = pSetupFindLineInSection(SectData,Key,NULL)) {
  770. lstrcpyn(Value, Line, BUF_SIZE);
  771. } else {
  772. *Value = TEXT('\0');
  773. }
  774. //
  775. // Look for the old field if specified and remove it.
  776. //
  777. if(Old) {
  778. if(pSetupFieldPresentInIniFileLine(Value,Old,&Start,&End)) {
  779. MoveMemory(Start,End,(lstrlen(End)+1)*sizeof(TCHAR));
  780. }
  781. }
  782. //
  783. // If a replacement/new field is specified, put it in there.
  784. //
  785. if(New) {
  786. //
  787. // Calculate the number of chars that can fit in the buffer.
  788. //
  789. Space = BUF_SIZE - (lstrlen(Value) + 1);
  790. //
  791. // If there's space, stick the new field at the end of the line.
  792. //
  793. if(Space >= (DWORD)lstrlen(Separator)) {
  794. lstrcat(Value,Separator);
  795. Space -= lstrlen(Separator);
  796. }
  797. if(Space >= (DWORD)lstrlen(New)) {
  798. lstrcat(Value,New);
  799. }
  800. }
  801. //
  802. // Write the line back out.
  803. //
  804. b = pSetupReplaceOrAddLineInSection(SectData,Key,Value,FALSE);
  805. d = b ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY;
  806. return(d);
  807. #undef BUF_SIZE
  808. }
  809. DWORD_PTR
  810. pSetupProcessDelRegLine(
  811. IN PVOID Inf,
  812. IN PINFCONTEXT InfLineContext,
  813. IN PVOID Context
  814. )
  815. /*++
  816. Routine Description:
  817. Process a line in the registry that contains delete-registry instructions.
  818. The line is expected to be in the following forms:
  819. <root-spec>,<subkey> - delete whole key
  820. <root-spec>,[<subkey>],[<value-name>][,[<flags>][,<string>]] - delete value
  821. <Root-spec> is one of HKR, HKLM, etc.
  822. <subkey> specifies the subkey relative to Root-spec.
  823. <value-name> is optional. If present if specifies a value entry to be deleted
  824. from the key. If not present the entire key is deleted. This routine
  825. cannot handle deleting subtrees; the key to be deleted must not have any
  826. subkeys or the routine will fail.
  827. <flags> indicate any special symantics on how to delete this value, and how to interpret the string
  828. <string> is optional. If flags = FLG_DELREG_MULTI_SZ_DELSTRING, all instances of this string will be removed
  829. Arguments:
  830. Inf - supplies an INF handle so we can get a LogContext.
  831. InfLineContext - supplies inf line context for the line containing
  832. delete-registry instructions.
  833. Context - supplies the address of a registry modification context
  834. structure used in deleting the registry value. The structure is
  835. defined as:
  836. typedef struct _REGMOD_CONTEXT {
  837. DWORD Flags; // indicates what fields are filled in
  838. HKEY UserRootKey; // HKR
  839. PGUID ClassGuid; // INF_PFLAG_CLASSPROP
  840. HMACHINE hMachine; // INF_PFLAG_CLASSPROP
  841. DWORD DevInst; // INF_PFLAG_DEVPROP
  842. } REGMOD_CONTEXT, *PREGMOD_CONTEXT;
  843. where UserRootKey is a handle to the open inf key to be used as
  844. the root when HKR is specified as the root for the operation, and
  845. DevInst is the optional device instance handle that is supplied when
  846. the DelReg section is for a hardware key (i.e., under the Enum branch).
  847. If this handle is supplied, then the value is checked to see whether it
  848. is the name of a Plug&Play device registry property, and if so, the
  849. registry property is deleted via a CM API _as well as_ via a registry API
  850. (the property is stored in a different location inaccessible to the registry
  851. APIs under Windows NT).
  852. Return Value:
  853. Win32 error code indicating outcome.
  854. --*/
  855. {
  856. PCTSTR RootKeySpec,SubKeyName,ValueName,Data;
  857. HKEY RootKey,Key;
  858. DWORD d,rc;
  859. PREGMOD_CONTEXT RegModContext = (PREGMOD_CONTEXT)Context;
  860. UINT_PTR CmPropertyCode;
  861. DWORD slot_regop = 0;
  862. BOOL CloseKey;
  863. UINT DelFlags = 0;
  864. BOOL NonFatal = FALSE;
  865. CONFIGRET cr;
  866. //
  867. // We shouldn't be doing this against a remote machine.
  868. //
  869. MYASSERT(!(RegModContext->hMachine));
  870. //
  871. // Get root key spec, subkey name, and value name.
  872. //
  873. d = ERROR_INVALID_DATA;
  874. if((RootKeySpec = pSetupGetField(InfLineContext,1))
  875. && (SubKeyName = pSetupGetField(InfLineContext,2))) {
  876. ValueName = pSetupGetField(InfLineContext,3);
  877. if(!SetupGetIntField(InfLineContext,4,&DelFlags)){
  878. DelFlags = 0;
  879. }
  880. RootKey = pSetupInfRegSpecToKeyHandle(RootKeySpec, RegModContext->UserRootKey, &CloseKey);
  881. if(RootKey) {
  882. //
  883. // Make an information log entry saying we are deleting a key.
  884. // Note that we must allow for the fact that some parts of the
  885. // name may be missing.
  886. //
  887. if (slot_regop == 0) {
  888. slot_regop = AllocLogInfoSlot(((PLOADED_INF) Inf)->LogContext,FALSE);
  889. }
  890. WriteLogEntry(
  891. ((PLOADED_INF) Inf)->LogContext,
  892. slot_regop,
  893. (ValueName ? MSG_LOG_DELETING_REG_VALUE : MSG_LOG_DELETING_REG_KEY),
  894. NULL,
  895. RootKeySpec,
  896. SubKeyName,
  897. (*SubKeyName && ValueName ? TEXT("\\") : TEXT("")),
  898. (ValueName ? (*ValueName ? ValueName : TEXT("-")) : TEXT("")));
  899. if(ValueName && !(DelFlags & FLG_DELREG_KEYONLY_COMMON)) {
  900. //
  901. // at this point, we have been given root,subkey,value
  902. // we might have flags and other parameters
  903. //
  904. if(DelFlags & FLG_ADDREG_DELREG_BIT) {
  905. //
  906. // if we have a flag and that flag indicates
  907. // that the entry must be interpreted as DELREG flags
  908. // determine how to process flag
  909. //
  910. switch (DelFlags) {
  911. case FLG_DELREG_32BITKEY | FLG_DELREG_MULTI_SZ_DELSTRING:
  912. case FLG_DELREG_64BITKEY | FLG_DELREG_MULTI_SZ_DELSTRING:
  913. case FLG_DELREG_MULTI_SZ_DELSTRING: {
  914. Data = pSetupGetField(InfLineContext,5);
  915. if (Data && *Data) {
  916. //
  917. // we have valid parameters for this flag
  918. //
  919. REGMOD_CONTEXT NewContext = *RegModContext;
  920. if(NewContext.UserRootKey != RootKey) {
  921. NewContext.Flags = 0; // if root is not HKR, clear context flags
  922. NewContext.UserRootKey = RootKey;
  923. }
  924. WriteLogEntry(
  925. ((PLOADED_INF) Inf)->LogContext,
  926. slot_regop,
  927. MSG_LOG_DELETING_REG_KEY_DELSTRING,
  928. NULL,
  929. RootKeySpec,
  930. SubKeyName,
  931. (*SubKeyName ? TEXT("\\") : TEXT("")),
  932. (*ValueName ? ValueName : TEXT("-")),
  933. Data);
  934. //
  935. // handling of all special cases done via this internal function
  936. //
  937. d = _DeleteStringFromMultiSz(
  938. SubKeyName,
  939. ValueName,
  940. Data,
  941. DelFlags, // specify exact flag
  942. &NewContext
  943. );
  944. if (d == ERROR_INVALID_DATA) {
  945. //
  946. // this error code is over-used :-( but get's returned if type mismatches
  947. // we don't consider type mismatch as fatal
  948. //
  949. NonFatal = TRUE;
  950. }
  951. } else {
  952. WriteLogEntry(
  953. ((PLOADED_INF) Inf)->LogContext,
  954. slot_regop,
  955. MSG_LOG_DELETING_REG_KEY_FLAGS,
  956. NULL,
  957. RootKeySpec,
  958. SubKeyName,
  959. (*SubKeyName ? TEXT("\\") : TEXT("")),
  960. (*ValueName ? ValueName : TEXT("-")),
  961. DelFlags);
  962. d = ERROR_INVALID_DATA;
  963. }
  964. goto clean0;
  965. }
  966. default:
  967. WriteLogEntry(
  968. ((PLOADED_INF) Inf)->LogContext,
  969. slot_regop,
  970. MSG_LOG_DELETING_REG_KEY_FLAGS,
  971. NULL,
  972. RootKeySpec,
  973. SubKeyName,
  974. (*SubKeyName ? TEXT("\\") : TEXT("")),
  975. (*ValueName ? ValueName : TEXT("-")),
  976. DelFlags);
  977. d = ERROR_INVALID_DATA;
  978. goto clean0;
  979. }
  980. }
  981. if(*ValueName && !(*SubKeyName)) {
  982. //
  983. // If the key being used is HKR with no subkey specified, and if we
  984. // are doing the DelReg for a hardware key (i.e., DevInst is non-NULL,
  985. // then we need to check to see whether the value entry is the name of
  986. // a device registry property.
  987. //
  988. if ((RegModContext->Flags & INF_PFLAG_CLASSPROP) != 0 &&
  989. LookUpStringInTable(InfRegValToClassRegProp, ValueName, &CmPropertyCode)) {
  990. //
  991. // This value is a class registry property--we must delete the property
  992. // by calling a CM API.
  993. //
  994. cr = CM_Set_Class_Registry_Property(RegModContext->ClassGuid,
  995. (ULONG)CmPropertyCode,
  996. NULL,
  997. 0,
  998. 0,
  999. RegModContext->hMachine
  1000. );
  1001. switch (cr) {
  1002. case CR_SUCCESS:
  1003. rc = NO_ERROR;
  1004. break;
  1005. case CR_NO_SUCH_VALUE:
  1006. rc = ERROR_FILE_NOT_FOUND;
  1007. break;
  1008. case CR_INVALID_DEVINST:
  1009. rc = ERROR_NO_SUCH_DEVINST;
  1010. break;
  1011. default:
  1012. rc = ERROR_INVALID_DATA;
  1013. break;
  1014. }
  1015. if (rc != NO_ERROR && rc != ERROR_FILE_NOT_FOUND) {
  1016. //
  1017. // Log that an error occurred accessing CM value
  1018. //
  1019. WriteLogError(
  1020. ((PLOADED_INF) Inf)->LogContext,
  1021. SETUP_LOG_ERROR,
  1022. rc);
  1023. }
  1024. //
  1025. // fall through to delete normal registry value, if one exists
  1026. //
  1027. } else if ((RegModContext->Flags & INF_PFLAG_DEVPROP) != 0 &&
  1028. LookUpStringInTable(InfRegValToDevRegProp, ValueName, &CmPropertyCode)) {
  1029. //
  1030. // This value is a device registry property--we must delete the property
  1031. // by calling a CM API.
  1032. //
  1033. cr = CM_Set_DevInst_Registry_Property(RegModContext->DevInst,
  1034. (ULONG)CmPropertyCode,
  1035. NULL,
  1036. 0,
  1037. 0
  1038. );
  1039. switch (cr) {
  1040. case CR_SUCCESS:
  1041. rc = NO_ERROR;
  1042. break;
  1043. case CR_NO_SUCH_VALUE:
  1044. rc = ERROR_FILE_NOT_FOUND;
  1045. break;
  1046. case CR_INVALID_DEVINST:
  1047. rc = ERROR_NO_SUCH_DEVINST;
  1048. break;
  1049. default:
  1050. rc = ERROR_INVALID_DATA;
  1051. break;
  1052. }
  1053. if (rc != NO_ERROR && rc != ERROR_FILE_NOT_FOUND) {
  1054. //
  1055. // Log that an error occurred accessing CM value
  1056. //
  1057. WriteLogError(
  1058. ((PLOADED_INF) Inf)->LogContext,
  1059. SETUP_LOG_ERROR,
  1060. rc);
  1061. }
  1062. //
  1063. // fall through to delete normal registry value, if one exists
  1064. //
  1065. }
  1066. }
  1067. //
  1068. // Open subkey for delete.
  1069. //
  1070. d = RegOpenKeyEx(
  1071. RootKey,
  1072. SubKeyName,
  1073. 0,
  1074. #ifdef _WIN64
  1075. (( DelFlags & FLG_DELREG_32BITKEY ) ? KEY_WOW64_32KEY:0) |
  1076. #else
  1077. (( DelFlags & FLG_DELREG_64BITKEY ) ? KEY_WOW64_64KEY:0) |
  1078. #endif
  1079. KEY_SET_VALUE | KEY_QUERY_VALUE,
  1080. &Key
  1081. );
  1082. if(d == NO_ERROR) {
  1083. d = RegDeleteValue(Key,ValueName);
  1084. RegCloseKey(Key);
  1085. }
  1086. } else {
  1087. //
  1088. // if we get here, we're only deleting the key
  1089. //
  1090. d = pSetupRegistryDelnodeEx(RootKey,SubKeyName,DelFlags);
  1091. }
  1092. if (CloseKey) {
  1093. RegCloseKey( RootKey );
  1094. }
  1095. } else {
  1096. d = ERROR_BADKEY;
  1097. }
  1098. } else {
  1099. WriteLogEntry(
  1100. ((PLOADED_INF) Inf)->LogContext,
  1101. SETUP_LOG_ERROR,
  1102. MSG_LOG_DELREG_PARAMS,
  1103. NULL);
  1104. return d;
  1105. }
  1106. clean0:
  1107. if (CloseKey) {
  1108. RegCloseKey( RootKey );
  1109. }
  1110. if (d != NO_ERROR && d != ERROR_FILE_NOT_FOUND) {
  1111. //
  1112. // Log that an error occurred.
  1113. //
  1114. WriteLogError(
  1115. ((PLOADED_INF) Inf)->LogContext,
  1116. (NonFatal?SETUP_LOG_INFO:SETUP_LOG_ERROR),
  1117. d);
  1118. if (NonFatal) {
  1119. d = NO_ERROR;
  1120. }
  1121. } else if (d != NO_ERROR) {
  1122. //
  1123. // verbose case, not full error, indicate what we did
  1124. //
  1125. WriteLogError(
  1126. ((PLOADED_INF) Inf)->LogContext,
  1127. SETUP_LOG_VERBOSE,
  1128. d);
  1129. d = NO_ERROR;
  1130. } else {
  1131. //
  1132. // just flush the buffer
  1133. //
  1134. WriteLogEntry(
  1135. ((PLOADED_INF) Inf)->LogContext,
  1136. SETUP_LOG_VERBOSE,
  1137. 0,
  1138. NULL);
  1139. }
  1140. if (slot_regop) {
  1141. ReleaseLogInfoSlot(((PLOADED_INF) Inf)->LogContext,slot_regop);
  1142. }
  1143. return(d);
  1144. }
  1145. DWORD_PTR
  1146. pSetupProcessAddRegLine(
  1147. IN PVOID Inf,
  1148. IN PINFCONTEXT InfLineContext,
  1149. IN PVOID Context
  1150. )
  1151. /*++
  1152. Routine Description:
  1153. Process a line in the INF that contains add-registry instructions.
  1154. The line is expected to be in the following form:
  1155. <root-spec>,<subkey>,<value-name>,<flags>,<value>...
  1156. <Root-spec> is one of HKR, HKLM, etc.
  1157. <subkey> specifies the subkey relative to Root-spec.
  1158. <value-name> is optional. If not present the default value is set.
  1159. <flags> is optional and supplies flags, such as to indicate the data type.
  1160. These are the FLG_ADDREG_* flags defined in setupapi.h, and are a
  1161. superset of those defined for Win95 in setupx.h.
  1162. <value> is one or more values used as the data. The format depends
  1163. on the value type. This value is optional. For REG_DWORD, the
  1164. default is 0. For REG_SZ, REG_EXPAND_SZ, the default is the
  1165. empty string. For REG_BINARY the default is a 0-length entry.
  1166. For REG_MULTI_SZ the default is a single empty string.
  1167. note that if <flags> has FLG_ADDREG_DELREG_BIT set, we ignore the line.
  1168. Arguments:
  1169. Inf - supplies an INF handle so we can get a LogContext.
  1170. InfLineContext - supplies inf line context for the line containing
  1171. add-registry instructions.
  1172. Context - supplies the address of a registry modification context
  1173. structure used in adding the registry value. The structure is
  1174. defined as:
  1175. typedef struct _REGMOD_CONTEXT {
  1176. DWORD Flags; // indicates what fields are filled in
  1177. HKEY UserRootKey; // HKR
  1178. PGUID ClassGuid; // INF_PFLAG_CLASSPROP
  1179. HMACHINE hMachine; // INF_PFLAG_CLASSPROP
  1180. DWORD DevInst; // INF_PFLAG_DEVPROP
  1181. } REGMOD_CONTEXT, *PREGMOD_CONTEXT;
  1182. where UserRootKey is a handle to the open inf key to be used as
  1183. the root when HKR is specified as the root for the operation, and
  1184. DevInst is the optional device instance handle that is supplied when
  1185. the AddReg section is for a hardware key (i.e., under the Enum branch).
  1186. If this handle is supplied, then the value is checked to see whether it
  1187. is the name of a Plug&Play device registry property, and if so, the
  1188. registry property is set via a CM API instead of via the registry API
  1189. (which doesn't refer to the same location on Windows NT).
  1190. Flags indicates if DevInst should be used, or if ClassGuid/hMachine pair should be used
  1191. Return Value:
  1192. Win32 error code indicating outcome.
  1193. --*/
  1194. {
  1195. PCTSTR RootKeySpec,SubKeyName,ValueName;
  1196. PCTSTR ValueTypeSpec;
  1197. DWORD ValueType;
  1198. HKEY RootKey,Key;
  1199. DWORD d = NO_ERROR;
  1200. BOOL b;
  1201. INT IntVal;
  1202. DWORD Size;
  1203. PVOID Data;
  1204. DWORD Disposition;
  1205. UINT Flags = 0;
  1206. PTSTR *Array;
  1207. PREGMOD_CONTEXT RegModContext = (PREGMOD_CONTEXT)Context;
  1208. UINT_PTR CmPropertyCode;
  1209. PVOID ConvertedBuffer;
  1210. DWORD ConvertedBufferSize;
  1211. CONFIGRET cr;
  1212. DWORD slot_regop = 0;
  1213. BOOL CloseKey = FALSE;
  1214. //
  1215. // We shouldn't be doing this against a remote machine.
  1216. //
  1217. MYASSERT(!(RegModContext->hMachine));
  1218. //
  1219. // Get root key spec. If we can't get the root key spec, we don't do anything and
  1220. // return NO_ERROR.
  1221. //
  1222. if(RootKeySpec = pSetupGetField(InfLineContext,1)) {
  1223. RootKey = pSetupInfRegSpecToKeyHandle(RootKeySpec, RegModContext->UserRootKey, &CloseKey);
  1224. if(!RootKey) {
  1225. WriteLogEntry(
  1226. ((PLOADED_INF) Inf)->LogContext,
  1227. SETUP_LOG_ERROR,
  1228. MSG_LOG_ADDREG_NOROOT,
  1229. NULL);
  1230. return(ERROR_BADKEY);
  1231. }
  1232. //
  1233. // SubKeyName is optional.
  1234. //
  1235. SubKeyName = pSetupGetField(InfLineContext,2);
  1236. //
  1237. // ValueName is optional. Either NULL or "" are acceptable
  1238. // to pass to RegSetValueEx.
  1239. //
  1240. ValueName = pSetupGetField(InfLineContext,3);
  1241. //
  1242. // If we don't have a value name, the type is REG_SZ to force
  1243. // the right behavior in RegSetValueEx. Otherwise get the data type.
  1244. //
  1245. ValueType = REG_SZ;
  1246. if(ValueName) {
  1247. if(!SetupGetIntField(InfLineContext,4,&Flags)) {
  1248. Flags = 0;
  1249. }
  1250. if (Flags & FLG_ADDREG_DELREG_BIT) {
  1251. d = NO_ERROR;
  1252. //
  1253. // Log that an error occurred
  1254. //
  1255. WriteLogEntry(
  1256. ((PLOADED_INF) Inf)->LogContext,
  1257. SETUP_LOG_VERBOSE,
  1258. MSG_LOG_SKIP_DELREG_KEY,
  1259. NULL,
  1260. RootKeySpec,
  1261. (SubKeyName ? SubKeyName : TEXT("")),
  1262. (SubKeyName && ValueName
  1263. && *SubKeyName && *ValueName ? TEXT("\\") : TEXT("")),
  1264. (ValueName ? ValueName : TEXT("")),
  1265. Flags);
  1266. goto clean1;
  1267. }
  1268. switch(Flags & FLG_ADDREG_TYPE_MASK) {
  1269. case FLG_ADDREG_TYPE_SZ :
  1270. ValueType = REG_SZ;
  1271. break;
  1272. case FLG_ADDREG_TYPE_MULTI_SZ :
  1273. ValueType = REG_MULTI_SZ;
  1274. break;
  1275. case FLG_ADDREG_TYPE_EXPAND_SZ :
  1276. ValueType = REG_EXPAND_SZ;
  1277. break;
  1278. case FLG_ADDREG_TYPE_BINARY :
  1279. ValueType = REG_BINARY;
  1280. break;
  1281. case FLG_ADDREG_TYPE_DWORD :
  1282. ValueType = REG_DWORD;
  1283. break;
  1284. case FLG_ADDREG_TYPE_NONE :
  1285. ValueType = REG_NONE;
  1286. break;
  1287. default :
  1288. //
  1289. // If the FLG_ADDREG_BINVALUETYPE is set, then the highword
  1290. // can contain just about any random reg data type ordinal value.
  1291. //
  1292. if(Flags & FLG_ADDREG_BINVALUETYPE) {
  1293. //
  1294. // Disallow the following reg data types:
  1295. //
  1296. // REG_NONE, REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ
  1297. //
  1298. ValueType = (DWORD)HIWORD(Flags);
  1299. if((ValueType < REG_BINARY) || (ValueType == REG_MULTI_SZ)) {
  1300. d = ERROR_INVALID_DATA;
  1301. goto clean1;
  1302. }
  1303. } else {
  1304. d = ERROR_INVALID_DATA;
  1305. goto clean1;
  1306. }
  1307. }
  1308. //
  1309. // Presently, the append behavior flag is only supported for
  1310. // REG_MULTI_SZ values.
  1311. //
  1312. if((Flags & FLG_ADDREG_APPEND) && (ValueType != REG_MULTI_SZ)) {
  1313. d = ERROR_INVALID_DATA;
  1314. goto clean1;
  1315. }
  1316. }
  1317. //
  1318. // On Win9x setting the unnamed value to REG_EXPAND_SZ doesn't
  1319. // work. So we convert to REG_SZ, assuming that anyone on Win9x trying
  1320. // to do this has done the appropriate substitutions. This is a fix
  1321. // for the IE guys, apparently advpack.dll does the right thing to
  1322. // make the fix below viable.
  1323. //
  1324. if((OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
  1325. && (!ValueName || (*ValueName == 0))
  1326. && (ValueType == REG_EXPAND_SZ)) {
  1327. ValueType = REG_SZ;
  1328. }
  1329. //
  1330. // Get the data based on type.
  1331. //
  1332. switch(ValueType) {
  1333. case REG_MULTI_SZ:
  1334. if(Flags & FLG_ADDREG_APPEND) {
  1335. //
  1336. // This is MULTI_SZ_APPEND, which means to append the string value to
  1337. // an existing multi_sz if it's not already there.
  1338. //
  1339. if(SetupGetStringField(InfLineContext,5,NULL,0,&Size)) {
  1340. Data = MyMalloc(Size*sizeof(TCHAR));
  1341. if(!Data) {
  1342. d = ERROR_NOT_ENOUGH_MEMORY;
  1343. goto clean1;
  1344. }
  1345. if(SetupGetStringField(InfLineContext,5,Data,Size,NULL)) {
  1346. REGMOD_CONTEXT NewContext = *RegModContext;
  1347. if(NewContext.UserRootKey != RootKey) {
  1348. NewContext.Flags = 0; // if new root, clear context flags
  1349. NewContext.UserRootKey = RootKey;
  1350. }
  1351. d = _AppendStringToMultiSz(
  1352. SubKeyName,
  1353. ValueName,
  1354. (PCTSTR)Data,
  1355. FALSE, // don't allow duplicates.
  1356. &NewContext,
  1357. Flags
  1358. );
  1359. } else {
  1360. d = GetLastError();
  1361. }
  1362. MyFree(Data);
  1363. } else {
  1364. d = ERROR_INVALID_DATA;
  1365. }
  1366. goto clean1;
  1367. } else {
  1368. if(SetupGetMultiSzField(InfLineContext, 5, NULL, 0, &Size)) {
  1369. Data = MyMalloc(Size*sizeof(TCHAR));
  1370. if(!Data) {
  1371. d = ERROR_NOT_ENOUGH_MEMORY;
  1372. goto clean1;
  1373. }
  1374. if(!SetupGetMultiSzField(InfLineContext, 5, Data, Size, NULL)) {
  1375. d = GetLastError();
  1376. MyFree(Data);
  1377. goto clean1;
  1378. }
  1379. Size *= sizeof(TCHAR);
  1380. } else {
  1381. Size = sizeof(TCHAR);
  1382. Data = MyMalloc(Size);
  1383. if(!Data) {
  1384. d = ERROR_NOT_ENOUGH_MEMORY;
  1385. goto clean1;
  1386. }
  1387. *((PTCHAR)Data) = TEXT('\0');
  1388. }
  1389. break;
  1390. }
  1391. case REG_DWORD:
  1392. //
  1393. // Since the old SetupX APIs only allowed REG_BINARY, INFs had to specify REG_DWORD
  1394. // by listing all 4 bytes separately. Support the old format here, by checking to
  1395. // see whether the line has 4 bytes, and if so, combine those to form the DWORD.
  1396. //
  1397. Size = sizeof(DWORD);
  1398. Data = MyMalloc(sizeof(DWORD));
  1399. if(!Data) {
  1400. d = ERROR_NOT_ENOUGH_MEMORY;
  1401. goto clean1;
  1402. }
  1403. if(SetupGetFieldCount(InfLineContext) == 8) {
  1404. //
  1405. // Then the DWORD is specified as a list of its constituent bytes.
  1406. //
  1407. if(!SetupGetBinaryField(InfLineContext,5,Data,Size,NULL)) {
  1408. d = GetLastError();
  1409. MyFree(Data);
  1410. goto clean1;
  1411. }
  1412. } else {
  1413. if(!SetupGetIntField(InfLineContext,5,(PINT)Data)) {
  1414. *(PINT)Data = 0;
  1415. }
  1416. }
  1417. break;
  1418. case REG_SZ:
  1419. case REG_EXPAND_SZ:
  1420. if(SetupGetStringField(InfLineContext,5,NULL,0,&Size)) {
  1421. Data = MyMalloc(Size*sizeof(TCHAR));
  1422. if(!Data) {
  1423. d = ERROR_NOT_ENOUGH_MEMORY;
  1424. goto clean1;
  1425. }
  1426. if(!SetupGetStringField(InfLineContext,5,Data,Size,NULL)) {
  1427. d = GetLastError();
  1428. MyFree(Data);
  1429. goto clean1;
  1430. }
  1431. Size *= sizeof(TCHAR);
  1432. } else {
  1433. Size = sizeof(TCHAR);
  1434. Data = DuplicateString(TEXT(""));
  1435. if(!Data) {
  1436. d = ERROR_NOT_ENOUGH_MEMORY;
  1437. goto clean1;
  1438. }
  1439. }
  1440. break;
  1441. case REG_BINARY:
  1442. default:
  1443. //
  1444. // All other values are specified in REG_BINARY form (i.e., one byte per field).
  1445. //
  1446. if(SetupGetBinaryField(InfLineContext, 5, NULL, 0, &Size)) {
  1447. Data = MyMalloc(Size);
  1448. if(!Data) {
  1449. d = ERROR_NOT_ENOUGH_MEMORY;
  1450. goto clean1;
  1451. }
  1452. if(!SetupGetBinaryField(InfLineContext, 5, Data, Size, NULL)) {
  1453. d = GetLastError();
  1454. MyFree(Data);
  1455. goto clean1;
  1456. }
  1457. } else {
  1458. //
  1459. // error occurred
  1460. //
  1461. d = GetLastError();
  1462. goto clean1;
  1463. }
  1464. break;
  1465. }
  1466. //
  1467. // Set this variable to TRUE only if this value should not be set later on in a call to
  1468. // RegSetValueEx (e.g., if this value is a DevReg Property).
  1469. //
  1470. b = FALSE;
  1471. //
  1472. // Open/create the key.
  1473. //
  1474. if(SubKeyName && *SubKeyName) {
  1475. #ifdef UNICODE
  1476. //
  1477. // Warning--extreme hack ahead!!!
  1478. //
  1479. // If we're running in non-interactive mode, we cannot allow
  1480. // RunOnce processing to happen in that context (typically, in TCB)
  1481. // because we have no control over what stuff gets registered for
  1482. // RunOnce. Also, we can't kick off RunOnce in the context of a
  1483. // logged-on user, because if it's a non-administrator, some of
  1484. // the operations may fail, and be lost forever (SWENUM is a prime
  1485. // example of this).
  1486. //
  1487. // Therefore, when we're in non-interactive mode, we "swallow" any
  1488. // AddReg directives for RunOnce entries that use rundll32, and
  1489. // squirrel them away in a global list. The caller (i.e.,
  1490. // umpnpmgr) can retrieve this list and do the job of rundll32
  1491. // manually for these entries. If we encounter any other kinds of
  1492. // runonce entries, we bail.
  1493. //
  1494. if((GlobalSetupFlags & PSPGF_NONINTERACTIVE) &&
  1495. (RootKey == HKEY_LOCAL_MACHINE) &&
  1496. !lstrcmpi(SubKeyName, pszPathRunOnce) &&
  1497. ((ValueType == REG_SZ) || (ValueType == REG_EXPAND_SZ))) {
  1498. TCHAR szBuffer[MAX_PATH];
  1499. PTSTR p, q, DontCare;
  1500. DWORD DllPathSize;
  1501. PTSTR DllFullPath, DllParams;
  1502. PSTR DllEntryPointName;
  1503. PPSP_RUNONCE_NODE CurNode, NewNode;
  1504. BOOL NodeAlreadyInList;
  1505. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform;
  1506. //
  1507. // We're looking at a RunOnce entry--see if it's rundll32-based.
  1508. //
  1509. p = _tcschr((PTSTR)Data, TEXT(' '));
  1510. if(p) {
  1511. *p = TEXT('\0'); // separate 1st part of string for comparison
  1512. if(!lstrcmpi((PTSTR)Data, TEXT("rundll32.exe")) ||
  1513. !lstrcmpi((PTSTR)Data, TEXT("rundll32"))) {
  1514. //
  1515. // We have ourselves a rundll32 entry! The next
  1516. // component (up until we hit a comma) is the name of
  1517. // the DLL we're supposed to load/run.
  1518. //
  1519. // NOTE--we don't deal with the (highly unlikely) case
  1520. // where the path has an embedded comma in it,
  1521. // surrounded by quotes. Oh well.
  1522. //
  1523. p++;
  1524. q = _tcschr(p, TEXT(','));
  1525. if(q) {
  1526. *(q++) = TEXT('\0'); // separate 2nd part of string
  1527. if(ValueType == REG_EXPAND_SZ) {
  1528. ExpandEnvironmentStrings(p, szBuffer, SIZECHARS(szBuffer));
  1529. } else {
  1530. lstrcpyn(szBuffer, p, (size_t)(q - p));
  1531. }
  1532. p = (PTSTR)pSetupGetFileTitle(szBuffer);
  1533. if(!_tcschr(p, TEXT('.'))) {
  1534. //
  1535. // The file doesn't have an extension--assume
  1536. // it's a DLL.
  1537. //
  1538. _tcscat(p, TEXT(".dll"));
  1539. }
  1540. p = DuplicateString(szBuffer);
  1541. if(!p) {
  1542. d = ERROR_NOT_ENOUGH_MEMORY;
  1543. goto clean0;
  1544. }
  1545. if(p == pSetupGetFileTitle(p)) {
  1546. //
  1547. // The filename is a simple filename--assume it
  1548. // exists in %windir%\system32.
  1549. //
  1550. lstrcpyn(szBuffer, SystemDirectory,SIZECHARS(szBuffer));
  1551. pSetupConcatenatePaths(szBuffer, p, SIZECHARS(szBuffer), NULL);
  1552. } else {
  1553. //
  1554. // The filename contains path information--get
  1555. // the fully-qualified path.
  1556. //
  1557. DllPathSize = GetFullPathName(
  1558. p,
  1559. SIZECHARS(szBuffer),
  1560. szBuffer,
  1561. &DontCare
  1562. );
  1563. if(!DllPathSize || (DllPathSize >= SIZECHARS(szBuffer))) {
  1564. //
  1565. // If we start failing because MAX_PATH
  1566. // isn't big enough anymore, we wanna know
  1567. // about it!
  1568. //
  1569. MYASSERT(DllPathSize < SIZECHARS(szBuffer));
  1570. MyFree(p);
  1571. d = GetLastError();
  1572. goto clean0;
  1573. }
  1574. }
  1575. //
  1576. // No longer need temp string copy.
  1577. //
  1578. MyFree(p);
  1579. DllFullPath = DuplicateString(szBuffer);
  1580. if(!DllFullPath) {
  1581. d = ERROR_NOT_ENOUGH_MEMORY;
  1582. goto clean0;
  1583. }
  1584. //
  1585. // OK, now that we have the full path of the DLL,
  1586. // verify its digital signature.
  1587. //
  1588. IsInfForDeviceInstall(((PLOADED_INF)Inf)->LogContext,
  1589. NULL,
  1590. (PLOADED_INF)Inf,
  1591. NULL,
  1592. &ValidationPlatform,
  1593. NULL,
  1594. NULL
  1595. );
  1596. d = _VerifyFile(((PLOADED_INF)Inf)->LogContext,
  1597. NULL,
  1598. NULL,
  1599. NULL,
  1600. NULL,
  1601. 0,
  1602. pSetupGetFileTitle(DllFullPath),
  1603. DllFullPath,
  1604. NULL,
  1605. NULL,
  1606. FALSE,
  1607. ValidationPlatform,
  1608. (VERIFY_FILE_USE_OEM_CATALOGS | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  1609. NULL,
  1610. NULL,
  1611. NULL,
  1612. NULL
  1613. );
  1614. //
  1615. // Free validation platform info struct, if we had
  1616. // one allocated above as a result of calling
  1617. // IsInfForDeviceInstall().
  1618. //
  1619. if(ValidationPlatform) {
  1620. MyFree(ValidationPlatform);
  1621. }
  1622. if(d != NO_ERROR) {
  1623. MyFree(DllFullPath);
  1624. goto clean0;
  1625. }
  1626. //
  1627. // The DLL seems acceptable to be loaded/run in the
  1628. // context of the caller. Retrieve the entrypoint
  1629. // name (in ANSI), as well as the argument string
  1630. // to be passed to the DLL.
  1631. //
  1632. p = _tcschr(q, TEXT(' '));
  1633. if(p) {
  1634. *(p++) = TEXT('\0');
  1635. DllParams = DuplicateString(p);
  1636. } else {
  1637. DllParams = DuplicateString(TEXT(""));
  1638. }
  1639. if(!DllParams) {
  1640. d = ERROR_NOT_ENOUGH_MEMORY;
  1641. MyFree(DllFullPath);
  1642. goto clean0;
  1643. }
  1644. DllEntryPointName = pSetupUnicodeToAnsi(q);
  1645. if(!DllEntryPointName) {
  1646. d = ERROR_NOT_ENOUGH_MEMORY;
  1647. MyFree(DllFullPath);
  1648. MyFree(DllParams);
  1649. goto clean0;
  1650. }
  1651. //
  1652. // If we get to this point, we have the full DLL
  1653. // path, the DLL entrypoint (always in ANSI, since
  1654. // that's what GetProcAddress wants), and the DLL
  1655. // argument string. Before we create a new node
  1656. // to add to our global list, scan the list to see
  1657. // if the node is already in there (if so, we don't
  1658. // need to add it again).
  1659. //
  1660. NodeAlreadyInList = FALSE;
  1661. if(RunOnceListHead) {
  1662. CurNode = NULL;
  1663. do {
  1664. if(CurNode) {
  1665. CurNode = CurNode->Next;
  1666. } else {
  1667. CurNode = RunOnceListHead;
  1668. }
  1669. if(!lstrcmpi(DllFullPath, CurNode->DllFullPath) &&
  1670. !lstrcmpiA(DllEntryPointName, CurNode->DllEntryPointName) &&
  1671. !lstrcmpi(DllParams, CurNode->DllParams)) {
  1672. //
  1673. // We have a duplicate--no need to do
  1674. // the same RunOnce operation twice.
  1675. //
  1676. NodeAlreadyInList = TRUE;
  1677. break;
  1678. }
  1679. } while(CurNode->Next);
  1680. }
  1681. //
  1682. // Now create a new rundll32 node and stick it in
  1683. // our global list (unless it's already in there).
  1684. //
  1685. if(NodeAlreadyInList) {
  1686. NewNode = NULL;
  1687. } else {
  1688. NewNode = MyMalloc(sizeof(PSP_RUNONCE_NODE));
  1689. if(!NewNode) {
  1690. d = ERROR_NOT_ENOUGH_MEMORY;
  1691. }
  1692. }
  1693. if(NewNode) {
  1694. NewNode->Next = NULL;
  1695. NewNode->DllFullPath = DllFullPath;
  1696. NewNode->DllEntryPointName = DllEntryPointName;
  1697. NewNode->DllParams = DllParams;
  1698. //
  1699. // Add our new node to the end of the list (we
  1700. // already found the end of the list above when
  1701. // doing our duplicate search.
  1702. //
  1703. if(RunOnceListHead) {
  1704. CurNode->Next = NewNode;
  1705. } else {
  1706. RunOnceListHead = NewNode;
  1707. }
  1708. } else {
  1709. //
  1710. // Either we couldn't allocate a new node entry
  1711. // (i.e., due to out-of-memory), or we didn't
  1712. // need to (because the node was already in the
  1713. // list.
  1714. //
  1715. MyFree(DllFullPath);
  1716. MyFree(DllEntryPointName);
  1717. MyFree(DllParams);
  1718. }
  1719. goto clean0;
  1720. } else {
  1721. //
  1722. // Improperly-formatted rundll32 entry.
  1723. //
  1724. d = ERROR_INVALID_DATA;
  1725. goto clean0;
  1726. }
  1727. } else {
  1728. //
  1729. // We don't know how to deal with anything else--abort!
  1730. //
  1731. d = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  1732. goto clean0;
  1733. }
  1734. } else {
  1735. //
  1736. // We don't know how to deal with anything else--abort!
  1737. //
  1738. d = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  1739. goto clean0;
  1740. }
  1741. }
  1742. #endif // UNICODE
  1743. if(Flags & FLG_ADDREG_OVERWRITEONLY) {
  1744. d = RegOpenKeyEx(
  1745. RootKey,
  1746. SubKeyName,
  1747. 0,
  1748. #ifdef _WIN64
  1749. (( Flags & FLG_ADDREG_32BITKEY ) ? KEY_WOW64_32KEY:0) |
  1750. #else
  1751. (( Flags & FLG_ADDREG_64BITKEY ) ? KEY_WOW64_64KEY:0) |
  1752. #endif
  1753. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1754. &Key
  1755. );
  1756. Disposition = REG_OPENED_EXISTING_KEY;
  1757. } else {
  1758. d = RegCreateKeyEx(
  1759. RootKey,
  1760. SubKeyName,
  1761. 0,
  1762. NULL,
  1763. REG_OPTION_NON_VOLATILE,
  1764. #ifdef _WIN64
  1765. (( Flags & FLG_ADDREG_32BITKEY ) ? KEY_WOW64_32KEY:0) |
  1766. #else
  1767. (( Flags & FLG_ADDREG_64BITKEY ) ? KEY_WOW64_64KEY:0) |
  1768. #endif
  1769. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1770. NULL,
  1771. &Key,
  1772. &Disposition
  1773. );
  1774. }
  1775. if(d == NO_ERROR) {
  1776. if(Disposition == REG_OPENED_EXISTING_KEY) {
  1777. //
  1778. // Work around hacked nonsense on Win95 where the unnamed value
  1779. // behaves differently.
  1780. //
  1781. if((Flags & FLG_ADDREG_NOCLOBBER)
  1782. && ((ValueName == NULL) || (*ValueName == 0))
  1783. && (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)) {
  1784. d = 0;
  1785. if(RegQueryValueEx(Key,TEXT(""),NULL,NULL,(BYTE *)&Disposition,&d) == NO_ERROR) {
  1786. //
  1787. // The unnamed value entry is not set.
  1788. //
  1789. Flags &= ~FLG_ADDREG_NOCLOBBER;
  1790. }
  1791. d = NO_ERROR;
  1792. }
  1793. if(Flags & FLG_ADDREG_DELVAL) {
  1794. //
  1795. // Added for compatibility with Setupx (lonnym):
  1796. // If this flag is present, then the data for this value is ignored, and
  1797. // the value entry is deleted.
  1798. //
  1799. b = TRUE;
  1800. RegDeleteValue(Key, ValueName);
  1801. }
  1802. } else {
  1803. //
  1804. // Win9x gets confused and thinks the nonamed value is there
  1805. // so we never overwrite if noclobber is set. Turn it off here.
  1806. //
  1807. Flags &= ~FLG_ADDREG_NOCLOBBER;
  1808. }
  1809. }
  1810. } else {
  1811. d = NO_ERROR;
  1812. //
  1813. // If the key being used is HKR with no subkey specified, and if we
  1814. // are doing the AddReg for a hardware key or for a ClassInstall32
  1815. // entry, then we need to check to see whether the value entry we
  1816. // have is the name of a device or class registry property.
  1817. //
  1818. if((RegModContext->Flags & INF_PFLAG_CLASSPROP) != 0 && ValueName && *ValueName &&
  1819. LookUpStringInTable(InfRegValToClassRegProp, ValueName, &CmPropertyCode)) {
  1820. ULONG ExistingPropDataSize = 0;
  1821. b = TRUE; // we're handling this name here
  1822. //
  1823. // This value is a class registry property--if noclobber flag
  1824. // is set, we must verify that the property doesn't currently
  1825. // exist.
  1826. //
  1827. if((!(Flags & FLG_ADDREG_NOCLOBBER)) ||
  1828. (CM_Get_Class_Registry_Property(RegModContext->ClassGuid,
  1829. (ULONG)CmPropertyCode,
  1830. NULL,
  1831. NULL,
  1832. &ExistingPropDataSize,
  1833. 0,
  1834. RegModContext->hMachine) == CR_NO_SUCH_VALUE)) {
  1835. //
  1836. // Next, make sure the data is valid (doing conversion if
  1837. // necessary and possible).
  1838. //
  1839. if((d = pSetupValidateClassRegProp((ULONG)CmPropertyCode,
  1840. ValueType,
  1841. Data,
  1842. Size,
  1843. &ConvertedBuffer,
  1844. &ConvertedBufferSize)) == NO_ERROR) {
  1845. if((cr = CM_Set_Class_Registry_Property(RegModContext->ClassGuid,
  1846. (ULONG)CmPropertyCode,
  1847. ConvertedBuffer ? ConvertedBuffer
  1848. : Data,
  1849. ConvertedBuffer ? ConvertedBufferSize
  1850. : Size,
  1851. 0,
  1852. RegModContext->hMachine)) != CR_SUCCESS) {
  1853. d = (cr == CR_INVALID_DEVINST) ? ERROR_NO_SUCH_DEVINST
  1854. : ERROR_INVALID_DATA;
  1855. }
  1856. if(ConvertedBuffer) {
  1857. MyFree(ConvertedBuffer);
  1858. }
  1859. }
  1860. }
  1861. } else if((RegModContext->Flags & INF_PFLAG_DEVPROP) != 0 && ValueName && *ValueName &&
  1862. LookUpStringInTable(InfRegValToDevRegProp, ValueName, &CmPropertyCode)) {
  1863. ULONG ExistingPropDataSize = 0;
  1864. b = TRUE; // we're handling this name here
  1865. //
  1866. // This value is a device registry property--if noclobber flag
  1867. // is set, we must verify that the property doesn't currently
  1868. // exist.
  1869. //
  1870. if((!(Flags & FLG_ADDREG_NOCLOBBER)) ||
  1871. (CM_Get_DevInst_Registry_Property(RegModContext->DevInst,
  1872. (ULONG)CmPropertyCode,
  1873. NULL,
  1874. NULL,
  1875. &ExistingPropDataSize,
  1876. 0) == CR_NO_SUCH_VALUE)) {
  1877. //
  1878. // Next, make sure the data is valid (doing conversion if
  1879. // necessary and possible).
  1880. //
  1881. if((d = pSetupValidateDevRegProp((ULONG)CmPropertyCode,
  1882. ValueType,
  1883. Data,
  1884. Size,
  1885. &ConvertedBuffer,
  1886. &ConvertedBufferSize)) == NO_ERROR) {
  1887. if((cr = CM_Set_DevInst_Registry_Property(RegModContext->DevInst,
  1888. (ULONG)CmPropertyCode,
  1889. ConvertedBuffer ? ConvertedBuffer
  1890. : Data,
  1891. ConvertedBuffer ? ConvertedBufferSize
  1892. : Size,
  1893. 0)) != CR_SUCCESS) {
  1894. d = (cr == CR_INVALID_DEVINST) ? ERROR_NO_SUCH_DEVINST
  1895. : ERROR_INVALID_DATA;
  1896. }
  1897. if(ConvertedBuffer) {
  1898. MyFree(ConvertedBuffer);
  1899. }
  1900. }
  1901. }
  1902. }
  1903. //
  1904. // Regardless of whether this value is a devinst registry property,
  1905. // we need to set the Key equal to the RootKey (So we won't think
  1906. // it's a newly-opened key and try to close it later.
  1907. //
  1908. Key = RootKey;
  1909. }
  1910. if(d == NO_ERROR) {
  1911. if(!b) {
  1912. //
  1913. // If noclobber flag is set, then make sure that the value entry doesn't already exist.
  1914. // Also respect the keyonly flag.
  1915. //
  1916. if(!(Flags & (FLG_ADDREG_KEYONLY | FLG_ADDREG_KEYONLY_COMMON))) {
  1917. if(Flags & FLG_ADDREG_NOCLOBBER) {
  1918. b = (RegQueryValueEx(Key,ValueName,NULL,NULL,NULL,NULL) != NO_ERROR);
  1919. } else {
  1920. if(Flags & FLG_ADDREG_OVERWRITEONLY) {
  1921. b = (RegQueryValueEx(Key,ValueName,NULL,NULL,NULL,NULL) == NO_ERROR);
  1922. } else {
  1923. b = TRUE;
  1924. }
  1925. }
  1926. //
  1927. // Set the value. Note that at this point d is NO_ERROR.
  1928. //
  1929. if(b) {
  1930. d = RegSetValueEx(Key,ValueName,0,ValueType,Data,Size);
  1931. }
  1932. }
  1933. }
  1934. if(Key != RootKey) {
  1935. RegCloseKey(Key);
  1936. }
  1937. } else {
  1938. if(Flags & FLG_ADDREG_OVERWRITEONLY) {
  1939. d = NO_ERROR;
  1940. }
  1941. }
  1942. #ifdef UNICODE
  1943. clean0:
  1944. #endif
  1945. MyFree(Data);
  1946. }
  1947. clean1:
  1948. if(d != NO_ERROR) {
  1949. //
  1950. // Log that an error occurred
  1951. //
  1952. WriteLogEntry(
  1953. ((PLOADED_INF) Inf)->LogContext,
  1954. SETUP_LOG_ERROR,
  1955. MSG_LOG_SETTING_REG_KEY,
  1956. NULL,
  1957. RootKeySpec,
  1958. (SubKeyName ? SubKeyName : TEXT("")),
  1959. (SubKeyName && ValueName
  1960. && *SubKeyName && *ValueName ? TEXT("\\") : TEXT("")),
  1961. (ValueName ? ValueName : TEXT("")));
  1962. WriteLogError(
  1963. ((PLOADED_INF) Inf)->LogContext,
  1964. SETUP_LOG_ERROR,
  1965. d);
  1966. }
  1967. if (CloseKey) {
  1968. RegCloseKey( RootKey );
  1969. }
  1970. if (slot_regop) {
  1971. ReleaseLogInfoSlot(((PLOADED_INF) Inf)->LogContext,slot_regop);
  1972. }
  1973. return d;
  1974. }
  1975. DWORD_PTR
  1976. pSetupProcessBitRegLine(
  1977. IN PVOID Inf,
  1978. IN PINFCONTEXT InfLineContext,
  1979. IN PVOID Context
  1980. )
  1981. /*++
  1982. Routine Description:
  1983. Process a line in the registry that contains bit-registry instructions.
  1984. The line is expected to be in the following form:
  1985. <root-spec>,<subkey>,<value-name>,<flags>,<byte-mask>,<byte-to-modify>
  1986. <Root-spec> is one of HKR, HKLM, etc.
  1987. <subkey> specifies the subkey relative to Root-spec.
  1988. <value-name> is optional. If not present the default value is set.
  1989. <flags> is optional and supplies flags, such as whether to set bits or clear
  1990. bits. Value Meaning
  1991. 0 (Default) Clear bits. (FLG_BITREG_CLEARBITS)
  1992. 1 Set bits. (FLG_BITREG_SETBITS)
  1993. These are the FLG_BITREG_* flags defined in setupapi.h, and are a
  1994. superset of those defined for Win95 in setupx.h.
  1995. <byte-mask> is a 1-byte hexadecimal value specifying which bits to operate on.
  1996. <byte-to-modify> is the zero based index of the byte number to modify
  1997. Arguments:
  1998. InfLineContext - supplies inf line context for the line containing
  1999. add-registry instructions.
  2000. Context - supplies the address of a registry modification context
  2001. structure used in adding the registry value. The structure is
  2002. defined as:
  2003. typedef struct _REGMOD_CONTEXT {
  2004. HKEY UserRootKey;
  2005. DEVINST DevInst;
  2006. } REGMOD_CONTEXT, *PREGMOD_CONTEXT;
  2007. where UserRootKey is a handle to the open inf key to be used as
  2008. the root when HKR is specified as the root for the operation, and
  2009. DevInst is the optional device instance handle that is supplied when
  2010. the BitReg section is for a hardware key (i.e., under the Enum branch).
  2011. If this handle is supplied, then the value is checked to see whether it
  2012. is the name of a Plug&Play device registry property, and if so, the
  2013. registry property is set via a CM API instead of via the registry API
  2014. (which doesn't refer to the same location on Windows NT).
  2015. Return Value:
  2016. Win32 error code indicating outcome.
  2017. --*/
  2018. {
  2019. PCTSTR RootKeySpec,SubKeyName,ValueName;
  2020. PCTSTR ValueTypeSpec;
  2021. DWORD ValueType;
  2022. HKEY RootKey,Key;
  2023. DWORD d = NO_ERROR;
  2024. DWORD cb;
  2025. BOOL b;
  2026. INT IntVal;
  2027. DWORD Size;
  2028. PBYTE Data = NULL;
  2029. BYTE Mask;
  2030. DWORD Disposition;
  2031. UINT Flags = 0, BitMask = 0, ByteNumber = 0;
  2032. PREGMOD_CONTEXT RegModContext = (PREGMOD_CONTEXT)Context;
  2033. BOOL DevOrClassProp = FALSE;
  2034. CONFIGRET cr;
  2035. UINT_PTR CmPropertyCode;
  2036. BOOL CloseKey;
  2037. //
  2038. // We shouldn't be doing this against a remote machine.
  2039. //
  2040. MYASSERT(!(RegModContext->hMachine));
  2041. //
  2042. // Get root key spec. If we can't get the root key spec, we don't do anything and
  2043. // return NO_ERROR.
  2044. //
  2045. if(RootKeySpec = pSetupGetField(InfLineContext,1)) {
  2046. RootKey = pSetupInfRegSpecToKeyHandle(RootKeySpec, RegModContext->UserRootKey, &CloseKey);
  2047. if(!RootKey) {
  2048. return(ERROR_BADKEY);
  2049. }
  2050. //
  2051. // SubKeyName is optional.
  2052. //
  2053. SubKeyName = pSetupGetField(InfLineContext,2);
  2054. //
  2055. // ValueName is optional. Either NULL or "" are acceptable
  2056. // to pass to RegSetValueEx.
  2057. //
  2058. ValueName = pSetupGetField(InfLineContext,3);
  2059. //
  2060. // get the flags
  2061. //
  2062. SetupGetIntField(InfLineContext,4,&Flags);
  2063. //
  2064. // get the bitmask
  2065. //
  2066. SetupGetIntField(InfLineContext,5,&BitMask);
  2067. if (BitMask > 0xFF) {
  2068. d = ERROR_INVALID_DATA;
  2069. goto exit;
  2070. }
  2071. //
  2072. // get the byte number to modify
  2073. //
  2074. SetupGetIntField(InfLineContext,6,&ByteNumber);
  2075. //
  2076. // Open the key.
  2077. //
  2078. if(SubKeyName && *SubKeyName) {
  2079. d = RegOpenKeyEx(
  2080. RootKey,
  2081. SubKeyName,
  2082. 0,
  2083. #ifdef _WIN64
  2084. (( Flags & FLG_BITREG_32BITKEY ) ? KEY_WOW64_32KEY:0) |
  2085. #else
  2086. (( Flags & FLG_BITREG_64BITKEY ) ? KEY_WOW64_64KEY:0) |
  2087. #endif
  2088. KEY_QUERY_VALUE | KEY_SET_VALUE,
  2089. &Key
  2090. );
  2091. if(d == NO_ERROR) {
  2092. //
  2093. // Work around hacked nonsense on Win95 where the unnamed value
  2094. // behaves differently.
  2095. //
  2096. if( ((ValueName == NULL) || (*ValueName == 0))
  2097. && (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)) {
  2098. d = 0;
  2099. if(RegQueryValueEx(Key,TEXT(""),NULL,&ValueType,(BYTE *)&Disposition,&d) == NO_ERROR) {
  2100. //
  2101. // The unnamed value entry is not set.
  2102. //
  2103. d = ERROR_INVALID_DATA;
  2104. }
  2105. }
  2106. }
  2107. } else {
  2108. //
  2109. // If the key being used is HKR with no subkey specified, and if we
  2110. // are doing the BitReg for a hardware key or for a ClassInstall32
  2111. // entry, then we need to check to see whether the value entry we
  2112. // have is the name of a device or class registry property.
  2113. //
  2114. if((RegModContext->Flags & INF_PFLAG_CLASSPROP) && ValueName && *ValueName &&
  2115. LookUpStringInTable(InfRegValToClassRegProp, ValueName, &CmPropertyCode)) {
  2116. //
  2117. // Retrieve the existing class property.
  2118. //
  2119. cb = 0;
  2120. cr = CM_Get_Class_Registry_Property(RegModContext->ClassGuid,
  2121. (ULONG)CmPropertyCode,
  2122. &ValueType,
  2123. NULL,
  2124. &cb,
  2125. 0,
  2126. RegModContext->hMachine
  2127. );
  2128. if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
  2129. //
  2130. // cb contains the required size for the buffer, in bytes.
  2131. //
  2132. if(cb) {
  2133. Data = (PBYTE)MyMalloc(cb) ;
  2134. if(!Data) {
  2135. d = ERROR_NOT_ENOUGH_MEMORY;
  2136. }
  2137. if(d == NO_ERROR) {
  2138. cr = CM_Get_Class_Registry_Property(RegModContext->ClassGuid,
  2139. (ULONG)CmPropertyCode,
  2140. &ValueType,
  2141. Data,
  2142. &cb,
  2143. 0,
  2144. RegModContext->hMachine
  2145. );
  2146. if(cr == CR_SUCCESS) {
  2147. DevOrClassProp = TRUE;
  2148. } else {
  2149. d = MapCrToSpError(cr, ERROR_INVALID_DATA);
  2150. MyFree(Data);
  2151. Data = NULL;
  2152. }
  2153. }
  2154. } else {
  2155. d = ERROR_INVALID_DATA;
  2156. }
  2157. } else {
  2158. //
  2159. // We can't access the property (probably because it doesn't
  2160. // exist. We return ERROR_INVALID_DATA for consistency with
  2161. // the return code used by SetupDiGetDeviceRegistryProperty.
  2162. //
  2163. d = ERROR_INVALID_DATA;
  2164. }
  2165. } else if((RegModContext->Flags & INF_PFLAG_DEVPROP) && ValueName && *ValueName &&
  2166. (b = LookUpStringInTable(InfRegValToDevRegProp, ValueName, &CmPropertyCode))) {
  2167. //
  2168. // Retrieve the existing device property.
  2169. //
  2170. cb = 0;
  2171. cr = CM_Get_DevInst_Registry_Property(RegModContext->DevInst,
  2172. (ULONG)CmPropertyCode,
  2173. &ValueType,
  2174. NULL,
  2175. &cb,
  2176. 0
  2177. );
  2178. if(cr == CR_BUFFER_SMALL) {
  2179. //
  2180. // cb contains the required size for the buffer, in bytes.
  2181. //
  2182. MYASSERT(cb);
  2183. Data = (PBYTE)MyMalloc(cb) ;
  2184. if(!Data) {
  2185. d = ERROR_NOT_ENOUGH_MEMORY;
  2186. }
  2187. if(d == NO_ERROR) {
  2188. cr = CM_Get_DevInst_Registry_Property(RegModContext->DevInst,
  2189. (ULONG)CmPropertyCode,
  2190. &ValueType,
  2191. Data,
  2192. &cb,
  2193. 0
  2194. );
  2195. if(cr == CR_SUCCESS) {
  2196. DevOrClassProp = TRUE;
  2197. } else {
  2198. d = MapCrToSpError(cr, ERROR_INVALID_DATA);
  2199. MyFree(Data);
  2200. Data = NULL;
  2201. }
  2202. }
  2203. } else {
  2204. //
  2205. // We can't access the property (probably because it doesn't
  2206. // exist. We return ERROR_INVALID_DATA for consistency with
  2207. // the return code used by SetupDiGetDeviceRegistryProperty.
  2208. //
  2209. d = ERROR_INVALID_DATA;
  2210. }
  2211. }
  2212. //
  2213. // Regardless of whether this value is a device or class registry
  2214. // property, we need to set the Key equal to the RootKey (So we
  2215. // won't think it's a newly-opened key and try to close it later.
  2216. //
  2217. Key = RootKey;
  2218. }
  2219. if(d == NO_ERROR) {
  2220. if(!DevOrClassProp) {
  2221. d = RegQueryValueEx(Key,ValueName,NULL,&ValueType,NULL,&cb);
  2222. if (d == NO_ERROR) {
  2223. if (cb != 0 ) {
  2224. Data = (PBYTE) MyMalloc( cb ) ;
  2225. if (!Data) {
  2226. d = ERROR_NOT_ENOUGH_MEMORY;
  2227. }
  2228. if (d == NO_ERROR) {
  2229. d = RegQueryValueEx(Key,ValueName,NULL,&ValueType,(PBYTE)Data,&cb);
  2230. }
  2231. } else {
  2232. d = ERROR_INVALID_DATA;
  2233. }
  2234. }
  2235. }
  2236. //
  2237. // byte number is zero-based where-as "cb" isn't
  2238. //
  2239. if(d == NO_ERROR) {
  2240. switch (ValueType) {
  2241. case REG_BINARY:
  2242. if (ByteNumber > (cb-1)) {
  2243. d = ERROR_INVALID_DATA;
  2244. }
  2245. break;
  2246. case REG_DWORD:
  2247. if (ByteNumber > 3) {
  2248. d = ERROR_INVALID_DATA;
  2249. }
  2250. break;
  2251. default:
  2252. d = ERROR_INVALID_DATA;
  2253. };
  2254. }
  2255. if (d == NO_ERROR) {
  2256. //
  2257. // set the target byte based on input flags
  2258. //
  2259. if (Flags == FLG_BITREG_SETBITS) {
  2260. Data[ByteNumber] |= BitMask;
  2261. } else {
  2262. Data[ByteNumber] &= ~(BitMask);
  2263. }
  2264. if(DevOrClassProp) {
  2265. if(RegModContext->Flags & INF_PFLAG_CLASSPROP) {
  2266. cr = CM_Set_Class_Registry_Property(RegModContext->ClassGuid,
  2267. (ULONG)CmPropertyCode,
  2268. Data,
  2269. cb,
  2270. 0,
  2271. RegModContext->hMachine
  2272. );
  2273. if(cr != CR_SUCCESS) {
  2274. d = MapCrToSpError(cr, ERROR_INVALID_DATA);
  2275. }
  2276. } else {
  2277. MYASSERT(RegModContext->Flags & INF_PFLAG_DEVPROP);
  2278. cr = CM_Set_DevInst_Registry_Property(RegModContext->DevInst,
  2279. (ULONG)CmPropertyCode,
  2280. Data,
  2281. cb,
  2282. 0
  2283. );
  2284. if(cr != CR_SUCCESS) {
  2285. d = MapCrToSpError(cr, ERROR_INVALID_DATA);
  2286. }
  2287. }
  2288. } else {
  2289. d = RegSetValueEx(Key,ValueName,0,ValueType,Data,cb);
  2290. }
  2291. }
  2292. if (Data) {
  2293. MyFree(Data);
  2294. }
  2295. }
  2296. if(Key != RootKey) {
  2297. RegCloseKey(Key);
  2298. }
  2299. exit:
  2300. if (CloseKey) {
  2301. RegCloseKey(RootKey);
  2302. }
  2303. }
  2304. return d;
  2305. }
  2306. DWORD_PTR
  2307. pSetupProcessIni2RegLine(
  2308. IN PVOID Inf,
  2309. IN PINFCONTEXT InfLineContext,
  2310. IN PVOID Context
  2311. )
  2312. {
  2313. PCTSTR Filename,Section;
  2314. PCTSTR Key,RegRootSpec,SubkeyPath;
  2315. PTCHAR key,value;
  2316. HKEY UserRootKey,RootKey,hKey;
  2317. DWORD Disposition;
  2318. PTCHAR Line;
  2319. PTCHAR Buffer;
  2320. DWORD d;
  2321. TCHAR val[512];
  2322. #define BUF_SIZE (sizeof(val)/sizeof(TCHAR))
  2323. UINT Flags;
  2324. DWORD slot_regop = 0;
  2325. DWORD slot_subop = 0;
  2326. BOOL CloseKey;
  2327. UserRootKey = (HKEY)Context;
  2328. //
  2329. // Get filename and section name of ini file.
  2330. //
  2331. Filename = pSetupGetField(InfLineContext,1);
  2332. Section = pSetupGetField(InfLineContext,2);
  2333. if(!Filename || !Section) {
  2334. return(ERROR_INVALID_DATA);
  2335. }
  2336. //
  2337. // Get the ini file key. If not specified,
  2338. // use the whole section.
  2339. //
  2340. Key = pSetupGetField(InfLineContext,3);
  2341. //
  2342. // Get the reg root spec and the subkey path.
  2343. //
  2344. RegRootSpec = pSetupGetField(InfLineContext,4);
  2345. SubkeyPath = pSetupGetField(InfLineContext,5);
  2346. if(SubkeyPath && (*SubkeyPath == 0)) {
  2347. SubkeyPath = NULL;
  2348. }
  2349. //
  2350. // Translate the root key spec into an hkey
  2351. //
  2352. RootKey = pSetupInfRegSpecToKeyHandle(RegRootSpec,UserRootKey, &CloseKey);
  2353. if(!RootKey) {
  2354. return(ERROR_BADKEY);
  2355. }
  2356. //
  2357. // Get the flags value.
  2358. //
  2359. if(!SetupGetIntField(InfLineContext,6,&Flags)) {
  2360. Flags = 0;
  2361. }
  2362. //
  2363. // Get the relevent line or section in the ini file.
  2364. //
  2365. if(Key = pSetupGetField(InfLineContext,3)) {
  2366. Buffer = MyMalloc(
  2367. ( lstrlen(Key)
  2368. + GetPrivateProfileString(Section,Key,TEXT(""),val,BUF_SIZE,Filename)
  2369. + 3)
  2370. * sizeof(TCHAR)
  2371. );
  2372. if(!Buffer) {
  2373. if (CloseKey) {
  2374. RegCloseKey( RootKey );
  2375. }
  2376. return(ERROR_NOT_ENOUGH_MEMORY);
  2377. }
  2378. Buffer[wsprintf((PTSTR)Buffer,TEXT("%s=%s"),Key,val)+1] = 0;
  2379. } else {
  2380. Buffer = MyMalloc(32768);
  2381. if(!Buffer) {
  2382. if (CloseKey) {
  2383. RegCloseKey( RootKey );
  2384. }
  2385. return(ERROR_NOT_ENOUGH_MEMORY);
  2386. }
  2387. if(!GetPrivateProfileSection(Section,Buffer,32768,Filename)) {
  2388. *Buffer = 0;
  2389. }
  2390. }
  2391. //
  2392. // Open/create the relevent key.
  2393. //
  2394. d = NO_ERROR;
  2395. //
  2396. // Make an information log entry saying we are adding values.
  2397. // Note that we must allow for the fact that the subkey
  2398. // name may be missing.
  2399. //
  2400. if (slot_regop == 0) {
  2401. slot_regop = AllocLogInfoSlot(((PLOADED_INF) Inf)->LogContext,FALSE);
  2402. }
  2403. WriteLogEntry(
  2404. ((PLOADED_INF) Inf)->LogContext,
  2405. slot_regop,
  2406. MSG_LOG_SETTING_VALUES_IN_KEY,
  2407. NULL,
  2408. RegRootSpec,
  2409. (SubkeyPath ? TEXT("\\") : TEXT("")),
  2410. (SubkeyPath ? SubkeyPath : TEXT("")));
  2411. if(SubkeyPath) {
  2412. d = RegCreateKeyEx(
  2413. RootKey,
  2414. SubkeyPath,
  2415. 0,
  2416. NULL,
  2417. REG_OPTION_NON_VOLATILE,
  2418. #ifdef _WIN64
  2419. (( Flags & FLG_INI2REG_32BITKEY ) ? KEY_WOW64_32KEY:0) |
  2420. #else
  2421. (( Flags & FLG_INI2REG_64BITKEY ) ? KEY_WOW64_64KEY:0) |
  2422. #endif
  2423. KEY_SET_VALUE,
  2424. NULL,
  2425. &hKey,
  2426. &Disposition
  2427. );
  2428. } else {
  2429. hKey = RootKey;
  2430. }
  2431. if (slot_subop == 0) {
  2432. slot_subop = AllocLogInfoSlot(((PLOADED_INF) Inf)->LogContext,FALSE);
  2433. }
  2434. for(Line=Buffer; (d==NO_ERROR) && *Line; Line+=lstrlen(Line)+1) {
  2435. //
  2436. // Line points to the key=value pair.
  2437. //
  2438. key = Line;
  2439. if(value = _tcschr(key,TEXT('='))) {
  2440. *value++ = 0;
  2441. } else {
  2442. key = TEXT("");
  2443. value = Line;
  2444. }
  2445. WriteLogEntry(
  2446. ((PLOADED_INF) Inf)->LogContext,
  2447. slot_subop,
  2448. MSG_LOG_SETTING_REG_VALUE,
  2449. NULL,
  2450. key,
  2451. value);
  2452. //
  2453. // Now key points to the value name and value to the value.
  2454. //
  2455. d = RegSetValueEx(
  2456. hKey,
  2457. key,
  2458. 0,
  2459. REG_SZ,
  2460. (CONST BYTE *)value,
  2461. (lstrlen(value)+1)*sizeof(TCHAR)
  2462. );
  2463. }
  2464. if (d != NO_ERROR) {
  2465. //
  2466. // Log that an error occurred, but I don't think that it
  2467. // matters if it was from create or set.
  2468. //
  2469. WriteLogError(
  2470. ((PLOADED_INF) Inf)->LogContext,
  2471. SETUP_LOG_ERROR,
  2472. d);
  2473. }
  2474. if(hKey != RootKey) {
  2475. RegCloseKey(hKey);
  2476. }
  2477. MyFree(Buffer);
  2478. if (slot_regop) {
  2479. ReleaseLogInfoSlot(((PLOADED_INF) Inf)->LogContext,slot_regop);
  2480. }
  2481. if (slot_subop) {
  2482. ReleaseLogInfoSlot(((PLOADED_INF) Inf)->LogContext,slot_subop);
  2483. }
  2484. if (CloseKey) {
  2485. RegCloseKey( RootKey );
  2486. }
  2487. return(d);
  2488. #undef BUF_SIZE
  2489. }
  2490. DWORD
  2491. pSetupInstallUpdateIniFiles(
  2492. IN HINF Inf,
  2493. IN PCTSTR SectionName
  2494. )
  2495. /*++
  2496. Routine Description:
  2497. Locate the UpdateInis= and UpdateIniField= lines in an install section
  2498. and process each section listed therein.
  2499. Arguments:
  2500. Inf - supplies inf handle for inf containing the section indicated
  2501. by SectionName.
  2502. SectionName - supplies name of install section.
  2503. Return Value:
  2504. Win32 error code indicating outcome.
  2505. --*/
  2506. {
  2507. DWORD d,x;
  2508. INISECTIONCACHE IniSectionCache;
  2509. ZeroMemory(&IniSectionCache,sizeof(INISECTIONCACHE));
  2510. d = pSetupEnumInstallationSections(
  2511. Inf,
  2512. SectionName,
  2513. pszUpdateInis,
  2514. pSetupProcessUpdateInisLine,
  2515. &IniSectionCache
  2516. );
  2517. if(d == NO_ERROR) {
  2518. d = pSetupEnumInstallationSections(
  2519. Inf,
  2520. SectionName,
  2521. pszUpdateIniFields,
  2522. pSetupProcessUpdateIniFieldsLine,
  2523. &IniSectionCache
  2524. );
  2525. }
  2526. x = pSetupUnloadIniFileSections(&IniSectionCache,(d == NO_ERROR));
  2527. return((d == NO_ERROR) ? x : d);
  2528. }
  2529. DWORD
  2530. pSetupInstallRegistry(
  2531. IN HINF Inf,
  2532. IN PCTSTR SectionName,
  2533. IN PREGMOD_CONTEXT RegContext
  2534. )
  2535. /*++
  2536. Routine Description:
  2537. Look for AddReg= and DelReg= directives within an inf section
  2538. and parse them.
  2539. Arguments:
  2540. Inf - supplies inf handle for inf containing the section indicated
  2541. by SectionName.
  2542. SectionName - supplies name of install section.
  2543. RegContext - supplies context passed into AddReg and DelReg callbacks.
  2544. Return Value:
  2545. Win32 error code indicating outcome.
  2546. --*/
  2547. {
  2548. DWORD d;
  2549. d = pSetupEnumInstallationSections(Inf,
  2550. SectionName,
  2551. pszDelReg,
  2552. pSetupProcessDelRegLine,
  2553. RegContext
  2554. );
  2555. if(d == NO_ERROR) {
  2556. d = pSetupEnumInstallationSections(Inf,
  2557. SectionName,
  2558. pszAddReg,
  2559. pSetupProcessAddRegLine,
  2560. RegContext
  2561. );
  2562. //
  2563. //Set Security on Keys that were created
  2564. //Ignore errors as per security folks
  2565. // pSetupSetSecurityForAddRegSection will log any security errors
  2566. //
  2567. #ifdef UNICODE
  2568. if(d == NO_ERROR) {
  2569. pSetupSetSecurityForAddRegSection(Inf, SectionName, RegContext);
  2570. }
  2571. #endif
  2572. }
  2573. return d;
  2574. }
  2575. DWORD
  2576. pSetupInstallBitReg(
  2577. IN HINF Inf,
  2578. IN PCTSTR SectionName,
  2579. IN PREGMOD_CONTEXT RegContext
  2580. )
  2581. /*++
  2582. Routine Description:
  2583. Look for BitReg= directives within an inf section and parse them.
  2584. Arguments:
  2585. Inf - supplies inf handle for inf containing the section indicated
  2586. by SectionName.
  2587. SectionName - supplies name of install section.
  2588. RegContext - supplies context passed into AddReg and DelReg callbacks.
  2589. Return Value:
  2590. Win32 error code indicating outcome.
  2591. --*/
  2592. {
  2593. return pSetupEnumInstallationSections(Inf,
  2594. SectionName,
  2595. pszBitReg,
  2596. pSetupProcessBitRegLine,
  2597. RegContext
  2598. );
  2599. }
  2600. DWORD
  2601. pSetupInstallIni2Reg(
  2602. IN HINF Inf,
  2603. IN PCTSTR SectionName,
  2604. IN HKEY UserRootKey
  2605. )
  2606. /*++
  2607. Routine Description:
  2608. Arguments:
  2609. Inf - supplies inf handle for inf containing the section indicated
  2610. by SectionName.
  2611. SectionName - supplies name of install section.
  2612. Return Value:
  2613. Win32 error code indicatinh outcome.
  2614. --*/
  2615. {
  2616. DWORD d;
  2617. d = pSetupEnumInstallationSections(
  2618. Inf,
  2619. SectionName,
  2620. pszIni2Reg,
  2621. pSetupProcessIni2RegLine,
  2622. (PVOID)UserRootKey
  2623. );
  2624. return(d);
  2625. }
  2626. DWORD
  2627. pSetupRegisterDllInstall(
  2628. IN POLE_CONTROL_DATA OleControlData,
  2629. IN HMODULE ControlDll,
  2630. IN PDWORD ExtendedStatus
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. call the "DllInstall" entrypoint for the specified dll
  2635. Arguments:
  2636. OleControlData - pointer to the OLE_CONTROL_DATA structure for the dll
  2637. to be registered
  2638. ControlDll - module handle to the dll to be registered
  2639. ExtendedStatus - receives updated SPREG_* flag indicating outcome
  2640. Return Value:
  2641. Win32 error code indicating outcome.
  2642. --*/
  2643. {
  2644. LPEXCEPTION_POINTERS ExceptionPointers = NULL;
  2645. HRESULT (__stdcall *InstallRoutine) (BOOL bInstall, LPCTSTR pszCmdLine);
  2646. HRESULT InstallStatus;
  2647. DWORD d = NO_ERROR;
  2648. //
  2649. // parameter validation
  2650. //
  2651. if (!ControlDll) {
  2652. *ExtendedStatus = SPREG_UNKNOWN;
  2653. return ERROR_INVALID_PARAMETER;
  2654. }
  2655. //
  2656. // get function pointer to "DllInstall" entrypoint
  2657. //
  2658. InstallRoutine = NULL; // shut up preFast
  2659. try {
  2660. (FARPROC)InstallRoutine = GetProcAddress(
  2661. ControlDll, DLLINSTALL );
  2662. } except (
  2663. ExceptionPointers = GetExceptionInformation(),
  2664. EXCEPTION_EXECUTE_HANDLER) {
  2665. }
  2666. if(ExceptionPointers) {
  2667. //
  2668. // something went wrong...record an error
  2669. //
  2670. d = ExceptionPointers->ExceptionRecord->ExceptionCode;
  2671. WriteLogEntry(
  2672. OleControlData->LogContext,
  2673. SETUP_LOG_ERROR,
  2674. MSG_LOG_OLE_CONTROL_INTERNAL_EXCEPTION,
  2675. NULL,
  2676. OleControlData->FullPath
  2677. );
  2678. DebugPrintEx(DPFLTR_TRACE_LEVEL, TEXT("SETUP: ...exception in GetProcAddress handled\n"));
  2679. *ExtendedStatus = SPREG_GETPROCADDR;
  2680. } else if(InstallRoutine) {
  2681. //
  2682. // now call the function
  2683. //
  2684. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: installing...\n"));
  2685. *ExtendedStatus = SPREG_DLLINSTALL;
  2686. try {
  2687. InstallStatus = InstallRoutine(OleControlData->Register, OleControlData->Argument);
  2688. if(FAILED(InstallStatus)) {
  2689. d = InstallStatus;
  2690. WriteLogEntry(
  2691. OleControlData->LogContext,
  2692. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  2693. MSG_LOG_OLE_CONTROL_API_FAILED,
  2694. NULL,
  2695. OleControlData->FullPath,
  2696. TEXT(DLLINSTALL)
  2697. );
  2698. WriteLogError(OleControlData->LogContext,
  2699. SETUP_LOG_ERROR,
  2700. d);
  2701. } else if(InstallStatus) {
  2702. WriteLogEntry(OleControlData->LogContext,
  2703. SETUP_LOG_WARNING,
  2704. MSG_LOG_OLE_CONTROL_API_WARN,
  2705. NULL,
  2706. OleControlData->FullPath,
  2707. TEXT(DLLINSTALL),
  2708. InstallStatus
  2709. );
  2710. } else {
  2711. WriteLogEntry(
  2712. OleControlData->LogContext,
  2713. SETUP_LOG_VERBOSE,
  2714. MSG_LOG_OLE_CONTROL_API_OK,
  2715. NULL,
  2716. OleControlData->FullPath,
  2717. TEXT(DLLINSTALL)
  2718. );
  2719. }
  2720. } except (
  2721. ExceptionPointers = GetExceptionInformation(),
  2722. EXCEPTION_EXECUTE_HANDLER) {
  2723. d = ExceptionPointers->ExceptionRecord->ExceptionCode;
  2724. WriteLogEntry(
  2725. OleControlData->LogContext,
  2726. SETUP_LOG_ERROR,
  2727. MSG_LOG_OLE_CONTROL_API_EXCEPTION,
  2728. NULL,
  2729. OleControlData->FullPath,
  2730. TEXT(DLLINSTALL)
  2731. );
  2732. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: ...exception in DllInstall handled\n"));
  2733. }
  2734. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: ...installed\n"));
  2735. } else {
  2736. *ExtendedStatus = SPREG_GETPROCADDR;
  2737. }
  2738. return d;
  2739. }
  2740. DWORD
  2741. pSetupRegisterDllRegister(
  2742. IN POLE_CONTROL_DATA OleControlData,
  2743. IN HMODULE ControlDll,
  2744. IN PDWORD ExtendedStatus
  2745. )
  2746. /*++
  2747. Routine Description:
  2748. call the "DllRegisterServer" or "DllUnregisterServer" entrypoint for the
  2749. specified dll
  2750. Arguments:
  2751. OleControlData - pointer to the OLE_CONTROL_DATA structure for the dll
  2752. to be registered
  2753. This is a copy of OleControlData from calling thread
  2754. Inf specified is locked, but not native to this thread
  2755. ControlDll - module handle to the dll to be registered
  2756. ExtendedStatus - receives an extended status depending on the outcome of
  2757. this operation
  2758. Return Value:
  2759. Win32 error code indicating outcome.
  2760. --*/
  2761. {
  2762. LPEXCEPTION_POINTERS ExceptionPointers = NULL;
  2763. HRESULT (__stdcall *RegisterRoutine) (VOID);
  2764. HRESULT RegisterStatus;
  2765. DWORD d = NO_ERROR;
  2766. //
  2767. // parameter validation
  2768. //
  2769. if (!ControlDll) {
  2770. return ERROR_INVALID_PARAMETER;
  2771. }
  2772. //
  2773. // get the function pointer to the actual routine we want to call
  2774. //
  2775. RegisterRoutine = NULL; // shut up preFast
  2776. try {
  2777. (FARPROC)RegisterRoutine = GetProcAddress(
  2778. ControlDll, OleControlData->Register ? DLLREGISTER : DLLUNREGISTER);
  2779. } except (
  2780. ExceptionPointers = GetExceptionInformation(),
  2781. EXCEPTION_EXECUTE_HANDLER) {
  2782. }
  2783. if(ExceptionPointers) {
  2784. //
  2785. // something went wrong, horribly wrong
  2786. //
  2787. d = ExceptionPointers->ExceptionRecord->ExceptionCode;
  2788. WriteLogEntry(
  2789. OleControlData->LogContext,
  2790. SETUP_LOG_ERROR,
  2791. MSG_LOG_OLE_CONTROL_INTERNAL_EXCEPTION,
  2792. NULL,
  2793. OleControlData->FullPath
  2794. );
  2795. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: ...exception in GetProcAddress handled\n"));
  2796. *ExtendedStatus = SPREG_GETPROCADDR;
  2797. } else if(RegisterRoutine) {
  2798. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: registering...\n"));
  2799. *ExtendedStatus = SPREG_REGSVR;
  2800. try {
  2801. RegisterStatus = RegisterRoutine();
  2802. if(FAILED(RegisterStatus)) {
  2803. d = RegisterStatus;
  2804. WriteLogEntry(OleControlData->LogContext,
  2805. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  2806. MSG_LOG_OLE_CONTROL_API_FAILED,
  2807. NULL,
  2808. OleControlData->FullPath,
  2809. OleControlData->Register ? TEXT(DLLREGISTER) : TEXT(DLLUNREGISTER)
  2810. );
  2811. WriteLogError(OleControlData->LogContext,
  2812. SETUP_LOG_ERROR,
  2813. d);
  2814. } else if(RegisterStatus) {
  2815. WriteLogEntry(OleControlData->LogContext,
  2816. SETUP_LOG_WARNING,
  2817. MSG_LOG_OLE_CONTROL_API_WARN,
  2818. NULL,
  2819. OleControlData->FullPath,
  2820. OleControlData->Register ? TEXT(DLLREGISTER) : TEXT(DLLUNREGISTER),
  2821. RegisterStatus
  2822. );
  2823. } else {
  2824. WriteLogEntry(OleControlData->LogContext,
  2825. SETUP_LOG_VERBOSE,
  2826. MSG_LOG_OLE_CONTROL_API_OK,
  2827. NULL,
  2828. OleControlData->FullPath,
  2829. OleControlData->Register ? TEXT(DLLREGISTER) : TEXT(DLLUNREGISTER)
  2830. );
  2831. }
  2832. } except (
  2833. ExceptionPointers = GetExceptionInformation(),
  2834. EXCEPTION_EXECUTE_HANDLER) {
  2835. d = ExceptionPointers->ExceptionRecord->ExceptionCode;
  2836. WriteLogEntry(
  2837. OleControlData->LogContext,
  2838. SETUP_LOG_ERROR,
  2839. MSG_LOG_OLE_CONTROL_API_EXCEPTION,
  2840. NULL,
  2841. OleControlData->FullPath,
  2842. OleControlData->Register ? TEXT(DLLREGISTER) : TEXT(DLLUNREGISTER)
  2843. );
  2844. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: ...exception in DllRegisterServer handled\n"));
  2845. }
  2846. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: ...registered\n"));
  2847. } else {
  2848. d = GetLastError();
  2849. WriteLogEntry(OleControlData->LogContext,
  2850. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  2851. MSG_LOG_OLE_CONTROL_NOT_REGISTERED_GETPROC_FAILED,
  2852. NULL,
  2853. OleControlData->FullPath,
  2854. OleControlData->Register ? TEXT(DLLREGISTER) : TEXT(DLLUNREGISTER)
  2855. );
  2856. WriteLogError(OleControlData->LogContext,
  2857. SETUP_LOG_ERROR,
  2858. d);
  2859. *ExtendedStatus = SPREG_GETPROCADDR;
  2860. }
  2861. return d;
  2862. }
  2863. DWORD
  2864. pSetupRegisterLoadDll(
  2865. IN POLE_CONTROL_DATA OleControlData,
  2866. OUT HMODULE *ControlDll
  2867. )
  2868. /*++
  2869. Routine Description:
  2870. get the module handle to the specified dll
  2871. Arguments:
  2872. OleControlData - pointer to the OLE_CONTROL_DATA structure for the dll
  2873. to be registered
  2874. ControlDll - module handle for the dll
  2875. Return Value:
  2876. Win32 error code indicating outcome.
  2877. --*/
  2878. {
  2879. LPEXCEPTION_POINTERS ExceptionPointers = NULL;
  2880. DWORD d = NO_ERROR;
  2881. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: loading dll...\n"));
  2882. try {
  2883. *ControlDll = LoadLibrary(OleControlData->FullPath);
  2884. } except (
  2885. ExceptionPointers = GetExceptionInformation(),
  2886. EXCEPTION_EXECUTE_HANDLER) {
  2887. }
  2888. if(ExceptionPointers) {
  2889. WriteLogEntry(
  2890. OleControlData->LogContext,
  2891. SETUP_LOG_ERROR,
  2892. MSG_LOG_OLE_CONTROL_LOADLIBRARY_EXCEPTION,
  2893. NULL,
  2894. OleControlData->FullPath
  2895. );
  2896. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: ...exception in LoadLibrary handled\n"));
  2897. d = ExceptionPointers->ExceptionRecord->ExceptionCode;
  2898. } else if (!*ControlDll) {
  2899. d = GetLastError();
  2900. //
  2901. // LoadLibrary failed.
  2902. // File not found is not an error. We want to know about
  2903. // other errors though.
  2904. //
  2905. d = GetLastError();
  2906. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: ...dll not loaded (%u)\n"),d);
  2907. WriteLogEntry(
  2908. OleControlData->LogContext,
  2909. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  2910. MSG_LOG_OLE_CONTROL_LOADLIBRARY_FAILED,
  2911. NULL,
  2912. OleControlData->FullPath
  2913. );
  2914. WriteLogError(
  2915. OleControlData->LogContext,
  2916. SETUP_LOG_ERROR,
  2917. d
  2918. );
  2919. } else {
  2920. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: ...dll loaded\n"));
  2921. }
  2922. return d;
  2923. }
  2924. HANDLE
  2925. pSetupRegisterExe(
  2926. POLE_CONTROL_DATA OleControlData,
  2927. PDWORD ExtendedStatus OPTIONAL
  2928. )
  2929. /*++
  2930. Routine Description:
  2931. register an exe by passing it the specified cmdline
  2932. Arguments:
  2933. OleControlData - pointer to the OLE_CONTROL_DATA structure for the dll
  2934. to be registered
  2935. ExtendedStatus - Win32 error code indicating outcome.
  2936. Return Value:
  2937. if success, a handle for the process which the caller may wait on.
  2938. if failure, return NULL;
  2939. --*/
  2940. {
  2941. TCHAR CmdLine[MAX_PATH *2];
  2942. STARTUPINFO StartupInfo;
  2943. PROCESS_INFORMATION ProcessInformation;
  2944. BOOL fallback = FALSE;
  2945. DWORD d = NO_ERROR;
  2946. //
  2947. // parameter validation
  2948. //
  2949. if (!OleControlData) {
  2950. if (ExtendedStatus) {
  2951. *ExtendedStatus = ERROR_INVALID_DATA;
  2952. }
  2953. return NULL;
  2954. }
  2955. //
  2956. // get the cmdline for the executable
  2957. //
  2958. wsprintf( CmdLine, TEXT("%s %s"),
  2959. OleControlData->FullPath,
  2960. (OleControlData->Argument
  2961. ? OleControlData->Argument
  2962. : (OleControlData->Register
  2963. ? EXEREGSVR
  2964. : EXEUNREGSVR)) );
  2965. //
  2966. // no UI
  2967. //
  2968. GetStartupInfo(&StartupInfo);
  2969. StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
  2970. StartupInfo.wShowWindow = SW_HIDE;
  2971. //
  2972. // we first try to create the process specifying FullPath
  2973. // as given as the image name
  2974. // this is to try to circumvent any security hole as outlined
  2975. // in Raid#415625.
  2976. //
  2977. // if that fails, then the INF entry is strange
  2978. // so we have to fall back on old method
  2979. //
  2980. if (! CreateProcess(OleControlData->FullPath,
  2981. CmdLine,
  2982. NULL,
  2983. NULL,
  2984. FALSE,
  2985. DETACHED_PROCESS|NORMAL_PRIORITY_CLASS,
  2986. NULL,
  2987. NULL,
  2988. &StartupInfo,
  2989. &ProcessInformation)) {
  2990. fallback = TRUE;
  2991. if (! CreateProcess(NULL,
  2992. CmdLine,
  2993. NULL,
  2994. NULL,
  2995. FALSE,
  2996. DETACHED_PROCESS|NORMAL_PRIORITY_CLASS,
  2997. NULL,
  2998. NULL,
  2999. &StartupInfo,
  3000. &ProcessInformation)) {
  3001. d = GetLastError() ;
  3002. }
  3003. }
  3004. if (d != NO_ERROR) {
  3005. WriteLogEntry(
  3006. OleControlData->LogContext,
  3007. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  3008. MSG_LOG_OLE_CONTROL_CREATEPROCESS_FAILED,
  3009. NULL,
  3010. OleControlData->FullPath,
  3011. (OleControlData->Argument
  3012. ? OleControlData->Argument
  3013. : (OleControlData->Register
  3014. ? EXEREGSVR
  3015. : EXEUNREGSVR))
  3016. );
  3017. WriteLogError(
  3018. OleControlData->LogContext,
  3019. SETUP_LOG_ERROR,
  3020. d
  3021. );
  3022. ProcessInformation.hProcess = NULL;
  3023. } else {
  3024. CloseHandle( ProcessInformation.hThread );
  3025. WriteLogEntry(
  3026. OleControlData->LogContext,
  3027. SETUP_LOG_VERBOSE,
  3028. MSG_LOG_OLE_CONTROL_CREATEPROCESS_OK,
  3029. NULL,
  3030. OleControlData->FullPath,
  3031. (OleControlData->Argument
  3032. ? OleControlData->Argument
  3033. : (OleControlData->Register
  3034. ? EXEREGSVR
  3035. : EXEUNREGSVR))
  3036. );
  3037. }
  3038. if (*ExtendedStatus) {
  3039. *ExtendedStatus = d;
  3040. }
  3041. return ProcessInformation.hProcess;
  3042. }
  3043. DWORD
  3044. __stdcall
  3045. pSetupRegisterUnregisterDll(
  3046. VOID *Param
  3047. )
  3048. /*++
  3049. Routine Description:
  3050. main registration routine for registering exe's and dlls.
  3051. Arguments:
  3052. Param - pointer to OLE_CONTROL_DATA structure indicating file to
  3053. be processed
  3054. Return Value:
  3055. Win32 error code indicating outcome.
  3056. --*/
  3057. {
  3058. POLE_CONTROL_DATA OleControlData = (POLE_CONTROL_DATA) Param;
  3059. LPEXCEPTION_POINTERS ExceptionPointers = NULL;
  3060. HMODULE ControlDll = NULL;
  3061. PTSTR Extension;
  3062. DWORD d = NO_ERROR;
  3063. DWORD Count;
  3064. SPFUSIONINSTANCE spFusionInstance;
  3065. if(!OleControlData) {
  3066. return ERROR_INVALID_PARAMETER;
  3067. }
  3068. spFusionEnterContext(NULL,&spFusionInstance);
  3069. d = (DWORD)OleInitialize(NULL);
  3070. if (d!= NO_ERROR) {
  3071. OleControlData->Status->ExtendedStatus = SPREG_UNKNOWN;
  3072. goto clean0;
  3073. }
  3074. try {
  3075. //
  3076. // protect everything in TRY-EXCEPT, we're calling unknown code (DLL's)
  3077. //
  3078. d = pSetupRegisterLoadDll( OleControlData, &ControlDll );
  3079. if (d == NO_ERROR) {
  3080. //
  3081. // We successfully loaded it. Now call the appropriate routines.
  3082. //
  3083. //
  3084. // On register, do DLLREGISTER, then DLLINSTALL
  3085. // On unregister, do DLLINSTALL, then DLLREGISTER
  3086. //
  3087. if (OleControlData->Register) {
  3088. if (OleControlData->RegType & FLG_REGSVR_DLLREGISTER && (d == NO_ERROR) ) {
  3089. d = pSetupRegisterDllRegister(
  3090. OleControlData,
  3091. ControlDll,
  3092. &OleControlData->Status->ExtendedStatus );
  3093. }
  3094. if (OleControlData->RegType & FLG_REGSVR_DLLINSTALL && (d == NO_ERROR) ) {
  3095. d = pSetupRegisterDllInstall(
  3096. OleControlData,
  3097. ControlDll,
  3098. &OleControlData->Status->ExtendedStatus );
  3099. }
  3100. } else {
  3101. if (OleControlData->RegType & FLG_REGSVR_DLLINSTALL && (d == NO_ERROR) ) {
  3102. d = pSetupRegisterDllInstall(
  3103. OleControlData,
  3104. ControlDll,
  3105. &OleControlData->Status->ExtendedStatus );
  3106. }
  3107. if (OleControlData->RegType & FLG_REGSVR_DLLREGISTER && (d == NO_ERROR) ) {
  3108. d = pSetupRegisterDllRegister(
  3109. OleControlData,
  3110. ControlDll,
  3111. &OleControlData->Status->ExtendedStatus );
  3112. }
  3113. }
  3114. } else {
  3115. ControlDll = NULL;
  3116. OleControlData->Status->ExtendedStatus = SPREG_LOADLIBRARY;
  3117. }
  3118. } except(EXCEPTION_EXECUTE_HANDLER) {
  3119. //
  3120. // If our exception was an AV, then use Win32 invalid param error, otherwise, assume it was
  3121. // an inpage error dealing with a mapped-in file.
  3122. //
  3123. d = ERROR_INVALID_DATA;
  3124. OleControlData->Status->ExtendedStatus = SPREG_UNKNOWN;
  3125. }
  3126. if (ControlDll) {
  3127. FreeLibrary(ControlDll);
  3128. }
  3129. //clean1:
  3130. OleUninitialize();
  3131. clean0:
  3132. spFusionLeaveContext(&spFusionInstance);
  3133. if (d == NO_ERROR) {
  3134. OleControlData->Status->ExtendedStatus = SPREG_SUCCESS;
  3135. }
  3136. //
  3137. // we don't need OleControlData anymore so deallocate it here.
  3138. //
  3139. pSetupFreeOleControlData(OleControlData);
  3140. return d;
  3141. }
  3142. #ifdef CHILDREGISTRATION
  3143. BOOL
  3144. IsThisANonNativeDll(
  3145. PCTSTR FullPath
  3146. )
  3147. /*++
  3148. Routine Description:
  3149. determines if a dll is a supported non-native os dll (and must therefore be registered
  3150. in a child process). Uses the imagehlp APIs to figure this out
  3151. Arguments:
  3152. FullPath - Fully qualified path to the dll to be processed
  3153. Return Value:
  3154. TRUE indicates that the file is non-native and should therefore be
  3155. registered in a different process.
  3156. --*/
  3157. {
  3158. LOADED_IMAGE LoadedImage;
  3159. BOOL RetVal = FALSE;
  3160. PSTR FullPathCopy;
  3161. BOOL locked = FALSE;
  3162. #ifndef _WIN64
  3163. if(!IsWow64) {
  3164. //
  3165. // we don't support proxying on 32
  3166. //
  3167. return FALSE;
  3168. }
  3169. #endif
  3170. //
  3171. // imagehlp takes an ANSI string, so convert it or make a non-const copy.
  3172. //
  3173. FullPathCopy = pSetupUnicodeToMultiByte(FullPath, CP_ACP);
  3174. if (!FullPathCopy) {
  3175. return(FALSE);
  3176. }
  3177. RtlZeroMemory(
  3178. &LoadedImage,
  3179. sizeof(LoadedImage) );
  3180. //
  3181. // get the image headers
  3182. //
  3183. try {
  3184. EnterCriticalSection(&ImageHlpMutex);
  3185. locked = TRUE;
  3186. } except(EXCEPTION_EXECUTE_HANDLER) {
  3187. }
  3188. if(!locked) {
  3189. MyFree(FullPathCopy);
  3190. return FALSE;
  3191. }
  3192. try {
  3193. if (MapAndLoad(
  3194. FullPathCopy,
  3195. NULL,
  3196. &LoadedImage,
  3197. TRUE, // assume it's a dll if there isn't any file extension
  3198. TRUE /* read only */ )) {
  3199. //
  3200. // let's not bother to do alot of validation on the file, we'll just
  3201. // see if it meets our search requirement of being a non-native dll.
  3202. //
  3203. if (LoadedImage.FileHeader->Signature == IMAGE_NT_SIGNATURE) {
  3204. #if defined(_X86_)
  3205. //
  3206. // this will need to work better for AMD64
  3207. //
  3208. if (LoadedImage.FileHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64) {
  3209. RetVal = TRUE;
  3210. }
  3211. #elif defined(_IA64_) || defined(_AMD64_)
  3212. if (LoadedImage.FileHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) {
  3213. RetVal = TRUE;
  3214. }
  3215. #else
  3216. #error Unknown platform
  3217. #endif
  3218. }
  3219. //
  3220. // we do not support 16 bit images
  3221. //
  3222. if (LoadedImage.fDOSImage) {
  3223. RetVal = FALSE;
  3224. }
  3225. UnMapAndLoad(&LoadedImage);
  3226. }
  3227. } except(EXCEPTION_EXECUTE_HANDLER) {
  3228. MYASSERT(FALSE && "exception in Map/Unmap");
  3229. }
  3230. LeaveCriticalSection(&ImageHlpMutex);
  3231. MyFree(FullPathCopy);
  3232. return(RetVal);
  3233. }
  3234. BOOL
  3235. BuildSecureSD(
  3236. OUT PSECURITY_DESCRIPTOR *SDIn
  3237. )
  3238. /*++
  3239. Routine Description:
  3240. builds a secure security descriptor to be used in securing a globally
  3241. named object. Our "secure" SD's DACL consists of the following permissions:
  3242. Authenticated users get "generic read" access.
  3243. Administrators get "generic all" access.
  3244. Arguments:
  3245. SDIn - pointer to the PSECURITY_DESCRIPTOR to be created.
  3246. Return Value:
  3247. TRUE - Success, the SECURITY_DESCRIPTOR was created successfully.
  3248. The caller is responsible for freeing the SECURITY_DESCRIPTOR
  3249. --*/
  3250. {
  3251. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  3252. PSID AuthenticatedUsers;
  3253. PSID BuiltInAdministrators;
  3254. PSECURITY_DESCRIPTOR Sd = NULL;
  3255. ACL *Acl;
  3256. ULONG AclSize;
  3257. BOOL RetVal = TRUE;
  3258. *SDIn = NULL;
  3259. //
  3260. // Allocate and initialize the required SIDs
  3261. //
  3262. if (!AllocateAndInitializeSid(
  3263. &NtAuthority,
  3264. 2,
  3265. SECURITY_BUILTIN_DOMAIN_RID,
  3266. DOMAIN_ALIAS_RID_ADMINS,
  3267. 0,0,0,0,0,0,
  3268. &BuiltInAdministrators)) {
  3269. return(FALSE);
  3270. }
  3271. if (!AllocateAndInitializeSid(
  3272. &NtAuthority,
  3273. 1,
  3274. SECURITY_AUTHENTICATED_USER_RID,
  3275. 0,0,0,0,0,0,0,
  3276. &AuthenticatedUsers)) {
  3277. RetVal = FALSE;
  3278. goto e0;
  3279. }
  3280. //
  3281. // "- sizeof (ULONG)" represents the SidStart field of the
  3282. // ACCESS_ALLOWED_ACE. Since we're adding the entire length of the
  3283. // SID, this field is counted twice.
  3284. //
  3285. AclSize = sizeof (ACL) +
  3286. (2 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (ULONG))) +
  3287. GetLengthSid(AuthenticatedUsers) +
  3288. GetLengthSid(BuiltInAdministrators);
  3289. Sd = MyMalloc(SECURITY_DESCRIPTOR_MIN_LENGTH + AclSize);
  3290. if (!Sd) {
  3291. RetVal = FALSE;
  3292. goto e1;
  3293. }
  3294. Acl = (ACL *)((BYTE *)Sd + SECURITY_DESCRIPTOR_MIN_LENGTH);
  3295. if (!InitializeAcl(Acl,
  3296. AclSize,
  3297. ACL_REVISION)) {
  3298. RetVal = FALSE;
  3299. goto e2;
  3300. } else if (!AddAccessAllowedAce(Acl,
  3301. ACL_REVISION,
  3302. SYNCHRONIZE | GENERIC_READ,
  3303. AuthenticatedUsers)) {
  3304. // Failed to build the ACE granting "Authenticated users"
  3305. // (SYNCHRONIZE | GENERIC_READ) access.
  3306. RetVal = FALSE;
  3307. goto e2;
  3308. } else if (!AddAccessAllowedAce(Acl,
  3309. ACL_REVISION,
  3310. GENERIC_ALL,
  3311. BuiltInAdministrators)) {
  3312. // Failed to build the ACE granting "Built-in Administrators"
  3313. // GENERIC_ALL access.
  3314. RetVal = FALSE;
  3315. goto e2;
  3316. } else if (!InitializeSecurityDescriptor(Sd,
  3317. SECURITY_DESCRIPTOR_REVISION)) {
  3318. RetVal = FALSE;
  3319. goto e2;
  3320. } else if (!SetSecurityDescriptorDacl(Sd,
  3321. TRUE,
  3322. Acl,
  3323. FALSE)) {
  3324. // error
  3325. RetVal = FALSE;
  3326. goto e2;
  3327. }
  3328. if (!IsValidSecurityDescriptor(Sd)) {
  3329. RetVal = FALSE;
  3330. goto e2;
  3331. }
  3332. //
  3333. // success
  3334. //
  3335. *SDIn = Sd;
  3336. goto e1;
  3337. e2:
  3338. MyFree(Sd);
  3339. e1:
  3340. FreeSid(AuthenticatedUsers);
  3341. e0:
  3342. FreeSid(BuiltInAdministrators);
  3343. return(RetVal);
  3344. }
  3345. BOOL
  3346. pSetupCleanupWowIpcStream(
  3347. IN OUT PWOWSURRAGATE_IPC WowIpcData
  3348. )
  3349. /*++
  3350. Routine Description:
  3351. This procedure will cleanup the structure that is used for creating
  3352. a child process for registering components.
  3353. Arguments:
  3354. WowIpcData - pointer to a WOWSURRAGATE_IPC structure which is cleaned up.
  3355. Return Value:
  3356. Returns TRUE if the structure is successfully signalled.
  3357. --*/
  3358. {
  3359. //
  3360. // if any items are allocated, free them and zero things out
  3361. //
  3362. if (WowIpcData->MemoryRegion) {
  3363. UnmapViewOfFile( WowIpcData->MemoryRegion );
  3364. }
  3365. if (WowIpcData->hFileMap) {
  3366. CloseHandle(WowIpcData->hFileMap);
  3367. }
  3368. if (WowIpcData->SignalReadyToRegister) {
  3369. CloseHandle(WowIpcData->SignalReadyToRegister);
  3370. }
  3371. if (WowIpcData->SignalRegistrationComplete) {
  3372. CloseHandle(WowIpcData->SignalRegistrationComplete);
  3373. }
  3374. if (WowIpcData->hProcess) {
  3375. CloseHandle(WowIpcData->hProcess);
  3376. }
  3377. RtlZeroMemory(WowIpcData,sizeof(WOWSURRAGATE_IPC));
  3378. return(TRUE);
  3379. }
  3380. BOOL
  3381. InitializeWowIpcStream(
  3382. OUT PWOWSURRAGATE_IPC WowIpcData
  3383. )
  3384. /*++
  3385. Routine Description:
  3386. This procedure will setup the structure that is used for creating
  3387. a child process for registering components.
  3388. Arguments:
  3389. WowIpcData - pointer to a WOWSURRAGATE_IPC structure which is filled in
  3390. with tbe information telling us what the process parameters
  3391. shall be and how to signal the process.
  3392. Return Value:
  3393. Returns TRUE if the structure is successfully signalled.
  3394. --*/
  3395. {
  3396. BOOL RetVal;
  3397. SECURITY_ATTRIBUTES wowsa,signalreadysa,signalcompletesa;
  3398. PSECURITY_DESCRIPTOR wowsd,signalreadysd,signalcompletesd;
  3399. TCHAR MemoryRegionNameString[GUID_STRING_LEN];
  3400. TCHAR SignalReadyToRegisterNameString[GUID_STRING_LEN];
  3401. TCHAR SignalRegistrationCompleteNameString[GUID_STRING_LEN];
  3402. //
  3403. // clean this thing up just in case there's something left over
  3404. //
  3405. pSetupCleanupWowIpcStream(WowIpcData);
  3406. //
  3407. // create the names of our events and shared memory region
  3408. //
  3409. CoCreateGuid( &WowIpcData->MemoryRegionName );
  3410. CoCreateGuid( &WowIpcData->SignalReadyToRegisterName );
  3411. CoCreateGuid( &WowIpcData->SignalRegistrationCompleteName );
  3412. pSetupStringFromGuid(&WowIpcData->MemoryRegionName,MemoryRegionNameString,GUID_STRING_LEN);
  3413. pSetupStringFromGuid(&WowIpcData->SignalReadyToRegisterName,SignalReadyToRegisterNameString,GUID_STRING_LEN);
  3414. pSetupStringFromGuid(&WowIpcData->SignalRegistrationCompleteName,SignalRegistrationCompleteNameString,GUID_STRING_LEN);
  3415. //
  3416. // now create the region and our named events
  3417. //
  3418. //
  3419. // we need to created a named memory region, and this must be properly
  3420. // secured, so we build a security descriptor
  3421. //
  3422. if (!BuildSecureSD(&wowsd)) {
  3423. RetVal = FALSE;
  3424. goto e0;
  3425. }
  3426. wowsa.nLength = sizeof(SECURITY_ATTRIBUTES);
  3427. wowsa.bInheritHandle = TRUE;
  3428. wowsa.lpSecurityDescriptor = wowsd;
  3429. //
  3430. // we need to created a named event, and this must be properly
  3431. // secured, so we build a security descriptor
  3432. //
  3433. if (!BuildSecureSD(&signalreadysd)) {
  3434. RetVal = FALSE;
  3435. goto e1;
  3436. }
  3437. signalreadysa.nLength = sizeof(SECURITY_ATTRIBUTES);
  3438. signalreadysa.bInheritHandle = TRUE;
  3439. signalreadysa.lpSecurityDescriptor = signalreadysd;
  3440. //
  3441. // we need to created a named event, and this must be properly
  3442. // secured, so we build a security descriptor
  3443. //
  3444. if (!BuildSecureSD(&signalcompletesd)) {
  3445. RetVal = FALSE;
  3446. goto e2;
  3447. }
  3448. signalcompletesa.nLength = sizeof(SECURITY_ATTRIBUTES);
  3449. signalcompletesa.bInheritHandle = TRUE;
  3450. signalcompletesa.lpSecurityDescriptor = signalcompletesd;
  3451. WowIpcData->hFileMap = CreateFileMappingW(
  3452. INVALID_HANDLE_VALUE,
  3453. &wowsa,
  3454. PAGE_READWRITE | SEC_COMMIT,
  3455. 0,
  3456. WOW_IPC_REGION_SIZE,
  3457. MemoryRegionNameString
  3458. );
  3459. if (!WowIpcData->hFileMap) {
  3460. RetVal = FALSE;
  3461. goto e2;
  3462. return(FALSE);
  3463. }
  3464. WowIpcData->MemoryRegion = MapViewOfFile(
  3465. WowIpcData->hFileMap,
  3466. FILE_MAP_WRITE,
  3467. 0,
  3468. 0,
  3469. 0
  3470. );
  3471. if (!WowIpcData->MemoryRegion) {
  3472. RetVal = FALSE;
  3473. goto e2;
  3474. }
  3475. WowIpcData->SignalReadyToRegister = CreateEventW(
  3476. &signalreadysa,
  3477. TRUE,
  3478. FALSE,
  3479. SignalReadyToRegisterNameString );
  3480. WowIpcData->SignalRegistrationComplete = CreateEventW(
  3481. &signalcompletesa,
  3482. TRUE,
  3483. FALSE,
  3484. SignalRegistrationCompleteNameString );
  3485. if (!WowIpcData->SignalReadyToRegister ||
  3486. !WowIpcData->SignalRegistrationComplete) {
  3487. RetVal = FALSE;
  3488. goto e2;
  3489. }
  3490. RetVal = TRUE;
  3491. //
  3492. // pSetupCleanupWowIpcStream cleans up most of the resources allocated in this routine.
  3493. //
  3494. e2:
  3495. MyFree(signalcompletesd);
  3496. e1:
  3497. MyFree(signalreadysd);
  3498. e0:
  3499. MyFree(wowsd);
  3500. if (!RetVal) {
  3501. pSetupCleanupWowIpcStream(WowIpcData);
  3502. }
  3503. return(RetVal);
  3504. }
  3505. BOOL
  3506. SignalSurragateProcess(
  3507. IN OUT PWOWSURRAGATE_IPC WowIpcData
  3508. )
  3509. /*++
  3510. Routine Description:
  3511. This procedure will signal our child process if it exists.
  3512. If the process is not running, we will create a new process.
  3513. Arguments:
  3514. WowIpcData - pointer to a WOWSURRAGATE_IPC structure which
  3515. tells us what the process parameters are and how
  3516. to signal the process
  3517. Return Value:
  3518. Returns TRUE if the process is successfully signalled.
  3519. --*/
  3520. {
  3521. BOOL RetVal;
  3522. WCHAR CmdLine[MAX_PATH];
  3523. WCHAR ProcessName[MAX_PATH];
  3524. PROCESS_INFORMATION ProcessInformation;
  3525. STARTUPINFO StartupInfo;
  3526. TCHAR MemoryRegionNameString[GUID_STRING_LEN];
  3527. TCHAR SignalReadyToRegisterNameString[GUID_STRING_LEN];
  3528. TCHAR SignalRegistrationCompleteNameString[GUID_STRING_LEN];
  3529. BOOL NeedToCreateProcess = FALSE;
  3530. //
  3531. // get the string version of our GUIDs, since we'll need these later
  3532. // on.
  3533. //
  3534. pSetupStringFromGuid(&WowIpcData->MemoryRegionName,MemoryRegionNameString,GUID_STRING_LEN);
  3535. pSetupStringFromGuid(&WowIpcData->SignalReadyToRegisterName,SignalReadyToRegisterNameString,GUID_STRING_LEN);
  3536. pSetupStringFromGuid(&WowIpcData->SignalRegistrationCompleteName,SignalRegistrationCompleteNameString,GUID_STRING_LEN);
  3537. //
  3538. // put together the cmdline for the child process just in case we need
  3539. // to launch it in a little bit.
  3540. //
  3541. ExpandEnvironmentStrings(
  3542. SURRAGATE_PROCESSNAME,
  3543. ProcessName,
  3544. sizeof(ProcessName)/sizeof(TCHAR) );
  3545. wsprintfW(CmdLine,
  3546. TEXT("%s %s %s %s %s %s %s"),
  3547. ProcessName,
  3548. SURRAGATE_REGIONNAME_SWITCH,
  3549. MemoryRegionNameString,
  3550. SURRAGATE_SIGNALREADY_SWITCH,
  3551. SignalReadyToRegisterNameString,
  3552. SURRAGATE_SIGNALCOMPLETE_SWITCH,
  3553. SignalRegistrationCompleteNameString );
  3554. //
  3555. // no UI
  3556. //
  3557. GetStartupInfo(&StartupInfo);
  3558. StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
  3559. StartupInfo.wShowWindow = SW_HIDE;
  3560. //
  3561. // do we need to create a new process or is our process still running?
  3562. //
  3563. // note that there is a fine race condition here where the child
  3564. // process could go away before we signal our event.
  3565. //
  3566. // I need to see how reachable that race condition is and if this needs
  3567. // to be addressed
  3568. //
  3569. if (!WowIpcData->hProcess) {
  3570. NeedToCreateProcess = TRUE;
  3571. } else if (WaitForSingleObject(WowIpcData->hProcess, 0) == WAIT_OBJECT_0) {
  3572. CloseHandle(WowIpcData->hProcess);
  3573. WowIpcData->hProcess = NULL;
  3574. NeedToCreateProcess = TRUE;
  3575. }
  3576. if (NeedToCreateProcess) {
  3577. //
  3578. // note that we just use the events we were already given, even
  3579. // if we had a process and it's gone away. Since we use GUIDs,
  3580. // we don't have to worry about any process conflicting with our
  3581. // named events, etc.
  3582. //
  3583. #ifndef _WIN64
  3584. if (IsWow64) {
  3585. //
  3586. // allow us to access 64-bit wowreg32 directly
  3587. //
  3588. Wow64DisableFilesystemRedirector(ProcessName);
  3589. }
  3590. #endif
  3591. if (! CreateProcessW(NULL,
  3592. CmdLine,
  3593. NULL,
  3594. NULL,
  3595. FALSE,
  3596. DETACHED_PROCESS|NORMAL_PRIORITY_CLASS,
  3597. NULL,
  3598. NULL,
  3599. &StartupInfo,
  3600. &ProcessInformation)) {
  3601. RetVal = FALSE;
  3602. goto e0;
  3603. }
  3604. #ifndef _WIN64
  3605. if (IsWow64) {
  3606. //
  3607. // re-enable redirection
  3608. //
  3609. Wow64EnableFilesystemRedirector();
  3610. }
  3611. #endif
  3612. //
  3613. // keep ahold of the child process handle so we can wait on it later
  3614. // on.
  3615. //
  3616. WowIpcData->hProcess = ProcessInformation.hProcess;
  3617. CloseHandle(ProcessInformation.hThread);
  3618. }
  3619. //
  3620. // we are completely initialized at this point, so fire off the surragate
  3621. // process with the appropriate parameters. It will wait until we signal
  3622. // our event before proceeding with reading the shared memory region
  3623. //
  3624. SetEvent(WowIpcData->SignalReadyToRegister);
  3625. RetVal = TRUE;
  3626. e0:
  3627. //
  3628. // if we failed to create the process, etc., then clean things up so that
  3629. // things may work better the next time around.
  3630. //
  3631. if (!RetVal) {
  3632. pSetupCleanupWowIpcStream(WowIpcData);
  3633. }
  3634. return(RetVal);
  3635. }
  3636. HANDLE
  3637. pSetupCallChildProcessForRegistration(
  3638. IN POLE_CONTROL_DATA OleControlData,
  3639. OUT PDWORD ExtendedStatus
  3640. )
  3641. /*++
  3642. Routine Description:
  3643. Procedure asks a child process to register the specified dll. If the
  3644. child process doesn't exist, it will be created.
  3645. Arguments:
  3646. OleControlData - pointer to a OLE_CONTROL_DATA structure which specifes
  3647. how the file is to be registered.
  3648. ExtendedStatus - receives a win32 error code with extended information
  3649. (if an error occurs)
  3650. Return Value:
  3651. Returns a waitable handle on success which will be signalled when
  3652. registration completes. If the registration cannot be started, the
  3653. return value is NULL.
  3654. --*/
  3655. {
  3656. PWOW_IPC_REGION_TOSURRAGATE IpcMemRegion;
  3657. PWSTR p;
  3658. //
  3659. // if the ipc mechanism isn't already initialized, then initialze it.
  3660. //
  3661. if (!OleControlData->WowIpcData->MemoryRegion) {
  3662. if (!InitializeWowIpcStream(OleControlData->WowIpcData)) {
  3663. *ExtendedStatus = GetLastError();
  3664. return NULL;
  3665. }
  3666. }
  3667. MYASSERT( OleControlData->WowIpcData->SignalReadyToRegister != NULL );
  3668. MYASSERT( OleControlData->WowIpcData->SignalRegistrationComplete != NULL );
  3669. //
  3670. // the region is initialized, so let's fill it in with the registration
  3671. // data
  3672. //
  3673. IpcMemRegion = (PWOW_IPC_REGION_TOSURRAGATE)OleControlData->WowIpcData->MemoryRegion;
  3674. wcscpy(IpcMemRegion->FullPath,OleControlData->FullPath);
  3675. if (OleControlData->Argument) {
  3676. wcscpy(IpcMemRegion->Argument,OleControlData->Argument);
  3677. } else {
  3678. IpcMemRegion->Argument[0] = UNICODE_NULL;
  3679. }
  3680. IpcMemRegion->RegType = OleControlData->RegType;
  3681. IpcMemRegion->Register = OleControlData->Register;
  3682. //
  3683. // the region is filled in, so now signal the event to tell
  3684. // the surragate to process the data
  3685. //
  3686. if (!SignalSurragateProcess(OleControlData->WowIpcData)) {
  3687. *ExtendedStatus = GetLastError();
  3688. return(NULL);
  3689. }
  3690. //
  3691. // surragate will signal below event when it completes registration
  3692. //
  3693. return(OleControlData->WowIpcData->SignalRegistrationComplete);
  3694. }
  3695. #endif
  3696. VOID
  3697. pSetupFreeOleControlData(
  3698. IN POLE_CONTROL_DATA OleControlData
  3699. )
  3700. /*++
  3701. Routine Description:
  3702. Frees the memory associated with OLE_CONTROL_DATA structure.
  3703. Arguments:
  3704. OleControlData - pointer to the OLE_CONTROL_DATA to be deallocated.
  3705. Return Value:
  3706. NONE.
  3707. --*/
  3708. {
  3709. DWORD Count;
  3710. MYASSERT(OleControlData != NULL);
  3711. if (OleControlData->Argument) {
  3712. MyFree(OleControlData->Argument);
  3713. }
  3714. if (OleControlData->FullPath) {
  3715. MyFree(OleControlData->FullPath);
  3716. }
  3717. if (OleControlData->LogContext) {
  3718. DeleteLogContext(OleControlData->LogContext);
  3719. }
  3720. //
  3721. // watch out here. this is ref-counted and we only free when the count
  3722. // reaches zero
  3723. //
  3724. if (OleControlData->Status) {
  3725. Count = InterlockedDecrement(&OleControlData->Status->RefCount);
  3726. if (Count == 0) {
  3727. MyFree(OleControlData->Status);
  3728. }
  3729. }
  3730. MyFree(OleControlData);
  3731. }
  3732. HANDLE
  3733. pSetupSpawnRegistration(
  3734. IN POLE_CONTROL_DATA OleControlData,
  3735. OUT PDWORD pHowToGetStatusLaterOn,
  3736. OUT PDWORD pExtendedStatus OPTIONAL
  3737. )
  3738. /*++
  3739. Routine Description:
  3740. This procedure determines what is the appropriate mechanism for the
  3741. specified file and kicks off registration of that file.
  3742. Arguments:
  3743. OleControlData - pointer to a OLE_CONTROL_DATA structure which specifes
  3744. how the file is to be registered.
  3745. pHowToGetStatusLaterOn - receives a DWORD constant SP_GETSTATUS_* value
  3746. which indicates how the file was registered so
  3747. that the caller can get back the appropriate
  3748. status information later on.
  3749. pExtendedStatus - receives a win32 error code with extended information
  3750. (if an error occurs)
  3751. Return Value:
  3752. Returns a waitable handle on success which will be signalled when
  3753. registration completes. If the registration cannot be started, the
  3754. return value is NULL.
  3755. --*/
  3756. {
  3757. intptr_t Thread;
  3758. DWORD ThreadId;
  3759. PCTSTR p;
  3760. BOOL ItsAnEXE;
  3761. HANDLE WaitableHandle;
  3762. DWORD ExtendedStatus;
  3763. PREF_STATUS RefStatus = OleControlData->Status;
  3764. MYASSERT(OleControlData != NULL &&
  3765. OleControlData->FullPath != NULL);
  3766. WaitableHandle = NULL;
  3767. ExtendedStatus = ERROR_SUCCESS;
  3768. if (pExtendedStatus) {
  3769. *pExtendedStatus = ERROR_SUCCESS;
  3770. }
  3771. //
  3772. // we keep a refcount on this status, and we increment it
  3773. // now to make sure that the data isn't freed prematurely
  3774. //
  3775. InterlockedIncrement(&OleControlData->Status->RefCount);
  3776. p = _tcsrchr(OleControlData->FullPath, TEXT('.'));
  3777. if (p) {
  3778. p +=1;
  3779. } else {
  3780. ExtendedStatus = ERROR_INVALID_DATA;
  3781. goto e0;
  3782. }
  3783. //
  3784. // let's determine what type of file we're dealing with
  3785. //
  3786. if (0 == _tcsicmp(p,TEXT("exe"))) {
  3787. ItsAnEXE = TRUE;
  3788. } else {
  3789. //
  3790. // let's (gulp!) assume that this is a dll,ocx, or something
  3791. // similar with some wierd extension. in any case, let's
  3792. // just put all of these in the same bucket for now. If
  3793. // it's really something bogus, then the worst that should
  3794. // happen is that the loadlibrary (in our other thread!) will
  3795. // fall over
  3796. //
  3797. ItsAnEXE = FALSE;
  3798. }
  3799. //
  3800. // if it's an exe, let's just create the process and wait on
  3801. // that handle.
  3802. //
  3803. if (ItsAnEXE) {
  3804. WaitableHandle = pSetupRegisterExe(
  3805. OleControlData,
  3806. &ExtendedStatus);
  3807. //
  3808. // we don't need OleControlData anymore, just free it here
  3809. //
  3810. pSetupFreeOleControlData(OleControlData);
  3811. *pHowToGetStatusLaterOn = SP_GETSTATUS_FROMPROCESS;
  3812. } else {
  3813. //
  3814. // we have a dll
  3815. //
  3816. //
  3817. // if we're on 64 bits, then we need to look if this dll is a
  3818. // 32 bit dll. If it is, then we need use a child process
  3819. // to register the dll. otherwise we can just treat the dll
  3820. // like "normal"
  3821. //
  3822. #ifdef CHILDREGISTRATION
  3823. if (IsThisANonNativeDll(OleControlData->FullPath)) {
  3824. WaitableHandle = pSetupCallChildProcessForRegistration(
  3825. OleControlData,
  3826. &ExtendedStatus
  3827. );
  3828. //
  3829. // we don't need OleControlData anymore, just free it here
  3830. //
  3831. pSetupFreeOleControlData(OleControlData);
  3832. *pHowToGetStatusLaterOn = SP_GETSTATUS_FROMSURRAGATE;
  3833. }
  3834. else
  3835. #endif
  3836. //
  3837. // we have a native dll.
  3838. // we handle these in another thread in case it hangs
  3839. //
  3840. {
  3841. Thread = _beginthreadex(
  3842. NULL,
  3843. 0,
  3844. pSetupRegisterUnregisterDll,
  3845. OleControlData,
  3846. 0,
  3847. &ThreadId
  3848. );
  3849. if (!Thread) {
  3850. //
  3851. // assume out of memory
  3852. //
  3853. ExtendedStatus = ERROR_NOT_ENOUGH_MEMORY;
  3854. //
  3855. // we don't need OleControlData anymore, just free it here
  3856. //
  3857. pSetupFreeOleControlData(OleControlData);
  3858. } else {
  3859. #if PRERELEASE
  3860. RefStatus->ThreadId = ThreadId;
  3861. #endif
  3862. }
  3863. WaitableHandle = (HANDLE) Thread;
  3864. *pHowToGetStatusLaterOn = SP_GETSTATUS_FROMDLL;
  3865. }
  3866. }
  3867. e0:
  3868. if (pExtendedStatus) {
  3869. *pExtendedStatus = ExtendedStatus;
  3870. }
  3871. return WaitableHandle;
  3872. }
  3873. DWORD
  3874. pSetupProcessRegSvrSection(
  3875. IN HINF Inf,
  3876. IN PCTSTR Section,
  3877. IN BOOL Register,
  3878. IN HWND hWndParent,
  3879. IN PSP_FILE_CALLBACK MsgHandler,
  3880. IN PVOID Context,
  3881. IN BOOL IsMsgHandlerNativeCharWidth,
  3882. IN BOOL RegistrationCallbackAware
  3883. )
  3884. /*++
  3885. Routine Description:
  3886. process all of the registration directives in the specefied RegisterDlls
  3887. section
  3888. each line is expected to be in the following format:
  3889. <dirid>,<subdir>,<filename>,<registration flags>,<optional timeout>,<arguments>
  3890. <dirid> supplies the base directory id of the file.
  3891. <subdir> if specified, specifies the subdir from the base directory
  3892. where the file resides
  3893. <filename> specifies the name of the file to be registered
  3894. <registration flags> specifies the registration action to be taken
  3895. FLG_REGSVR_DLLREGISTER ( 0x00000001 )
  3896. FLG_REGSVR_DLLINSTALL ( 0x00000002 )
  3897. <optional timeout> specifies how long to wait for the registration to
  3898. complete. if not specified, use the default timeout
  3899. <arguments> if specified, contains the cmdline to pass to an executable
  3900. if we're not handling an EXE, this argument is ignored
  3901. Arguments:
  3902. Inf - Inf handle for the section to be processed
  3903. Section - name of the section to be processed
  3904. Register - if TRUE, we are registering items, if FALSE, we are
  3905. unregistering. this allows the inf to share one section
  3906. for install and uninstall
  3907. hWndParent - parent window handle we use for a messagebox
  3908. MsgHandler - pointer to callback routine if we're dealing with a
  3909. "registration aware" callback
  3910. Context - context pointer for callback routine
  3911. IsMsgHandlerNativeCharWidth - indicates if message pieces need translation
  3912. RegistrationCallbackAware - indicates if the callback routine is aware of
  3913. registration callbacks
  3914. Return Value:
  3915. Win32 error code indicating outcome.
  3916. --*/
  3917. {
  3918. DWORD dircount,d = NO_ERROR;
  3919. DWORD FailureCode,Count;
  3920. INFCONTEXT InfLine;
  3921. PCTSTR DirId,Subdir,FileName, Args;
  3922. UINT RegType, Timeout;
  3923. PCTSTR FullPathTemp;
  3924. TCHAR FullPath[MAX_PATH];
  3925. TCHAR pwd[MAX_PATH];
  3926. POLE_CONTROL_DATA pOleControlData;
  3927. intptr_t Thread;
  3928. unsigned ThreadId;
  3929. DWORD WaitResult;
  3930. HANDLE SignifyRegistration;
  3931. PSETUP_LOG_CONTEXT LogContext = NULL;
  3932. DWORD log_slot = 0;
  3933. DWORD HowToGetStatus;
  3934. UINT u;
  3935. PREF_STATUS RefStatus;
  3936. PLOADED_INF pLoadedInf = NULL;
  3937. #ifdef CHILDREGISTRATION
  3938. WOWSURRAGATE_IPC WowIpcData;
  3939. #endif
  3940. #ifdef PRERELEASE
  3941. BOOL LastTimeHadTimeout = FALSE;
  3942. TCHAR LastTimeoutFileName[MAX_PATH];
  3943. DWORD DebugTraceInfo = 0; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  3944. #endif
  3945. //
  3946. // save the current directory so we can restore it later on
  3947. //
  3948. dircount = GetCurrentDirectory(MAX_PATH,pwd);
  3949. if(!dircount || (dircount >= MAX_PATH)) {
  3950. pwd[0] = 0;
  3951. }
  3952. #ifdef CHILDREGISTRATION
  3953. ZeroMemory(&WowIpcData,sizeof(WowIpcData));
  3954. #endif
  3955. try {
  3956. if(Inf == NULL || Inf == (HINF)INVALID_HANDLE_VALUE || !LockInf((PLOADED_INF)Inf)) {
  3957. d = ERROR_INVALID_PARAMETER;
  3958. leave;
  3959. }
  3960. } except(EXCEPTION_EXECUTE_HANDLER) {
  3961. d = ERROR_INVALID_PARAMETER;
  3962. }
  3963. if (d!=NO_ERROR) {
  3964. MYASSERT(d==NO_ERROR);
  3965. goto clean0;
  3966. }
  3967. pLoadedInf = (PLOADED_INF)Inf; // Inf is locked
  3968. d = InheritLogContext(pLoadedInf->LogContext,&LogContext);
  3969. if(d!=NO_ERROR) {
  3970. goto clean0;
  3971. }
  3972. log_slot = AllocLogInfoSlot(LogContext,FALSE);
  3973. //
  3974. // retrieve the items from section and process them one at a time
  3975. //
  3976. if(SetupFindFirstLine(Inf,Section,NULL,&InfLine)) {
  3977. do {
  3978. //
  3979. // retrieve pointers to the parameters for this file
  3980. //
  3981. DirId = pSetupGetField(&InfLine,1);
  3982. Subdir = pSetupGetField(&InfLine,2);
  3983. FileName = pSetupGetField(&InfLine,3);
  3984. RegType = 0;
  3985. SetupGetIntField(&InfLine,4,&RegType);
  3986. Timeout = 0;
  3987. SetupGetIntField(&InfLine,5,&Timeout);
  3988. Args = pSetupGetField(&InfLine,6);
  3989. pOleControlData = MyMalloc(sizeof(OLE_CONTROL_DATA));
  3990. if (!pOleControlData) {
  3991. d = ERROR_NOT_ENOUGH_MEMORY;
  3992. goto clean0;
  3993. }
  3994. ZeroMemory(pOleControlData,sizeof(OLE_CONTROL_DATA));
  3995. RefStatus = pOleControlData->Status = MyMalloc(sizeof(REF_STATUS));
  3996. if (!pOleControlData->Status) {
  3997. d = ERROR_NOT_ENOUGH_MEMORY;
  3998. pSetupFreeOleControlData(pOleControlData);
  3999. goto clean0;
  4000. }
  4001. ZeroMemory(pOleControlData->Status,sizeof(REF_STATUS));
  4002. InterlockedIncrement(&pOleControlData->Status->RefCount);
  4003. if (!Timeout) {
  4004. Timeout = REGISTER_WAIT_TIMEOUT_DEFAULT;
  4005. }
  4006. //
  4007. // timeout is specified in seconds, we need to convert to millseconds
  4008. //
  4009. Timeout = Timeout * TIME_SCALAR;
  4010. if(DirId && FileName) {
  4011. if(Subdir && (*Subdir == 0)) {
  4012. Subdir = NULL;
  4013. }
  4014. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: filename for file to register is %ws\n"),FileName);
  4015. WriteLogEntry(
  4016. LogContext,
  4017. log_slot,
  4018. MSG_LOG_REGISTER_PARAMS,
  4019. NULL,
  4020. Section,
  4021. DirId,
  4022. Subdir ? Subdir : TEXT(""),
  4023. Subdir ? TEXT("\\") : TEXT(""),
  4024. FileName,
  4025. RegType,
  4026. Timeout/TIME_SCALAR);
  4027. try {
  4028. #ifdef PRERELEASE
  4029. DebugTraceInfo |= 2; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4030. #endif
  4031. //
  4032. // Get full path to the file
  4033. //
  4034. if(FullPathTemp = pGetPathFromDirId(DirId,Subdir,pLoadedInf)) {
  4035. #ifdef PRERELEASE
  4036. DebugTraceInfo |= 4; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4037. #endif
  4038. lstrcpyn(FullPath,FullPathTemp,MAX_PATH);
  4039. SetCurrentDirectory(FullPath);
  4040. pSetupConcatenatePaths(FullPath,FileName,MAX_PATH,NULL);
  4041. #ifdef PRERELEASE
  4042. DebugTraceInfo |= 8; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4043. #endif
  4044. //
  4045. // We key off the global "don't verify INFs" flag to
  4046. // indicate whether crypto support is available yet. We
  4047. // don't want to complain about registering unsigned DLLs
  4048. // when those DLLs are the ones necessary to enable crypto
  4049. // (e.g., rsaenh.dll, rsaaes.dll, dssenh.dll, initpki.dll)
  4050. //
  4051. if(!(GlobalSetupFlags & PSPGF_NO_VERIFY_INF)) {
  4052. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform = NULL;
  4053. PTSTR LocalDeviceDesc = NULL;
  4054. #ifdef PRERELEASE
  4055. DebugTraceInfo |= 8; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4056. #endif
  4057. //
  4058. // Verify the digital signature for the file we're
  4059. // about to register/unregister. We use a policy of
  4060. // "Ignore" so that unsigned files will silently be
  4061. // processed (with logging) except for the case when
  4062. // we're in non-interactive mode.
  4063. //
  4064. // (First, retrieve validation information relevant to
  4065. // this device setup class.)
  4066. //
  4067. IsInfForDeviceInstall(LogContext,
  4068. NULL,
  4069. pLoadedInf,
  4070. &LocalDeviceDesc,
  4071. &ValidationPlatform,
  4072. NULL,
  4073. NULL
  4074. );
  4075. d = _VerifyFile(LogContext,
  4076. NULL,
  4077. NULL,
  4078. NULL,
  4079. NULL,
  4080. 0,
  4081. pSetupGetFileTitle(FullPath),
  4082. FullPath,
  4083. NULL,
  4084. NULL,
  4085. FALSE,
  4086. ValidationPlatform,
  4087. (VERIFY_FILE_USE_OEM_CATALOGS | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4088. NULL,
  4089. NULL,
  4090. NULL,
  4091. NULL
  4092. );
  4093. if(d != NO_ERROR) {
  4094. if(pSetupHandleFailedVerification(
  4095. hWndParent,
  4096. SetupapiVerifyRegSvrFileProblem,
  4097. FullPath,
  4098. LocalDeviceDesc,
  4099. DRIVERSIGN_NONE,
  4100. TRUE,
  4101. d,
  4102. LogContext,
  4103. NULL,
  4104. NULL)) {
  4105. //
  4106. // We can continue on registering the file, even
  4107. // though it's unsigned.
  4108. //
  4109. d = NO_ERROR;
  4110. }
  4111. }
  4112. #ifdef PRERELEASE
  4113. DebugTraceInfo |= 0x10; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4114. #endif
  4115. //
  4116. // Free buffers we may have retrieved when calling
  4117. // IsInfForDeviceInstall().
  4118. //
  4119. if(LocalDeviceDesc) {
  4120. MyFree(LocalDeviceDesc);
  4121. }
  4122. if(ValidationPlatform) {
  4123. MyFree(ValidationPlatform);
  4124. }
  4125. if(d != NO_ERROR) {
  4126. //
  4127. // We need to abort the registration...
  4128. //
  4129. MyFree(FullPathTemp);
  4130. pSetupFreeOleControlData(pOleControlData);
  4131. leave;
  4132. }
  4133. #ifdef PRERELEASE
  4134. DebugTraceInfo |= 0x20; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4135. #endif
  4136. } else {
  4137. //
  4138. // Our global flag indicates crypto support isn't
  4139. // available yet. Log an entry indicating we skipped
  4140. // digital signature verification for this file.
  4141. //
  4142. WriteLogEntry(LogContext,
  4143. SETUP_LOG_WARNING,
  4144. (Register
  4145. ? MSG_LOG_REGSVR_FILE_VERIFICATION_SKIPPED
  4146. : MSG_LOG_UNREGSVR_FILE_VERIFICATION_SKIPPED),
  4147. NULL,
  4148. FullPath
  4149. );
  4150. }
  4151. pOleControlData->Register = Register;
  4152. pOleControlData->FullPath = DuplicateString(FullPath);
  4153. #ifdef PRERELEASE
  4154. DebugTraceInfo |= 0x40; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4155. #endif
  4156. if (!pOleControlData->FullPath) {
  4157. MyFree(FullPathTemp);
  4158. d = ERROR_NOT_ENOUGH_MEMORY;
  4159. pSetupFreeOleControlData(pOleControlData);
  4160. leave;
  4161. }
  4162. #ifdef CHILDREGISTRATION
  4163. pOleControlData->WowIpcData = &WowIpcData;
  4164. #endif
  4165. pOleControlData->RegType = RegType;
  4166. pOleControlData->Argument = Args
  4167. ? DuplicateString(Args)
  4168. : NULL;
  4169. if (Args && !pOleControlData->Argument) {
  4170. MyFree(FullPathTemp);
  4171. d = ERROR_NOT_ENOUGH_MEMORY;
  4172. pSetupFreeOleControlData(pOleControlData);
  4173. goto clean0;
  4174. }
  4175. InheritLogContext(LogContext,&pOleControlData->LogContext);
  4176. if (RegistrationCallbackAware && MsgHandler) {
  4177. //
  4178. // Inform the callback that we are about to start
  4179. // a registration operation, giving it the chance
  4180. // to abort if it wants to.
  4181. //
  4182. SP_REGISTER_CONTROL_STATUS ControlStatus;
  4183. ZeroMemory(
  4184. &ControlStatus,
  4185. sizeof(SP_REGISTER_CONTROL_STATUS));
  4186. ControlStatus.cbSize = sizeof(SP_REGISTER_CONTROL_STATUS);
  4187. ControlStatus.FileName = FullPath;
  4188. u = pSetupCallMsgHandler(
  4189. LogContext,
  4190. MsgHandler,
  4191. IsMsgHandlerNativeCharWidth,
  4192. Context,
  4193. SPFILENOTIFY_STARTREGISTRATION,
  4194. (UINT_PTR)&ControlStatus,
  4195. Register
  4196. );
  4197. } else {
  4198. //
  4199. // not registration aware, assume a default
  4200. //
  4201. #ifdef PRERELEASE
  4202. DebugTraceInfo |= 0x80; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4203. #endif
  4204. u = FILEOP_DOIT;
  4205. }
  4206. if(u == FILEOP_ABORT) {
  4207. #ifdef PRERELEASE
  4208. DebugTraceInfo |= 0x100; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4209. #endif
  4210. d = GetLastError();
  4211. if (d==NO_ERROR) {
  4212. d = ERROR_OPERATION_ABORTED;
  4213. }
  4214. WriteLogEntry(
  4215. LogContext,
  4216. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  4217. MSG_LOG_STARTREGISTRATION_ABORT,
  4218. NULL);
  4219. WriteLogError(
  4220. LogContext,
  4221. SETUP_LOG_ERROR,
  4222. d
  4223. );
  4224. pSetupFreeOleControlData(pOleControlData);
  4225. MyFree(FullPathTemp);
  4226. goto clean0;
  4227. } else if (u == FILEOP_SKIP) {
  4228. #ifdef PRERELEASE
  4229. DebugTraceInfo |= 0x200; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4230. #endif
  4231. WriteLogEntry(
  4232. LogContext,
  4233. SETUP_LOG_WARNING,
  4234. MSG_LOG_STARTREGISTRATION_SKIP,
  4235. NULL
  4236. );
  4237. pSetupFreeOleControlData(pOleControlData);
  4238. //
  4239. // set to NULL so we don't try to free it later
  4240. //
  4241. RefStatus = NULL;
  4242. } else if(u == FILEOP_DOIT) {
  4243. //
  4244. // Attempt the registration and inform the callback,
  4245. //
  4246. DWORD ExtendedError;
  4247. #ifdef PRERELEASE
  4248. DebugTraceInfo |= 0x200; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4249. #endif
  4250. #ifdef PRERELEASE
  4251. ASSERT_HEAP_IS_VALID();
  4252. #endif
  4253. SignifyRegistration = pSetupSpawnRegistration(
  4254. pOleControlData,
  4255. &HowToGetStatus,
  4256. &ExtendedError );
  4257. #ifdef PRERELEASE
  4258. DebugTraceInfo |= 0x1000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4259. #endif
  4260. if(SignifyRegistration) {
  4261. HANDLE hEvents[1];
  4262. int CurEvent = 0;
  4263. //
  4264. // wait until thread has done a minimal amount of work
  4265. // when this work is done, we can re-use or trash this structure
  4266. // and we know timeout for this thread
  4267. //
  4268. hEvents[0] = (HANDLE)SignifyRegistration;
  4269. do {
  4270. WaitResult = MyMsgWaitForMultipleObjectsEx(
  4271. 1,
  4272. &hEvents[0],
  4273. Timeout,
  4274. QS_ALLINPUT,
  4275. MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
  4276. #ifdef PRERELEASE
  4277. DebugTraceInfo |= 0x2000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4278. #endif
  4279. if (WaitResult == WAIT_OBJECT_0 + 1) {
  4280. MSG msg;
  4281. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  4282. TranslateMessage(&msg);
  4283. DispatchMessage(&msg);
  4284. }
  4285. }
  4286. } while(WaitResult != WAIT_TIMEOUT &&
  4287. WaitResult != WAIT_OBJECT_0 &&
  4288. WaitResult != WAIT_FAILED);
  4289. #ifdef PRERELEASE
  4290. DebugTraceInfo |= 0x4000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4291. #endif
  4292. if (WaitResult == WAIT_TIMEOUT) {
  4293. #ifdef PRERELEASE
  4294. if (HowToGetStatus == SP_GETSTATUS_FROMDLL) {
  4295. int __pass;
  4296. for(__pass = 0;__pass < 2;__pass ++) {
  4297. //
  4298. // All stop so this can get debugged
  4299. //
  4300. DebugPrintEx(
  4301. DPFLTR_ERROR_LEVEL,
  4302. TEXT("Windows has detected that\n")
  4303. TEXT("Registration of \"%s\" appears to have hung\n")
  4304. TEXT("Contact owner of the hung DLL to diagnose\n")
  4305. TEXT("Timeout for DLL was set to %u seconds\n")
  4306. TEXT("ThreadID of hung DLL is %u (0x%x)\n%s"),
  4307. FullPath,
  4308. Timeout/TIME_SCALAR,
  4309. RefStatus->ThreadId,RefStatus->ThreadId,
  4310. ((__pass==0) ? TEXT("Hitting 'g' will display this again\n") : TEXT(""))
  4311. );
  4312. DebugBreak();
  4313. }
  4314. }
  4315. #endif
  4316. //
  4317. // the ole registration is hung
  4318. // log an error
  4319. //
  4320. WriteLogEntry(
  4321. LogContext,
  4322. SETUP_LOG_ERROR,
  4323. MSG_LOG_OLE_REGISTRATION_HUNG,
  4324. NULL,
  4325. FullPath
  4326. );
  4327. d = WAIT_TIMEOUT;
  4328. FailureCode = SPREG_TIMEOUT;
  4329. #ifdef PRERELEASE
  4330. //
  4331. // This is to catch setup errors
  4332. // and does not indicate an error
  4333. // in SetupAPI
  4334. //
  4335. if (LastTimeHadTimeout) {
  4336. #ifdef CHILDREGISTRATION
  4337. if (HowToGetStatus == SP_GETSTATUS_FROMSURRAGATE) {
  4338. DebugPrintEx(
  4339. DPFLTR_ERROR_LEVEL,
  4340. #ifdef _WIN64
  4341. TEXT("Windows has detected that ")
  4342. TEXT("32-bit WOWREG32 has timed out while registering \"%s\". ")
  4343. TEXT("Prior to this, \"%s\" timed out. ")
  4344. TEXT("This may indicate a persistent error. ")
  4345. TEXT("To diagnose, try to ")
  4346. TEXT("register them by hand or contact ")
  4347. TEXT("the owners of these files ")
  4348. TEXT("to determine why they are timing out. ")
  4349. TEXT("also try running other 32-bit executables.\n"),
  4350. #else
  4351. TEXT("Windows has detected that ")
  4352. TEXT("64-bit WOWREG32 has timed out while registering \"%s\". ")
  4353. TEXT("Prior to this, \"%s\" timed out. ")
  4354. TEXT("This may indicate a persistent error. ")
  4355. TEXT("To diagnose, try to ")
  4356. TEXT("register them by hand or contact ")
  4357. TEXT("the owners of these files ")
  4358. TEXT("to determine why they are timing out. ")
  4359. TEXT("also try running other 64-bit executables.\n"),
  4360. #endif
  4361. FileName,
  4362. LastTimeoutFileName
  4363. );
  4364. } else {
  4365. #endif
  4366. DebugPrintEx(
  4367. DPFLTR_ERROR_LEVEL,
  4368. TEXT("Windows has detected that ")
  4369. TEXT("the registration of \"%s\" timed out. ")
  4370. TEXT("Prior to this, \"%s\" timed out. ")
  4371. TEXT("This may indicate a persistent error. ")
  4372. TEXT("To diagnose, try to ")
  4373. TEXT("register them by hand or contact ")
  4374. TEXT("the owners of these files ")
  4375. TEXT("to determine why they are timing out.\n"),
  4376. FileName,
  4377. LastTimeoutFileName
  4378. );
  4379. #ifdef CHILDREGISTRATION
  4380. }
  4381. #endif
  4382. DebugBreak();
  4383. }
  4384. LastTimeHadTimeout = TRUE;
  4385. lstrcpyn(LastTimeoutFileName,FileName,MAX_PATH);
  4386. #endif
  4387. #ifdef CHILDREGISTRATION
  4388. if (HowToGetStatus == SP_GETSTATUS_FROMSURRAGATE) {
  4389. //
  4390. // we have no choice but to abandon the process
  4391. //
  4392. pSetupCleanupWowIpcStream(&WowIpcData);
  4393. //
  4394. // set our handle to NULL so we don't
  4395. // accidentally close it
  4396. //
  4397. SignifyRegistration = NULL;
  4398. }
  4399. #endif
  4400. } else {
  4401. #ifdef PRERELEASE
  4402. LastTimeHadTimeout = FALSE;
  4403. #endif
  4404. switch(HowToGetStatus) {
  4405. case SP_GETSTATUS_FROMDLL:
  4406. #ifdef PRERELEASE
  4407. DebugTraceInfo |= 0x10000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4408. #endif
  4409. GetExitCodeThread(SignifyRegistration,&d);
  4410. FailureCode = RefStatus->ExtendedStatus;
  4411. break;
  4412. #ifdef CHILDREGISTRATION
  4413. case SP_GETSTATUS_FROMSURRAGATE:
  4414. #ifdef PRERELEASE
  4415. DebugTraceInfo |= 0x20000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4416. #endif
  4417. //
  4418. // get the status code from the shared
  4419. // memory region
  4420. //
  4421. MYASSERT(WowIpcData.MemoryRegion != NULL);
  4422. d = ((PWOW_IPC_REGION_FROMSURRAGATE)WowIpcData.MemoryRegion)->Win32Error;
  4423. FailureCode = ((PWOW_IPC_REGION_FROMSURRAGATE)WowIpcData.MemoryRegion)->FailureCode;
  4424. //
  4425. // reset the "it's complete" event so
  4426. // we don't loop on it.
  4427. //
  4428. ResetEvent(WowIpcData.SignalRegistrationComplete);
  4429. //
  4430. // set the handle to NULL so we don't
  4431. // accidentally close it
  4432. //
  4433. SignifyRegistration = NULL;
  4434. break;
  4435. #endif
  4436. case SP_GETSTATUS_FROMPROCESS:
  4437. #ifdef PRERELEASE
  4438. DebugTraceInfo |= 0x40000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4439. #endif
  4440. GetExitCodeProcess(SignifyRegistration,&d);
  4441. FailureCode = SPREG_SUCCESS;
  4442. d = NO_ERROR;
  4443. break;
  4444. default:
  4445. MYASSERT(FALSE);
  4446. }
  4447. }
  4448. #ifdef PRERELEASE
  4449. DebugTraceInfo |= 0x80000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4450. #endif
  4451. if (SignifyRegistration) {
  4452. CloseHandle( SignifyRegistration );
  4453. }
  4454. #ifdef PRERELEASE
  4455. DebugTraceInfo |= 0x100000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4456. #endif
  4457. } else {
  4458. //
  4459. // the dll spawning failed.
  4460. // let's go onto the next one
  4461. //
  4462. d = ExtendedError;
  4463. FailureCode = SPREG_UNKNOWN;
  4464. }
  4465. #ifdef PRERELEASE
  4466. DebugTraceInfo |= 0x200000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4467. #endif
  4468. // make sure the dll, etc., didn't corrupt the heap
  4469. ASSERT_HEAP_IS_VALID();
  4470. if(d) {
  4471. WriteLogEntry(
  4472. LogContext,
  4473. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  4474. MSG_LOG_REGISTRATION_FAILED,
  4475. NULL,
  4476. FullPath
  4477. );
  4478. WriteLogError(
  4479. LogContext,
  4480. SETUP_LOG_ERROR,
  4481. d
  4482. );
  4483. }
  4484. if (RegistrationCallbackAware && MsgHandler) {
  4485. SP_REGISTER_CONTROL_STATUS ControlStatus;
  4486. #ifdef PRERELEASE
  4487. DebugTraceInfo |= 0x400000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4488. #endif
  4489. ZeroMemory(
  4490. &ControlStatus,
  4491. sizeof(SP_REGISTER_CONTROL_STATUS));
  4492. ControlStatus.cbSize = sizeof(SP_REGISTER_CONTROL_STATUS);
  4493. ControlStatus.FileName = FullPath;
  4494. ControlStatus.Win32Error = d;
  4495. ControlStatus.FailureCode = FailureCode;
  4496. u = pSetupCallMsgHandler(
  4497. LogContext,
  4498. MsgHandler,
  4499. IsMsgHandlerNativeCharWidth,
  4500. Context,
  4501. SPFILENOTIFY_ENDREGISTRATION,
  4502. (UINT_PTR)&ControlStatus,
  4503. Register );
  4504. #ifdef PRERELEASE
  4505. DebugTraceInfo |= 0x800000; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4506. #endif
  4507. if (u == FILEOP_ABORT) {
  4508. d = GetLastError();
  4509. if (d==NO_ERROR) {
  4510. d = ERROR_OPERATION_ABORTED;
  4511. }
  4512. WriteLogEntry(
  4513. LogContext,
  4514. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  4515. MSG_LOG_ENDREGISTRATION_ABORT,
  4516. NULL);
  4517. WriteLogError(
  4518. LogContext,
  4519. SETUP_LOG_ERROR,
  4520. d
  4521. );
  4522. //
  4523. // need a refcount on this cause we will free this if the
  4524. // child thread has timed out (or if we never had a thread
  4525. // this will just be deallocated).
  4526. //
  4527. Count = InterlockedDecrement(&RefStatus->RefCount);
  4528. if (!Count) {
  4529. MyFree(RefStatus);
  4530. }
  4531. MyFree(FullPathTemp);
  4532. goto clean0;
  4533. } else {
  4534. //
  4535. // the callback indicated that it saw any error
  4536. // which occurred and it wants to continue, so
  4537. // reset the error code to "none" so that we
  4538. // continue processing items in this section.
  4539. //
  4540. d = NO_ERROR;
  4541. }
  4542. }
  4543. } else {
  4544. #ifdef PRERELEASE
  4545. DebugTraceInfo |= 0x400; // ISSUE-JamieHun-2001/01/29 attempt to catch a strange stress break
  4546. #endif
  4547. pSetupFreeOleControlData(pOleControlData);
  4548. //
  4549. // set to NULL so we don't try to free it later
  4550. //
  4551. RefStatus = NULL;
  4552. }
  4553. //
  4554. // need a refcount on this cause we will free this if the
  4555. // child thread has timed out (or if we never had a thread
  4556. // this will just be deallocated).
  4557. //
  4558. if (RefStatus) {
  4559. Count = InterlockedDecrement(&RefStatus->RefCount);
  4560. if (!Count) {
  4561. MyFree(RefStatus);
  4562. }
  4563. }
  4564. MyFree(FullPathTemp);
  4565. }
  4566. #ifdef PRERELEASE
  4567. DebugTraceInfo = 1; // attempt to catch a strange stress break
  4568. #endif
  4569. d = NO_ERROR;
  4570. } except(EXCEPTION_EXECUTE_HANDLER) {
  4571. MYASSERT(FALSE && "Exception taken during register/unregister");
  4572. d = ERROR_INVALID_DATA;
  4573. }
  4574. } else {
  4575. DebugPrintEx(DPFLTR_TRACE_LEVEL,TEXT("SETUP: dll skipped, bad dirid\n"));
  4576. WriteLogEntry(
  4577. LogContext,
  4578. SETUP_LOG_ERROR,
  4579. MSG_LOG_CANT_OLE_CONTROL_DIRID,
  4580. NULL,
  4581. FileName,
  4582. DirId
  4583. );
  4584. d = ERROR_INVALID_DATA;
  4585. }
  4586. } while(SetupFindNextLine(&InfLine,&InfLine) && d == NO_ERROR);
  4587. } else {
  4588. WriteLogEntry(
  4589. LogContext,
  4590. SETUP_LOG_ERROR,
  4591. MSG_LOG_NOSECTION_MIN,
  4592. NULL,
  4593. Section,
  4594. ((PLOADED_INF) Inf)->OriginalInfName
  4595. );
  4596. d = ERROR_INVALID_DATA;
  4597. }
  4598. //
  4599. // cleanup
  4600. //
  4601. clean0:
  4602. #ifdef CHILDREGISTRATION
  4603. pSetupCleanupWowIpcStream(&WowIpcData);
  4604. #endif
  4605. if(log_slot) {
  4606. ReleaseLogInfoSlot(LogContext,log_slot);
  4607. }
  4608. if(LogContext) {
  4609. DeleteLogContext(LogContext); // this is ref-counted
  4610. }
  4611. if(pLoadedInf) {
  4612. UnlockInf(pLoadedInf);
  4613. }
  4614. //
  4615. // put back the current working directory
  4616. //
  4617. if (pwd && pwd[0]) {
  4618. SetCurrentDirectory(pwd);
  4619. }
  4620. return d;
  4621. }
  4622. DWORD
  4623. pSetupInstallRegisterUnregisterDlls(
  4624. IN HINF Inf,
  4625. IN PCTSTR SectionName,
  4626. IN BOOL Register,
  4627. IN HWND hWndParent,
  4628. IN PSP_FILE_CALLBACK Callback,
  4629. IN PVOID Context,
  4630. IN BOOL IsMsgHandlerNativeCharWidth,
  4631. IN BOOL RegistrationCallbackAware
  4632. )
  4633. /*++
  4634. Routine Description:
  4635. Locate the RegisterDlls= lines in an install section
  4636. and process each section listed therein.
  4637. Arguments:
  4638. Inf - supplies inf handle for inf containing the section indicated
  4639. by SectionName.
  4640. SectionName - supplies name of install section.
  4641. Register - TRUE if register, FALSE if unregister
  4642. hWndParent - parent window handle
  4643. Callback - pointer to queue callback routine
  4644. Context - context pointer for callback routine
  4645. IsMsgHandlerNativeCharWidth - indicates if message pieces need translation
  4646. RegistrationCallbackAware - indicates if callback routine wants to receive
  4647. registration callback notifications
  4648. Return Value:
  4649. Win32 error code indicating outcome.
  4650. --*/
  4651. {
  4652. DWORD d = NO_ERROR;
  4653. INFCONTEXT LineContext;
  4654. DWORD Field, FieldCount;
  4655. PCTSTR SectionSpec;
  4656. //
  4657. // Find the RegisterDlls line in the given install section.
  4658. // If not present then we're done with this operation.
  4659. //
  4660. if(!SetupFindFirstLine( Inf
  4661. , SectionName
  4662. , Register? pszRegSvr : pszUnRegSvr
  4663. , &LineContext )) {
  4664. DWORD rc = GetLastError();
  4665. if((rc != NO_ERROR) && (rc != ERROR_SECTION_NOT_FOUND) && (rc != ERROR_LINE_NOT_FOUND)) {
  4666. pSetupLogSectionError(Inf,NULL,NULL,NULL,SectionName,MSG_LOG_INSTALLSECT_ERROR,rc,NULL);
  4667. }
  4668. SetLastError(NO_ERROR); // for compatibility with older versions of SetupAPI
  4669. return NO_ERROR;
  4670. }
  4671. do {
  4672. //
  4673. // Each value on the line in the given install section
  4674. // is the name of another section.
  4675. //
  4676. FieldCount = SetupGetFieldCount(&LineContext);
  4677. for(Field=1; d == NO_ERROR && (Field<=FieldCount); Field++) {
  4678. if(SectionSpec = pSetupGetField(&LineContext,Field)) {
  4679. if(SetupGetLineCount(Inf,SectionSpec) > 0) {
  4680. //
  4681. // The section exists and is not empty.
  4682. // So process it.
  4683. //
  4684. d = pSetupProcessRegSvrSection(
  4685. Inf,
  4686. SectionSpec,
  4687. Register,
  4688. hWndParent,
  4689. Callback,
  4690. Context,
  4691. IsMsgHandlerNativeCharWidth,
  4692. RegistrationCallbackAware);
  4693. if(d!=NO_ERROR) {
  4694. pSetupLogSectionError(Inf,NULL,NULL,NULL,SectionSpec,MSG_LOG_SECT_ERROR,d,Register? pszRegSvr : pszUnRegSvr);
  4695. }
  4696. }
  4697. }
  4698. }
  4699. } while(SetupFindNextMatchLine( &LineContext
  4700. , Register? pszRegSvr : pszUnRegSvr
  4701. , &LineContext));
  4702. SetLastError(d);
  4703. return d;
  4704. }
  4705. #ifndef ANSI_SETUPAPI
  4706. BOOL
  4707. pSetupProcessProfileSection(
  4708. IN HINF Inf,
  4709. IN PCTSTR Section
  4710. )
  4711. /*
  4712. Routine Description :
  4713. process all the directives specified in this single ProfileItems section . This section can have the following
  4714. directives in the listed format
  4715. [SectionX]
  4716. Name = <Name> (as appears in Start Menu), <Flags>, <CSIDL>
  4717. SubDir = <subdir>
  4718. CmdLine = <dirid>,<subdirectory>,<filename>, <args>
  4719. IconPath = <dirid>,<subdirectory>,<filename>
  4720. IconIndex = <index>
  4721. WorkingDir = <dirid>,<subdirectory>
  4722. HotKey = <hotkey>
  4723. InfoTip = <infotip>
  4724. DisplayResource = <dllname>,<resid>
  4725. Comments on the various parameters -
  4726. By default all links are created under Start Menu\Programs. This can be over-ridden by using CSIDLs.
  4727. Flags - can be specified by ORing the necessary flags - OPTIONAL
  4728. FLG_PROFITEM_CURRENTUSER ( 0x00000001 ) - Operates on item in the current user's profile (Default is All User)
  4729. FLG_PROFITEM_DELETE ( 0x00000002 ) - Operation is to delete the item (Default is to add)
  4730. FLG_PROFITEM_GROUP ( 0x00000004 ) - Operation is on a group (Default is on a item)
  4731. FLG_PROFITEM_CSIDL ( 0x00000008 ) - Don't default to Start Menu and use CSIDL specified - default CSIDL is 0
  4732. CSIDL - Used with FLG_PROFITEM_CSIDL and should be in decimal. OPTIONAL
  4733. Note: Will not work with FLG_PROFITEM_CURRENTUSER or FLG_PROFITEM_GROUP.
  4734. subdir - Specify a subdirectory relative to the CSIDL group (default CSIDL group is Programs/StartMenu. OPTIONAL
  4735. CmdLine - Required in the case of add operations but not for delete.
  4736. dirid - supplies the base directory id of the file. (Required if CmdLine exists)
  4737. subdir - if specified, is the sub directory off the base directory where the file resides (Optional)
  4738. filename - specifies the name of the binary that we are creating a link for. (Required if CmdLine exists)
  4739. args - If we need to specif a binary that contains spaces in its name then this can be used for args. (Optional)
  4740. IconPath - Optional. If not specified will default to NULL
  4741. dirid - supplies the base directory id of the file that contains the icon. (Required if IconPath exists)
  4742. subdir - if specified, is the sub directory off the base directory where the file resides (Optional)
  4743. filename - specifies the name of the binary that contains the icon. (Required if IconPath exists)
  4744. IconIndex - Optional, defaults to 0
  4745. index - index of the icon in the executable. Default is 0. (Optional)
  4746. WorkingDir - Optional
  4747. dirid - supplies the base directory id of the working directory as needed by the shell. (Required if WorkingDir exists)
  4748. subdir - if specified, is the sub directory off the base working directory (Optional)
  4749. HotKey - Optional
  4750. hotkey - hotkey code (optional)
  4751. InfoTip - Optional
  4752. infotip - String that contains description of the link
  4753. DisplayResource - Optional
  4754. filename - File, DLL/Executable where resource id resides
  4755. resid - Identifier of resource, integer
  4756. */
  4757. {
  4758. PCTSTR Keys[9] = { TEXT("Name"), TEXT("SubDir"), TEXT("CmdLine"), TEXT("IconPath"), \
  4759. TEXT("IconIndex"), TEXT("WorkingDir"),TEXT("HotKey"), \
  4760. TEXT("InfoTip"), TEXT("DisplayResource") };
  4761. INFCONTEXT InfLine;
  4762. UINT Flags, Opt_csidl, i, j, Apply_csidl;
  4763. TCHAR CmdLine[MAX_PATH+2], IconPath[MAX_PATH+2];
  4764. PCTSTR Name = NULL, SubDir=NULL;
  4765. PCTSTR WorkingDir=NULL, InfoTip=NULL, Temp_Args=NULL, BadInf;
  4766. PCTSTR Temp_DirId = NULL, Temp_Subdir = NULL, Temp_Filename = NULL, FullPathTemp = NULL;
  4767. UINT IconIndex = 0, t=0;
  4768. DWORD HotKey = 0;
  4769. DWORD DisplayResource = 0;
  4770. BOOL ret, space;
  4771. DWORD LineCount,Err;
  4772. PTSTR ptr;
  4773. PCTSTR OldFileName;
  4774. PCTSTR DisplayResourceFile = NULL;
  4775. PLOADED_INF pLoadedInf = NULL;
  4776. CmdLine[0]=0;
  4777. IconPath[0]=0;
  4778. try {
  4779. if(Inf == NULL || Inf == (HINF)INVALID_HANDLE_VALUE || !LockInf((PLOADED_INF)Inf)) {
  4780. ret = FALSE;
  4781. leave;
  4782. }
  4783. ret = TRUE;
  4784. } except(EXCEPTION_EXECUTE_HANDLER) {
  4785. ret = FALSE;
  4786. }
  4787. if (!ret) {
  4788. Err = ERROR_INVALID_PARAMETER;
  4789. MYASSERT(Err == NO_ERROR);
  4790. goto clean0;
  4791. }
  4792. pLoadedInf = (PLOADED_INF)Inf; // Inf is locked
  4793. //
  4794. // Get the correct name of the inf to use while logging
  4795. //
  4796. BadInf = pLoadedInf->OriginalInfName ? pLoadedInf->OriginalInfName :
  4797. pLoadedInf->VersionBlock.Filename;
  4798. if(SetupFindFirstLine(Inf,Section,NULL,&InfLine)) {
  4799. LineCount = SetupGetLineCount(Inf, Section);
  4800. //
  4801. // caller should make sure we have a non-empty section
  4802. //
  4803. MYASSERT( LineCount > 0 );
  4804. ret = FALSE;
  4805. for( i=0; LineCount && (i < 9 ); i++ ){
  4806. if( !SetupFindFirstLine( Inf, Section, Keys[i], &InfLine ) )
  4807. continue;
  4808. switch( i ){
  4809. // Name
  4810. case 0:
  4811. Name = pSetupGetField( &InfLine, 1 );
  4812. Flags = 0x0;
  4813. SetupGetIntField( &InfLine, 2, &Flags );
  4814. Opt_csidl = 0x0;
  4815. if(Flags & FLG_PROFITEM_CSIDL)
  4816. SetupGetIntField( &InfLine, 3, &Opt_csidl );
  4817. break;
  4818. case 1: // SubDir
  4819. SubDir = pSetupGetField( &InfLine, 1 );
  4820. break;
  4821. // CmdLine
  4822. case 2:
  4823. Temp_DirId = pSetupGetField( &InfLine, 1 );
  4824. Temp_Subdir = pSetupGetField( &InfLine, 2 );
  4825. Temp_Filename = pSetupGetField( &InfLine, 3 );
  4826. OldFileName = NULL;
  4827. Temp_Args = pSetupGetField( &InfLine, 4 ); //Not published - useful in the case of spaces in filename itself
  4828. if( Temp_DirId && Temp_Filename ){
  4829. if( Temp_Subdir && (*Temp_Subdir == 0))
  4830. Temp_Subdir = NULL;
  4831. }
  4832. else
  4833. break;
  4834. // Do the "quote or not to quote" to make shell happy in the different cases
  4835. FullPathTemp = pGetPathFromDirId(Temp_DirId,Temp_Subdir,pLoadedInf);
  4836. if( FullPathTemp && Temp_Filename ){
  4837. space = FALSE;
  4838. if(_tcschr(FullPathTemp, TEXT(' ')) || Temp_Args ) //Check for space in path or if args specified as seperate parameter
  4839. space = TRUE;
  4840. if( space ){
  4841. CmdLine[0] = TEXT('\"');
  4842. t = 1;
  4843. }
  4844. else
  4845. t = 0;
  4846. lstrcpyn(CmdLine+t, FullPathTemp, MAX_PATH);
  4847. if( space ){
  4848. if( Temp_Args )
  4849. ptr = (PTSTR)Temp_Args;
  4850. else{
  4851. ptr = NULL;
  4852. //
  4853. // Temp_Filename is a constant string. we
  4854. // make a copy of it so we can manipulate it
  4855. //
  4856. //
  4857. OldFileName = Temp_Filename;
  4858. Temp_Filename = DuplicateString( OldFileName );
  4859. if( ptr = _tcschr(Temp_Filename, TEXT(' ')) ){ //in case of space in path look for the filename part (not argument)
  4860. *ptr = 0;
  4861. ptr++;
  4862. }
  4863. }
  4864. }
  4865. pSetupConcatenatePaths(CmdLine,Temp_Filename,MAX_PATH,NULL);
  4866. if( space ){
  4867. lstrcat( CmdLine, TEXT("\"")); //put the last quote
  4868. if( ptr ){ //If there is an argument concatenate it
  4869. lstrcat( CmdLine, TEXT(" ") );
  4870. lstrcat( CmdLine, ptr );
  4871. }
  4872. }
  4873. MyFree( FullPathTemp );
  4874. if (OldFileName) {
  4875. MyFree( Temp_Filename );
  4876. Temp_Filename = OldFileName;
  4877. }
  4878. }
  4879. break;
  4880. //Icon Path
  4881. case 3:
  4882. Temp_DirId = pSetupGetField( &InfLine, 1 );
  4883. Temp_Subdir = pSetupGetField( &InfLine, 2 );
  4884. Temp_Filename = pSetupGetField( &InfLine, 3 );
  4885. if( Temp_DirId && Temp_Filename ){
  4886. if( Temp_Subdir && (*Temp_Subdir == 0))
  4887. Temp_Subdir = NULL;
  4888. }
  4889. else
  4890. break;
  4891. FullPathTemp = pGetPathFromDirId(Temp_DirId,Temp_Subdir,pLoadedInf);
  4892. if( FullPathTemp && Temp_Filename ){
  4893. lstrcpyn(IconPath, FullPathTemp, MAX_PATH);
  4894. pSetupConcatenatePaths(IconPath,Temp_Filename,MAX_PATH,NULL);
  4895. MyFree( FullPathTemp );
  4896. }
  4897. break;
  4898. case 4: //Icon Index
  4899. SetupGetIntField( &InfLine, 1, &IconIndex );
  4900. break;
  4901. case 5: // Working Dir
  4902. Temp_DirId = pSetupGetField( &InfLine, 1 );
  4903. Temp_Subdir = pSetupGetField( &InfLine, 2 );
  4904. if( Temp_DirId ){
  4905. if( Temp_Subdir && (*Temp_Subdir == 0))
  4906. Temp_Subdir = NULL ;
  4907. }
  4908. else
  4909. break;
  4910. WorkingDir = pGetPathFromDirId(Temp_DirId,Temp_Subdir,pLoadedInf);
  4911. break;
  4912. case 6: // Hot Key
  4913. HotKey = 0;
  4914. SetupGetIntField( &InfLine, 1, &HotKey );
  4915. break;
  4916. case 7: // Info Tip
  4917. InfoTip = pSetupGetField( &InfLine, 1 );
  4918. break;
  4919. case 8: // Display Resource
  4920. DisplayResourceFile = pSetupGetField( &InfLine, 1);
  4921. DisplayResource = 0;
  4922. SetupGetIntField( &InfLine, 2, &DisplayResource );
  4923. break;
  4924. }//switch
  4925. }//for
  4926. if( Name && (*Name != 0) ){
  4927. if( Flags & FLG_PROFITEM_GROUP ){
  4928. if( Flags & FLG_PROFITEM_DELETE ){
  4929. ret = DeleteGroup( Name, ((Flags & FLG_PROFITEM_CURRENTUSER) ? FALSE : TRUE) );
  4930. if( !ret && ( (GetLastError() == ERROR_FILE_NOT_FOUND) ||
  4931. (GetLastError() == ERROR_PATH_NOT_FOUND) )){
  4932. ret = TRUE;
  4933. SetLastError( NO_ERROR );
  4934. }
  4935. }else {
  4936. ret = CreateGroupEx( Name,
  4937. ((Flags & FLG_PROFITEM_CURRENTUSER) ? FALSE : TRUE),
  4938. (DisplayResourceFile && DisplayResourceFile[0]) ? DisplayResourceFile : NULL,
  4939. (DisplayResourceFile && DisplayResourceFile[0]) ? DisplayResource : 0);
  4940. }
  4941. }
  4942. else{
  4943. if( Flags & FLG_PROFITEM_CSIDL )
  4944. Apply_csidl = Opt_csidl;
  4945. else
  4946. Apply_csidl = (Flags & FLG_PROFITEM_CURRENTUSER) ? CSIDL_PROGRAMS : CSIDL_COMMON_PROGRAMS;
  4947. if( SubDir && (*SubDir == 0 ))
  4948. SubDir = NULL;
  4949. if( Flags & FLG_PROFITEM_DELETE ){
  4950. ret = DeleteLinkFile(
  4951. Apply_csidl,
  4952. SubDir,
  4953. Name,
  4954. TRUE
  4955. );
  4956. if( !ret && ( (GetLastError() == ERROR_FILE_NOT_FOUND) ||
  4957. (GetLastError() == ERROR_PATH_NOT_FOUND) )){
  4958. ret = TRUE;
  4959. SetLastError( NO_ERROR );
  4960. }
  4961. }
  4962. else{
  4963. if( CmdLine && (*CmdLine != 0)){
  4964. ret = CreateLinkFileEx(
  4965. Apply_csidl,
  4966. SubDir,
  4967. Name,
  4968. CmdLine,
  4969. IconPath,
  4970. IconIndex,
  4971. WorkingDir,
  4972. (WORD)HotKey,
  4973. SW_SHOWNORMAL,
  4974. InfoTip,
  4975. (DisplayResourceFile && DisplayResourceFile[0]) ? DisplayResourceFile : NULL,
  4976. (DisplayResourceFile && DisplayResourceFile[0]) ? DisplayResource : 0
  4977. );
  4978. }else{
  4979. WriteLogEntry(
  4980. ((PLOADED_INF) Inf)->LogContext,
  4981. SETUP_LOG_ERROR,
  4982. MSG_LOG_PROFILE_BAD_CMDLINE,
  4983. NULL,
  4984. Section,
  4985. BadInf
  4986. );
  4987. ret = FALSE;
  4988. SetLastError(ERROR_INVALID_DATA);
  4989. }
  4990. }
  4991. }
  4992. if( !ret ){
  4993. Err = GetLastError();
  4994. WriteLogEntry(
  4995. ((PLOADED_INF) Inf)->LogContext,
  4996. SETUP_LOG_ERROR|SETUP_LOG_BUFFER,
  4997. MSG_LOG_PROFILE_OPERATION_ERROR,
  4998. NULL,
  4999. Section,
  5000. BadInf
  5001. );
  5002. WriteLogError(
  5003. ((PLOADED_INF) Inf)->LogContext,
  5004. SETUP_LOG_ERROR,
  5005. Err);
  5006. }
  5007. }else{
  5008. WriteLogEntry(
  5009. ((PLOADED_INF) Inf)->LogContext,
  5010. SETUP_LOG_ERROR,
  5011. MSG_LOG_PROFILE_BAD_NAME,
  5012. NULL,
  5013. Section,
  5014. BadInf
  5015. );
  5016. ret = FALSE;
  5017. Err = ERROR_INVALID_DATA;
  5018. }
  5019. }else{
  5020. ret = FALSE;
  5021. Err = GetLastError();
  5022. WriteLogEntry(
  5023. ((PLOADED_INF) Inf)->LogContext,
  5024. SETUP_LOG_ERROR,
  5025. MSG_LOG_PROFILE_LINE_ERROR,
  5026. NULL,
  5027. Section,
  5028. BadInf
  5029. );
  5030. }
  5031. clean0:
  5032. if( WorkingDir ) {
  5033. MyFree( WorkingDir );
  5034. }
  5035. if(pLoadedInf) {
  5036. UnlockInf(pLoadedInf);
  5037. }
  5038. if(ret) {
  5039. SetLastError( NO_ERROR );
  5040. } else {
  5041. SetLastError( Err );
  5042. }
  5043. return ret;
  5044. }
  5045. DWORD
  5046. pSetupInstallProfileItems(
  5047. IN HINF Inf,
  5048. IN PCTSTR SectionName
  5049. )
  5050. /*++
  5051. Routine Description:
  5052. Locate the ProfileItems= lines in an install section
  5053. and process each section listed therein. Each section specified here
  5054. will point to a section that lists the needed directives for a single
  5055. profile item.
  5056. Arguments:
  5057. Inf - supplies inf handle for inf containing the section indicated
  5058. by SectionName.
  5059. SectionName - supplies name of install section.
  5060. Return Value:
  5061. Win32 error code indicating outcome.
  5062. --*/
  5063. {
  5064. DWORD d = NO_ERROR;
  5065. INFCONTEXT LineContext;
  5066. DWORD Field, FieldCount;
  5067. PCTSTR SectionSpec;
  5068. //
  5069. // Find the ProfileItems line in the given install section.
  5070. // If not present then we're done with this operation.
  5071. //
  5072. if(!SetupFindFirstLine( Inf,
  5073. SectionName,
  5074. pszProfileItems,
  5075. &LineContext )) {
  5076. DWORD rc = GetLastError();
  5077. if((rc != NO_ERROR) && (rc != ERROR_SECTION_NOT_FOUND) && (rc != ERROR_LINE_NOT_FOUND)) {
  5078. pSetupLogSectionError(Inf,NULL,NULL,NULL,SectionName,MSG_LOG_INSTALLSECT_ERROR,rc,NULL);
  5079. }
  5080. SetLastError(NO_ERROR); // for compatibility with older versions of SetupAPI
  5081. return NO_ERROR;
  5082. }
  5083. do {
  5084. //
  5085. // Each value on the line in the given install section
  5086. // is the name of another section.
  5087. //
  5088. FieldCount = SetupGetFieldCount(&LineContext);
  5089. for(Field=1; d == NO_ERROR && (Field<=FieldCount); Field++) {
  5090. if(SectionSpec = pSetupGetField(&LineContext,Field)) {
  5091. if(SetupGetLineCount(Inf,SectionSpec) > 0) {
  5092. //
  5093. // The section exists and is not empty.
  5094. // So process it.
  5095. //
  5096. if(!pSetupProcessProfileSection(Inf,SectionSpec )) {
  5097. d = GetLastError();
  5098. pSetupLogSectionError(Inf,NULL,NULL,NULL,SectionSpec,MSG_LOG_SECT_ERROR,d,pszProfileItems);
  5099. }
  5100. }
  5101. }
  5102. }
  5103. } while(SetupFindNextMatchLine( &LineContext,
  5104. pszProfileItems,
  5105. &LineContext));
  5106. SetLastError( d );
  5107. return d;
  5108. }
  5109. #endif
  5110. DWORD
  5111. pSetupInstallFiles(
  5112. IN HINF Inf,
  5113. IN HINF LayoutInf, OPTIONAL
  5114. IN PCTSTR SectionName,
  5115. IN PCTSTR SourceRootPath, OPTIONAL
  5116. IN PSP_FILE_CALLBACK MsgHandler, OPTIONAL
  5117. IN PVOID Context, OPTIONAL
  5118. IN UINT CopyStyle,
  5119. IN HWND Owner, OPTIONAL
  5120. IN HSPFILEQ UserFileQ, OPTIONAL
  5121. IN BOOL IsMsgHandlerNativeCharWidth
  5122. )
  5123. /*++
  5124. Routine Description:
  5125. Look for file operation lines in an install section and process them.
  5126. Arguments:
  5127. Inf - supplies inf handle for inf containing the section indicated
  5128. by SectionName.
  5129. LayoutInf - optionally, supplies a separate INF handle containing source
  5130. media information about the files to be installed. If this value is
  5131. NULL or INVALID_HANDLE_VALUE, then it is assumed that this information
  5132. is in the INF(s) whose handle was passed to us in the Inf parameter.
  5133. SectionName - supplies name of install section.
  5134. MsgHandler - supplies a callback to be used when the file queue is
  5135. committed. Not used if UserFileQ is specified.
  5136. Context - supplies context for callback function. Not used if UserFileQ
  5137. is specified.
  5138. Owner - supplies the window handle of a window to be the parent/owner
  5139. of any dialogs that are created. Not used if UserFileQ is specified.
  5140. UserFileQ - if specified, then this routine neither created nor commits the
  5141. file queue. File operations are queued on this queue and it is up to the
  5142. caller to flush the queue when it so desired. If this parameter is not
  5143. specified then this routine creates a file queue and commits it
  5144. before returning.
  5145. IsMsgHandlerNativeCharWidth - indicates whether any message handler callback
  5146. expects native char width args (or ansi ones, in the unicode build
  5147. of this dll).
  5148. Return Value:
  5149. Win32 error code indicating outcome.
  5150. --*/
  5151. {
  5152. DWORD Field;
  5153. unsigned i;
  5154. PCTSTR Operations[3] = { TEXT("Copyfiles"),TEXT("Renfiles"),TEXT("Delfiles") };
  5155. BOOL b;
  5156. INFCONTEXT LineContext;
  5157. DWORD FieldCount;
  5158. PCTSTR SectionSpec;
  5159. INFCONTEXT SectionLineContext;
  5160. HSPFILEQ FileQueue;
  5161. DWORD rc = NO_ERROR;
  5162. BOOL FreeSourceRoot;
  5163. DWORD InfSourceMediaType;
  5164. //
  5165. // see if install section exists for diagnostics (this will also check Inf)
  5166. //
  5167. if (!SetupFindFirstLine(Inf,SectionName,NULL,&LineContext)) {
  5168. DWORD x = GetLastError();
  5169. if((x != NO_ERROR) && (x != ERROR_SECTION_NOT_FOUND) && (x != ERROR_LINE_NOT_FOUND)) {
  5170. pSetupLogSectionError(Inf,NULL,NULL,UserFileQ,SectionName,MSG_LOG_INSTALLSECT_ERROR,x,NULL);
  5171. return x;
  5172. }
  5173. }
  5174. if(!LayoutInf || (LayoutInf == INVALID_HANDLE_VALUE)) {
  5175. LayoutInf = Inf;
  5176. }
  5177. //
  5178. // Create a file queue.
  5179. //
  5180. if(UserFileQ) {
  5181. FileQueue = UserFileQ;
  5182. } else {
  5183. FileQueue = SetupOpenFileQueue();
  5184. if(FileQueue == INVALID_HANDLE_VALUE) {
  5185. return(GetLastError());
  5186. }
  5187. }
  5188. ShareLogContext(&((PLOADED_INF)LayoutInf)->LogContext,&((PSP_FILE_QUEUE)FileQueue)->LogContext);
  5189. //
  5190. // The following code is broken because it implies one default source root path per INF
  5191. // file. While this is correct for an OEM install, it's broken for os based installs
  5192. //
  5193. FreeSourceRoot = FALSE;
  5194. if(!SourceRootPath) {
  5195. if(SourceRootPath = pSetupGetDefaultSourcePath(Inf, 0, &InfSourceMediaType)) {
  5196. //
  5197. // For now, if the INF is from the internet, just use
  5198. // the default OEM source path (A:\) instead.
  5199. //
  5200. if(InfSourceMediaType == SPOST_URL) {
  5201. MyFree(SourceRootPath);
  5202. //
  5203. // Fall back to default OEM source path.
  5204. //
  5205. SourceRootPath = pszOemInfDefaultPath;
  5206. } else {
  5207. FreeSourceRoot = TRUE;
  5208. }
  5209. } else {
  5210. //
  5211. // lock this!
  5212. //
  5213. if (LockInf((PLOADED_INF)Inf)) {
  5214. if (pSetupInfIsFromOemLocation(((PLOADED_INF)Inf)->VersionBlock.Filename, TRUE)) {
  5215. SourceRootPath = DuplicateString(((PLOADED_INF)Inf)->VersionBlock.Filename);
  5216. if (SourceRootPath) {
  5217. PTSTR p;
  5218. p = _tcsrchr( SourceRootPath, TEXT('\\') );
  5219. if (p) *p = TEXT('\0');
  5220. FreeSourceRoot = TRUE;
  5221. }
  5222. }
  5223. UnlockInf((PLOADED_INF)Inf);
  5224. }
  5225. }
  5226. }
  5227. b = TRUE;
  5228. for(i=0; b && (i<3); i++) {
  5229. //
  5230. // Find the relevent line in the given install section.
  5231. // If not present then we're done with this operation.
  5232. //
  5233. if(!SetupFindFirstLine(Inf,SectionName,Operations[i],&LineContext)) {
  5234. continue;
  5235. }
  5236. do {
  5237. //
  5238. // Each value on the line in the given install section
  5239. // is the name of another section.
  5240. //
  5241. FieldCount = SetupGetFieldCount(&LineContext);
  5242. for(Field=1; b && (Field<=FieldCount); Field++) {
  5243. if(SectionSpec = pSetupGetField(&LineContext,Field)) {
  5244. //
  5245. // Handle single-file copy specially.
  5246. //
  5247. if((i == 0) && (*SectionSpec == TEXT('@'))) {
  5248. b = SetupQueueDefaultCopy(
  5249. FileQueue,
  5250. LayoutInf,
  5251. SourceRootPath,
  5252. SectionSpec + 1,
  5253. SectionSpec + 1,
  5254. CopyStyle
  5255. );
  5256. if (!b) {
  5257. rc = GetLastError();
  5258. pSetupLogSectionError(Inf,NULL,NULL,FileQueue,SectionSpec+1,MSG_LOG_COPYSECT_ERROR,rc,Operations[i]);
  5259. }
  5260. } else if(SetupGetLineCount(Inf,SectionSpec) > 0) {
  5261. //
  5262. // The section exists and is not empty.
  5263. // Add it to the copy/delete/rename queue.
  5264. //
  5265. switch(i) {
  5266. case 0:
  5267. b = SetupQueueCopySection(
  5268. FileQueue,
  5269. SourceRootPath,
  5270. LayoutInf,
  5271. Inf,
  5272. SectionSpec,
  5273. CopyStyle
  5274. );
  5275. break;
  5276. case 1:
  5277. b = SetupQueueRenameSection(FileQueue,Inf,NULL,SectionSpec);
  5278. break;
  5279. case 2:
  5280. b = SetupQueueDeleteSection(FileQueue,Inf,NULL,SectionSpec);
  5281. break;
  5282. }
  5283. if (!b) {
  5284. rc = GetLastError();
  5285. pSetupLogSectionError(Inf,NULL,NULL,FileQueue,SectionSpec,MSG_LOG_SECT_ERROR,rc,Operations[i]);
  5286. }
  5287. }
  5288. }
  5289. }
  5290. } while(SetupFindNextMatchLine(&LineContext,Operations[i],&LineContext));
  5291. }
  5292. if(b && (FileQueue != UserFileQ)) {
  5293. //
  5294. // Perform the file operations.
  5295. //
  5296. b = _SetupCommitFileQueue(
  5297. Owner,
  5298. FileQueue,
  5299. MsgHandler,
  5300. Context,
  5301. IsMsgHandlerNativeCharWidth
  5302. );
  5303. rc = b ? NO_ERROR : GetLastError();
  5304. }
  5305. if(FileQueue != UserFileQ) {
  5306. SetupCloseFileQueue(FileQueue);
  5307. }
  5308. if(FreeSourceRoot) {
  5309. MyFree(SourceRootPath);
  5310. }
  5311. return(rc);
  5312. }
  5313. BOOL
  5314. _SetupInstallFromInfSection(
  5315. IN HWND Owner, OPTIONAL
  5316. IN HINF InfHandle,
  5317. IN PCTSTR SectionName,
  5318. IN UINT Flags,
  5319. IN HKEY RelativeKeyRoot, OPTIONAL
  5320. IN PCTSTR SourceRootPath, OPTIONAL
  5321. IN UINT CopyFlags,
  5322. IN PVOID MsgHandler,
  5323. IN PVOID Context, OPTIONAL
  5324. IN HDEVINFO DeviceInfoSet, OPTIONAL
  5325. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  5326. IN BOOL IsMsgHandlerNativeCharWidth,
  5327. IN PREGMOD_CONTEXT RegContext OPTIONAL
  5328. )
  5329. {
  5330. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  5331. PDEVINFO_ELEM DevInfoElem;
  5332. DWORD d = NO_ERROR;
  5333. BOOL CloseRelativeKeyRoot;
  5334. REGMOD_CONTEXT DefRegContext;
  5335. //
  5336. // Validate the flags passed in.
  5337. //
  5338. if(Flags & ~(SPINST_ALL | SPINST_SINGLESECTION |
  5339. SPINST_LOGCONFIG_IS_FORCED | SPINST_LOGCONFIGS_ARE_OVERRIDES |
  5340. SPINST_REGISTERCALLBACKAWARE)) {
  5341. d = ERROR_INVALID_FLAGS;
  5342. goto clean1;
  5343. }
  5344. //
  5345. // If the caller wants us to run a specific section, then they'd better
  5346. // have told us what kind of section it is (i.e., one and only one of
  5347. // the install action types must be specified).
  5348. //
  5349. // Presently, only LogConfig sections are allowed, since the other
  5350. // flags flags encompass multiple actions (e.g., AddReg _and_ DelReg).
  5351. //
  5352. if((Flags & SPINST_SINGLESECTION) && ((Flags & SPINST_ALL) != SPINST_LOGCONFIG)) {
  5353. d = ERROR_INVALID_FLAGS;
  5354. goto clean1;
  5355. }
  5356. //
  5357. // You can (optionally) specify SPINST_LOGCONFIG_IS_FORCED or SPINST_LOGCONFIGS_ARE_OVERRIDES,
  5358. // but not both.
  5359. //
  5360. if((Flags & (SPINST_LOGCONFIG_IS_FORCED | SPINST_LOGCONFIGS_ARE_OVERRIDES)) ==
  5361. (SPINST_LOGCONFIG_IS_FORCED | SPINST_LOGCONFIGS_ARE_OVERRIDES)) {
  5362. d = ERROR_INVALID_FLAGS;
  5363. goto clean1;
  5364. }
  5365. //
  5366. // We only want to acquire the HDEVINFO lock if we're supposed to do some install
  5367. // actions against a device instance.
  5368. //
  5369. if((Flags & (SPINST_REGISTRY | SPINST_BITREG | SPINST_INI2REG | SPINST_LOGCONFIG)) &&
  5370. DeviceInfoSet && (DeviceInfoSet != INVALID_HANDLE_VALUE) && DeviceInfoData) {
  5371. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  5372. d = ERROR_INVALID_HANDLE;
  5373. goto clean1;
  5374. }
  5375. } else {
  5376. //This is ok in the remote case, since to call pSetupInstallLogConfig
  5377. //We won't really get here (we'll take the if case)
  5378. pDeviceInfoSet = NULL;
  5379. }
  5380. d = NO_ERROR;
  5381. DevInfoElem = NULL;
  5382. CloseRelativeKeyRoot = FALSE;
  5383. try {
  5384. //
  5385. // Get a pointer to the element for the specified device
  5386. // instance.
  5387. //
  5388. if(pDeviceInfoSet) {
  5389. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  5390. DeviceInfoData,
  5391. NULL))) {
  5392. d = ERROR_INVALID_PARAMETER;
  5393. goto RegModsDone;
  5394. }
  5395. }
  5396. if((Flags & (SPINST_REGISTRY | SPINST_BITREG | SPINST_INI2REG)) && DevInfoElem) {
  5397. //
  5398. // If the caller supplied a device information set and element, then this is
  5399. // a device installation, and the registry modifications should be made to the
  5400. // device instance's hardware registry key.
  5401. //
  5402. if((RelativeKeyRoot = SetupDiCreateDevRegKey(DeviceInfoSet,
  5403. DeviceInfoData,
  5404. DICS_FLAG_GLOBAL,
  5405. 0,
  5406. DIREG_DEV,
  5407. NULL,
  5408. NULL)) == INVALID_HANDLE_VALUE) {
  5409. d = GetLastError();
  5410. goto RegModsDone;
  5411. }
  5412. CloseRelativeKeyRoot = TRUE;
  5413. }
  5414. if((Flags & SPINST_LOGCONFIG) && DevInfoElem) {
  5415. d = pSetupInstallLogConfig(InfHandle,
  5416. SectionName,
  5417. DevInfoElem->DevInst,
  5418. Flags,
  5419. pDeviceInfoSet->hMachine);
  5420. if(d != NO_ERROR) {
  5421. goto RegModsDone;
  5422. }
  5423. }
  5424. if(Flags & SPINST_INIFILES) {
  5425. d = pSetupInstallUpdateIniFiles(InfHandle,SectionName);
  5426. if(d != NO_ERROR) {
  5427. goto RegModsDone;
  5428. }
  5429. }
  5430. if(Flags & (SPINST_REGISTRY | SPINST_BITREG)) {
  5431. if(!RegContext) {
  5432. ZeroMemory(&DefRegContext, sizeof(DefRegContext));
  5433. if(DevInfoElem) {
  5434. DefRegContext.Flags = INF_PFLAG_DEVPROP;
  5435. DefRegContext.DevInst = DevInfoElem->DevInst;
  5436. }
  5437. RegContext = &DefRegContext;
  5438. }
  5439. //
  5440. // We check for the INF_PFLAG_HKR flag in case the caller supplied
  5441. // us with a context that included a UserRootKey they wanted us to
  5442. // use (i.e., instead of the RelativeKeyRoot)...
  5443. //
  5444. if(!(RegContext->Flags & INF_PFLAG_HKR)) {
  5445. RegContext->UserRootKey = RelativeKeyRoot;
  5446. }
  5447. if(Flags & SPINST_REGISTRY) {
  5448. d = pSetupInstallRegistry(InfHandle,
  5449. SectionName,
  5450. RegContext
  5451. );
  5452. }
  5453. if((d == NO_ERROR) && (Flags & SPINST_BITREG)) {
  5454. d = pSetupInstallBitReg(InfHandle,
  5455. SectionName,
  5456. RegContext
  5457. );
  5458. }
  5459. if(d != NO_ERROR) {
  5460. goto RegModsDone;
  5461. }
  5462. }
  5463. if(Flags & SPINST_INI2REG) {
  5464. d = pSetupInstallIni2Reg(InfHandle,SectionName,RelativeKeyRoot);
  5465. if (d != NO_ERROR) {
  5466. goto RegModsDone;
  5467. }
  5468. }
  5469. if(Flags & SPINST_REGSVR) {
  5470. d = pSetupInstallRegisterUnregisterDlls(
  5471. InfHandle,
  5472. SectionName,
  5473. TRUE,
  5474. Owner,
  5475. MsgHandler,
  5476. Context,
  5477. IsMsgHandlerNativeCharWidth,
  5478. (Flags & SPINST_REGISTERCALLBACKAWARE) != 0 );
  5479. if (d != NO_ERROR) {
  5480. goto RegModsDone;
  5481. }
  5482. }
  5483. if(Flags & SPINST_UNREGSVR) {
  5484. d = pSetupInstallRegisterUnregisterDlls(
  5485. InfHandle,
  5486. SectionName,
  5487. FALSE,
  5488. Owner,
  5489. MsgHandler,
  5490. Context,
  5491. IsMsgHandlerNativeCharWidth,
  5492. (Flags & SPINST_REGISTERCALLBACKAWARE) != 0 );
  5493. if (d != NO_ERROR) {
  5494. goto RegModsDone;
  5495. }
  5496. }
  5497. #ifndef ANSI_SETUPAPI
  5498. if(Flags & SPINST_PROFILEITEMS) {
  5499. d = pSetupInstallProfileItems(InfHandle,SectionName);
  5500. if (d != NO_ERROR) {
  5501. goto RegModsDone;
  5502. }
  5503. }
  5504. #endif
  5505. if(Flags & SPINST_COPYINF) {
  5506. d = pSetupCopyRelatedInfs(InfHandle,
  5507. NULL,
  5508. SectionName,
  5509. SPOST_PATH,
  5510. NULL);
  5511. if (d != NO_ERROR) {
  5512. goto RegModsDone;
  5513. }
  5514. }
  5515. RegModsDone:
  5516. ; // nothing to do.
  5517. } except(EXCEPTION_EXECUTE_HANDLER) {
  5518. d = ERROR_INVALID_PARAMETER;
  5519. //
  5520. // Access the following variable, so that the compiler will respect statement
  5521. // ordering w.r.t. its assignment.
  5522. //
  5523. CloseRelativeKeyRoot = CloseRelativeKeyRoot;
  5524. }
  5525. if(CloseRelativeKeyRoot) {
  5526. RegCloseKey(RelativeKeyRoot);
  5527. }
  5528. if(d == NO_ERROR) {
  5529. if(Flags & SPINST_FILES) {
  5530. d = pSetupInstallFiles(
  5531. InfHandle,
  5532. NULL,
  5533. SectionName,
  5534. SourceRootPath,
  5535. MsgHandler,
  5536. Context,
  5537. CopyFlags,
  5538. Owner,
  5539. NULL,
  5540. IsMsgHandlerNativeCharWidth
  5541. );
  5542. }
  5543. }
  5544. clean1:
  5545. pSetupLogSectionError(InfHandle,DeviceInfoSet,DeviceInfoData,NULL,SectionName,MSG_LOG_INSTALLSECT_ERROR,d,NULL);
  5546. if(pDeviceInfoSet) {
  5547. UnlockDeviceInfoSet(pDeviceInfoSet);
  5548. }
  5549. SetLastError(d);
  5550. return(d==NO_ERROR);
  5551. }
  5552. DWORD
  5553. pSetupLogSection(
  5554. IN DWORD SetupLogLevel,
  5555. IN DWORD DriverLogLevel,
  5556. IN HINF InfHandle, OPTIONAL
  5557. IN HDEVINFO DeviceInfoSet, OPTIONAL
  5558. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  5559. IN PSP_FILE_QUEUE Queue, OPTIONAL
  5560. IN PCTSTR SectionName,
  5561. IN DWORD MsgID,
  5562. IN DWORD Err,
  5563. IN PCTSTR KeyName OPTIONAL
  5564. )
  5565. /*++
  5566. Routine Description:
  5567. Log error with section context
  5568. error will be logged at SETUP_LOG_ERROR or DRIVER_LOG_ERROR depending if DeviceInfoSet/Data given
  5569. error will contain inf name & section name used (%2 & %1 respectively)
  5570. Arguments:
  5571. SetupLogLevel - log level apropriate for regular setup related log
  5572. DriverLogLevel - log level apropriate for driver related log
  5573. InfHandle - supplies inf handle for inf containing the section indicated
  5574. by SectionName.
  5575. DeviceInfoSet, DeviceInfoData - supplies driver install context
  5576. SectionName - supplies name of install section.
  5577. Queue - supplies file queue
  5578. MsgID - supplies ID of message string to display
  5579. Err - supplies error
  5580. KeyName - passed as 3rd parameter
  5581. Return Value:
  5582. Err.
  5583. --*/
  5584. {
  5585. DWORD d = NO_ERROR;
  5586. BOOL inf_locked = FALSE;
  5587. DWORD level = SetupLogLevel;
  5588. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  5589. PDEVINFO_ELEM DevInfoElem = NULL;
  5590. PSETUP_LOG_CONTEXT LogContext = NULL;
  5591. PCTSTR szInfName = NULL;
  5592. if (Err == NO_ERROR) {
  5593. return Err;
  5594. }
  5595. //
  5596. // determine LogContext/Level
  5597. //
  5598. try {
  5599. //
  5600. // first attempt to get the context from DeviceInfoSet/DeviceInfoData
  5601. //
  5602. if (DeviceInfoSet != NULL && DeviceInfoSet != INVALID_HANDLE_VALUE) {
  5603. if((pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))!=NULL) {
  5604. level = DriverLogLevel;
  5605. LogContext = pDeviceInfoSet->InstallParamBlock.LogContext;
  5606. if (DeviceInfoData) {
  5607. if((DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  5608. DeviceInfoData,
  5609. NULL))!=NULL) {
  5610. LogContext = DevInfoElem->InstallParamBlock.LogContext;
  5611. }
  5612. }
  5613. }
  5614. }
  5615. //
  5616. // if that fails, see if we can get it from a file queue
  5617. //
  5618. if(LogContext == NULL && Queue != NULL && Queue != INVALID_HANDLE_VALUE && Queue->Signature == SP_FILE_QUEUE_SIG) {
  5619. LogContext = Queue->LogContext;
  5620. }
  5621. //
  5622. // if no InfHandle was provided, we're done
  5623. //
  5624. if(InfHandle == NULL || InfHandle == INVALID_HANDLE_VALUE || !LockInf((PLOADED_INF)InfHandle)) {
  5625. leave;
  5626. }
  5627. inf_locked = TRUE;
  5628. //
  5629. // if we still don't have logging context, use the inf's
  5630. //
  5631. if (LogContext == NULL) {
  5632. LogContext = ((PLOADED_INF)InfHandle)->LogContext;
  5633. }
  5634. //
  5635. // ideally we want the inf file name
  5636. //
  5637. szInfName = ((PLOADED_INF)InfHandle)->VersionBlock.Filename;
  5638. } except(EXCEPTION_EXECUTE_HANDLER) {
  5639. }
  5640. if (LogContext) {
  5641. //
  5642. // indicate install failed, display error
  5643. //
  5644. WriteLogEntry(
  5645. LogContext,
  5646. level | SETUP_LOG_BUFFER,
  5647. MsgID,
  5648. NULL,
  5649. SectionName?SectionName:TEXT("-"),
  5650. szInfName?szInfName:TEXT("-"),
  5651. KeyName
  5652. );
  5653. WriteLogError(
  5654. LogContext,
  5655. level,
  5656. Err
  5657. );
  5658. }
  5659. if (inf_locked) {
  5660. UnlockInf((PLOADED_INF)InfHandle);
  5661. }
  5662. if(pDeviceInfoSet) {
  5663. UnlockDeviceInfoSet(pDeviceInfoSet);
  5664. }
  5665. SetLastError(Err);
  5666. return Err;
  5667. }
  5668. DWORD
  5669. pSetupLogSectionError(
  5670. IN HINF InfHandle, OPTIONAL
  5671. IN HDEVINFO DeviceInfoSet, OPTIONAL
  5672. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  5673. IN PSP_FILE_QUEUE Queue, OPTIONAL
  5674. IN PCTSTR SectionName,
  5675. IN DWORD MsgID,
  5676. IN DWORD Err,
  5677. IN PCTSTR KeyName OPTIONAL
  5678. )
  5679. /*++
  5680. Routine Description:
  5681. See pSetupLogSection
  5682. Log at ERROR level
  5683. Arguments:
  5684. See pSetupLogSection
  5685. Return Value:
  5686. Err.
  5687. --*/
  5688. {
  5689. return pSetupLogSection(SETUP_LOG_ERROR,DRIVER_LOG_ERROR,
  5690. InfHandle,DeviceInfoSet,DeviceInfoData,
  5691. Queue,SectionName,MsgID,Err,KeyName);
  5692. }
  5693. DWORD
  5694. pSetupLogSectionWarning(
  5695. IN HINF InfHandle, OPTIONAL
  5696. IN HDEVINFO DeviceInfoSet, OPTIONAL
  5697. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  5698. IN PSP_FILE_QUEUE Queue, OPTIONAL
  5699. IN PCTSTR SectionName,
  5700. IN DWORD MsgID,
  5701. IN DWORD Err,
  5702. IN PCTSTR KeyName OPTIONAL
  5703. )
  5704. /*++
  5705. Routine Description:
  5706. See pSetupLogSection
  5707. Log at ERROR level
  5708. Arguments:
  5709. See pSetupLogSection
  5710. Return Value:
  5711. Err.
  5712. --*/
  5713. {
  5714. return pSetupLogSection(SETUP_LOG_WARNING,DRIVER_LOG_WARNING,
  5715. InfHandle,DeviceInfoSet,DeviceInfoData,
  5716. Queue,SectionName,MsgID,Err,KeyName);
  5717. }
  5718. #ifdef UNICODE
  5719. //
  5720. // ANSI version
  5721. //
  5722. BOOL
  5723. SetupInstallFromInfSectionA(
  5724. IN HWND Owner, OPTIONAL
  5725. IN HINF InfHandle,
  5726. IN PCSTR SectionName,
  5727. IN UINT Flags,
  5728. IN HKEY RelativeKeyRoot, OPTIONAL
  5729. IN PCSTR SourceRootPath, OPTIONAL
  5730. IN UINT CopyFlags,
  5731. IN PSP_FILE_CALLBACK_A MsgHandler,
  5732. IN PVOID Context, OPTIONAL
  5733. IN HDEVINFO DeviceInfoSet, OPTIONAL
  5734. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  5735. )
  5736. {
  5737. PCWSTR sectionName;
  5738. PCWSTR sourceRootPath;
  5739. BOOL b;
  5740. DWORD d;
  5741. sectionName = NULL;
  5742. sourceRootPath = NULL;
  5743. d = NO_ERROR;
  5744. if(SectionName) {
  5745. d = pSetupCaptureAndConvertAnsiArg(SectionName,&sectionName);
  5746. }
  5747. if((d == NO_ERROR) && SourceRootPath) {
  5748. d = pSetupCaptureAndConvertAnsiArg(SourceRootPath,&sourceRootPath);
  5749. }
  5750. if(d == NO_ERROR) {
  5751. b = _SetupInstallFromInfSection(
  5752. Owner,
  5753. InfHandle,
  5754. sectionName,
  5755. Flags,
  5756. RelativeKeyRoot,
  5757. sourceRootPath,
  5758. CopyFlags,
  5759. MsgHandler,
  5760. Context,
  5761. DeviceInfoSet,
  5762. DeviceInfoData,
  5763. FALSE,
  5764. NULL
  5765. );
  5766. d = GetLastError();
  5767. } else {
  5768. b = FALSE;
  5769. }
  5770. if(sectionName) {
  5771. MyFree(sectionName);
  5772. }
  5773. if(sourceRootPath) {
  5774. MyFree(sourceRootPath);
  5775. }
  5776. SetLastError(d);
  5777. return(b);
  5778. }
  5779. #else
  5780. //
  5781. // Unicode stub
  5782. //
  5783. BOOL
  5784. SetupInstallFromInfSectionW(
  5785. IN HWND Owner, OPTIONAL
  5786. IN HINF InfHandle,
  5787. IN PCWSTR SectionName,
  5788. IN UINT Flags,
  5789. IN HKEY RelativeKeyRoot, OPTIONAL
  5790. IN PCWSTR SourceRootPath, OPTIONAL
  5791. IN UINT CopyFlags,
  5792. IN PSP_FILE_CALLBACK_W MsgHandler,
  5793. IN PVOID Context, OPTIONAL
  5794. IN HDEVINFO DeviceInfoSet, OPTIONAL
  5795. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  5796. )
  5797. {
  5798. UNREFERENCED_PARAMETER(Owner);
  5799. UNREFERENCED_PARAMETER(InfHandle);
  5800. UNREFERENCED_PARAMETER(SectionName);
  5801. UNREFERENCED_PARAMETER(Flags);
  5802. UNREFERENCED_PARAMETER(RelativeKeyRoot);
  5803. UNREFERENCED_PARAMETER(SourceRootPath);
  5804. UNREFERENCED_PARAMETER(CopyFlags);
  5805. UNREFERENCED_PARAMETER(MsgHandler);
  5806. UNREFERENCED_PARAMETER(Context);
  5807. UNREFERENCED_PARAMETER(DeviceInfoSet);
  5808. UNREFERENCED_PARAMETER(DeviceInfoData);
  5809. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  5810. return(FALSE);
  5811. }
  5812. #endif
  5813. BOOL
  5814. SetupInstallFromInfSection(
  5815. IN HWND Owner, OPTIONAL
  5816. IN HINF InfHandle,
  5817. IN PCTSTR SectionName,
  5818. IN UINT Flags,
  5819. IN HKEY RelativeKeyRoot, OPTIONAL
  5820. IN PCTSTR SourceRootPath, OPTIONAL
  5821. IN UINT CopyFlags,
  5822. IN PSP_FILE_CALLBACK MsgHandler,
  5823. IN PVOID Context, OPTIONAL
  5824. IN HDEVINFO DeviceInfoSet, OPTIONAL
  5825. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  5826. )
  5827. {
  5828. BOOL b;
  5829. b = _SetupInstallFromInfSection(
  5830. Owner,
  5831. InfHandle,
  5832. SectionName,
  5833. Flags,
  5834. RelativeKeyRoot,
  5835. SourceRootPath,
  5836. CopyFlags,
  5837. MsgHandler,
  5838. Context,
  5839. DeviceInfoSet,
  5840. DeviceInfoData,
  5841. TRUE,
  5842. NULL
  5843. );
  5844. return(b);
  5845. }
  5846. #ifdef UNICODE
  5847. //
  5848. // ANSI version
  5849. //
  5850. BOOL
  5851. SetupInstallFilesFromInfSectionA(
  5852. IN HINF InfHandle,
  5853. IN HINF LayoutInfHandle, OPTIONAL
  5854. IN HSPFILEQ FileQueue,
  5855. IN PCSTR SectionName,
  5856. IN PCSTR SourceRootPath, OPTIONAL
  5857. IN UINT CopyFlags
  5858. )
  5859. {
  5860. PCWSTR sectionName;
  5861. PCWSTR sourceRootPath;
  5862. BOOL b;
  5863. DWORD d;
  5864. d = pSetupCaptureAndConvertAnsiArg(SectionName,&sectionName);
  5865. if((d == NO_ERROR) && SourceRootPath) {
  5866. d = pSetupCaptureAndConvertAnsiArg(SourceRootPath,&sourceRootPath);
  5867. } else {
  5868. sourceRootPath = NULL;
  5869. }
  5870. if(d == NO_ERROR) {
  5871. b = SetupInstallFilesFromInfSectionW(
  5872. InfHandle,
  5873. LayoutInfHandle,
  5874. FileQueue,
  5875. sectionName,
  5876. sourceRootPath,
  5877. CopyFlags
  5878. );
  5879. d = GetLastError();
  5880. } else {
  5881. b = FALSE;
  5882. }
  5883. if(sectionName) {
  5884. MyFree(sectionName);
  5885. }
  5886. if(sourceRootPath) {
  5887. MyFree(sourceRootPath);
  5888. }
  5889. SetLastError(d);
  5890. return(b);
  5891. }
  5892. #else
  5893. //
  5894. // Unicode stub
  5895. //
  5896. BOOL
  5897. SetupInstallFilesFromInfSectionW(
  5898. IN HINF InfHandle,
  5899. IN HINF LayoutInfHandle, OPTIONAL
  5900. IN HSPFILEQ FileQueue,
  5901. IN PCWSTR SectionName,
  5902. IN PCWSTR SourceRootPath, OPTIONAL
  5903. IN UINT CopyFlags
  5904. )
  5905. {
  5906. UNREFERENCED_PARAMETER(InfHandle);
  5907. UNREFERENCED_PARAMETER(LayoutInfHandle);
  5908. UNREFERENCED_PARAMETER(FileQueue);
  5909. UNREFERENCED_PARAMETER(SectionName);
  5910. UNREFERENCED_PARAMETER(SourceRootPath);
  5911. UNREFERENCED_PARAMETER(CopyFlags);
  5912. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  5913. return(FALSE);
  5914. }
  5915. #endif
  5916. BOOL
  5917. SetupInstallFilesFromInfSection(
  5918. IN HINF InfHandle,
  5919. IN HINF LayoutInfHandle, OPTIONAL
  5920. IN HSPFILEQ FileQueue,
  5921. IN PCTSTR SectionName,
  5922. IN PCTSTR SourceRootPath, OPTIONAL
  5923. IN UINT CopyFlags
  5924. )
  5925. {
  5926. DWORD d;
  5927. d = pSetupInstallFiles(
  5928. InfHandle,
  5929. LayoutInfHandle,
  5930. SectionName,
  5931. SourceRootPath,
  5932. NULL,
  5933. NULL,
  5934. CopyFlags,
  5935. NULL,
  5936. FileQueue,
  5937. TRUE // not used by pSetupInstallFiles with this combo of args
  5938. );
  5939. SetLastError(d);
  5940. return(d == NO_ERROR);
  5941. }
  5942. HKEY
  5943. pSetupInfRegSpecToKeyHandle(
  5944. IN PCTSTR InfRegSpec,
  5945. IN HKEY UserRootKey,
  5946. OUT PBOOL NeedToCloseKey
  5947. )
  5948. {
  5949. BOOL b;
  5950. // make sure the whole handle is NULL as LookUpStringTable only
  5951. // returns 32 bits
  5952. UINT_PTR v;
  5953. HKEY h = NULL;
  5954. DWORD d;
  5955. *NeedToCloseKey = FALSE;
  5956. if (LookUpStringInTable(InfRegSpecTohKey, InfRegSpec, &v)) {
  5957. if (v) {
  5958. h = (HKEY)v;
  5959. } else {
  5960. h = UserRootKey;
  5961. }
  5962. } else {
  5963. h = NULL;
  5964. }
  5965. return h;
  5966. }
  5967. //////////////////////////////////////////////////////////////////////////////
  5968. //
  5969. // Ini file support stuff.
  5970. //
  5971. // In Win95, the UpdateIni stuff is supported by a set of TpXXX routines.
  5972. // Those routines directly manipulate the ini file, which is bad news for us
  5973. // because inis can be mapped into the registry.
  5974. //
  5975. // Thus we want to use the profile APIs. However the profile APIs make it hard
  5976. // to manipulate lines without keys, so we have to manipulate whole sections
  5977. // at a time.
  5978. //
  5979. // [Section]
  5980. // a
  5981. //
  5982. // There is no way to get at the line "a" with the profile APIs. But the
  5983. // profile section APIs do let us get at it.
  5984. //
  5985. //////////////////////////////////////////////////////////////////////////////
  5986. PINIFILESECTION
  5987. pSetupLoadIniFileSection(
  5988. IN PCTSTR FileName,
  5989. IN PCTSTR SectionName,
  5990. IN OUT PINISECTIONCACHE SectionList
  5991. )
  5992. /*++
  5993. Routine Description:
  5994. Arguments:
  5995. Return Value:
  5996. --*/
  5997. {
  5998. DWORD d;
  5999. PTSTR SectionData;
  6000. PVOID p;
  6001. DWORD BufferSize;
  6002. PINIFILESECTION Desc;
  6003. #define BUF_GROW 4096
  6004. //
  6005. // See if this section is already loaded.
  6006. //
  6007. for(Desc=SectionList->Sections; Desc; Desc=Desc->Next) {
  6008. if(!lstrcmpi(Desc->IniFileName,FileName) && !lstrcmpi(Desc->SectionName,SectionName)) {
  6009. return(Desc);
  6010. }
  6011. }
  6012. BufferSize = 0;
  6013. SectionData = NULL;
  6014. //
  6015. // Read the entire section. We don't know how big it is
  6016. // so keep growing the buffer until we succeed.
  6017. //
  6018. do {
  6019. BufferSize += BUF_GROW;
  6020. if(SectionData) {
  6021. p = MyRealloc(SectionData,BufferSize*sizeof(TCHAR));
  6022. } else {
  6023. p = MyMalloc(BufferSize*sizeof(TCHAR));
  6024. }
  6025. if(p) {
  6026. SectionData = p;
  6027. } else {
  6028. if(SectionData) {
  6029. MyFree(SectionData);
  6030. }
  6031. return(NULL);
  6032. }
  6033. //
  6034. // Attempt to get the entire section.
  6035. //
  6036. d = GetPrivateProfileSection(SectionName,SectionData,BufferSize,FileName);
  6037. } while(d == (BufferSize-2));
  6038. if(Desc = MyMalloc(sizeof(INIFILESECTION))) {
  6039. if(Desc->IniFileName = DuplicateString(FileName)) {
  6040. if(Desc->SectionName = DuplicateString(SectionName)) {
  6041. Desc->SectionData = SectionData;
  6042. Desc->BufferSize = BufferSize;
  6043. Desc->BufferUsed = d + 1;
  6044. Desc->Next = SectionList->Sections;
  6045. SectionList->Sections = Desc;
  6046. } else {
  6047. MyFree(SectionData);
  6048. MyFree(Desc->IniFileName);
  6049. MyFree(Desc);
  6050. Desc = NULL;
  6051. }
  6052. } else {
  6053. MyFree(SectionData);
  6054. MyFree(Desc);
  6055. Desc = NULL;
  6056. }
  6057. } else {
  6058. MyFree(SectionData);
  6059. }
  6060. return(Desc);
  6061. }
  6062. PTSTR
  6063. pSetupFindLineInSection(
  6064. IN PINIFILESECTION Section,
  6065. IN PCTSTR KeyName, OPTIONAL
  6066. IN PCTSTR RightHandSide OPTIONAL
  6067. )
  6068. /*++
  6069. Routine Description:
  6070. Arguments:
  6071. Return Value:
  6072. --*/
  6073. {
  6074. PTSTR p,q,r;
  6075. BOOL b1,b2;
  6076. if(!KeyName && !RightHandSide) {
  6077. return(NULL);
  6078. }
  6079. for(p=Section->SectionData; *p; p+=lstrlen(p)+1) {
  6080. //
  6081. // Locate key separator if present.
  6082. //
  6083. q = _tcschr(p,TEXT('='));
  6084. //
  6085. // If we need to match by key, attempt that here.
  6086. // If the line has no key then it can't match.
  6087. //
  6088. if(KeyName) {
  6089. if(q) {
  6090. *q = 0;
  6091. b1 = (lstrcmpi(KeyName,p) == 0);
  6092. *q = TEXT('=');
  6093. } else {
  6094. b1 = FALSE;
  6095. }
  6096. } else {
  6097. b1 = TRUE;
  6098. }
  6099. //
  6100. // If we need to match by right hand side, attempt
  6101. // that here.
  6102. //
  6103. if(RightHandSide) {
  6104. //
  6105. // If we have a key, then the right hand side is everything
  6106. // after. If we have no key, then the right hand side is
  6107. // the entire line.
  6108. //
  6109. if(q) {
  6110. r = q + 1;
  6111. } else {
  6112. r = p;
  6113. }
  6114. b2 = (lstrcmpi(r,RightHandSide) == 0);
  6115. } else {
  6116. b2 = TRUE;
  6117. }
  6118. if(b1 && b2) {
  6119. //
  6120. // Return pointer to beginning of line.
  6121. //
  6122. return(p);
  6123. }
  6124. }
  6125. return(NULL);
  6126. }
  6127. BOOL
  6128. pSetupReplaceOrAddLineInSection(
  6129. IN PINIFILESECTION Section,
  6130. IN PCTSTR KeyName, OPTIONAL
  6131. IN PCTSTR RightHandSide, OPTIONAL
  6132. IN BOOL MatchRHS
  6133. )
  6134. {
  6135. PTSTR LineInBuffer,NextLine;
  6136. int CurrentCharsInBuffer;
  6137. int ExistingLineLength,NewLineLength,BufferUsedDelta;
  6138. PVOID p;
  6139. //
  6140. // Locate the line.
  6141. //
  6142. LineInBuffer = pSetupFindLineInSection(
  6143. Section,
  6144. KeyName,
  6145. MatchRHS ? RightHandSide : NULL
  6146. );
  6147. if(LineInBuffer) {
  6148. //
  6149. // Line is in the section. Replace.
  6150. //
  6151. CurrentCharsInBuffer = Section->BufferUsed;
  6152. ExistingLineLength = lstrlen(LineInBuffer)+1;
  6153. NewLineLength = (KeyName ? (lstrlen(KeyName) + 1) : 0) // key=
  6154. + (RightHandSide ? lstrlen(RightHandSide) : 0) // RHS
  6155. + 1; // terminating nul
  6156. //
  6157. // Empty lines not allowed but not error either.
  6158. //
  6159. if(NewLineLength == 1) {
  6160. return(TRUE);
  6161. }
  6162. //
  6163. // Figure out whether we need to grow the buffer.
  6164. //
  6165. BufferUsedDelta = NewLineLength - ExistingLineLength;
  6166. if((BufferUsedDelta > 0) && ((Section->BufferSize - Section->BufferUsed) < BufferUsedDelta)) {
  6167. p = MyRealloc(
  6168. Section->SectionData,
  6169. (Section->BufferUsed + BufferUsedDelta)*sizeof(TCHAR)
  6170. );
  6171. if(p) {
  6172. (PUCHAR)LineInBuffer += (PUCHAR)p - (PUCHAR)Section->SectionData;
  6173. Section->SectionData = p;
  6174. Section->BufferSize = Section->BufferUsed + BufferUsedDelta;
  6175. } else {
  6176. return(FALSE);
  6177. }
  6178. }
  6179. NextLine = LineInBuffer + lstrlen(LineInBuffer) + 1;
  6180. Section->BufferUsed += BufferUsedDelta;
  6181. MoveMemory(
  6182. //
  6183. // Leave exactly enough space for the new line. Since the new line
  6184. // will start at the same place the existing line is at now, the
  6185. // target for the move is simply the first char past what will be
  6186. // copied in later as the new line.
  6187. //
  6188. LineInBuffer + NewLineLength,
  6189. //
  6190. // The rest of the buffer past the line as it exists now must be
  6191. // preserved. Thus the source for the move is the first char of
  6192. // the next line as it is now.
  6193. //
  6194. NextLine,
  6195. //
  6196. // Subtract out the chars in the line as it exists now, since we're
  6197. // going to overwrite it and are making room for the line in its
  6198. // new form. Also subtract out the chars in the buffer that are
  6199. // before the start of the line we're operating on.
  6200. //
  6201. ((CurrentCharsInBuffer - ExistingLineLength) - (LineInBuffer - Section->SectionData))*sizeof(TCHAR)
  6202. );
  6203. if(KeyName) {
  6204. lstrcpy(LineInBuffer,KeyName);
  6205. lstrcat(LineInBuffer,TEXT("="));
  6206. }
  6207. if(RightHandSide) {
  6208. if(KeyName) {
  6209. lstrcat(LineInBuffer,RightHandSide);
  6210. } else {
  6211. lstrcpy(LineInBuffer,RightHandSide);
  6212. }
  6213. }
  6214. return(TRUE);
  6215. } else {
  6216. //
  6217. // Line is not already in the section. Add it to the end.
  6218. //
  6219. return(pSetupAppendLineToSection(Section,KeyName,RightHandSide));
  6220. }
  6221. }
  6222. BOOL
  6223. pSetupAppendLineToSection(
  6224. IN PINIFILESECTION Section,
  6225. IN PCTSTR KeyName, OPTIONAL
  6226. IN PCTSTR RightHandSide OPTIONAL
  6227. )
  6228. {
  6229. int LineLength;
  6230. PVOID p;
  6231. int EndOffset;
  6232. LineLength = (KeyName ? (lstrlen(KeyName) + 1) : 0) // Key=
  6233. + (RightHandSide ? lstrlen(RightHandSide) : 0) // RHS
  6234. + 1; // terminating nul
  6235. //
  6236. // Empty lines not allowed but not error either.
  6237. //
  6238. if(LineLength == 1) {
  6239. return(TRUE);
  6240. }
  6241. if((Section->BufferSize - Section->BufferUsed) < LineLength) {
  6242. p = MyRealloc(
  6243. Section->SectionData,
  6244. (Section->BufferUsed + LineLength) * sizeof(WCHAR)
  6245. );
  6246. if(p) {
  6247. Section->SectionData = p;
  6248. Section->BufferSize = Section->BufferUsed + LineLength;
  6249. } else {
  6250. return(FALSE);
  6251. }
  6252. }
  6253. //
  6254. // Put new text at end of section, remembering that the section
  6255. // is termianted with an extra nul character.
  6256. //
  6257. if(KeyName) {
  6258. lstrcpy(Section->SectionData + Section->BufferUsed - 1,KeyName);
  6259. lstrcat(Section->SectionData + Section->BufferUsed - 1,TEXT("="));
  6260. }
  6261. if(RightHandSide) {
  6262. if(KeyName) {
  6263. lstrcat(Section->SectionData + Section->BufferUsed - 1,RightHandSide);
  6264. } else {
  6265. lstrcpy(Section->SectionData + Section->BufferUsed - 1,RightHandSide);
  6266. }
  6267. }
  6268. Section->BufferUsed += LineLength;
  6269. Section->SectionData[Section->BufferUsed-1] = 0;
  6270. return(TRUE);
  6271. }
  6272. BOOL
  6273. pSetupDeleteLineFromSection(
  6274. IN PINIFILESECTION Section,
  6275. IN PCTSTR KeyName, OPTIONAL
  6276. IN PCTSTR RightHandSide OPTIONAL
  6277. )
  6278. {
  6279. int LineLength;
  6280. PTSTR Line;
  6281. if(!KeyName && !RightHandSide) {
  6282. return(TRUE);
  6283. }
  6284. //
  6285. // Locate the line.
  6286. //
  6287. if(Line = pSetupFindLineInSection(Section,KeyName,RightHandSide)) {
  6288. LineLength = lstrlen(Line) + 1;
  6289. MoveMemory(
  6290. Line,
  6291. Line + LineLength,
  6292. ((Section->SectionData + Section->BufferUsed) - (Line + LineLength))*sizeof(TCHAR)
  6293. );
  6294. Section->BufferUsed -= LineLength;
  6295. }
  6296. return(TRUE);
  6297. }
  6298. DWORD
  6299. pSetupUnloadIniFileSections(
  6300. IN PINISECTIONCACHE SectionList,
  6301. IN BOOL WriteToFile
  6302. )
  6303. {
  6304. DWORD d;
  6305. BOOL b;
  6306. PINIFILESECTION Section,Temp;
  6307. d = NO_ERROR;
  6308. for(Section=SectionList->Sections; Section; Section=Temp) {
  6309. Temp = Section->Next;
  6310. if(WriteToFile) {
  6311. //
  6312. // Delete the existing section first and then recreate it.
  6313. //
  6314. b = WritePrivateProfileString(
  6315. Section->SectionName,
  6316. NULL,
  6317. NULL,
  6318. Section->IniFileName
  6319. );
  6320. if(b) {
  6321. b = WritePrivateProfileSection(
  6322. Section->SectionName,
  6323. Section->SectionData,
  6324. Section->IniFileName
  6325. );
  6326. }
  6327. if(!b && (d == NO_ERROR)) {
  6328. d = GetLastError();
  6329. //
  6330. // Allow invalid param because sometime we have problems
  6331. // when ini files are mapped into the registry.
  6332. //
  6333. if(d == ERROR_INVALID_PARAMETER) {
  6334. d = NO_ERROR;
  6335. }
  6336. }
  6337. }
  6338. MyFree(Section->SectionData);
  6339. MyFree(Section->SectionName);
  6340. MyFree(Section->IniFileName);
  6341. MyFree(Section);
  6342. }
  6343. return(d);
  6344. }
  6345. DWORD
  6346. pSetupValidateDevRegProp(
  6347. IN ULONG CmPropertyCode,
  6348. IN DWORD ValueType,
  6349. IN PCVOID Data,
  6350. IN DWORD DataSize,
  6351. OUT PVOID *ConvertedBuffer,
  6352. OUT PDWORD ConvertedBufferSize
  6353. )
  6354. /*++
  6355. Routine Description:
  6356. This routine validates the data buffer passed in with respect to the
  6357. specified device registry property code. If the code is not of the correct
  6358. form, but can be converted (e.g., REG_EXPAND_SZ -> REG_SZ), then the
  6359. conversion is done and placed into a new buffer, that is returned to the
  6360. caller.
  6361. Arguments:
  6362. CmPropertyCode - Specifies the CM_DRP code indentifying the device registry property
  6363. with which this data buffer is associated.
  6364. ValueType - Specifies the registry data type for the supplied buffer.
  6365. Data - Supplies the address of the data buffer.
  6366. DataSize - Supplies the size, in bytes, of the data buffer.
  6367. ConvertedBuffer - Supplies the address of a variable that receives a newly-allocated
  6368. buffer containing a converted form of the supplied data. If the data needs no
  6369. conversion, this parameter will be set to NULL on return.
  6370. ConvertedBufferSize - Supplies the address of a variable that receives the size, in
  6371. bytes, of the converted buffer, or 0 if no conversion was required.
  6372. Return Value:
  6373. If successful, the return value is NO_ERROR, otherwise it is an ERROR_* code.
  6374. --*/
  6375. {
  6376. //
  6377. // Initialize ConvertedBuffer output params to indicate that no conversion was necessary.
  6378. //
  6379. *ConvertedBuffer = NULL;
  6380. *ConvertedBufferSize = 0;
  6381. //
  6382. // Group all properties expecting the same data type together.
  6383. //
  6384. switch(CmPropertyCode) {
  6385. //
  6386. // REG_SZ properties. No other data type is supported.
  6387. //
  6388. case CM_DRP_DEVICEDESC :
  6389. case CM_DRP_SERVICE :
  6390. case CM_DRP_CLASS :
  6391. case CM_DRP_CLASSGUID :
  6392. case CM_DRP_DRIVER :
  6393. case CM_DRP_MFG :
  6394. case CM_DRP_FRIENDLYNAME :
  6395. case CM_DRP_LOCATION_INFORMATION :
  6396. case CM_DRP_SECURITY_SDS :
  6397. case CM_DRP_UI_NUMBER_DESC_FORMAT:
  6398. if(ValueType != REG_SZ) {
  6399. return ERROR_INVALID_REG_PROPERTY;
  6400. }
  6401. break;
  6402. //
  6403. // REG_MULTI_SZ properties. Allow REG_SZ as well, by simply double-terminating
  6404. // the string (i.e., make it a REG_MULTI_SZ with only one string).
  6405. //
  6406. case CM_DRP_HARDWAREID :
  6407. case CM_DRP_COMPATIBLEIDS :
  6408. case CM_DRP_UPPERFILTERS:
  6409. case CM_DRP_LOWERFILTERS:
  6410. if(ValueType == REG_SZ) {
  6411. if(*ConvertedBuffer = MyMalloc(*ConvertedBufferSize = DataSize + sizeof(TCHAR))) {
  6412. CopyMemory(*ConvertedBuffer, Data, DataSize);
  6413. *((PTSTR)((PBYTE)(*ConvertedBuffer) + DataSize)) = TEXT('\0');
  6414. } else {
  6415. return ERROR_NOT_ENOUGH_MEMORY;
  6416. }
  6417. } else if(ValueType != REG_MULTI_SZ) {
  6418. return ERROR_INVALID_REG_PROPERTY;
  6419. }
  6420. break;
  6421. //
  6422. // REG_DWORD properties. Also allow REG_BINARY, as long as the size is right.
  6423. //
  6424. case CM_DRP_CONFIGFLAGS :
  6425. case CM_DRP_CAPABILITIES :
  6426. case CM_DRP_UI_NUMBER :
  6427. case CM_DRP_DEVTYPE :
  6428. case CM_DRP_EXCLUSIVE :
  6429. case CM_DRP_CHARACTERISTICS :
  6430. case CM_DRP_ADDRESS:
  6431. case CM_DRP_REMOVAL_POLICY_OVERRIDE:
  6432. if(((ValueType != REG_DWORD) && (ValueType != REG_BINARY)) || (DataSize != sizeof(DWORD))) {
  6433. return ERROR_INVALID_REG_PROPERTY;
  6434. }
  6435. break;
  6436. //
  6437. // No other properties are supported. Save the trouble of calling a CM API and
  6438. // return failure now.
  6439. //
  6440. default :
  6441. return ERROR_INVALID_REG_PROPERTY;
  6442. }
  6443. return NO_ERROR;
  6444. }
  6445. DWORD
  6446. pSetupValidateClassRegProp(
  6447. IN ULONG CmPropertyCode,
  6448. IN DWORD ValueType,
  6449. IN PCVOID Data,
  6450. IN DWORD DataSize,
  6451. OUT PVOID *ConvertedBuffer,
  6452. OUT PDWORD ConvertedBufferSize
  6453. )
  6454. /*++
  6455. Routine Description:
  6456. This routine validates the data buffer passed in with respect to the specified
  6457. class registry property code.
  6458. Arguments:
  6459. CmPropertyCode - Specifies the CM_CRP code indentifying the device registry property
  6460. with which this data buffer is associated.
  6461. ValueType - Specifies the registry data type for the supplied buffer.
  6462. Data - Supplies the address of the data buffer.
  6463. DataSize - Supplies the size, in bytes, of the data buffer.
  6464. ConvertedBuffer - Supplies the address of a variable that receives a newly-allocated
  6465. buffer containing a converted form of the supplied data. If the data needs no
  6466. conversion, this parameter will be set to NULL on return.
  6467. ConvertedBufferSize - Supplies the address of a variable that receives the size, in
  6468. bytes, of the converted buffer, or 0 if no conversion was required.
  6469. Return Value:
  6470. If successful, the return value is NO_ERROR, otherwise it is an ERROR_* code.
  6471. --*/
  6472. {
  6473. //
  6474. // Initialize ConvertedBuffer output params to indicate that no conversion was necessary.
  6475. //
  6476. *ConvertedBuffer = NULL;
  6477. *ConvertedBufferSize = 0;
  6478. //
  6479. // Group all properties expecting the same data type together.
  6480. //
  6481. switch(CmPropertyCode) {
  6482. //
  6483. // REG_SZ properties. No other data type is supported.
  6484. //
  6485. case CM_CRP_SECURITY_SDS :
  6486. if(ValueType != REG_SZ) {
  6487. return ERROR_INVALID_REG_PROPERTY;
  6488. }
  6489. break;
  6490. //
  6491. // REG_DWORD properties. Also allow REG_BINARY, as long as the size is right.
  6492. //
  6493. case CM_CRP_DEVTYPE :
  6494. case CM_CRP_EXCLUSIVE :
  6495. case CM_CRP_CHARACTERISTICS :
  6496. if(((ValueType != REG_DWORD) && (ValueType != REG_BINARY)) || (DataSize != sizeof(DWORD))) {
  6497. return ERROR_INVALID_REG_PROPERTY;
  6498. }
  6499. break;
  6500. //
  6501. // No other properties are supported. Save the trouble of calling a CM API and
  6502. // return failure now.
  6503. //
  6504. default :
  6505. return ERROR_INVALID_REG_PROPERTY;
  6506. }
  6507. return NO_ERROR;
  6508. }
  6509. #ifdef UNICODE
  6510. //
  6511. // ANSI version
  6512. //
  6513. BOOL
  6514. WINAPI
  6515. SetupInstallServicesFromInfSectionA(
  6516. IN HINF InfHandle,
  6517. IN PCSTR SectionName,
  6518. IN DWORD Flags
  6519. )
  6520. {
  6521. PCWSTR UnicodeSectionName;
  6522. BOOL b;
  6523. DWORD d;
  6524. if((d = pSetupCaptureAndConvertAnsiArg(SectionName, &UnicodeSectionName)) == NO_ERROR) {
  6525. b = SetupInstallServicesFromInfSectionExW(InfHandle,
  6526. UnicodeSectionName,
  6527. Flags,
  6528. INVALID_HANDLE_VALUE,
  6529. NULL,
  6530. NULL,
  6531. NULL
  6532. );
  6533. d = GetLastError();
  6534. MyFree(UnicodeSectionName);
  6535. } else {
  6536. b = FALSE;
  6537. }
  6538. SetLastError(d);
  6539. return b;
  6540. }
  6541. #else
  6542. //
  6543. // Unicode stub
  6544. //
  6545. BOOL
  6546. WINAPI
  6547. SetupInstallServicesFromInfSectionW(
  6548. IN HINF InfHandle,
  6549. IN PCWSTR SectionName,
  6550. IN DWORD Flags
  6551. )
  6552. {
  6553. UNREFERENCED_PARAMETER(InfHandle);
  6554. UNREFERENCED_PARAMETER(SectionName);
  6555. UNREFERENCED_PARAMETER(Flags);
  6556. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  6557. return FALSE;
  6558. }
  6559. #endif
  6560. BOOL
  6561. WINAPI
  6562. SetupInstallServicesFromInfSection(
  6563. IN HINF InfHandle,
  6564. IN PCTSTR SectionName,
  6565. IN DWORD Flags
  6566. )
  6567. /*++
  6568. Routine Description:
  6569. This API performs service installation/deletion operations specified in a service
  6570. install section. Refer to devinstd.c!InstallNtService() for details on the format
  6571. of this section.
  6572. Arguments:
  6573. InfHandle - Supplies the handle of the INF containing the service install section
  6574. SectionName - Supplies the name of the service install section to run.
  6575. Flags - Supplies flags controlling the installation. May be a combination of the
  6576. following values:
  6577. SPSVCINST_TAGTOFRONT - For every kernel or filesystem driver installed (that has
  6578. an associated LoadOrderGroup), always move this service's tag to the front
  6579. of the ordering list.
  6580. SPSVCINST_DELETEEVENTLOGENTRY - For every service specified in a DelService entry,
  6581. delete the associated event log entry (if there is one).
  6582. SPSVCINST_NOCLOBBER_DISPLAYNAME - If this flag is specified, then we will
  6583. not overwrite the service's display name, if it already exists.
  6584. SPSVCINST_NOCLOBBER_STARTTYPE - If this flag is specified, then we will
  6585. not overwrite the service's start type if the service already exists.
  6586. SPSVCINST_NOCLOBBER_ERRORCONTROL - If this flag is specified, then we
  6587. will not overwrite the service's error control value if the service
  6588. already exists.
  6589. SPSVCINST_NOCLOBBER_LOADORDERGROUP - If this flag is specified, then we
  6590. will not overwrite the service's load order group if it already
  6591. exists.
  6592. SPSVCINST_NOCLOBBER_DEPENDENCIES - If this flag is specified, then we
  6593. will not overwrite the service's dependencies list if it already
  6594. exists.
  6595. Return Value:
  6596. If the function succeeds, the return value is TRUE.
  6597. If the function fails, the return value is FALSE. To get extended error
  6598. information, call GetLastError.
  6599. --*/
  6600. {
  6601. return SetupInstallServicesFromInfSectionEx(InfHandle,
  6602. SectionName,
  6603. Flags,
  6604. INVALID_HANDLE_VALUE,
  6605. NULL,
  6606. NULL,
  6607. NULL
  6608. );
  6609. }
  6610. #ifdef UNICODE
  6611. //
  6612. // ANSI version
  6613. //
  6614. BOOL
  6615. WINAPI
  6616. SetupInstallServicesFromInfSectionExA(
  6617. IN HINF InfHandle,
  6618. IN PCSTR SectionName,
  6619. IN DWORD Flags,
  6620. IN HDEVINFO DeviceInfoSet, OPTIONAL
  6621. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  6622. IN PVOID Reserved1,
  6623. IN PVOID Reserved2
  6624. )
  6625. {
  6626. PCWSTR UnicodeSectionName;
  6627. BOOL b;
  6628. DWORD d;
  6629. if((d = pSetupCaptureAndConvertAnsiArg(SectionName, &UnicodeSectionName)) == NO_ERROR) {
  6630. b = SetupInstallServicesFromInfSectionExW(InfHandle,
  6631. UnicodeSectionName,
  6632. Flags,
  6633. DeviceInfoSet,
  6634. DeviceInfoData,
  6635. Reserved1,
  6636. Reserved2
  6637. );
  6638. d = GetLastError();
  6639. MyFree(UnicodeSectionName);
  6640. } else {
  6641. b = FALSE;
  6642. }
  6643. SetLastError(d);
  6644. return b;
  6645. }
  6646. #else
  6647. //
  6648. // Unicode stub
  6649. //
  6650. BOOL
  6651. WINAPI
  6652. SetupInstallServicesFromInfSectionExW(
  6653. IN HINF InfHandle,
  6654. IN PCWSTR SectionName,
  6655. IN DWORD Flags,
  6656. IN HDEVINFO DeviceInfoSet, OPTIONAL
  6657. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  6658. IN PVOID Reserved1,
  6659. IN PVOID Reserved2
  6660. )
  6661. {
  6662. UNREFERENCED_PARAMETER(InfHandle);
  6663. UNREFERENCED_PARAMETER(SectionName);
  6664. UNREFERENCED_PARAMETER(Flags);
  6665. UNREFERENCED_PARAMETER(DeviceInfoSet);
  6666. UNREFERENCED_PARAMETER(DeviceInfoData);
  6667. UNREFERENCED_PARAMETER(Reserved1);
  6668. UNREFERENCED_PARAMETER(Reserved2);
  6669. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  6670. return FALSE;
  6671. }
  6672. #endif
  6673. BOOL
  6674. WINAPI
  6675. SetupInstallServicesFromInfSectionEx(
  6676. IN HINF InfHandle,
  6677. IN PCTSTR SectionName,
  6678. IN DWORD Flags,
  6679. IN HDEVINFO DeviceInfoSet, OPTIONAL
  6680. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  6681. IN PVOID Reserved1,
  6682. IN PVOID Reserved2
  6683. )
  6684. /*++
  6685. Routine Description:
  6686. This API performs service installation/deletion operations specified in a service
  6687. install section. Refer to devinstd.c!InstallNtService() for details on the format
  6688. of this section.
  6689. Arguments:
  6690. InfHandle - Supplies the handle of the INF containing the service install section
  6691. SectionName - Supplies the name of the service install section to run.
  6692. Flags - Supplies flags controlling the installation. May be a combination of the
  6693. following values:
  6694. SPSVCINST_TAGTOFRONT - For every kernel or filesystem driver installed (that has
  6695. an associated LoadOrderGroup), always move this service's tag to the front
  6696. of the ordering list.
  6697. SPSVCINST_ASSOCSERVICE - This flag may only be specified if a device information
  6698. set and a device information element are specified. If set, this flag
  6699. specifies that the service being installed is the owning service (i.e.,
  6700. function driver) for this device instance. If the service install section
  6701. contains more than AddService entry, then this flag is ignored (only 1
  6702. service can be the function driver for a device instance).
  6703. SPSVCINST_DELETEEVENTLOGENTRY - For every service specified in a DelService entry,
  6704. delete the associated event log entry (if there is one).
  6705. SPSVCINST_NOCLOBBER_DISPLAYNAME - If this flag is specified, then we will
  6706. not overwrite the service's display name, if it already exists.
  6707. SPSVCINST_NOCLOBBER_STARTTYPE - If this flag is specified, then we will
  6708. not overwrite the service's start type if the service already exists.
  6709. SPSVCINST_NOCLOBBER_ERRORCONTROL - If this flag is specified, then we
  6710. will not overwrite the service's error control value if the service
  6711. already exists.
  6712. SPSVCINST_NOCLOBBER_LOADORDERGROUP - If this flag is specified, then we
  6713. will not overwrite the service's load order group if it already
  6714. exists.
  6715. SPSVCINST_NOCLOBBER_DEPENDENCIES - If this flag is specified, then we
  6716. will not overwrite the service's dependencies list if it already
  6717. exists.
  6718. DeviceInfoSet - Optionally, supplies a handle to the device information set containing
  6719. an element that is to be associated with the service being installed. If this
  6720. parameter is not specified, then DeviceInfoData is ignored.
  6721. DeviceInfoData - Optionally, specifies the device information element that is to be
  6722. associated with the service being installed. If DeviceInfoSet is specified, then
  6723. this parameter must be specified.
  6724. Reserved1, Reserved2 - Reserved for future use--must be NULL.
  6725. Return Value:
  6726. If the function succeeds, the return value is TRUE.
  6727. If the function fails, the return value is FALSE. To get extended error
  6728. information, call GetLastError.
  6729. --*/
  6730. {
  6731. PDEVICE_INFO_SET pDeviceInfoSet;
  6732. PDEVINFO_ELEM DevInfoElem;
  6733. INFCONTEXT InfContext;
  6734. DWORD d;
  6735. BOOL DontCare;
  6736. BOOL NeedReboot = FALSE;
  6737. //
  6738. // Validate the flags passed in.
  6739. //
  6740. if(Flags & SPSVCINST_ILLEGAL_FLAGS) {
  6741. SetLastError(ERROR_INVALID_FLAGS);
  6742. return FALSE;
  6743. }
  6744. //
  6745. // Make sure that a device information set and element were specified if the
  6746. // SPSVCINST_ASSOCSERVICE flag is set.
  6747. //
  6748. if(Flags & SPSVCINST_ASSOCSERVICE) {
  6749. if(!DeviceInfoSet ||
  6750. (DeviceInfoSet == INVALID_HANDLE_VALUE) ||
  6751. !DeviceInfoData) {
  6752. SetLastError(ERROR_INVALID_PARAMETER);
  6753. return FALSE;
  6754. }
  6755. }
  6756. //
  6757. // Make sure the caller didn't pass us anything in the Reserved parameters.
  6758. //
  6759. if(Reserved1 || Reserved2) {
  6760. SetLastError(ERROR_INVALID_PARAMETER);
  6761. return FALSE;
  6762. }
  6763. //
  6764. // Make sure we were given a section name.
  6765. //
  6766. if(!SectionName) {
  6767. SetLastError(ERROR_INVALID_PARAMETER);
  6768. return FALSE;
  6769. }
  6770. //
  6771. // Lock down the device information set for the duration of this call.
  6772. //
  6773. if(Flags & SPSVCINST_ASSOCSERVICE) {
  6774. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  6775. SetLastError(ERROR_INVALID_HANDLE);
  6776. return FALSE;
  6777. }
  6778. } else {
  6779. pDeviceInfoSet = NULL;
  6780. }
  6781. d = NO_ERROR;
  6782. DevInfoElem = NULL;
  6783. try {
  6784. if(pDeviceInfoSet) {
  6785. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  6786. DeviceInfoData,
  6787. NULL))) {
  6788. d = ERROR_INVALID_PARAMETER;
  6789. goto clean0;
  6790. }
  6791. }
  6792. //
  6793. // We don't do any validation that the section exists in the worker routine--make
  6794. // sure that it does exist.
  6795. //
  6796. if(SetupFindFirstLine(InfHandle, SectionName, NULL, &InfContext)) {
  6797. //
  6798. // If SPSVCINST_ASSOCSERVICE is specified, then ensure that there is exactly
  6799. // one AddService entry in this service install section. If not, then clear
  6800. // this flag.
  6801. //
  6802. if((Flags & SPSVCINST_ASSOCSERVICE) &&
  6803. SetupFindFirstLine(InfHandle, SectionName, pszAddService, &InfContext) &&
  6804. SetupFindNextMatchLine(&InfContext, pszAddService, &InfContext))
  6805. {
  6806. Flags &= ~SPSVCINST_ASSOCSERVICE;
  6807. }
  6808. d = InstallNtService(DevInfoElem,
  6809. InfHandle,
  6810. NULL,
  6811. SectionName,
  6812. NULL,
  6813. Flags | SPSVCINST_NO_DEVINST_CHECK,
  6814. &DontCare
  6815. );
  6816. if ((d == NO_ERROR) && GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) {
  6817. NeedReboot = TRUE;
  6818. }
  6819. } else {
  6820. d = GetLastError();
  6821. pSetupLogSectionWarning(InfHandle,DeviceInfoSet,DeviceInfoData,NULL,SectionName,MSG_LOG_NOSECTION_SERVICE,d,NULL);
  6822. //
  6823. // some callers expect this specific error
  6824. //
  6825. d = ERROR_SECTION_NOT_FOUND;
  6826. }
  6827. clean0: ; // nothing to do.
  6828. } except(EXCEPTION_EXECUTE_HANDLER) {
  6829. d = ERROR_INVALID_PARAMETER;
  6830. }
  6831. if(pDeviceInfoSet) {
  6832. UnlockDeviceInfoSet(pDeviceInfoSet);
  6833. }
  6834. if (!NeedReboot) {
  6835. SetLastError(d);
  6836. } else {
  6837. MYASSERT( d == NO_ERROR );
  6838. }
  6839. return (d == NO_ERROR);
  6840. }
  6841. //
  6842. // Taken from Win95 sxgen.c. These are flags used when
  6843. // we are installing an inf such as when a user right-clicks
  6844. // on one and selects the 'install' action.
  6845. //
  6846. #define HOW_NEVER_REBOOT 0
  6847. #define HOW_ALWAYS_SILENT_REBOOT 1
  6848. #define HOW_ALWAYS_PROMPT_REBOOT 2
  6849. #define HOW_SILENT_REBOOT 3
  6850. #define HOW_PROMPT_REBOOT 4
  6851. #ifdef UNICODE
  6852. //
  6853. // ANSI version
  6854. //
  6855. VOID
  6856. WINAPI
  6857. InstallHinfSectionA(
  6858. IN HWND Window,
  6859. IN HINSTANCE ModuleHandle,
  6860. IN PCSTR CommandLine,
  6861. IN INT ShowCommand
  6862. )
  6863. #else
  6864. //
  6865. // Unicode version
  6866. //
  6867. VOID
  6868. WINAPI
  6869. InstallHinfSectionW(
  6870. IN HWND Window,
  6871. IN HINSTANCE ModuleHandle,
  6872. IN PCWSTR CommandLine,
  6873. IN INT ShowCommand
  6874. )
  6875. #endif
  6876. {
  6877. UNREFERENCED_PARAMETER(Window);
  6878. UNREFERENCED_PARAMETER(ModuleHandle);
  6879. UNREFERENCED_PARAMETER(CommandLine);
  6880. UNREFERENCED_PARAMETER(ShowCommand);
  6881. }
  6882. VOID
  6883. WINAPI
  6884. InstallHinfSection(
  6885. IN HWND Window,
  6886. IN HINSTANCE ModuleHandle,
  6887. IN PCTSTR CommandLine,
  6888. IN INT ShowCommand
  6889. )
  6890. /*++
  6891. Routine Description:
  6892. This is the entry point that performs the INSTALL action when
  6893. a user right-clicks an inf file. It is called by the shell via rundll32.
  6894. The command line is expected to be of the following form:
  6895. <section name> <flags> <file name>
  6896. The section is expected to be a general format install section, and
  6897. may also have an include= line and a needs= line. Infs listed on the
  6898. include= line are append-loaded to the inf on the command line prior to
  6899. any installation. Sections on the needs= line are installed after the
  6900. section listed on the command line.
  6901. After the specified section has been installed, a section of the form:
  6902. [<section name>.Services]
  6903. is used in a call to SetupInstallServicesFromInfSection.
  6904. Arguments:
  6905. Flags - supplies flags for operation.
  6906. 1 - reboot the machine in all cases
  6907. 2 - ask the user if he wants to reboot
  6908. 3 - reboot the machine without asking the user, if we think it is necessary
  6909. 4 - if we think reboot is necessary, ask the user if he wants to reboot
  6910. 0x80 - set the default file source path for file installation to
  6911. the path where the inf is located. (NOTE: this is hardly ever
  6912. necessary for the Setup APIs, since we intelligently determine what
  6913. the source path should be. The only case where this would still be
  6914. useful is if there were a directory that contained INFs that was in
  6915. our INF search path list, but that also contained the files to be
  6916. copied by this INF install action. In that case, this flag would
  6917. still need to be set, or we would look for the files in the location
  6918. from which the OS was installed.
  6919. Return Value:
  6920. None.
  6921. --*/
  6922. {
  6923. TCHAR SourcePathBuffer[MAX_PATH];
  6924. PTSTR SourcePath;
  6925. TCHAR szCmd[MAX_PATH];
  6926. PTCHAR p;
  6927. PTCHAR szHow;
  6928. PTSTR szInfFile, szSectionName;
  6929. INT iHow, NeedRebootFlags;
  6930. HINF InfHandle;
  6931. TCHAR InfSearchPath[MAX_PATH];
  6932. HSPFILEQ FileQueue;
  6933. PVOID QueueContext;
  6934. BOOL b, Error;
  6935. TCHAR ActualSection[MAX_SECT_NAME_LEN];
  6936. DWORD ActualSectionLength;
  6937. DWORD Win32ErrorCode;
  6938. INFCONTEXT InfContext;
  6939. BOOL DontCare;
  6940. DWORD RequiredSize;
  6941. DWORD slot_section = 0;
  6942. BOOL NoProgressUI;
  6943. BOOL reboot = FALSE;
  6944. UNREFERENCED_PARAMETER(ModuleHandle);
  6945. UNREFERENCED_PARAMETER(ShowCommand);
  6946. //
  6947. // Initialize variables that will later contain resource requiring clean-up.
  6948. //
  6949. InfHandle = INVALID_HANDLE_VALUE;
  6950. FileQueue = INVALID_HANDLE_VALUE;
  6951. QueueContext = NULL;
  6952. Error = TRUE; // assume failure.
  6953. try {
  6954. //
  6955. // Take a copy of the command line then get pointers to the fields.
  6956. //
  6957. lstrcpyn(szCmd, CommandLine, SIZECHARS(szCmd));
  6958. szSectionName = szCmd;
  6959. szHow = _tcschr(szSectionName, TEXT(' '));
  6960. if(!szHow) {
  6961. goto c0;
  6962. }
  6963. *szHow++ = TEXT('\0');
  6964. szInfFile = _tcschr(szHow, TEXT(' '));
  6965. if(!szInfFile) {
  6966. goto c0;
  6967. }
  6968. *szInfFile++ = TEXT('\0');
  6969. iHow = _tcstol(szHow, NULL, 10);
  6970. //
  6971. // Get the full path to the INF, so that the path may be used as a
  6972. // first-pass attempt at locating any associated INFs.
  6973. //
  6974. RequiredSize = GetFullPathName(szInfFile,
  6975. SIZECHARS(InfSearchPath),
  6976. InfSearchPath,
  6977. &p
  6978. );
  6979. if(!RequiredSize || (RequiredSize >= SIZECHARS(InfSearchPath))) {
  6980. //
  6981. // If we start failing because MAX_PATH isn't big enough anymore, we
  6982. // wanna know about it!
  6983. //
  6984. MYASSERT(RequiredSize < SIZECHARS(InfSearchPath));
  6985. goto c0;
  6986. }
  6987. //
  6988. // If flag is set (and INF filename includes a path), set up so DIRID_SRCPATH is
  6989. // path where INF is located (i.e., override our default SourcePath determination).
  6990. //
  6991. if((iHow & 0x80) && (pSetupGetFileTitle(szInfFile) != szInfFile)) {
  6992. SourcePath = lstrcpyn(SourcePathBuffer, InfSearchPath, (int)(p - InfSearchPath) + 1);
  6993. } else {
  6994. SourcePath = NULL;
  6995. }
  6996. iHow &= 0x7f;
  6997. //
  6998. // If we're non-interactive, then we don't want to allow any possibility
  6999. // of a reboot prompt happening.
  7000. //
  7001. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  7002. switch(iHow) {
  7003. case HOW_NEVER_REBOOT:
  7004. case HOW_ALWAYS_SILENT_REBOOT:
  7005. case HOW_SILENT_REBOOT:
  7006. //
  7007. // These cases are OK--they're all silent.
  7008. //
  7009. break;
  7010. default:
  7011. //
  7012. // Anything else is disallowed in non-interactive mode.
  7013. //
  7014. goto c0;
  7015. }
  7016. }
  7017. //
  7018. // Load the inf file that was passed on the command line.
  7019. //
  7020. InfHandle = SetupOpenInfFile(szInfFile, NULL, INF_STYLE_WIN4, NULL);
  7021. if(InfHandle == INVALID_HANDLE_VALUE) {
  7022. goto c0;
  7023. }
  7024. //
  7025. // See if there is an nt-specific section
  7026. //
  7027. if(!SetupDiGetActualSectionToInstall(InfHandle,
  7028. szSectionName,
  7029. ActualSection,
  7030. SIZECHARS(ActualSection),
  7031. &ActualSectionLength,
  7032. NULL
  7033. )) {
  7034. goto c0;
  7035. }
  7036. //
  7037. // Check to see if the install section has a "Reboot" line.
  7038. //
  7039. if(SetupFindFirstLine(InfHandle, ActualSection, pszReboot, &InfContext)) {
  7040. reboot = TRUE;
  7041. }
  7042. //
  7043. // Assume there is only one layout file and load it.
  7044. //
  7045. SetupOpenAppendInfFile(NULL, InfHandle, NULL);
  7046. //
  7047. // Append-load any included INFs specified in an "include=" line in our
  7048. // install section.
  7049. //
  7050. AppendLoadIncludedInfs(InfHandle, InfSearchPath, ActualSection, TRUE);
  7051. //
  7052. // Create a setup file queue and initialize the default queue callback.
  7053. //
  7054. FileQueue = SetupOpenFileQueue();
  7055. if(FileQueue == INVALID_HANDLE_VALUE) {
  7056. goto c1;
  7057. }
  7058. //
  7059. // Replace the file queue's log context with the Inf's
  7060. //
  7061. ShareLogContext(&((PLOADED_INF)InfHandle)->LogContext,&((PSP_FILE_QUEUE)FileQueue)->LogContext);
  7062. NoProgressUI = (GuiSetupInProgress || (GlobalSetupFlags & PSPGF_NONINTERACTIVE));
  7063. QueueContext = SetupInitDefaultQueueCallbackEx(
  7064. Window,
  7065. (NoProgressUI ? INVALID_HANDLE_VALUE : NULL),
  7066. 0,
  7067. 0,
  7068. 0
  7069. );
  7070. if(!QueueContext) {
  7071. goto c2;
  7072. }
  7073. if (slot_section == 0) {
  7074. slot_section = AllocLogInfoSlot(((PSP_FILE_QUEUE) FileQueue)->LogContext,FALSE);
  7075. }
  7076. WriteLogEntry(((PSP_FILE_QUEUE) FileQueue)->LogContext,
  7077. slot_section,
  7078. MSG_LOG_INSTALLING_SECTION_FROM,
  7079. NULL,
  7080. ActualSection,
  7081. szInfFile);
  7082. b = (NO_ERROR == InstallFromInfSectionAndNeededSections(NULL,
  7083. InfHandle,
  7084. ActualSection,
  7085. SPINST_FILES,
  7086. NULL,
  7087. SourcePath,
  7088. SP_COPY_NEWER | SP_COPY_LANGUAGEAWARE,
  7089. NULL,
  7090. NULL,
  7091. INVALID_HANDLE_VALUE,
  7092. NULL,
  7093. FileQueue
  7094. ));
  7095. //
  7096. // Commit file queue.
  7097. //
  7098. if(!SetupCommitFileQueue(Window, FileQueue, SetupDefaultQueueCallback, QueueContext)) {
  7099. goto c3;
  7100. }
  7101. //
  7102. // Note, if the INF contains a (non-NULL) ClassGUID, then it will have
  7103. // been installed into %windir%\Inf during the above queue committal.
  7104. // We make no effort to subsequently uninstall it (and its associated
  7105. // PNF and CAT) if something fails below.
  7106. //
  7107. //
  7108. // Perform non-file operations for the section passed on the cmd line.
  7109. //
  7110. b = (NO_ERROR == InstallFromInfSectionAndNeededSections(Window,
  7111. InfHandle,
  7112. ActualSection,
  7113. SPINST_ALL ^ SPINST_FILES,
  7114. NULL,
  7115. NULL,
  7116. 0,
  7117. NULL,
  7118. NULL,
  7119. INVALID_HANDLE_VALUE,
  7120. NULL,
  7121. NULL
  7122. ));
  7123. //
  7124. // Now run the corresponding ".Services" section (if there is one), and
  7125. // then finish up the install.
  7126. //
  7127. CopyMemory(&(ActualSection[ActualSectionLength - 1]),
  7128. pszServicesSectionSuffix,
  7129. sizeof(pszServicesSectionSuffix)
  7130. );
  7131. //
  7132. // We don't do any validation that the section exists in the worker
  7133. // routine--make sure that it does exist.
  7134. //
  7135. if(SetupFindFirstLine(InfHandle, ActualSection, NULL, &InfContext)) {
  7136. Win32ErrorCode = InstallNtService(NULL,
  7137. InfHandle,
  7138. InfSearchPath,
  7139. ActualSection,
  7140. NULL,
  7141. SPSVCINST_NO_DEVINST_CHECK,
  7142. &DontCare
  7143. );
  7144. if(Win32ErrorCode != NO_ERROR) {
  7145. SetLastError(Win32ErrorCode);
  7146. goto c3;
  7147. } else if(GetLastError()==ERROR_SUCCESS_REBOOT_REQUIRED) {
  7148. reboot = TRUE;
  7149. }
  7150. }
  7151. if(reboot) {
  7152. //
  7153. // we've been asked to reboot either by reboot keyword or because of boot-start service
  7154. //
  7155. if(iHow == HOW_SILENT_REBOOT) {
  7156. //
  7157. // We were supposed to only do a silent reboot if necessary.
  7158. // Change this to _always_ do a silent reboot.
  7159. //
  7160. iHow = HOW_ALWAYS_SILENT_REBOOT;
  7161. } else if(iHow != HOW_ALWAYS_SILENT_REBOOT) {
  7162. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  7163. //
  7164. // In the non-interactive case, we have a problem. The
  7165. // caller said to never reboot, but the INF wants us to ask
  7166. // the user. We obviously cannot ask the user.
  7167. //
  7168. // In this case, we assert (we should never be running INFs
  7169. // non-interactively that require a reboot unless we've
  7170. // specified one of the silent reboot flags). We then
  7171. // ignore the reboot flag, since the caller obviously
  7172. // doesn't want it/isn't prepared to deal with it.
  7173. //
  7174. MYASSERT(0);
  7175. } else {
  7176. //
  7177. // In the interactive case, we want to force the (non-
  7178. // silent) reboot prompt (i.e., the INF flag overrides the
  7179. // caller).
  7180. //
  7181. iHow = HOW_ALWAYS_PROMPT_REBOOT;
  7182. }
  7183. }
  7184. }
  7185. if(NO_ERROR != (Win32ErrorCode = pSetupInstallStopEx(TRUE, 0, ((PSP_FILE_QUEUE)FileQueue)->LogContext))) {
  7186. SetLastError(Win32ErrorCode);
  7187. goto c3;
  7188. }
  7189. //
  7190. // Refresh the desktop.
  7191. //
  7192. SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_FLUSHNOWAIT,0,0);
  7193. switch(iHow) {
  7194. case HOW_NEVER_REBOOT:
  7195. break;
  7196. case HOW_ALWAYS_PROMPT_REBOOT:
  7197. RestartDialogEx(Window, NULL, EWX_REBOOT,REASON_PLANNED_FLAG);
  7198. break;
  7199. case HOW_PROMPT_REBOOT:
  7200. SetupPromptReboot(FileQueue, Window, FALSE);
  7201. break;
  7202. case HOW_SILENT_REBOOT:
  7203. if(!(NeedRebootFlags = SetupPromptReboot(FileQueue, Window, TRUE))) {
  7204. break;
  7205. } else if(NeedRebootFlags == -1) {
  7206. //
  7207. // An error occurred--this should never happen.
  7208. //
  7209. goto c3;
  7210. }
  7211. //
  7212. // Let fall through to same code that handles 'always silent reboot'
  7213. // case.
  7214. //
  7215. case HOW_ALWAYS_SILENT_REBOOT:
  7216. //
  7217. // Assumption that user has reboot privs
  7218. //
  7219. if(pSetupEnablePrivilege(SE_SHUTDOWN_NAME, TRUE)) {
  7220. ExitWindowsEx(EWX_REBOOT, 0);
  7221. }
  7222. break;
  7223. }
  7224. //
  7225. // If we get to here, then this routine has been successful.
  7226. //
  7227. Error = FALSE;
  7228. c3:
  7229. if(Error && (GetLastError() == ERROR_CANCELLED)) {
  7230. //
  7231. // If the error was because the user cancelled, then we don't want
  7232. // to consider that as an error (i.e., we don't want to give an
  7233. // error popup later).
  7234. //
  7235. Error = FALSE;
  7236. }
  7237. SetupTermDefaultQueueCallback(QueueContext);
  7238. QueueContext = NULL;
  7239. c2:
  7240. if (slot_section) {
  7241. ReleaseLogInfoSlot(((PSP_FILE_QUEUE) FileQueue)->LogContext,slot_section);
  7242. slot_section = 0;
  7243. }
  7244. SetupCloseFileQueue(FileQueue);
  7245. FileQueue = INVALID_HANDLE_VALUE;
  7246. c1:
  7247. SetupCloseInfFile(InfHandle);
  7248. InfHandle = INVALID_HANDLE_VALUE;
  7249. c0: ; // nothing to do.
  7250. } except(EXCEPTION_EXECUTE_HANDLER) {
  7251. if(QueueContext) {
  7252. SetupTermDefaultQueueCallback(QueueContext);
  7253. }
  7254. if(FileQueue != INVALID_HANDLE_VALUE) {
  7255. if (slot_section) {
  7256. ReleaseLogInfoSlot(((PSP_FILE_QUEUE) FileQueue)->LogContext,slot_section);
  7257. slot_section = 0;
  7258. }
  7259. SetupCloseFileQueue(FileQueue);
  7260. }
  7261. if(InfHandle != INVALID_HANDLE_VALUE) {
  7262. SetupCloseInfFile(InfHandle);
  7263. }
  7264. }
  7265. if(Error) {
  7266. if(!(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP))) {
  7267. //
  7268. // Re-use 'ActualSection' buffer to hold error dialog title.
  7269. //
  7270. if(!LoadString(MyDllModuleHandle,
  7271. IDS_ERROR,
  7272. ActualSection,
  7273. SIZECHARS(ActualSection))) {
  7274. *ActualSection = TEXT('\0');
  7275. }
  7276. FormatMessageBox(MyDllModuleHandle,
  7277. Window,
  7278. MSG_INF_FAILED,
  7279. ActualSection,
  7280. MB_OK | MB_ICONSTOP
  7281. );
  7282. }
  7283. }
  7284. }
  7285. PTSTR
  7286. GetMultiSzFromInf(
  7287. IN HINF InfHandle,
  7288. IN PCTSTR SectionName,
  7289. IN PCTSTR Key,
  7290. OUT PBOOL pSetupOutOfMemory
  7291. )
  7292. /*++
  7293. Routine Description:
  7294. This routine returns a newly-allocated buffer filled with the multi-sz list contained
  7295. in the specified INF line. The caller must free this buffer via MyFree().
  7296. Arguments:
  7297. InfHandle - Supplies a handle to the INF containing the line
  7298. SectionName - Specifies which section within the INF contains the line
  7299. Key - Specifies the line whose fields are to be retrieved as a multi-sz list
  7300. pSetupOutOfMemory - Supplies the address of a boolean variable that is set upon return
  7301. to indicate whether or not a failure occurred because of an out-of-memory condition.
  7302. (Failure for any other reason is assumed to be OK.)
  7303. Return Value:
  7304. If successful, the return value is the address of a newly-allocated buffer containing
  7305. the multi-sz list, otherwise, it is NULL.
  7306. --*/
  7307. {
  7308. INFCONTEXT InfContext;
  7309. PTSTR MultiSz;
  7310. DWORD Size;
  7311. //
  7312. // Initialize out-of-memory indicator to FALSE.
  7313. //
  7314. *pSetupOutOfMemory = FALSE;
  7315. if(!SetupFindFirstLine(InfHandle, SectionName, Key, &InfContext) ||
  7316. !SetupGetMultiSzField(&InfContext, 1, NULL, 0, &Size) || (Size < 3)) {
  7317. return NULL;
  7318. }
  7319. if(MultiSz = MyMalloc(Size * sizeof(TCHAR))) {
  7320. if(SetupGetMultiSzField(&InfContext, 1, MultiSz, Size, &Size)) {
  7321. return MultiSz;
  7322. }
  7323. MyFree(MultiSz);
  7324. } else {
  7325. *pSetupOutOfMemory = TRUE;
  7326. }
  7327. return NULL;
  7328. }
  7329. DWORD
  7330. pSetupInstallStopEx(
  7331. IN BOOL DoRunOnce,
  7332. IN DWORD Flags,
  7333. IN PVOID Reserved OPTIONAL
  7334. )
  7335. /*++
  7336. Routine Description:
  7337. This routine sets up runonce/grpconv to run after a successful INF installation.
  7338. Arguments:
  7339. DoRunOnce - If TRUE, then invoke (via WinExec) the runonce utility to perform the
  7340. runonce actions. If this flag is FALSE, then this routine simply sets the
  7341. runonce registry values and returns.
  7342. NOTE: The return code from WinExec is not currently being checked, so the return
  7343. value of InstallStop only reflects whether the registry values were set up
  7344. successfully--_not_ whether 'runonce -r' was successfully run.
  7345. Flags - Supplies flags that modify the behavior of this routine. May be a
  7346. combination of the following values:
  7347. INSTALLSTOP_NO_UI - Don't display any UI
  7348. INSTALLSTOP_NO_GRPCONV - Don't do GrpConv
  7349. Reserved - Reserved for internal use--external callers must pass NULL.
  7350. Return Value:
  7351. If successful, the return value is NO_ERROR, otherwise it is the Win32 error code
  7352. indicating the error that was encountered.
  7353. --*/
  7354. {
  7355. HKEY hKey, hSetupKey;
  7356. DWORD Error = NO_ERROR;
  7357. LONG l;
  7358. DWORD nValues = 0;
  7359. PSETUP_LOG_CONTEXT lc = (PSETUP_LOG_CONTEXT)Reserved;
  7360. //
  7361. // If we're batching up RunOnce operations for server-side processing, then
  7362. // return immediately without doing a thing.
  7363. //
  7364. if(GlobalSetupFlags & PSPGF_NONINTERACTIVE) {
  7365. return NO_ERROR;
  7366. }
  7367. //
  7368. // First, open the key "HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce"
  7369. //
  7370. if((l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,pszPathRunOnce,0,KEY_WRITE|KEY_READ,&hKey)) != ERROR_SUCCESS) {
  7371. return (DWORD)l;
  7372. }
  7373. if(!(Flags & INSTALLSTOP_NO_GRPCONV)) {
  7374. //
  7375. // If we need to run the runonce exe for the setup key...
  7376. //
  7377. MYASSERT(*pszKeySetup == TEXT('\\'));
  7378. if(RegOpenKeyEx(hKey,
  7379. pszKeySetup + 1, // skip the preceding '\'
  7380. 0,
  7381. KEY_READ,
  7382. &hSetupKey) == ERROR_SUCCESS) {
  7383. //
  7384. // We don't need the key--we just needed to check its existence.
  7385. //
  7386. RegCloseKey(hSetupKey);
  7387. //
  7388. // Add the runonce value.
  7389. //
  7390. Error = (DWORD)RegSetValueEx(hKey,
  7391. REGSTR_VAL_WRAPPER,
  7392. 0,
  7393. REG_SZ,
  7394. (PBYTE)pszRunOnceExe,
  7395. sizeof(pszRunOnceExe)
  7396. );
  7397. } else {
  7398. //
  7399. // We're OK so far.
  7400. //
  7401. Error = NO_ERROR;
  7402. }
  7403. //
  7404. // GroupConv is always run.
  7405. //
  7406. if(Flags & INSTALLSTOP_NO_UI) {
  7407. l = RegSetValueEx(hKey,
  7408. TEXT("GrpConv"),
  7409. 0,
  7410. REG_SZ,
  7411. (PBYTE)pszGrpConvNoUi,
  7412. sizeof(pszGrpConvNoUi));
  7413. } else {
  7414. l = RegSetValueEx(hKey,
  7415. TEXT("GrpConv"),
  7416. 0,
  7417. REG_SZ,
  7418. (PBYTE)pszGrpConv,
  7419. sizeof(pszGrpConv));
  7420. }
  7421. }
  7422. if( l != ERROR_SUCCESS ) {
  7423. //
  7424. // Since GrpConv is always run, consider it a more serious error than any error
  7425. // encountered when setting 'runonce'. (This decision is rather arbitrary, but
  7426. // in practice, it should never make any difference. Once we get the registry key
  7427. // opened, there's no reason either of these calls to RegSetValueEx should fail.)
  7428. //
  7429. Error = (DWORD)l;
  7430. }
  7431. if (DoRunOnce && (GlobalSetupFlags & PSPGF_NO_RUNONCE)==0) {
  7432. STARTUPINFO StartupInfo;
  7433. PROCESS_INFORMATION ProcessInformation;
  7434. BOOL started;
  7435. TCHAR cmdline[MAX_PATH];
  7436. //
  7437. // we want to know how many items we'll be executing in RunOnce to estimate a timeout
  7438. //
  7439. // This is black-art, we'll allow 5 mins + 1 min per item we
  7440. // find in RunOnce key, but we don't know if there are any other (new) RunOnce keys
  7441. //
  7442. l = RegQueryInfoKey(hKey,NULL,NULL,NULL,
  7443. NULL,NULL,NULL,
  7444. &nValues,
  7445. NULL, NULL, NULL, NULL);
  7446. if ( l != ERROR_SUCCESS ) {
  7447. nValues = 5;
  7448. } else {
  7449. nValues += 5;
  7450. }
  7451. RegCloseKey(hKey);
  7452. ZeroMemory(&StartupInfo,sizeof(StartupInfo));
  7453. ZeroMemory(&ProcessInformation,sizeof(ProcessInformation));
  7454. StartupInfo.cb = sizeof(StartupInfo);
  7455. StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  7456. StartupInfo.wShowWindow = SW_SHOWNORMAL; // runonce -r ignores this anyway
  7457. lstrcpy(cmdline,TEXT("runonce -r"));
  7458. if (lc) {
  7459. //
  7460. // log this information only if we have a context, else don't waste space
  7461. //
  7462. WriteLogEntry(lc,
  7463. SETUP_LOG_INFO,
  7464. MSG_LOG_RUNONCE_CALL,
  7465. NULL,
  7466. nValues
  7467. );
  7468. }
  7469. started = CreateProcess(NULL, // use application name below
  7470. cmdline, // command to execute
  7471. NULL, // default process security
  7472. NULL, // default thread security
  7473. FALSE, // don't inherit handles
  7474. 0, // default flags
  7475. NULL, // inherit environment
  7476. NULL, // inherit current directory
  7477. &StartupInfo,
  7478. &ProcessInformation);
  7479. if(started) {
  7480. DWORD WaitProcStatus;
  7481. DWORD Timeout;
  7482. BOOL KeepWaiting = TRUE;
  7483. if (nValues > RUNONCE_THRESHOLD) {
  7484. Timeout = RUNONCE_TIMEOUT * RUNONCE_THRESHOLD;
  7485. } else if (nValues > 0) {
  7486. Timeout = RUNONCE_TIMEOUT * nValues;
  7487. } else {
  7488. //
  7489. // assume something strange - shouldn't occur
  7490. //
  7491. Timeout = RUNONCE_TIMEOUT * RUNONCE_THRESHOLD;
  7492. }
  7493. while (KeepWaiting) {
  7494. WaitProcStatus = MyMsgWaitForMultipleObjectsEx(
  7495. 1,
  7496. &ProcessInformation.hProcess,
  7497. Timeout,
  7498. QS_ALLINPUT,
  7499. MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
  7500. switch (WaitProcStatus) {
  7501. case WAIT_OBJECT_0 + 1: { // Process gui messages
  7502. MSG msg;
  7503. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  7504. TranslateMessage(&msg);
  7505. DispatchMessage(&msg);
  7506. }
  7507. // fall through ...
  7508. }
  7509. case WAIT_IO_COMPLETION:
  7510. break;
  7511. case WAIT_OBJECT_0:
  7512. case WAIT_TIMEOUT:
  7513. default:
  7514. KeepWaiting = FALSE;
  7515. break;
  7516. }
  7517. }
  7518. if (WaitProcStatus == WAIT_TIMEOUT) {
  7519. //
  7520. // We won't consider this a critical failure--the runonce task
  7521. // will continue. We do want to log an error about this.
  7522. //
  7523. WriteLogEntry(lc,
  7524. SETUP_LOG_ERROR,
  7525. MSG_LOG_RUNONCE_TIMEOUT,
  7526. NULL
  7527. );
  7528. }
  7529. CloseHandle(ProcessInformation.hThread);
  7530. CloseHandle(ProcessInformation.hProcess);
  7531. } else {
  7532. DWORD CreateProcError;
  7533. //
  7534. // We won't consider this a critical failure--the runonce task
  7535. // should get picked up later by someone else (e.g., at next
  7536. // login). We do want to log an error about this, however.
  7537. //
  7538. CreateProcError = GetLastError();
  7539. WriteLogEntry(lc,
  7540. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  7541. MSG_LOG_RUNONCE_FAILED,
  7542. NULL
  7543. );
  7544. WriteLogError(lc,
  7545. SETUP_LOG_ERROR,
  7546. CreateProcError
  7547. );
  7548. }
  7549. } else {
  7550. RegCloseKey(hKey);
  7551. }
  7552. return Error;
  7553. }
  7554. PPSP_RUNONCE_NODE
  7555. pSetupAccessRunOnceNodeList(
  7556. VOID
  7557. )
  7558. /*++
  7559. Routine Description:
  7560. This routine returns a pointer to the head of the global RunOnce node list.
  7561. The caller may traverse the list (via the Next pointer), but does not own
  7562. the list, and may not modify it in any way.
  7563. To cause the list to be freed, use pSetupDestroyRunOnceNodeList.
  7564. Arguments:
  7565. None
  7566. Return Value:
  7567. Pointer to the first item in the list, or NULL if the list is empty.
  7568. Remarks:
  7569. THIS ROUTINE IS NOT THREAD SAFE, AND IS FOR USE SOLELY BY THE SINGLE THREAD
  7570. IN UMPNPMGR THAT DOES DEVICE INSTALLATIONS.
  7571. --*/
  7572. {
  7573. return RunOnceListHead;
  7574. }
  7575. VOID
  7576. pSetupDestroyRunOnceNodeList(
  7577. VOID
  7578. )
  7579. /*++
  7580. Routine Description:
  7581. This routine frees the global list of RunOnce nodes, setting it back to an
  7582. empty list.
  7583. Arguments:
  7584. None
  7585. Return Value:
  7586. None
  7587. Remarks:
  7588. THIS ROUTINE IS NOT THREAD SAFE, AND IS FOR USE SOLELY BY THE SINGLE THREAD
  7589. IN UMPNPMGR THAT DOES DEVICE INSTALLATIONS.
  7590. --*/
  7591. {
  7592. PPSP_RUNONCE_NODE NextNode;
  7593. while(RunOnceListHead) {
  7594. NextNode = RunOnceListHead->Next;
  7595. MyFree(RunOnceListHead->DllFullPath);
  7596. MyFree(RunOnceListHead->DllEntryPointName);
  7597. MyFree(RunOnceListHead->DllParams);
  7598. MyFree(RunOnceListHead);
  7599. RunOnceListHead = NextNode;
  7600. }
  7601. }