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.

645 lines
17 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <io.h>
  4. typedef struct _STANDALONE_COMP {
  5. struct _STANDALONE_COMP *Next;
  6. LPTSTR ComponentId;
  7. HINF Inf;
  8. OCMANAGER_ROUTINES HelperRoutines;
  9. } STANDALONE_COMP, *PSTANDALONE_COMP;
  10. PSTANDALONE_COMP StandaloneComponents = NULL;
  11. DWORD
  12. InvokeStandAloneInstaller(
  13. IN LPCTSTR ComponentId,
  14. IN BOOL PreQueueCommit
  15. );
  16. DWORD
  17. WaitOnApp(
  18. IN HANDLE Process,
  19. OUT PDWORD ExitCode
  20. );
  21. void
  22. SetSuiteCurrentDir(
  23. IN PSTANDALONE_COMP Standalone
  24. )
  25. {
  26. TCHAR NewPath[MAX_PATH];
  27. LPTSTR p;
  28. PHELPER_CONTEXT pContext = (PHELPER_CONTEXT) Standalone->HelperRoutines.OcManagerContext;
  29. _tcscpy(NewPath,pContext->OcManager->MasterOcInfPath);
  30. p = _tcsrchr(NewPath,TEXT('\\'));
  31. if (p) {
  32. *p = 0;
  33. }
  34. SetCurrentDirectory(NewPath);
  35. }
  36. BOOL
  37. CheckIfExistAndAskForMedia(
  38. IN PSTANDALONE_COMP Standalone,
  39. IN LPTSTR ExePath,
  40. IN LPCTSTR Description
  41. )
  42. {
  43. // Check to see if the Exe even exits... if not ask the
  44. PHELPER_CONTEXT pContext = (PHELPER_CONTEXT) Standalone->HelperRoutines.OcManagerContext;
  45. SOURCE_MEDIA Media;
  46. TCHAR NewPath[MAX_PATH*3];
  47. LPTSTR p;
  48. BOOL b = FALSE;
  49. UINT i;
  50. // Prepare Exe file name, Strip off arguments
  51. // Can't have spaces in Exe name.
  52. _tcscpy(NewPath,ExePath);
  53. p = _tcschr(NewPath,TEXT(' '));
  54. if(!p) {
  55. p = _tcschr(NewPath,TEXT('\t'));
  56. }
  57. if(p) {
  58. *p = 0;
  59. }
  60. // Check if we can find the file -
  61. // Assumes that we have right CD or full path
  62. i = GetFileAttributes(NewPath);
  63. if ( i == -1 ) {
  64. // now backup to file part, strip off path leave file name.
  65. p = _tcsrchr(NewPath,TEXT('\\'));
  66. if (!p) {
  67. p = NewPath;
  68. }
  69. Media.Reserved = NULL; // PCWSTR
  70. Media.Description= Description; // PCWSTR
  71. Media.SourcePath = NULL; // PCWSTR
  72. Media.SourceFile = p; // PCWSTR
  73. Media.Tagfile = p; // PCWSTR may be NULL
  74. Media.Flags = 0; // DWORD subset of SP_COPY_xxx
  75. for(b=FALSE,i=0; (i<pContext->OcManager->TopLevelOcCount) && !b; i++) {
  76. b = OcInterfaceNeedMedia(
  77. pContext->OcManager,
  78. pContext->OcManager->TopLevelOcStringIds[i],
  79. &Media,
  80. (LPTSTR)NewPath
  81. );
  82. if (b) {
  83. // Now we have a new Path to the file
  84. // get the last segment of the path
  85. p = _tcsrchr(ExePath,TEXT('\\'));
  86. if (p) {
  87. _tcscat(NewPath,p);
  88. } else {
  89. _tcscat(NewPath,TEXT("\\"));
  90. _tcscat(NewPath,ExePath);
  91. }
  92. // Rewrite path
  93. _tcscpy(ExePath,NewPath);
  94. break;
  95. }
  96. }
  97. }
  98. return b;
  99. }
  100. DWORD
  101. StandAloneSetupAppInterfaceRoutine(
  102. IN LPCVOID ComponentId,
  103. IN LPCVOID SubcomponentId,
  104. IN UINT Function,
  105. IN UINT_PTR Param1,
  106. IN OUT PVOID Param2
  107. )
  108. {
  109. DWORD d;
  110. PSTANDALONE_COMP Standalone,Prev;
  111. switch(Function) {
  112. case OC_PREINITIALIZE:
  113. //
  114. // Run with native character width.
  115. //
  116. #ifdef UNICODE
  117. d = OCFLAG_UNICODE;
  118. #else
  119. d = OCFLAG_ANSI;
  120. #endif
  121. break;
  122. case OC_INIT_COMPONENT:
  123. //
  124. // Inform OC Manager of the version we want.
  125. //
  126. ((PSETUP_INIT_COMPONENT)Param2)->ComponentVersion = OCMANAGER_VERSION;
  127. d = ERROR_NOT_ENOUGH_MEMORY;
  128. if(Standalone = pSetupMalloc(sizeof(STANDALONE_COMP))) {
  129. if(Standalone->ComponentId = pSetupMalloc((lstrlen(ComponentId)+1) * sizeof(TCHAR))) {
  130. lstrcpy(Standalone->ComponentId,ComponentId);
  131. Standalone->Inf = ((PSETUP_INIT_COMPONENT)Param2)->ComponentInfHandle;
  132. Standalone->HelperRoutines = ((PSETUP_INIT_COMPONENT)Param2)->HelperRoutines;
  133. Standalone->Next = StandaloneComponents;
  134. StandaloneComponents = Standalone;
  135. d = NO_ERROR;
  136. } else {
  137. pSetupFree(Standalone);
  138. }
  139. }
  140. break;
  141. case OC_SET_LANGUAGE:
  142. d = TRUE;
  143. break;
  144. case OC_QUERY_IMAGE:
  145. d = 0;
  146. break;
  147. case OC_REQUEST_PAGES:
  148. //
  149. // This component has no pages.
  150. //
  151. d = 0;
  152. break;
  153. case OC_QUERY_SKIP_PAGE:
  154. d = FALSE;
  155. break;
  156. case OC_QUERY_STATE:
  157. {
  158. DWORD dSetupMode;
  159. //
  160. // Allow selection state transition.
  161. //
  162. for(Standalone=StandaloneComponents; Standalone; Standalone=Standalone->Next) {
  163. if(!lstrcmpi(ComponentId,Standalone->ComponentId)) {
  164. break;
  165. }
  166. }
  167. dSetupMode = Standalone->HelperRoutines.GetSetupMode(
  168. Standalone->HelperRoutines.OcManagerContext);
  169. //
  170. // Use default if we have no option...
  171. //
  172. d = SubcompUseOcManagerDefault;
  173. if (Param1 == OCSELSTATETYPE_CURRENT) {
  174. switch(dSetupMode & SETUPMODE_PRIVATE_MASK) {
  175. default:
  176. d = SubcompUseOcManagerDefault;
  177. break;
  178. case SETUPMODE_REMOVEALL:
  179. d = SubcompOff;
  180. break;
  181. case SETUPMODE_ADDEXTRACOMPS:
  182. case SETUPMODE_ADDREMOVE:
  183. case SETUPMODE_UPGRADEONLY:
  184. case SETUPMODE_REINSTALL:
  185. d = Standalone->HelperRoutines.QuerySelectionState(
  186. Standalone->HelperRoutines.OcManagerContext,
  187. SubcomponentId,
  188. OCSELSTATETYPE_ORIGINAL) ? SubcompOn : SubcompOff;
  189. break;
  190. }
  191. }
  192. break;
  193. }
  194. case OC_QUERY_CHANGE_SEL_STATE:
  195. d = TRUE;
  196. break;
  197. case OC_CALC_DISK_SPACE:
  198. for(Standalone=StandaloneComponents; Standalone; Standalone=Standalone->Next) {
  199. if(!lstrcmpi(ComponentId,Standalone->ComponentId)) {
  200. break;
  201. }
  202. }
  203. if(Standalone) {
  204. INFCONTEXT Context;
  205. if(SetupFindFirstLine(Standalone->Inf,ComponentId,TEXT("DiskSpaceEstimate"),&Context)) {
  206. LONGLONG Space;
  207. int SpaceMB;
  208. BOOL b;
  209. TCHAR Path[MAX_PATH];
  210. if(SetupGetIntField(&Context,1,&SpaceMB)) {
  211. Space = (LONGLONG)SpaceMB * (1024*1024);
  212. if(!Param1) {
  213. Space = 0 - Space;
  214. }
  215. GetWindowsDirectory(Path,MAX_PATH);
  216. Path[3] = 0;
  217. b = SetupAdjustDiskSpaceList((HDSKSPC)Param2,Path,Space,0,0);
  218. d = b ? NO_ERROR : GetLastError();
  219. } else {
  220. d = ERROR_INVALID_DATA;
  221. }
  222. }
  223. } else {
  224. d = NO_ERROR;
  225. }
  226. break;
  227. case OC_QUEUE_FILE_OPS:
  228. //
  229. // No files to queue.
  230. //
  231. d = NO_ERROR;
  232. break;
  233. case OC_NOTIFICATION_FROM_QUEUE:
  234. d = 0;
  235. break;
  236. case OC_QUERY_STEP_COUNT:
  237. //
  238. // Just use 1 step.
  239. //
  240. d = 1;
  241. break;
  242. case OC_ABOUT_TO_COMMIT_QUEUE:
  243. case OC_COMPLETE_INSTALLATION:
  244. // Figure out whether state changed, and if so, invoke
  245. // the install/uninstall cmd line. Just to be safe, we ignore
  246. // any requests that are not for the component as a whole,
  247. // since these were not supposed to have been specified in the first place.
  248. //
  249. d = SubcomponentId
  250. ? NO_ERROR
  251. : InvokeStandAloneInstaller(ComponentId,Function == OC_ABOUT_TO_COMMIT_QUEUE);
  252. break;
  253. case OC_CLEANUP:
  254. //
  255. // Return value is ignored.
  256. //
  257. Prev = NULL;
  258. for(Standalone=StandaloneComponents; Standalone; Standalone=Standalone->Next) {
  259. if(!lstrcmpi(ComponentId,Standalone->ComponentId)) {
  260. if(Prev) {
  261. Prev->Next = Standalone->Next;
  262. } else {
  263. StandaloneComponents = Standalone->Next;
  264. }
  265. pSetupFree(Standalone->ComponentId);
  266. pSetupFree(Standalone);
  267. break;
  268. }
  269. Prev = Standalone;
  270. }
  271. break;
  272. default:
  273. //
  274. // Return something sane.
  275. //
  276. d = 0;
  277. break;
  278. }
  279. return(d);
  280. }
  281. DWORD
  282. RunStandaloneCmd(
  283. IN PSTANDALONE_COMP Standalone,
  284. IN LPCTSTR Description,
  285. IN LPCTSTR cmd
  286. )
  287. {
  288. STARTUPINFO StartupInfo;
  289. PROCESS_INFORMATION ProcessInfo;
  290. TCHAR ExePath[3*MAX_PATH];
  291. DWORD ExitCode;
  292. BOOL b;
  293. ZeroMemory(&StartupInfo,sizeof(STARTUPINFO));
  294. ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION));
  295. StartupInfo.cb = sizeof(STARTUPINFO);
  296. lstrcpyn(ExePath,cmd,3*MAX_PATH);
  297. pOcExternalProgressIndicator(Standalone->HelperRoutines.OcManagerContext,TRUE);
  298. // We will try two times to invoke the external setup. For both attempt the Current
  299. // Directory is set the same directory of where the suite.inf file is located.
  300. // In the first attempt we invoke the command line as we find it from the Standalone
  301. // inf file. An for almost all cases this will work. If we fail in that invokcation we
  302. // ask the suite dll for a "Needs Media" can allow them to tell us where the Standalone exe is.
  303. // This accounts the two following form of commands
  304. // InstalledCmd = "wpie15-x86.exe /Q:A /R:NG"
  305. // UninstallCmd = "RunDll32 ADVPACK.DLL,LaunchINFSection %17%\enuwpie.inf,WebPostUninstall,5"
  306. // Where Wpie15-x86.exe will be found in the Current Directory, and if it's not we will ask the
  307. // suite to provide it. (Web Download) or in the second case where a system dll must be executed
  308. // to uninstall the product. What's not covered here is if we fail to do a createProcess on the
  309. // second form of command.
  310. b = FALSE;
  311. while( ! b) {
  312. b = CreateProcess(
  313. NULL,
  314. ExePath,
  315. NULL,
  316. NULL,
  317. FALSE,
  318. 0,
  319. NULL,
  320. NULL, // Sysocmgr set CD to sourcedir
  321. &StartupInfo,
  322. &ProcessInfo
  323. );
  324. // If we failed to start the external setup, try asking the suite where
  325. // to find this
  326. if ( ! b) {
  327. if ( ! CheckIfExistAndAskForMedia(Standalone, ExePath, Description)) {
  328. // if the Suite could not locate the exe thengive up
  329. break;
  330. }
  331. }
  332. }
  333. if (!b) {
  334. pOcExternalProgressIndicator(Standalone->HelperRoutines.OcManagerContext,FALSE);
  335. return GetLastError();
  336. }
  337. CloseHandle(ProcessInfo.hThread);
  338. WaitOnApp(ProcessInfo.hProcess,&ExitCode);
  339. CloseHandle(ProcessInfo.hProcess);
  340. pOcExternalProgressIndicator(Standalone->HelperRoutines.OcManagerContext,FALSE);
  341. return NO_ERROR;
  342. }
  343. DWORD
  344. InvokeStandAloneInstaller(
  345. IN LPCTSTR ComponentId,
  346. IN BOOL PreQueueCommit
  347. )
  348. {
  349. PSTANDALONE_COMP Standalone;
  350. BOOL OldState,NewState;
  351. LPCTSTR Key;
  352. INFCONTEXT Context;
  353. LPCTSTR CmdLine;
  354. TCHAR CurDir[MAX_PATH];
  355. BOOL b;
  356. LPCTSTR Description;
  357. TCHAR Text[150];
  358. TCHAR Text2[350];
  359. TCHAR *p;
  360. DWORD ExitCode;
  361. DWORD d;
  362. DWORD dSetupMode;
  363. //
  364. // Find the component.
  365. //
  366. for(Standalone=StandaloneComponents; Standalone; Standalone=Standalone->Next) {
  367. if(!lstrcmpi(ComponentId,Standalone->ComponentId)) {
  368. break;
  369. }
  370. }
  371. if(!Standalone) {
  372. d = NO_ERROR;
  373. goto c0;
  374. }
  375. //
  376. // Determine whether this component wants to be invoked pre or post-queue.
  377. // If this doesn't match the notification we're processing then bail.
  378. //
  379. b = FALSE;
  380. if(SetupFindFirstLine(Standalone->Inf,ComponentId,TEXT("InvokeBeforeQueueCommit"),&Context)
  381. && SetupGetIntField(&Context,1,&d)) {
  382. b = (d != 0);
  383. }
  384. if((b == FALSE) != (PreQueueCommit == FALSE)) {
  385. d = NO_ERROR;
  386. goto c0;
  387. }
  388. OldState = Standalone->HelperRoutines.QuerySelectionState(
  389. Standalone->HelperRoutines.OcManagerContext,
  390. ComponentId,
  391. OCSELSTATETYPE_ORIGINAL
  392. );
  393. NewState = Standalone->HelperRoutines.QuerySelectionState(
  394. Standalone->HelperRoutines.OcManagerContext,
  395. ComponentId,
  396. OCSELSTATETYPE_CURRENT
  397. );
  398. dSetupMode = Standalone->HelperRoutines.GetSetupMode(
  399. Standalone->HelperRoutines.OcManagerContext);
  400. // Qualify this setup mode and see if we do anything
  401. // if no change in state
  402. // SETUPMODE_UPGRADE
  403. // SETUPMODE_UPGRADEONLY
  404. // SETUPMODE_ADDEXTRACOMPS
  405. //
  406. // SETUPMODE_MAINTANENCE
  407. // SETUPMODE_ADDREMOVE
  408. // SETUPMODE_REINSTALL
  409. // SETUPMODE_REMOVEALL
  410. // SETUPMODE_FRESH
  411. d = NO_ERROR;
  412. if ( NewState == OldState ) {
  413. // no change in slected state What we do depends on the secondary setup modes
  414. // if Setupmode is AddRemove or Removeall then Skip this
  415. if ( NewState == 0) {
  416. goto c0; // do nothing
  417. }
  418. // Mask off Public mode bits
  419. //
  420. dSetupMode &= SETUPMODE_PRIVATE_MASK;
  421. if ( dSetupMode == SETUPMODE_ADDREMOVE || dSetupMode == SETUPMODE_REMOVEALL ) {
  422. goto c0; // do nothing
  423. }
  424. // What remains here is NewState=1
  425. // and Reinstall and Upgrade
  426. }
  427. Description = NULL;
  428. if(SetupFindFirstLine(Standalone->Inf,ComponentId,TEXT("OptionDesc"),&Context)) {
  429. Description = pSetupGetField(&Context,1);
  430. }
  431. if(Description) {
  432. LoadString(
  433. MyModuleHandle,
  434. OldState ? (NewState ? IDS_EXTERNAL_UPGRADE : IDS_EXTERNAL_UNINST)
  435. : (NewState ? IDS_EXTERNAL_INST : IDS_EXTERNAL_EXAMINE),
  436. Text,
  437. sizeof(Text)/sizeof(TCHAR)
  438. );
  439. wsprintf(Text2,Text,Description);
  440. Standalone->HelperRoutines.SetProgressText(
  441. Standalone->HelperRoutines.OcManagerContext,
  442. Text2
  443. );
  444. } else {
  445. Standalone->HelperRoutines.SetProgressText(
  446. Standalone->HelperRoutines.OcManagerContext,
  447. TEXT("")
  448. );
  449. }
  450. if(OldState == NewState) {
  451. Key = OldState ? TEXT("InstalledCmd") : TEXT("UninstalledCmd");
  452. } else {
  453. Key = OldState ? TEXT("UninstallCmd") : TEXT("InstallCmd");
  454. }
  455. d = NO_ERROR;
  456. if(!SetupFindFirstLine(Standalone->Inf,ComponentId,Key,&Context))
  457. goto c0;
  458. // The current Directory to the Suite's Inf Path, with Initial installs "-N" option
  459. // this may on the CD, with Mainatiance mode it will be the %systemroot%\system32\setup
  460. SetSuiteCurrentDir(Standalone);
  461. do {
  462. if (!(CmdLine = pSetupGetField(&Context,1)))
  463. break;
  464. d = RunStandaloneCmd(Standalone, Description, CmdLine);
  465. if (d != NO_ERROR)
  466. break;
  467. } while (SetupFindNextMatchLine(&Context,Key,&Context));
  468. c0:
  469. Standalone->HelperRoutines.TickGauge(
  470. Standalone->HelperRoutines.OcManagerContext
  471. );
  472. return d;
  473. }
  474. DWORD
  475. WaitOnApp(
  476. IN HANDLE Process,
  477. OUT PDWORD ExitCode
  478. )
  479. {
  480. DWORD dw;
  481. BOOL Done;
  482. MSG msg;
  483. //
  484. // Process any messages that may already be in the queue.
  485. //
  486. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  487. DispatchMessage(&msg);
  488. }
  489. //
  490. // Wait for process to terminate or more messages in the queue.
  491. //
  492. Done = FALSE;
  493. do {
  494. switch(MsgWaitForMultipleObjects(1,&Process,FALSE,INFINITE,QS_ALLINPUT)) {
  495. case WAIT_OBJECT_0:
  496. //
  497. // Process has terminated.
  498. //
  499. dw = GetExitCodeProcess(Process,ExitCode) ? NO_ERROR : GetLastError();
  500. Done = TRUE;
  501. break;
  502. case WAIT_OBJECT_0+1:
  503. //
  504. // Messages in the queue.
  505. //
  506. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  507. DispatchMessage(&msg);
  508. }
  509. break;
  510. default:
  511. //
  512. // Error.
  513. //
  514. dw = GetLastError();
  515. Done = TRUE;
  516. break;
  517. }
  518. } while(!Done);
  519. return(dw);
  520. }