Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

639 lines
14 KiB

  1. #include "svcpack.h"
  2. //
  3. // The module instance and name
  4. //
  5. HINSTANCE hDllInstance;
  6. //
  7. // The path to the OS Source
  8. //
  9. TCHAR OsSourcePath[MAX_PATH];
  10. //
  11. // Function declarations
  12. //
  13. BOOL
  14. DoPhaseOneWork(VOID);
  15. BOOL
  16. DoPhaseTwoWork(VOID);
  17. BOOL
  18. DoPhaseThreeWork(VOID);
  19. BOOL
  20. DoPhaseFourWork(VOID);
  21. BOOL
  22. InitializeSourcePath(
  23. PTSTR SourcePath,
  24. HINF hInf
  25. );
  26. BOOL
  27. MyInstallProductCatalog(
  28. LPCTSTR PathToCatalog,
  29. LPCTSTR CatalogNoPath
  30. );
  31. LPTSTR
  32. CombinePaths(
  33. IN LPTSTR ParentPath,
  34. IN LPCTSTR ChildPath,
  35. OUT LPTSTR TargetPath // can be same as ParentPath if want to append
  36. );
  37. BOOL
  38. SpawnProcessAndWaitForItToComplete(
  39. IN LPTSTR CommandLine,
  40. OUT PDWORD ReturnCode OPTIONAL
  41. );
  42. BOOL
  43. RunInfProcesses(
  44. IN HINF hInf
  45. );
  46. BOOL
  47. GetInfValue(
  48. IN HINF hInf,
  49. IN LPTSTR SectionName,
  50. IN LPTSTR KeyName,
  51. OUT PDWORD pdwValue
  52. );
  53. BOOL
  54. DoesInfVersionInfoMatch(
  55. IN HINF hInf
  56. );
  57. BOOL
  58. CALLBACK
  59. SvcPackCallbackRoutine(
  60. IN DWORD dwSetupInterval,
  61. IN DWORD dwParam1,
  62. IN DWORD dwParam2,
  63. IN DWORD dwParam3
  64. )
  65. {
  66. switch ( dwSetupInterval ) {
  67. case SVCPACK_PHASE_1:
  68. //
  69. // install catalogs, etc.
  70. //
  71. DoPhaseOneWork();
  72. case SVCPACK_PHASE_2:
  73. case SVCPACK_PHASE_3:
  74. break;
  75. case SVCPACK_PHASE_4:
  76. //
  77. // Do registry changes, etc.
  78. //
  79. DoPhaseFourWork();
  80. break;
  81. }
  82. return TRUE;
  83. }
  84. BOOL
  85. WINAPI
  86. DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvResreved)
  87. {
  88. switch (fdwReason) {
  89. case DLL_PROCESS_ATTACH:
  90. //
  91. // Save the module instance and name
  92. //
  93. hDllInstance = hInstance;
  94. break;
  95. case DLL_THREAD_DETACH:
  96. break;
  97. case DLL_PROCESS_DETACH:
  98. break;
  99. case DLL_THREAD_ATTACH:
  100. default:
  101. break;
  102. }
  103. return TRUE;
  104. }
  105. BOOL
  106. DoPhaseOneWork(
  107. VOID
  108. )
  109. /*++
  110. Routine Description:
  111. Routine installs the catalogs listed in the svcpack.inf's
  112. [ProductCatalogsToInstall] section. It is assumed that these
  113. catalogs are present at the os source path.
  114. Arguments:
  115. None.
  116. Return Value:
  117. TRUE if the catalogs were successfully installed.
  118. --*/
  119. {
  120. HINF hInf;
  121. TCHAR CatalogSourcePath[MAX_PATH];
  122. INFCONTEXT InfContext;
  123. BOOL RetVal = TRUE;
  124. //
  125. // Open the svcpack.inf so we can install items from it.
  126. //
  127. hInf = SetupOpenInfFile(
  128. TEXT("SVCPACK.INF"),
  129. NULL,
  130. INF_STYLE_WIN4,
  131. NULL);
  132. if (hInf == INVALID_HANDLE_VALUE) {
  133. return(FALSE);
  134. }
  135. //
  136. // Make sure the INF has matching version info
  137. // Return TRUE even if the versions don't match so setup doesn't barf.
  138. //
  139. if (!DoesInfVersionInfoMatch(hInf)) {
  140. goto e0;
  141. }
  142. //
  143. // Initialize the source path global variable and save it off for later.
  144. //
  145. if (!InitializeSourcePath(OsSourcePath,hInf)) {
  146. RetVal = FALSE;
  147. goto e0;
  148. }
  149. //
  150. // see if we actually have any catalogs to install
  151. //
  152. if (SetupFindFirstLine(
  153. hInf,
  154. TEXT("ProductCatalogsToInstall"),
  155. NULL,
  156. &InfContext)) {
  157. UINT Count,Total;
  158. //
  159. // we have catalogs in the section, so let's install them.
  160. //
  161. Total = SetupGetLineCount(hInf, TEXT("ProductCatalogsToInstall"));
  162. for (Count = 0; Count < Total; Count++) {
  163. PCTSTR CatalogNoPath;
  164. //
  165. // retrieve a catalog name
  166. //
  167. if(SetupGetLineByIndex(
  168. hInf,
  169. TEXT("ProductCatalogsToInstall"),
  170. Count,
  171. &InfContext)) {
  172. CatalogNoPath = pSetupGetField(&InfContext,1);
  173. //
  174. // build the full path to the catalog
  175. //
  176. _tcscpy(CatalogSourcePath,OsSourcePath);
  177. CombinePaths(
  178. CatalogSourcePath,
  179. CatalogNoPath,
  180. CatalogSourcePath);
  181. //
  182. // now install the catalog
  183. //
  184. if (!MyInstallProductCatalog(
  185. CatalogSourcePath,
  186. CatalogNoPath)) {
  187. RetVal = FALSE;
  188. }
  189. } else {
  190. RetVal = FALSE;
  191. }
  192. }
  193. }
  194. e0:
  195. SetupCloseInfFile( hInf );
  196. return(RetVal);
  197. }
  198. BOOL
  199. MyInstallProductCatalog(
  200. LPCTSTR PathToCatalog,
  201. LPCTSTR CatalogSourceNoPath
  202. )
  203. /*++
  204. Routine Description:
  205. Routine installs the specified catalog with the given source name.
  206. The routine will copy (and if necessary, expand) the catalog file.
  207. It then validates and installs the catalog.
  208. Arguments:
  209. PathToCatalog - full path to catalog
  210. CatalogSourceNoPath - just the filename part of the catalog, which we use
  211. as the filename of the catalog to be installed.
  212. Return Value:
  213. TRUE if the catalogs were successfully installed.
  214. --*/
  215. {
  216. TCHAR CatalogDestPath[MAX_PATH];
  217. TCHAR CatalogDestWithPath[MAX_PATH];
  218. BOOL RetVal = FALSE;
  219. SetupapiVerifyProblem Problem = SetupapiVerifyCatalogProblem;
  220. //
  221. // we need to copy (and potentially expand) the catalog from the source,
  222. // and we use %windir% as a working directory.
  223. //
  224. if(GetWindowsDirectory(
  225. CatalogDestPath,
  226. sizeof(CatalogDestPath)/sizeof(CatalogDestPath[0]))
  227. && GetTempFileName(
  228. CatalogDestPath,
  229. TEXT("SETP"),
  230. 0,
  231. CatalogDestWithPath)) {
  232. //
  233. // assume that media is already present -- since product catalogs
  234. // we installed just prior to this, we know that media was present
  235. // just a few moments ago
  236. //
  237. if ((SetupDecompressOrCopyFile(
  238. PathToCatalog,
  239. CatalogDestWithPath,
  240. NULL) == NO_ERROR)
  241. && (pSetupVerifyCatalogFile(CatalogDestWithPath) == NO_ERROR)
  242. && (pSetupInstallCatalog(
  243. CatalogDestWithPath,
  244. CatalogSourceNoPath,
  245. NULL) == NO_ERROR)) {
  246. RetVal = TRUE;
  247. }
  248. //
  249. // cleanup the temp file.
  250. //
  251. DeleteFile(CatalogDestWithPath);
  252. }
  253. return(RetVal);
  254. }
  255. BOOL
  256. InitializeSourcePath(
  257. PTSTR SourcePath,
  258. HINF hInf
  259. )
  260. /*++
  261. Routine Description:
  262. Routine retrieves the os source path from the registry, then appends
  263. the subdirectory in the specified inf.
  264. Arguments:
  265. None.
  266. Return Value:
  267. TRUE if the catalogs were successfully installed.
  268. --*/
  269. {
  270. HKEY hKey = NULL;
  271. TCHAR TempPath[MAX_PATH];
  272. TCHAR MyAnswerFile[MAX_PATH];
  273. DWORD Type,Size = MAX_PATH;
  274. INFCONTEXT InfContext;
  275. BOOL RetVal = FALSE;
  276. //
  277. // if it was already initialized to something, just return TRUE.
  278. //
  279. if (*SourcePath != (TCHAR)TEXT('\0')) {
  280. RetVal = TRUE;
  281. goto e0;
  282. }
  283. GetSystemDirectory(MyAnswerFile, MAX_PATH);
  284. CombinePaths( MyAnswerFile, TEXT("$winnt$.inf"), MyAnswerFile );
  285. GetPrivateProfileString( TEXT("Data"),
  286. TEXT("DosPath"),
  287. TEXT(""),
  288. TempPath,
  289. sizeof(TempPath)/sizeof(TCHAR),
  290. MyAnswerFile );
  291. _tcscpy(SourcePath,TempPath);
  292. RetVal = TRUE;
  293. //
  294. // now append the subdirectory specified in the inf (if any)
  295. //
  296. if (hInf && SetupFindFirstLine(
  297. hInf,
  298. TEXT("SetupData"),
  299. TEXT("CatalogSubDir"),
  300. &InfContext)) {
  301. PCTSTR p = pSetupGetField(&InfContext,1);
  302. CombinePaths(
  303. SourcePath,
  304. p,
  305. SourcePath);
  306. }
  307. e0:
  308. return(RetVal);
  309. }
  310. BOOL
  311. DoPhaseFourWork(VOID)
  312. {
  313. BOOL Success = TRUE;
  314. HINF hInf = NULL;
  315. //
  316. // Attempt to open the SVCPACK.INF file.
  317. // If found, and no problems with it, do
  318. // the associated work.
  319. //
  320. hInf = SetupOpenInfFile (
  321. TEXT("SVCPACK.INF"),
  322. NULL,
  323. INF_STYLE_WIN4,
  324. NULL
  325. );
  326. if (( hInf == NULL ) || ( hInf == INVALID_HANDLE_VALUE )) {
  327. Success = FALSE;
  328. goto exit0;
  329. }
  330. //
  331. // Make sure the INF has matching version info.
  332. // Return TRUE even if the versions don't match so setup doesn't barf.
  333. //
  334. if (!DoesInfVersionInfoMatch(hInf)) {
  335. goto exit1;
  336. }
  337. Success = RunInfProcesses( hInf );
  338. exit1:
  339. SetupCloseInfFile( hInf );
  340. exit0:
  341. return Success;
  342. }
  343. BOOL
  344. SpawnProcessAndWaitForItToComplete(
  345. IN LPTSTR CommandLine,
  346. OUT PDWORD ReturnCode OPTIONAL
  347. )
  348. {
  349. LPTSTR InternalCommandLine = NULL;
  350. PROCESS_INFORMATION ProcessInfo;
  351. STARTUPINFO StartupInfo;
  352. BOOL Success;
  353. //
  354. // CreateProcess needs a non-const command line buffer because it likes
  355. // to party on it.
  356. //
  357. InternalCommandLine = malloc( MAX_PATH );
  358. if ( InternalCommandLine == NULL ) {
  359. return FALSE;
  360. }
  361. _tcscpy( InternalCommandLine, CommandLine );
  362. ZeroMemory( &StartupInfo, sizeof( StartupInfo ));
  363. StartupInfo.cb = sizeof( StartupInfo );
  364. Success = CreateProcess(
  365. NULL,
  366. InternalCommandLine,
  367. NULL,
  368. NULL,
  369. FALSE,
  370. 0,
  371. NULL,
  372. NULL,
  373. &StartupInfo,
  374. &ProcessInfo
  375. );
  376. if ( ! Success ) {
  377. free( InternalCommandLine );
  378. return FALSE;
  379. }
  380. WaitForSingleObject( ProcessInfo.hProcess, INFINITE );
  381. if ( ReturnCode != NULL ) {
  382. GetExitCodeProcess( ProcessInfo.hProcess, ReturnCode );
  383. }
  384. CloseHandle( ProcessInfo.hProcess );
  385. CloseHandle( ProcessInfo.hThread );
  386. free( InternalCommandLine );
  387. return TRUE;
  388. }
  389. LPTSTR
  390. CombinePaths(
  391. IN LPTSTR ParentPath,
  392. IN LPCTSTR ChildPath,
  393. OUT LPTSTR TargetPath // can be same as ParentPath if want to append
  394. )
  395. {
  396. ULONG ParentLength = _tcslen( ParentPath );
  397. LPTSTR p;
  398. if ( ParentPath != TargetPath ) {
  399. memcpy( TargetPath, ParentPath, ParentLength * sizeof(TCHAR) );
  400. }
  401. p = TargetPath + ParentLength;
  402. if (( ParentLength > 0 ) &&
  403. ( *( p - 1 ) != '\\' ) &&
  404. ( *( p - 1 ) != '/' )) {
  405. *p++ = '\\';
  406. }
  407. _tcscpy( p, ChildPath );
  408. return TargetPath;
  409. }
  410. BOOL
  411. RunInfProcesses(
  412. IN HINF hInf
  413. )
  414. {
  415. LPTSTR SectionName = TEXT("SetupHotfixesToRun");
  416. LPTSTR szFileName;
  417. LPTSTR szFullPath;
  418. INFCONTEXT InfContext;
  419. BOOL Success = TRUE;
  420. //
  421. // Loop through all the lines in the SetupHotfixesToRun section,
  422. // spawning off each one.
  423. //
  424. szFileName = malloc( MAX_PATH );
  425. if (szFileName == NULL) {
  426. Success = FALSE;
  427. goto exit0;
  428. }
  429. szFullPath = malloc( MAX_PATH );
  430. if (szFullPath == NULL) {
  431. Success = FALSE;
  432. goto exit1;
  433. }
  434. Success = SetupFindFirstLine( hInf, SectionName, NULL, &InfContext ) &&
  435. SetupGetLineText( &InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL );
  436. while ( Success ) {
  437. *szFullPath = 0;
  438. CombinePaths( OsSourcePath, szFileName, szFullPath );
  439. //
  440. // OK, spawn the EXE, and ignore any errors returned
  441. //
  442. SpawnProcessAndWaitForItToComplete( szFullPath, NULL );
  443. Success = SetupFindNextLine( &InfContext, &InfContext ) &&
  444. SetupGetLineText( &InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL );
  445. }
  446. Success = TRUE;
  447. free( (PVOID)szFullPath );
  448. exit1:
  449. free( (PVOID)szFileName );
  450. exit0:
  451. return Success;
  452. }
  453. BOOL
  454. GetInfValue(
  455. IN HINF hInf,
  456. IN LPTSTR SectionName,
  457. IN LPTSTR KeyName,
  458. OUT PDWORD pdwValue
  459. )
  460. {
  461. BOOL Success;
  462. TCHAR TextBuffer[MAX_PATH];
  463. Success = SetupGetLineText(
  464. NULL,
  465. hInf,
  466. SectionName,
  467. KeyName,
  468. TextBuffer,
  469. sizeof( TextBuffer ),
  470. NULL
  471. );
  472. *pdwValue = _tcstoul( TextBuffer, NULL, 0 );
  473. return Success;
  474. }
  475. BOOL
  476. DoesInfVersionInfoMatch(
  477. IN HINF hInf
  478. )
  479. {
  480. DWORD dwBuildNumber, dwMajorVersion, dwMinorVersion;
  481. OSVERSIONINFOEX OsVersionInfo;
  482. if (( ! GetInfValue( hInf, TEXT("Version"), TEXT("BuildNumber"), &dwBuildNumber )) ||
  483. ( ! GetInfValue( hInf, TEXT("Version"), TEXT("MajorVersion"), &dwMajorVersion )) ||
  484. ( ! GetInfValue( hInf, TEXT("Version"), TEXT("MinorVersion"), &dwMinorVersion ))) {
  485. return FALSE;
  486. }
  487. OsVersionInfo.dwOSVersionInfoSize = sizeof( OsVersionInfo );
  488. if (!GetVersionEx( (LPOSVERSIONINFO) &OsVersionInfo )) {
  489. return FALSE;
  490. }
  491. if ((OsVersionInfo.dwBuildNumber != dwBuildNumber) ||
  492. (OsVersionInfo.dwMajorVersion != dwMajorVersion) ||
  493. (OsVersionInfo.dwMinorVersion != dwMinorVersion)) {
  494. return FALSE;
  495. }
  496. return TRUE;
  497. }