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.

981 lines
31 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All Rights Reserved.
  3. Module Name:
  4. msoobci.c
  5. Abstract:
  6. Exception Pack installer helper DLL
  7. Can be used as a co-installer, or called via setup app, or RunDll32 stub
  8. This DLL is for internal distribution of exception packs to update
  9. OS components.
  10. Author:
  11. Jamie Hunter (jamiehun) 2001-11-27
  12. Revision History:
  13. Jamie Hunter (jamiehun) 2001-11-27
  14. Initial Version
  15. --*/
  16. #include "msoobcip.h"
  17. typedef struct _INST_POSTPROCESSING_INFO {
  18. DWORD Flags;
  19. } INST_POSTPROCESSING_INFO;
  20. DWORD
  21. CALLBACK
  22. DriverInstallComponents (
  23. IN DI_FUNCTION InstallFunction,
  24. IN HDEVINFO DeviceInfoSet,
  25. IN PSP_DEVINFO_DATA DeviceInfoData,
  26. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  27. )
  28. /*++
  29. Routine Description:
  30. co-installer callback
  31. catch the moment of call to DIF_INSTALLDEVICE
  32. Consider installing exception packs at this point
  33. If we succeed, we may need to restart device install
  34. Arguments:
  35. InstallFunction - DIF_INSTALLDEVICE
  36. DeviceInfoSet/DeviceInfoData - describes device
  37. Return Value:
  38. status, normally NO_ERROR
  39. --*/
  40. {
  41. DWORD Status = NO_ERROR;
  42. if((g_VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && (g_VerInfo.dwMajorVersion >= 5)) {
  43. //
  44. // we should only be executing co-installers on Win2k+
  45. // but this is an added sanity check
  46. //
  47. switch (InstallFunction)
  48. {
  49. case DIF_INSTALLDEVICE:
  50. VerbosePrint(TEXT("handling DIF_INSTALLDEVICE"));
  51. if(Context->PostProcessing) {
  52. Status = DoDriverInstallComponentsPostProcessing(DeviceInfoSet,DeviceInfoData,Context);
  53. } else {
  54. Status = DoDriverInstallComponents(DeviceInfoSet,DeviceInfoData,Context);
  55. }
  56. VerbosePrint(TEXT("finished DIF_INSTALLDEVICE with status=0x%08x"),Status);
  57. break;
  58. default:
  59. break;
  60. }
  61. }
  62. return Status;
  63. }
  64. DWORD
  65. DoDriverInstallComponents (
  66. IN HDEVINFO DeviceInfoSet,
  67. IN PSP_DEVINFO_DATA DeviceInfoData,
  68. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  69. )
  70. /*++
  71. Routine Description:
  72. co-installer callback
  73. enumerate all the components sections
  74. Arguments:
  75. DeviceInfoSet/DeviceInfoData - describes device
  76. Context - callback context
  77. Return Value:
  78. status, normally NO_ERROR
  79. --*/
  80. {
  81. SP_DRVINFO_DATA DriverInfoData;
  82. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  83. HINF InfFile = INVALID_HANDLE_VALUE;
  84. DWORD AndFlags = (DWORD)(-1);
  85. DWORD OrFlags = (DWORD)0;
  86. INFCONTEXT CompLine;
  87. TCHAR InstallSectionName[LINE_LEN];
  88. TCHAR CompSectionName[LINE_LEN];
  89. DWORD FieldIndex;
  90. DWORD FieldCount;
  91. DWORD Status;
  92. DWORD FinalStatus = NO_ERROR;
  93. INST_POSTPROCESSING_INFO PostProcess;
  94. ZeroMemory(&PostProcess,sizeof(PostProcess));
  95. //
  96. // determine selected driver
  97. // and INF
  98. //
  99. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  100. if (!SetupDiGetSelectedDriver( DeviceInfoSet,
  101. DeviceInfoData,
  102. &DriverInfoData)) {
  103. Status = GetLastError();
  104. DebugPrint(TEXT("Fail: SetupDiGetSelectedDriver, Error: 0x%08x"),Status);
  105. goto clean;
  106. }
  107. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  108. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  109. DeviceInfoData,
  110. &DriverInfoData,
  111. &DriverInfoDetailData,
  112. sizeof(SP_DRVINFO_DETAIL_DATA),
  113. NULL)) {
  114. Status = GetLastError();
  115. if (Status == ERROR_INSUFFICIENT_BUFFER) {
  116. //
  117. // We don't need the extended information. Ignore.
  118. //
  119. } else {
  120. DebugPrint(TEXT("Fail: SetupDiGetDriverInfoDetail, 0xError: %08x"),Status);
  121. goto clean;
  122. }
  123. }
  124. InfFile = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
  125. NULL,
  126. INF_STYLE_WIN4,
  127. NULL);
  128. if (InfFile == INVALID_HANDLE_VALUE) {
  129. Status = GetLastError();
  130. DebugPrint(TEXT("Fail: SetupOpenInfFile"));
  131. goto clean;
  132. }
  133. if(!SetupDiGetActualSectionToInstall(InfFile,
  134. DriverInfoDetailData.SectionName,
  135. InstallSectionName,
  136. LINE_LEN,
  137. NULL,
  138. NULL)) {
  139. Status = GetLastError();
  140. DebugPrint(TEXT("Fail: SetupDiGetActualSectionToInstall, Error: 0x%08x"),Status);
  141. goto clean;
  142. }
  143. //
  144. // look for one or more Components= entries in INF section
  145. //
  146. if (SetupFindFirstLine(InfFile,
  147. InstallSectionName,
  148. KEY_COMPONENTS,
  149. &CompLine)) {
  150. VerbosePrint(TEXT("Components keyword found in %s"),DriverInfoDetailData.InfFileName);
  151. do {
  152. //
  153. // Components = section,section,...
  154. // first section @ index 1.
  155. //
  156. FieldCount = SetupGetFieldCount(&CompLine);
  157. for(FieldIndex = 1;FieldIndex<=FieldCount;FieldIndex++) {
  158. if(SetupGetStringField(&CompLine,
  159. FieldIndex,
  160. CompSectionName,
  161. LINE_LEN,
  162. NULL)) {
  163. //
  164. // we have a listed section
  165. //
  166. Status = DoDriverComponentsSection(InfFile,
  167. CompSectionName,
  168. &AndFlags,
  169. &OrFlags);
  170. if(Status != NO_ERROR) {
  171. FinalStatus = Status;
  172. goto clean;
  173. }
  174. } else {
  175. Status = GetLastError();
  176. DebugPrint(TEXT("Fail: SetupGetStringField, Error: 0x%08x"),Status);
  177. //
  178. // non-fatal
  179. //
  180. }
  181. }
  182. } while (SetupFindNextMatchLine(&CompLine,
  183. KEY_COMPONENTS,
  184. &CompLine));
  185. //
  186. // handle AndFlags/OrFlags here
  187. //
  188. if(OrFlags & (FLAGS_REBOOT|FLAGS_REINSTALL)) {
  189. //
  190. // reboot is required
  191. //
  192. HMACHINE hMachine = NULL;
  193. SP_DEVINFO_LIST_DETAIL_DATA DevInfoListDetail;
  194. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  195. DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
  196. if(SetupDiGetDeviceInstallParams(DeviceInfoSet,
  197. DeviceInfoData,
  198. &DeviceInstallParams)) {
  199. //
  200. // set reboot flags
  201. //
  202. DeviceInstallParams.Flags |= DI_NEEDRESTART|DI_NEEDREBOOT;
  203. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  204. DeviceInfoData,
  205. &DeviceInstallParams);
  206. }
  207. DevInfoListDetail.cbSize = sizeof(DevInfoListDetail);
  208. if(GetDeviceInfoListDetail(DeviceInfoSet,&DevInfoListDetail)) {
  209. hMachine = DevInfoListDetail.RemoteMachineHandle;
  210. }
  211. Set_DevNode_Problem_Ex(DeviceInfoData->DevInst,
  212. CM_PROB_NEED_RESTART,
  213. CM_SET_DEVINST_PROBLEM_OVERRIDE,
  214. hMachine);
  215. }
  216. if(OrFlags & FLAGS_REINSTALL) {
  217. //
  218. // we'll need to mark the device as needing reinstall when we go through post-processing
  219. //
  220. FinalStatus = ERROR_DI_POSTPROCESSING_REQUIRED;
  221. PostProcess.Flags |= POSTFLAGS_REINSTALL;
  222. }
  223. }
  224. clean:
  225. if (InfFile != INVALID_HANDLE_VALUE) {
  226. SetupCloseInfFile(InfFile);
  227. }
  228. if(FinalStatus == ERROR_DI_POSTPROCESSING_REQUIRED) {
  229. //
  230. // data to use during post-processing
  231. //
  232. INST_POSTPROCESSING_INFO *pPostProcess = malloc(sizeof(INST_POSTPROCESSING_INFO));
  233. if(!pPostProcess) {
  234. return ERROR_OUTOFMEMORY;
  235. }
  236. *pPostProcess = PostProcess;
  237. Context->PrivateData = pPostProcess;
  238. }
  239. return FinalStatus;
  240. }
  241. DWORD
  242. DoDriverInstallComponentsPostProcessing (
  243. IN HDEVINFO DeviceInfoSet,
  244. IN PSP_DEVINFO_DATA DeviceInfoData,
  245. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  246. )
  247. /*++
  248. Routine Description:
  249. co-installer callback
  250. enumerate all the components sections
  251. Arguments:
  252. DeviceInfoSet/DeviceInfoData - describes device
  253. Context - callback context
  254. Return Value:
  255. status, normally NO_ERROR
  256. --*/
  257. {
  258. INST_POSTPROCESSING_INFO PostProcess;
  259. SP_DEVINFO_LIST_DETAIL_DATA DevInfoListDetail;
  260. HMACHINE hMachine = NULL;
  261. if(!Context->PrivateData) {
  262. return Context->InstallResult;
  263. }
  264. PostProcess = *(INST_POSTPROCESSING_INFO*)(Context->PrivateData);
  265. free(Context->PrivateData);
  266. Context->PrivateData = NULL;
  267. DevInfoListDetail.cbSize = sizeof(DevInfoListDetail);
  268. if(GetDeviceInfoListDetail(DeviceInfoSet,&DevInfoListDetail)) {
  269. hMachine = DevInfoListDetail.RemoteMachineHandle;
  270. }
  271. if(PostProcess.Flags & POSTFLAGS_REINSTALL) {
  272. Set_DevNode_Problem_Ex(DeviceInfoData->DevInst,
  273. CM_PROB_REINSTALL,
  274. CM_SET_DEVINST_PROBLEM_OVERRIDE,
  275. hMachine);
  276. }
  277. return Context->InstallResult;
  278. }
  279. DWORD
  280. DoDriverComponentsSection(
  281. IN HINF InfFile,
  282. IN LPCTSTR CompSectionName,
  283. IN OUT DWORD *AndFlags,
  284. IN OUT DWORD *OrFlags
  285. )
  286. /*++
  287. Routine Description:
  288. enumerate all the component entries in component section
  289. component entry consists of
  290. filename,flags,identity,version
  291. filename is absolute directory, eg, %1%\foo.inf
  292. flags - bit 16 set indicating Exception Pack
  293. bit 0 set indicating device install needs restarting
  294. identity - component GUID
  295. version - component version
  296. Arguments:
  297. InfFile - handle to INF file
  298. CompSectionName - handle to components section
  299. AndFlags/OrFlags - accumulated flags
  300. Return Value:
  301. status, normally NO_ERROR
  302. --*/
  303. {
  304. INFCONTEXT EntryLine;
  305. TCHAR Path[MAX_PATH];
  306. DWORD Flags;
  307. INT FieldVal;
  308. DWORD SubFlags;
  309. DWORD Status;
  310. if (!SetupFindFirstLine(InfFile,
  311. CompSectionName,
  312. NULL,
  313. &EntryLine)) {
  314. //
  315. // section was empty
  316. //
  317. VerbosePrint(TEXT("Section [%s] is empty"),CompSectionName);
  318. return NO_ERROR;
  319. }
  320. VerbosePrint(TEXT("Processing components section [%s]"),CompSectionName);
  321. do {
  322. if(!SetupGetStringField(&EntryLine,COMPFIELD_NAME,Path,MAX_PATH,NULL)) {
  323. Status = GetLastError();
  324. DebugPrint(TEXT("- Fail: SetupGetStringField(1), Error: 0x%08x"),Status);
  325. return NO_ERROR;
  326. }
  327. VerbosePrint(TEXT("Processing component %s"),Path);
  328. if(SetupGetIntField(&EntryLine,COMPFIELD_FLAGS,&FieldVal)) {
  329. Flags = (DWORD)FieldVal;
  330. } else {
  331. Status = GetLastError();
  332. DebugPrint(TEXT("- Fail: SetupGetIntField(2), Error: 0x%08x"),Status);
  333. return NO_ERROR;
  334. }
  335. SubFlags = Flags & ~ FLAGS_METHOD;
  336. switch(Flags & FLAGS_METHOD) {
  337. case FLAGS_EXPACK:
  338. Status = DoDriverExPack(&EntryLine,Path,&SubFlags);
  339. break;
  340. case FLAGS_QFE:
  341. Status = DoDriverQfe(&EntryLine,Path,&SubFlags);
  342. break;
  343. default:
  344. DebugPrint(TEXT("- Fail: Invalid component type"));
  345. Status = ERROR_INVALID_DATA;
  346. break;
  347. }
  348. if(Status != NO_ERROR) {
  349. return Status;
  350. }
  351. if(SubFlags & FLAGS_INSTALLED) {
  352. *AndFlags &= SubFlags;
  353. *OrFlags |= SubFlags;
  354. }
  355. } while (SetupFindNextLine(&EntryLine,&EntryLine));
  356. return NO_ERROR;
  357. }
  358. DWORD
  359. DoDriverExPack(
  360. IN INFCONTEXT *EntryLine,
  361. IN LPCTSTR PathName,
  362. IN OUT DWORD *Flags
  363. )
  364. /*++
  365. Routine Description:
  366. queries and potentially installs exception-pack component
  367. Arguments:
  368. EntryLine - context for remaining information
  369. PathName - name of exception pack INF (param 1)
  370. SubFlags - flags passed in (param 2) sans type of install
  371. component entry consists of
  372. filename,flags,identity,version
  373. filename is absolute directory, eg, %1%\foo.inf
  374. identity - component GUID
  375. version - component version
  376. Return Value:
  377. status, normally NO_ERROR
  378. if return value >= 0x80000000 then it's a HRESULT error
  379. --*/
  380. {
  381. TCHAR CompIdentity[64]; // expecting a GUID
  382. TCHAR CompVersion[64]; // major.minor
  383. TCHAR CompDesc[DESC_SIZE]; // description
  384. GUID ComponentGuid;
  385. INT VerMajor = -1;
  386. INT VerMinor = -1;
  387. INT VerBuild = -1;
  388. INT VerQFE = -1;
  389. DWORD Status;
  390. DWORD dwLen;
  391. HRESULT hrStatus;
  392. SETUP_OS_COMPONENT_DATA OsComponentData;
  393. SETUP_OS_EXCEPTION_DATA OsExceptionData;
  394. UINT uiRes;
  395. TCHAR SrcPath[MAX_PATH];
  396. TCHAR NewSrcPath[MAX_PATH];
  397. TCHAR CompOsVerRange[128];
  398. LPTSTR ToVerPart;
  399. LPTSTR SrcName;
  400. BOOL PreInst = FALSE;
  401. VerbosePrint(TEXT("- %s is an exception pack"),PathName);
  402. //
  403. // now read in identity and version
  404. // we can then check to see if an apropriate version installed
  405. //
  406. if(!SetupGetStringField(EntryLine,COMPFIELD_COMP,CompIdentity,ARRAY_SIZE(CompIdentity),NULL)) {
  407. Status = GetLastError();
  408. DebugPrint(TEXT("- Fail: SetupGetStringField(3), Error: 0x%08x"),Status);
  409. return Status;
  410. }
  411. if(!SetupGetStringField(EntryLine,COMPFIELD_VER,CompVersion,ARRAY_SIZE(CompVersion),NULL)) {
  412. Status = GetLastError();
  413. DebugPrint(TEXT("- Fail: SetupGetStringField(4), Error: 0x%08x"),Status);
  414. return Status;
  415. }
  416. if(!SetupGetStringField(EntryLine,COMPFIELD_DESC,CompDesc,ARRAY_SIZE(CompDesc),NULL)) {
  417. CompDesc[0] = TEXT('\0');
  418. }
  419. if(SetupGetStringField(EntryLine,COMPFIELD_OSVER,CompOsVerRange,ARRAY_SIZE(CompOsVerRange),NULL)) {
  420. //
  421. // need to verify OS version range, do that now
  422. //
  423. int maj_f,min_f,build_f,qfe_f;
  424. int maj_t,min_t,build_t,qfe_t;
  425. ToVerPart = _tcschr(CompOsVerRange,TEXT('-'));
  426. if(ToVerPart) {
  427. *ToVerPart = TEXT('\0');
  428. ToVerPart++;
  429. }
  430. hrStatus = VersionFromString(CompOsVerRange,&maj_f,&min_f,&build_f,&qfe_f);
  431. if(!SUCCEEDED(hrStatus)) {
  432. return (DWORD)hrStatus;
  433. }
  434. if((hrStatus == S_FALSE) || (qfe_f != 0)) {
  435. return ERROR_INVALID_PARAMETER;
  436. }
  437. if(ToVerPart) {
  438. hrStatus = VersionFromString(ToVerPart,&maj_t,&min_t,&build_t,&qfe_t);
  439. if(!SUCCEEDED(hrStatus)) {
  440. return (DWORD)hrStatus;
  441. }
  442. if((hrStatus == S_FALSE) || (qfe_t != 0)) {
  443. return ERROR_INVALID_PARAMETER;
  444. }
  445. if(CompareVersion(maj_f,
  446. min_f,
  447. build_f>0 ? build_f : -1,
  448. 0,
  449. g_VerInfo.dwMajorVersion,
  450. g_VerInfo.dwMinorVersion,
  451. g_VerInfo.dwBuildNumber,
  452. 0) > 0) {
  453. VerbosePrint(TEXT("- Skipped (OS < %u.%u.%u)"),
  454. maj_f,min_f,build_f);
  455. return NO_ERROR;
  456. } else if(CompareVersion(maj_t,
  457. min_t,
  458. build_t>0 ? build_t : -1,
  459. 0,
  460. g_VerInfo.dwMajorVersion,
  461. g_VerInfo.dwMinorVersion,
  462. g_VerInfo.dwBuildNumber,
  463. 0) < 0) {
  464. VerbosePrint(TEXT("- Skipped (OS > %u.%u.%u)"),
  465. maj_t,min_t,build_t);
  466. return NO_ERROR;
  467. }
  468. } else {
  469. if(CompareVersion(maj_f,
  470. min_f,
  471. build_f,
  472. 0,
  473. g_VerInfo.dwMajorVersion,
  474. g_VerInfo.dwMajorVersion,
  475. g_VerInfo.dwMajorVersion,
  476. 0) != 0) {
  477. VerbosePrint(TEXT("- Skipped (OS != %u.%u.%u)"),
  478. maj_f,min_f,build_f);
  479. return NO_ERROR;
  480. }
  481. }
  482. }
  483. //
  484. // fold CompIdentity into a GUID
  485. //
  486. hrStatus = GuidFromString(CompIdentity,&ComponentGuid);
  487. if(!SUCCEEDED(hrStatus)) {
  488. return (DWORD)hrStatus;
  489. }
  490. //
  491. // and version
  492. //
  493. hrStatus = VersionFromString(CompVersion,&VerMajor,&VerMinor,&VerBuild,&VerQFE);
  494. if(hrStatus == S_FALSE) {
  495. return ERROR_INVALID_PARAMETER;
  496. }
  497. if(!SUCCEEDED(hrStatus)) {
  498. return (DWORD)hrStatus;
  499. }
  500. //
  501. // now do a component check
  502. //
  503. ZeroMemory(&OsComponentData,sizeof(OsComponentData));
  504. OsComponentData.SizeOfStruct = sizeof(OsComponentData);
  505. ZeroMemory(&OsExceptionData,sizeof(OsExceptionData));
  506. OsExceptionData.SizeOfStruct = sizeof(OsExceptionData);
  507. if(QueryRegisteredOsComponent(&ComponentGuid,&OsComponentData,&OsExceptionData)) {
  508. //
  509. // maybe already registered?
  510. //
  511. if(CompareCompVersion(VerMajor,VerMinor,VerBuild,VerQFE,&OsComponentData)<=0) {
  512. VerbosePrint(TEXT("- Skipped, %u.%u.%u.%u <= %u.%u.%u.%u"),
  513. VerMajor,VerMinor,VerBuild,VerQFE,
  514. OsComponentData.VersionMajor,
  515. OsComponentData.VersionMinor,
  516. OsComponentData.BuildNumber,
  517. OsComponentData.QFENumber);
  518. return NO_ERROR;
  519. }
  520. }
  521. VerbosePrint(TEXT("- Install, %u.%u.%u.%u > %u.%u.%u.%u"),
  522. VerMajor,VerMinor,VerBuild,VerQFE,
  523. OsComponentData.VersionMajor,
  524. OsComponentData.VersionMinor,
  525. OsComponentData.BuildNumber,
  526. OsComponentData.QFENumber);
  527. //
  528. // we need to make sure component INF media is in
  529. // prompt for media if interactive and INF cannot be found
  530. //
  531. dwLen = GetFullPathName(PathName,MAX_PATH,SrcPath,&SrcName);
  532. if(dwLen >= MAX_PATH) {
  533. return ERROR_INSUFFICIENT_BUFFER;
  534. }
  535. if(SrcName == SrcPath) {
  536. //
  537. // shouldn't happen
  538. //
  539. return ERROR_INVALID_DATA;
  540. }
  541. *CharPrev(SrcPath,SrcName) = TEXT('\0');
  542. uiRes = SetupPromptForDisk(
  543. NULL, // parent
  544. NULL, // title
  545. CompDesc[0] ? CompDesc : NULL, // disk name
  546. SrcPath, // path to source
  547. SrcName, // name of file
  548. NULL, // tag file
  549. IDF_CHECKFIRST|IDF_NOCOMPRESSED|IDF_NOSKIP,
  550. NewSrcPath,
  551. ARRAY_SIZE(NewSrcPath),
  552. NULL);
  553. switch(uiRes) {
  554. case DPROMPT_SUCCESS:
  555. break;
  556. case DPROMPT_CANCEL:
  557. case DPROMPT_SKIPFILE:
  558. return ERROR_FILE_NOT_FOUND;
  559. case DPROMPT_BUFFERTOOSMALL:
  560. return ERROR_INSUFFICIENT_BUFFER;
  561. case DPROMPT_OUTOFMEMORY:
  562. return ERROR_OUTOFMEMORY;
  563. default:
  564. //
  565. // shouldn't happen
  566. //
  567. return ERROR_INVALID_DATA;
  568. }
  569. hrStatus = ConcatPath(NewSrcPath,MAX_PATH,SrcName);
  570. if(!SUCCEEDED(hrStatus)) {
  571. return (DWORD)hrStatus;
  572. }
  573. hrStatus = InstallComponent(NewSrcPath,
  574. COMP_FLAGS_NOUI,
  575. &ComponentGuid,
  576. VerMajor,
  577. VerMinor,
  578. VerBuild,
  579. VerQFE,
  580. CompDesc[0] ? CompDesc : NULL);
  581. if(!SUCCEEDED(hrStatus)) {
  582. return (DWORD)hrStatus;
  583. }
  584. //
  585. // if install was not skipped, we get S_OK, else S_FALSE
  586. //
  587. if(hrStatus == S_OK) {
  588. *Flags |= FLAGS_INSTALLED;
  589. } else if(hrStatus == INST_S_REBOOT) {
  590. *Flags |= FLAGS_INSTALLED|FLAGS_REBOOT;
  591. }
  592. return NO_ERROR;
  593. }
  594. DWORD
  595. CheckQfe(
  596. IN INT SpNum,
  597. IN LPCTSTR QfeNum
  598. )
  599. /*++
  600. Routine Description:
  601. This is pretty dirty, it knows where the QFE #'s will go
  602. in registry for Win2k/WinXP so checks there
  603. this saves us running the QFE unless we need to
  604. (assumption is that target OS version already checked)
  605. Arguments:
  606. SpNum - service pack # that fix should be in
  607. QfeNum - QfeNum of fix
  608. Return Value:
  609. ERROR_INVALID_PARAMETER if version not supported
  610. NO_ERROR if QFE installed
  611. other status if QFE might not be installed
  612. --*/
  613. {
  614. HKEY hKey;
  615. TCHAR KeyPath[MAX_PATH*2];
  616. LONG res;
  617. //
  618. // what about the SP level?
  619. //
  620. if(g_VerInfo.wServicePackMajor >= SpNum) {
  621. VerbosePrint(TEXT("- Skipped (SP >= %u)"),SpNum);
  622. return NO_ERROR;
  623. }
  624. if((g_VerInfo.dwMajorVersion == 5) && (g_VerInfo.dwMinorVersion == 0)) {
  625. //
  626. // check for QFE presence on Windows 2000
  627. //
  628. _sntprintf(KeyPath,ARRAY_SIZE(KeyPath),
  629. TEXT("Software\\Microsoft\\Updates\\Windows 2000\\SP%u\\%s"),
  630. SpNum,
  631. QfeNum);
  632. res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  633. KeyPath,
  634. 0,
  635. KEY_READ,
  636. &hKey);
  637. if(res == NO_ERROR) {
  638. RegCloseKey(hKey);
  639. }
  640. return (DWORD)res;
  641. } else if((g_VerInfo.dwMajorVersion == 5) && (g_VerInfo.dwMinorVersion == 1)) {
  642. //
  643. // check for QFE presence on Windows XP
  644. //
  645. _sntprintf(KeyPath,ARRAY_SIZE(KeyPath),
  646. TEXT("Software\\Microsoft\\Updates\\Windows XP\\SP%u\\%s"),
  647. SpNum,
  648. QfeNum);
  649. res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  650. KeyPath,
  651. 0,
  652. KEY_READ,
  653. &hKey);
  654. if(res == NO_ERROR) {
  655. RegCloseKey(hKey);
  656. }
  657. return (DWORD)res;
  658. } else {
  659. return ERROR_INVALID_PARAMETER;
  660. }
  661. }
  662. DWORD
  663. DoDriverQfe(
  664. IN INFCONTEXT *EntryLine,
  665. IN LPCTSTR PathName,
  666. IN OUT DWORD *Flags
  667. )
  668. /*++
  669. Routine Description:
  670. queries and potentially installs QFE
  671. Arguments:
  672. EntryLine - context for remaining information
  673. PathName - name of exception pack INF (param 1)
  674. SubFlags - flags passed in (param 2) sans type of install
  675. component entry consists of
  676. <path\name>,<flags>,<osver>,<os-sp>,<qfenum>
  677. filename is absolute directory, eg, %1%\foo.exe
  678. <flags> indicates what to do if qfe installed
  679. <osver> indicates os version QFE is for, eg, 5.0
  680. <os-sp> indicates service pack QFE is in, eg, 1
  681. <qfenum> indicates the qfe number as found in registry
  682. Return Value:
  683. status, normally NO_ERROR
  684. if return value >= 0x80000000 then it's a HRESULT error
  685. --*/
  686. {
  687. TCHAR QfeOs[64]; // expecting major.minor
  688. TCHAR QfeNum[64]; // some descriptive name
  689. INT QfeSp;
  690. INT VerMaj,VerMin,VerBuild,VerQfe;
  691. TCHAR Buffer[MAX_PATH];
  692. TCHAR CmdLine[MAX_PATH*3];
  693. STARTUPINFO StartupInfo;
  694. PROCESS_INFORMATION ProcessInfo;
  695. DWORD ExitCode;
  696. DWORD Status;
  697. HRESULT hrStatus;
  698. UINT uiRes;
  699. DWORD dwLen;
  700. TCHAR SrcPath[MAX_PATH];
  701. TCHAR NewSrcPath[MAX_PATH];
  702. LPTSTR SrcName;
  703. VerbosePrint(TEXT("- %s is a QFE"),PathName);
  704. if(!SetupGetStringField(EntryLine,COMPFIELD_QFEOS,QfeOs,ARRAY_SIZE(QfeOs),NULL)) {
  705. Status = GetLastError();
  706. DebugPrint(TEXT("- Fail: SetupGetStringField(3), Error: 0x%08x"),Status);
  707. return Status;
  708. }
  709. if(!SetupGetIntField(EntryLine,COMPFIELD_QFESP,&QfeSp)) {
  710. Status = GetLastError();
  711. DebugPrint(TEXT("- Fail: SetupGetIntField(4), Error: 0x%08x"),Status);
  712. return Status;
  713. }
  714. if(!SetupGetStringField(EntryLine,COMPFIELD_QFENUM,QfeNum,ARRAY_SIZE(QfeNum),NULL)) {
  715. Status = GetLastError();
  716. DebugPrint(TEXT("- Fail: SetupGetStringField(5), Error: 0x%08x"),Status);
  717. return Status;
  718. }
  719. //
  720. // see if QFE is targeted at this version?
  721. //
  722. hrStatus = VersionFromString(QfeOs,&VerMaj,&VerMin,&VerBuild,&VerQfe);
  723. if(!SUCCEEDED(hrStatus)) {
  724. return (DWORD)hrStatus;
  725. }
  726. if((hrStatus == S_FALSE) || (VerBuild != 0) || (VerQfe != 0)) {
  727. return ERROR_INVALID_PARAMETER;
  728. }
  729. if(CompareVersion(VerMaj,
  730. VerMin,
  731. 0,
  732. 0,
  733. g_VerInfo.dwMajorVersion,
  734. g_VerInfo.dwMinorVersion,
  735. 0,
  736. 0) != 0) {
  737. VerbosePrint(TEXT("- Skipped (OS != %u.%u)"),VerMaj,VerMin);
  738. return NO_ERROR;
  739. }
  740. //
  741. // see if the Qfe needs to be installed on this OS
  742. //
  743. Status = CheckQfe(QfeSp,QfeNum);
  744. if(Status == ERROR_INVALID_PARAMETER) {
  745. //
  746. // invalid parameter because in invalid version was
  747. // specified
  748. //
  749. DebugPrint(TEXT("- Cannot install QFE's for %u.%u"),
  750. g_VerInfo.dwMajorVersion,
  751. g_VerInfo.dwMinorVersion);
  752. return Status;
  753. }
  754. //
  755. // ok, has the QFE already been installed?
  756. //
  757. if(Status == NO_ERROR) {
  758. return NO_ERROR;
  759. }
  760. //
  761. // we need to make sure component INF media is in
  762. // prompt for media if interactive and INF cannot be found
  763. //
  764. dwLen = GetFullPathName(PathName,MAX_PATH,SrcPath,&SrcName);
  765. if(dwLen >= MAX_PATH) {
  766. return ERROR_INSUFFICIENT_BUFFER;
  767. }
  768. if(SrcName == SrcPath) {
  769. //
  770. // shouldn't happen
  771. //
  772. return ERROR_INVALID_DATA;
  773. }
  774. *CharPrev(SrcPath,SrcName) = TEXT('\0');
  775. uiRes = SetupPromptForDisk(
  776. NULL, // parent
  777. NULL, // title
  778. QfeNum, // disk name
  779. SrcPath, // path to source
  780. SrcName, // name of file
  781. NULL, // tag file
  782. IDF_CHECKFIRST|IDF_NOCOMPRESSED|IDF_NOSKIP,
  783. NewSrcPath,
  784. ARRAY_SIZE(NewSrcPath),
  785. NULL);
  786. switch(uiRes) {
  787. case DPROMPT_SUCCESS:
  788. break;
  789. case DPROMPT_CANCEL:
  790. case DPROMPT_SKIPFILE:
  791. return ERROR_FILE_NOT_FOUND;
  792. case DPROMPT_BUFFERTOOSMALL:
  793. return ERROR_INSUFFICIENT_BUFFER;
  794. case DPROMPT_OUTOFMEMORY:
  795. return ERROR_OUTOFMEMORY;
  796. default:
  797. //
  798. // shouldn't happen
  799. //
  800. return ERROR_INVALID_DATA;
  801. }
  802. hrStatus = ConcatPath(NewSrcPath,MAX_PATH,SrcName);
  803. if(!SUCCEEDED(hrStatus)) {
  804. return (DWORD)hrStatus;
  805. }
  806. // now build up command line
  807. //
  808. lstrcpy(CmdLine,NewSrcPath);
  809. lstrcat(CmdLine,TEXT(" -n -o -z -q"));
  810. ZeroMemory(&StartupInfo,sizeof(StartupInfo));
  811. StartupInfo.cb = sizeof(StartupInfo);
  812. ZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
  813. //
  814. // kick off rundll32 process to install QFE
  815. //
  816. if(!CreateProcess(NewSrcPath,
  817. CmdLine,
  818. NULL,
  819. NULL,
  820. FALSE, // don't inherit handles
  821. CREATE_NO_WINDOW, // creation flags
  822. NULL, // environment
  823. NULL, // directory
  824. &StartupInfo,
  825. &ProcessInfo
  826. )) {
  827. return GetLastError();
  828. }
  829. if(WaitForSingleObject(ProcessInfo.hProcess,INFINITE) == WAIT_OBJECT_0) {
  830. //
  831. // process terminated 'fine', retrieve status from shared data
  832. //
  833. if(GetExitCodeProcess(ProcessInfo.hProcess,&ExitCode)) {
  834. Status = (DWORD)ExitCode;
  835. } else {
  836. Status = GetLastError();
  837. }
  838. } else {
  839. //
  840. // failure
  841. //
  842. Status = ERROR_INVALID_PARAMETER;
  843. }
  844. CloseHandle(ProcessInfo.hThread);
  845. CloseHandle(ProcessInfo.hProcess);
  846. if(Status != NO_ERROR) {
  847. return Status;
  848. }
  849. if(CheckQfe(QfeSp,QfeNum)!=NO_ERROR) {
  850. //
  851. // sanity check failed
  852. //
  853. return E_UNEXPECTED;
  854. }
  855. //
  856. // if install was not skipped, we get S_OK, else S_FALSE
  857. //
  858. #if 0
  859. if(hrStatus == S_OK) {
  860. *Flags |= FLAGS_INSTALLED;
  861. } else if(hrStatus == INST_S_REBOOT) {
  862. }
  863. #endif
  864. *Flags |= FLAGS_INSTALLED|FLAGS_REBOOT;
  865. return NO_ERROR;
  866. }