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.

575 lines
15 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. external.c
  5. Abstract:
  6. Routines for handling external INFs
  7. Author:
  8. Andrew Ritz (andrewr) 20-Nov-1998
  9. Revision History:
  10. stole a bunch of code from optional.c for this
  11. --*/
  12. #include "setupp.h"
  13. #pragma hdrstop
  14. #include <windowsx.h>
  15. #include <shlobj.h>
  16. VOID
  17. ReportError (
  18. IN LogSeverity Severity,
  19. IN PTSTR MessageString,
  20. IN UINT MessageId,
  21. ...
  22. )
  23. /*++
  24. Routine Description:
  25. Records an error message in the setup action log if we're in Setup,
  26. or puts the message in a dialog box if we're in the cpl.
  27. Arguments:
  28. Severity - the type of message being written
  29. ... - the message id and its arguments
  30. Return Value:
  31. nothing.
  32. --*/
  33. {
  34. va_list arglist;
  35. va_start (arglist, MessageId);
  36. SetuplogErrorV(
  37. Severity,
  38. MessageString,
  39. MessageId,
  40. &arglist);
  41. va_end (arglist);
  42. }
  43. VOID
  44. DoRunonce (
  45. )
  46. /*++
  47. Routine Description:
  48. Invokes runonce.
  49. Arguments:
  50. none.
  51. Return Value:
  52. nothing.
  53. --*/
  54. {
  55. #define RUNONCE_TIMEOUT 60*1000*30 //30 minutes
  56. DWORD reRet = NO_ERROR;
  57. if((reRet = pSetupInstallStopEx( FALSE, INSTALLSTOP_NO_UI, NULL)) == NO_ERROR) {
  58. //
  59. // We successfully setup the registry values - now do runonce
  60. //
  61. InvokeExternalApplicationEx(NULL, L"RUNONCE -r", &reRet, RUNONCE_TIMEOUT, FALSE);
  62. } else {
  63. //
  64. // Log/report an error that registry mods failed for optional compononent.
  65. //
  66. ReportError(LogSevError,
  67. SETUPLOG_USE_MESSAGEID,
  68. MSG_LOG_INF_REGISTRY_ERROR,
  69. TEXT("HKEY_LOCAL_MACHINE\\") REGSTR_PATH_RUNONCE,
  70. 0,
  71. SETUPLOG_USE_MESSAGEID,
  72. reRet,
  73. 0,
  74. 0
  75. );
  76. }
  77. #ifdef _WIN64
  78. //
  79. // on win64, invoke the 32 bit version of runonce as well
  80. //
  81. {
  82. WCHAR Path[MAX_PATH+50];
  83. ExpandEnvironmentStrings(
  84. L"%systemroot%\\SysWOW64\\RUNONCE.EXE -r",
  85. Path,
  86. sizeof(Path)/sizeof(WCHAR));
  87. InvokeExternalApplicationEx(NULL, Path , &reRet, RUNONCE_TIMEOUT, FALSE);
  88. }
  89. #endif
  90. }
  91. BOOL
  92. DoInstallComponentInfs(
  93. IN HWND hwndParent,
  94. IN HWND hProgress, OPTIONAL
  95. IN UINT ProgressMessage,
  96. IN HINF InfHandle,
  97. IN PCWSTR InfSection
  98. )
  99. {
  100. HINF *hInfs = NULL;
  101. PCWSTR *Sections = NULL, *InfNames = NULL;
  102. PCWSTR Inf,Section;
  103. PVOID p;
  104. INFCONTEXT Context;
  105. PVOID QContext = NULL;
  106. HSPFILEQ FileQueue = INVALID_HANDLE_VALUE;
  107. DWORD ScanQueueResult;
  108. LONG NumInfs, InfCount, i;
  109. DWORD LastErrorValue = ERROR_SUCCESS;
  110. BOOL b = FALSE;
  111. REGISTRATION_CONTEXT RegistrationContext;
  112. RtlZeroMemory(&RegistrationContext,sizeof(RegistrationContext));
  113. //
  114. // initialize a file queue
  115. //
  116. FileQueue = SetupOpenFileQueue();
  117. if (FileQueue == INVALID_HANDLE_VALUE) {
  118. ReportError(
  119. LogSevError,
  120. SETUPLOG_USE_MESSAGEID,
  121. MSG_LOG_INF_ALWAYS_ERROR, 0,
  122. SETUPLOG_USE_MESSAGEID,
  123. ERROR_NOT_ENOUGH_MEMORY, 0,0);
  124. goto e0;
  125. }
  126. //
  127. // Initialize the default queue callback.
  128. //
  129. QContext = InitSysSetupQueueCallbackEx(
  130. hwndParent,
  131. hProgress,
  132. ProgressMessage,
  133. 0,NULL);
  134. if (!QContext) {
  135. ReportError(
  136. LogSevError,
  137. SETUPLOG_USE_MESSAGEID,
  138. MSG_LOG_INF_ALWAYS_ERROR, 0,
  139. SETUPLOG_USE_MESSAGEID,
  140. ERROR_NOT_ENOUGH_MEMORY, 0,0);
  141. goto e1;
  142. }
  143. //
  144. // process 'mandatory' component infs.
  145. //
  146. NumInfs = SetupGetLineCount(InfHandle, InfSection);
  147. if (NumInfs <= 0)
  148. {
  149. //
  150. // nothing in section. return success for doing nothing
  151. //
  152. b = TRUE;
  153. goto e2;
  154. }
  155. hInfs = MyMalloc( sizeof(HINF) * NumInfs );
  156. Sections = MyMalloc( sizeof(PCWSTR) * NumInfs );
  157. InfNames = MyMalloc( sizeof(PCWSTR) * NumInfs );
  158. if (!hInfs) {
  159. ReportError(
  160. LogSevError,
  161. SETUPLOG_USE_MESSAGEID,
  162. MSG_LOG_INF_ALWAYS_ERROR, 0,
  163. SETUPLOG_USE_MESSAGEID,
  164. ERROR_NOT_ENOUGH_MEMORY, 0,0);
  165. goto e2;
  166. }
  167. if (!Sections) {
  168. ReportError(
  169. LogSevError,
  170. SETUPLOG_USE_MESSAGEID,
  171. MSG_LOG_INF_ALWAYS_ERROR, 0,
  172. SETUPLOG_USE_MESSAGEID,
  173. ERROR_NOT_ENOUGH_MEMORY, 0,0);
  174. goto e3;
  175. }
  176. if (!InfNames) {
  177. ReportError(
  178. LogSevError,
  179. SETUPLOG_USE_MESSAGEID,
  180. MSG_LOG_INF_ALWAYS_ERROR, 0,
  181. SETUPLOG_USE_MESSAGEID,
  182. ERROR_NOT_ENOUGH_MEMORY, 0,0);
  183. goto e4;
  184. }
  185. RemainingTime = CalcTimeRemaining(Phase_InstallComponentInfs);
  186. SetRemainingTime(RemainingTime);
  187. BEGIN_SECTION(L"Installing component files");
  188. InfCount = 0;
  189. if(SetupFindFirstLine(InfHandle,InfSection,NULL,&Context)) {
  190. do {
  191. if((Inf = pSetupGetField(&Context,1)) && (Section = pSetupGetField(&Context,2))) {
  192. MYASSERT(InfCount < NumInfs);
  193. //
  194. // save away the section name for later on
  195. //
  196. Sections[InfCount] = pSetupDuplicateString(Section);
  197. if (!Sections[InfCount]) {
  198. ReportError(
  199. LogSevError,
  200. SETUPLOG_USE_MESSAGEID,
  201. MSG_LOG_INF_ALWAYS_ERROR, 0,
  202. SETUPLOG_USE_MESSAGEID,
  203. ERROR_NOT_ENOUGH_MEMORY, 0,0);
  204. goto e6;
  205. }
  206. InfNames[InfCount] = pSetupDuplicateString(Inf);
  207. if (!InfNames[InfCount]) {
  208. ReportError(
  209. LogSevError,
  210. SETUPLOG_USE_MESSAGEID,
  211. MSG_LOG_INF_ALWAYS_ERROR, 0,
  212. SETUPLOG_USE_MESSAGEID,
  213. ERROR_NOT_ENOUGH_MEMORY, 0,0);
  214. goto e6;
  215. }
  216. BEGIN_SECTION((PWSTR)Section);
  217. SetupDebugPrint2( TEXT("Installing Section [%s] from %s\n"), Section, Inf );
  218. //
  219. // queue files and save away the inf handle for later on
  220. //
  221. hInfs[InfCount] = SetupOpenInfFile(Inf,NULL,INF_STYLE_OLDNT|INF_STYLE_WIN4,NULL);
  222. if(hInfs[InfCount] && (hInfs[InfCount] != INVALID_HANDLE_VALUE)) {
  223. PCWSTR Signature;
  224. INFCONTEXT Cntxt;
  225. HINF layout = NULL;
  226. if (SetupFindFirstLine( hInfs[InfCount], L"Version",L"Signature", &Cntxt)) {
  227. Signature = pSetupGetField(&Cntxt,1);
  228. MYASSERT(Signature);
  229. if (_wcsicmp(Signature,L"$Windows NT$") == 0) {
  230. SetupOpenAppendInfFile(NULL,hInfs[InfCount],NULL);
  231. } else {
  232. layout = InfCacheOpenLayoutInf(hInfs[InfCount]);
  233. }
  234. }
  235. b = SetupInstallFilesFromInfSection(
  236. hInfs[InfCount],
  237. layout,
  238. FileQueue,
  239. Section,
  240. NULL,
  241. SP_COPY_NEWER
  242. );
  243. if (!b) {
  244. //
  245. // report error but continue with the rest of the infs
  246. //
  247. ReportError(
  248. LogSevError,
  249. SETUPLOG_USE_MESSAGEID,
  250. MSG_LOG_BAD_SECTION,
  251. Section,
  252. Inf,
  253. NULL,
  254. SETUPLOG_USE_MESSAGEID,
  255. GetLastError(),
  256. 0,
  257. 0
  258. );
  259. SetupCloseInfFile(hInfs[InfCount]);
  260. hInfs[InfCount] = INVALID_HANDLE_VALUE;
  261. }
  262. } else {
  263. //
  264. // failed to open inf file
  265. //
  266. ReportError(
  267. LogSevError,
  268. SETUPLOG_USE_MESSAGEID,
  269. MSG_LOG_CANT_OPEN_INF, Inf,
  270. 0,0);
  271. END_SECTION((PWSTR)Section);
  272. goto e5;
  273. }
  274. }
  275. InfCount++;
  276. END_SECTION((PWSTR)Section);
  277. } while(SetupFindNextLine(&Context,&Context));
  278. } else {
  279. // We should have caught this case when we created the buffers!
  280. MYASSERT(FALSE);
  281. }
  282. //
  283. // queued all the files. check if we really have to install any files. if not, we can save
  284. // the time required to commit the queue to disk
  285. //
  286. if(!SetupScanFileQueue(
  287. FileQueue,
  288. SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
  289. hwndParent,
  290. NULL,
  291. NULL,
  292. &ScanQueueResult)) {
  293. //
  294. // SetupScanFileQueue should really never
  295. // fail when you don't ask it to call a
  296. // callback routine, but if it does, just
  297. // go ahead and commit the queue.
  298. //
  299. ScanQueueResult = 0;
  300. }
  301. if( ScanQueueResult != 1 ){
  302. b = SetupCommitFileQueue(
  303. hwndParent,
  304. FileQueue,
  305. SysSetupQueueCallback,
  306. QContext
  307. );
  308. }
  309. LastErrorValue = b ? NO_ERROR : GetLastError();
  310. END_SECTION(L"Installing component files");
  311. TermSysSetupQueueCallback(QContext);
  312. QContext = NULL;
  313. //
  314. // Delete the file queue.
  315. //
  316. if(FileQueue != INVALID_HANDLE_VALUE) {
  317. SetupCloseFileQueue(FileQueue);
  318. FileQueue = INVALID_HANDLE_VALUE;
  319. }
  320. if (!b) {
  321. //
  322. // error commiting the queue. we can't continue at this point since the next operations
  323. // might require the files that we (didn't) copy
  324. //
  325. ReportError(
  326. LogSevError,
  327. SETUPLOG_USE_MESSAGEID,
  328. MSG_LOG_INF_ALWAYS_ERROR, 0,
  329. SETUPLOG_USE_MESSAGEID,
  330. LastErrorValue, 0,0);
  331. goto e6;
  332. }
  333. BEGIN_SECTION(L"Installing component reg settings");
  334. for (i = 0; i< InfCount; i++) {
  335. INFCONTEXT Cntxt;
  336. TCHAR ScratchSectionName[100];
  337. if (hInfs[i] != INVALID_HANDLE_VALUE) {
  338. //
  339. // if the section contains an Addservice or DelService directive,
  340. // we must explicitly install it since SetupInstallFromInfSection
  341. // does not process services. Note that we create the service
  342. // BEFORE we do the other stuff in the section, in case that
  343. // "other stuff" wants to use the service.
  344. //
  345. lstrcpy( ScratchSectionName, Sections[i]);
  346. lstrcat( ScratchSectionName, TEXT(".Services"));
  347. if (SetupFindFirstLine(
  348. hInfs[i],
  349. ScratchSectionName,
  350. L"AddService",
  351. &Cntxt) ||
  352. SetupFindFirstLine(
  353. hInfs[i],
  354. Sections[i],
  355. ScratchSectionName,
  356. &Cntxt)) {
  357. b = SetupInstallServicesFromInfSectionEx(
  358. hInfs[i],
  359. ScratchSectionName,
  360. 0,
  361. NULL,
  362. NULL,
  363. NULL,
  364. NULL);
  365. if (!b) {
  366. //
  367. // log an error and continue
  368. //
  369. ReportError(
  370. LogSevError,
  371. SETUPLOG_USE_MESSAGEID,
  372. MSG_LOG_BAD_SECTION,
  373. Sections[i],InfNames[i], 0,
  374. SETUPLOG_USE_MESSAGEID,
  375. GetLastError(), 0,0);
  376. }
  377. }
  378. b = SetupInstallFromInfSection(
  379. hwndParent,
  380. hInfs[i],
  381. Sections[i],
  382. (SPINST_ALL & ~SPINST_FILES) | SPINST_REGISTERCALLBACKAWARE,
  383. NULL,
  384. NULL,
  385. 0,
  386. RegistrationQueueCallback,
  387. (PVOID)&RegistrationContext,
  388. NULL,
  389. NULL
  390. );
  391. if (!b) {
  392. //
  393. // log an error and continue
  394. //
  395. ReportError(
  396. LogSevError,
  397. SETUPLOG_USE_MESSAGEID,
  398. MSG_LOG_BAD_SECTION,
  399. Sections[i],InfNames[i], 0,
  400. SETUPLOG_USE_MESSAGEID,
  401. GetLastError(), 0,0);
  402. }
  403. }
  404. }
  405. END_SECTION(L"Installing component reg settings");
  406. b = TRUE;
  407. e6:
  408. for (i = 0; i < InfCount; i++) {
  409. MYASSERT(Sections != NULL);
  410. MYASSERT(InfNames != NULL);
  411. MYASSERT(hInfs != INVALID_HANDLE_VALUE);
  412. if (Sections[i]) {
  413. MyFree(Sections[i]);
  414. }
  415. if (InfNames[i]) {
  416. MyFree(InfNames[i]);
  417. }
  418. if (hInfs[i] != INVALID_HANDLE_VALUE) {
  419. SetupCloseInfFile(hInfs[i]);
  420. }
  421. }
  422. e5:
  423. if (InfNames) {
  424. MyFree(InfNames);
  425. }
  426. e4:
  427. if (Sections) {
  428. MyFree(Sections);
  429. }
  430. e3:
  431. if (hInfs) {
  432. MyFree(hInfs);
  433. }
  434. e2:
  435. if (QContext) {
  436. TermSysSetupQueueCallback(QContext);
  437. }
  438. e1:
  439. if (FileQueue != INVALID_HANDLE_VALUE) {
  440. SetupCloseFileQueue(FileQueue);
  441. }
  442. e0:
  443. return(b);
  444. }
  445. BOOL
  446. SetupCreateOptionalComponentsPage(
  447. IN LPFNADDPROPSHEETPAGE AddPageCallback,
  448. IN LPARAM Context
  449. )
  450. {
  451. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  452. return( FALSE );
  453. }
  454. BOOL
  455. ProcessCompatibilityInfs(
  456. IN HWND hwndParent,
  457. IN HWND hProgress, OPTIONAL
  458. IN UINT ProgressMessage
  459. )
  460. {
  461. WCHAR UnattendFile[MAX_PATH];
  462. PCWSTR SectionName = pwCompatibility;
  463. HINF UnattendInf;
  464. GetSystemDirectory(UnattendFile,MAX_PATH);
  465. pSetupConcatenatePaths(UnattendFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  466. UnattendInf = SetupOpenInfFile(UnattendFile,NULL,INF_STYLE_OLDNT,NULL);
  467. if(UnattendInf == INVALID_HANDLE_VALUE) {
  468. return FALSE;
  469. }
  470. DoInstallComponentInfs(hwndParent,
  471. hProgress,
  472. ProgressMessage,
  473. UnattendInf,
  474. SectionName );
  475. SetupCloseInfFile( UnattendInf );
  476. return( TRUE );
  477. }