Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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